From 7c127c8f6435a6e571bc8a261eaeadbb8b057c2d Mon Sep 17 00:00:00 2001 From: Joseph Schultz Date: Fri, 23 Dec 2022 16:52:20 -0600 Subject: [PATCH] Begin C# Documentation based off Flutter v1 docs --- apps/docs/components/CodeBlock/CodeBlock.tsx | 4 +- .../Navigation/NavigationMenu/HomeMenu.tsx | 6 + .../NavigationMenu.constants.ts | 35 + .../NavigationMenu/NavigationMenu.tsx | 17 + apps/docs/data/nav/supabase-csharp/v0.ts | 134 + apps/docs/data/nonGeneratedReferencePages.ts | 4 +- apps/docs/docs/ref/csharp/initialization.mdx | 67 + apps/docs/docs/ref/csharp/installing.mdx | 33 + apps/docs/docs/ref/csharp/introduction.mdx | 20 + apps/docs/docs/ref/csharp/release-notes.mdx | 6 + .../docs/docs/ref/csharp/v0/release-notes.mdx | 6 + apps/docs/layouts/SiteLayout.tsx | 4 + apps/docs/middleware.ts | 2 +- apps/docs/package.json | 8 +- .../docs/pages/reference/csharp/[...slug].tsx | 21 + .../reference/csharp/crawlers/[...slug].tsx | 43 + .../pages/reference/csharp/v0/[...slug].tsx | 21 + .../csharp/v0/crawlers/[...slug].tsx | 42 + apps/docs/public/img/icons/csharp.png | Bin 0 -> 6935 bytes .../public/img/icons/menu/c-sharp-icon.svg | 9 + .../img/icons/menu/reference-csharp.svg | 9 + package-lock.json | 17 + spec/common-client-libs-sections.json | 130 +- spec/supabase_csharp_v0.yml | 2388 +++++++++++++++++ 24 files changed, 2956 insertions(+), 70 deletions(-) create mode 100644 apps/docs/data/nav/supabase-csharp/v0.ts create mode 100644 apps/docs/docs/ref/csharp/initialization.mdx create mode 100644 apps/docs/docs/ref/csharp/installing.mdx create mode 100644 apps/docs/docs/ref/csharp/introduction.mdx create mode 100644 apps/docs/docs/ref/csharp/release-notes.mdx create mode 100644 apps/docs/docs/ref/csharp/v0/release-notes.mdx create mode 100644 apps/docs/pages/reference/csharp/[...slug].tsx create mode 100644 apps/docs/pages/reference/csharp/crawlers/[...slug].tsx create mode 100644 apps/docs/pages/reference/csharp/v0/[...slug].tsx create mode 100644 apps/docs/pages/reference/csharp/v0/crawlers/[...slug].tsx create mode 100644 apps/docs/public/img/icons/csharp.png create mode 100644 apps/docs/public/img/icons/menu/c-sharp-icon.svg create mode 100644 apps/docs/public/img/icons/menu/reference-csharp.svg create mode 100644 spec/supabase_csharp_v0.yml diff --git a/apps/docs/components/CodeBlock/CodeBlock.tsx b/apps/docs/components/CodeBlock/CodeBlock.tsx index f4e962bb2a..c29120c7bf 100644 --- a/apps/docs/components/CodeBlock/CodeBlock.tsx +++ b/apps/docs/components/CodeBlock/CodeBlock.tsx @@ -6,6 +6,7 @@ import { Button, IconCheck, IconCopy } from 'ui' import js from 'react-syntax-highlighter/dist/cjs/languages/hljs/javascript' import ts from 'react-syntax-highlighter/dist/cjs/languages/hljs/typescript' +import csharp from 'react-syntax-highlighter/dist/cjs/languages/hljs/csharp' import py from 'react-syntax-highlighter/dist/cjs/languages/hljs/python' import sql from 'react-syntax-highlighter/dist/cjs/languages/hljs/sql' import bash from 'react-syntax-highlighter/dist/cjs/languages/hljs/bash' @@ -17,7 +18,7 @@ import { useTheme } from 'common/Providers' interface Props { title?: string - language: 'js' | 'jsx' | 'sql' | 'py' | 'bash' | 'ts' | 'dart' | 'json' + language: 'js' | 'jsx' | 'sql' | 'py' | 'bash' | 'ts' | 'dart' | 'json' | 'csharp' linesToHighlight?: number[] hideCopy?: boolean hideLineNumbers?: boolean @@ -62,6 +63,7 @@ const CodeBlock: FC = ({ SyntaxHighlighter.registerLanguage('sql', sql) SyntaxHighlighter.registerLanguage('bash', bash) SyntaxHighlighter.registerLanguage('dart', dart) + SyntaxHighlighter.registerLanguage('csharp', csharp) SyntaxHighlighter.registerLanguage('json', json) const large = false diff --git a/apps/docs/components/Navigation/NavigationMenu/HomeMenu.tsx b/apps/docs/components/Navigation/NavigationMenu/HomeMenu.tsx index 9a1f712f85..dcbafaa330 100644 --- a/apps/docs/components/Navigation/NavigationMenu/HomeMenu.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/HomeMenu.tsx @@ -94,6 +94,12 @@ const home = [ href: '/reference/dart/introduction', level: 'reference_dart', }, + { + label: 'C#', + icon: '/img/icons/menu/reference-csharp', + href: '/reference/csharp/introduction', + level: 'reference_csharp', + }, { label: 'Tools Reference', }, diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index d9837f2ea6..ff7a0b3aa6 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -22,6 +22,12 @@ export const REFERENCES: References = { versions: ['v1', 'v0'], icon: '/docs/img/libraries/flutter-icon.svg', }, + csharp: { + name: 'C#', + library: 'supabase-csharp', + versions: ['v0'], + icon: '/docs/img/libraries/c-sharp-icon.svg', + }, cli: { name: 'CLI', library: undefined, @@ -697,6 +703,20 @@ export const reference = { items: [], icon: '/img/icons/menu/reference-dart', }, + { + name: 'supabase-csharp', + url: '/reference/csharp/start', + level: 'reference_csharp', + items: [], + icon: '/img/icons/menu/reference-csharp', + }, + { + name: 'supbase-python', + url: '/reference/python/start', + level: 'reference_python', + items: [], + icon: 'docs/img/icons/javascript.svg', + }, // { // name: 'supabase-python', // url: '/reference/python/start', @@ -746,6 +766,7 @@ export const reference_dart_v0 = { url: '/guides/reference/dart', parent: '/reference', } + export const reference_dart_v1 = { icon: 'reference-dart', title: 'dart', @@ -753,6 +774,13 @@ export const reference_dart_v1 = { parent: '/reference', } +export const reference_csharp_v0 = { + icon: 'reference-csharp', + title: 'c#', + url: 'guides/reference/csharp', + parent: '/reference', +} + export const reference_cli = { icon: 'reference-cli', title: 'Supabase CLI', @@ -846,6 +874,13 @@ export const references = [ icon: '/docs/img/icons/dart-icon.svg', url: '/reference/dart/start', }, + { + label: 'supabase-csharp', + versions: ['v0'], + description: 'something about the reference', + icon: '/docs/img/icons/c-sharp-icon.svg', + url: '/reference/csharp/start', + }, ], }, { diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx index cfb4d87b14..29bfc21edf 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx @@ -11,6 +11,8 @@ import spec_js_v1 from '~/../../spec/supabase_js_v1.yml' assert { type: 'yml' } import spec_dart_v1 from '~/../../spec/supabase_dart_v1.yml' assert { type: 'yml' } // @ts-expect-error import spec_dart_v0 from '~/../../spec/supabase_dart_v0.yml' assert { type: 'yml' } +// @ts-expect-error +import spec_csharp_v0 from '~/../../spec/supabase_csharp_v0.yml' assert { type: 'yml' } // import { gen_v3 } from '~/lib/refGenerator/helpers' import apiCommonSections from '~/../../spec/common-api-sections.json' import cliCommonSections from '~/../../spec/common-cli-sections.json' @@ -47,6 +49,7 @@ export type RefIdOptions = | 'reference_javascript_v2' | 'reference_dart_v0' | 'reference_dart_v1' + | 'reference_csharp_v0' | 'reference_cli' | 'reference_api' | 'reference_self_hosting_auth' @@ -56,6 +59,7 @@ export type RefIdOptions = export type RefKeyOptions = | 'javascript' | 'dart' + | 'csharp' | 'cli' | 'api' | 'self-hosting-auth' @@ -126,6 +130,10 @@ const NavigationMenu = () => { case url.includes(`/docs/reference/dart`) && url: menuState.setMenuLevelId('reference_dart_v1') break + // C# v0 (latest) + case url.includes(`/docs/reference/csharp`) && url: + menuState.setMenuLevelId('reference_csharp_v0') + break case url.includes(`/docs/reference/cli`) && url: menuState.setMenuLevelId('reference_cli') break @@ -175,6 +183,7 @@ const NavigationMenu = () => { const isReference_Javascript_V2 = 'reference_javascript_v2' === level const isReference_Dart_V0 = 'reference_dart_v0' === level const isReference_Dart_V1 = 'reference_dart_v1' === level + const isReference_Csharp_V0 = 'reference_csharp_v0' === level const isReference_Cli = 'reference_cli' === level const isReference_Api = 'reference_api' === level const isReference_Self_Hosting_Auth = 'reference_self_hosting_auth' === level @@ -229,6 +238,14 @@ const NavigationMenu = () => { lib="dart" spec={spec_dart_v1} /> + {/* // Tools */} + + +Initializing a new client is pretty straightforward. Find your project url and public key from the +admin panel and pass it into your client initialization function. + + + + + + + + + ```csharp + var url = Environment.GetEnvironmentVariable("SUPABASE_URL"); + var key = Environment.GetEnvironmentVariable("SUPABASE_KEY"); + + var options = new Supabase.SupabaseOptions + { + AutoConnectRealtime = true + }; + + var supabase = new Supabase.Client(url, key, options); + await supabase.InitializeAsync(); + ``` + + + + + + ```csharp + public static MauiApp CreateMauiApp() + { + // ... + var builder = MauiApp.CreateBuilder(); + + var url = Environment.GetEnvironmentVariable("SUPABASE_URL"); + var key = Environment.GetEnvironmentVariable("SUPABASE_KEY"); + var options = new SupabaseOptions + { + AutoRefreshToken = true, + AutoConnectRealtime = true, + SessionHandler = new SupabaseSessionHandler() + }; + + // Note the creation as a singleton. + builder.Services.AddSingleton(provider => new Supabase.Client(url, key, options)); + } + ``` + + + + + + diff --git a/apps/docs/docs/ref/csharp/installing.mdx b/apps/docs/docs/ref/csharp/installing.mdx new file mode 100644 index 0000000000..e274af8e28 --- /dev/null +++ b/apps/docs/docs/ref/csharp/installing.mdx @@ -0,0 +1,33 @@ +--- +id: installing +title: 'Installing & Initialization' +slug: installing +custom_edit_url: https://github.com/supabase/supabase/edit/master/web/spec/supabase.yml +--- + +### Install from NuGet + + + + + You can install Supabase package from [nuget.org](https://www.nuget.org/packages/supabase-csharp/) + + + + + + + + + ```sh Terminal + dotnet add package supabase-csharp + ``` + + + + + + diff --git a/apps/docs/docs/ref/csharp/introduction.mdx b/apps/docs/docs/ref/csharp/introduction.mdx new file mode 100644 index 0000000000..6c69931493 --- /dev/null +++ b/apps/docs/docs/ref/csharp/introduction.mdx @@ -0,0 +1,20 @@ +--- +id: introduction +title: Introduction +hideTitle: true +--- + +
+ +
+

C# Client Library

+

supabase-csharp

+
+
+ +
+ This reference documents every object and method available in Supabase's C# + library, [supabase-csharp](https://www.nuget.org/packages/supabase-csharp). You can + use supabase-csharp to interact with your Postgres database, listen to database changes, invoke + Deno Edge Functions, build login and user management functionality, and manage large files. +
diff --git a/apps/docs/docs/ref/csharp/release-notes.mdx b/apps/docs/docs/ref/csharp/release-notes.mdx new file mode 100644 index 0000000000..b5e0e21891 --- /dev/null +++ b/apps/docs/docs/ref/csharp/release-notes.mdx @@ -0,0 +1,6 @@ +--- +id: release-notes +title: Release Notes +--- + +## dart this is the release notes file. diff --git a/apps/docs/docs/ref/csharp/v0/release-notes.mdx b/apps/docs/docs/ref/csharp/v0/release-notes.mdx new file mode 100644 index 0000000000..2ecb0ef399 --- /dev/null +++ b/apps/docs/docs/ref/csharp/v0/release-notes.mdx @@ -0,0 +1,6 @@ +--- +id: release-notes +title: Release Notes +--- + +## dart v0 this is the release notes file. diff --git a/apps/docs/layouts/SiteLayout.tsx b/apps/docs/layouts/SiteLayout.tsx index eb017378ef..3bf76800ee 100644 --- a/apps/docs/layouts/SiteLayout.tsx +++ b/apps/docs/layouts/SiteLayout.tsx @@ -71,6 +71,10 @@ const levelsData = { icon: '/docs/img/icons/menu/reference-dart', name: 'Dart Reference v0.0', }, + reference_csharp_v0: { + icon: '/docs/img/icons/menu/reference-csharp', + name: 'C# Reference v0.0', + }, reference_cli: { icon: '/docs/img/icons/menu/reference-cli', name: 'CLI Reference', diff --git a/apps/docs/middleware.ts b/apps/docs/middleware.ts index d13ce4a442..254486ccf0 100644 --- a/apps/docs/middleware.ts +++ b/apps/docs/middleware.ts @@ -3,7 +3,7 @@ import type { NextRequest } from 'next/server' import isbot from 'isbot' export function middleware(request: NextRequest) { - const specs = ['javascript', 'dart'] + const specs = ['javascript', 'dart', 'csharp'] let version = '' if (request.url.includes('/v1/')) { diff --git a/apps/docs/package.json b/apps/docs/package.json index 2abc71adb5..009c9759c9 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -9,7 +9,7 @@ "lint": "next lint", "build:sitemap": "node ./internals/generate-sitemap.mjs", "postbuild": "ts-node ./scripts/build-search.ts && node ./internals/generate-sitemap.mjs", - "generate:all": "npm-run-all --parallel gen:api gen:cli gen:gotrue gen:storage gen:supabase-dart:v0 gen:supabase-dart:v1 gen:supabase-js:v1 gen:supabase-js:v2 gen:realtime", + "generate:all": "npm-run-all --parallel gen:api gen:cli gen:gotrue gen:storage gen:supabase-dart:v0 gen:supabase-dart:v1 gen:supabase-csharp:v0 gen:supabase-js:v1 gen:supabase-js:v2 gen:realtime", "gen:api": "npm-run-all gen:api:usage", "gen:api:usage": "ts-node ./generator/index.ts gen --type api --url https://api.supabase.com --input ../../spec/transforms/api_v0_openapi_deparsed.json --output ./docs/reference/api/generated/usage.mdx", "gen:cli": "npm-run-all gen:cli:commands gen:cli:config", @@ -25,6 +25,8 @@ "gen:supabase-dart:v0:ref": "ts-node ./generator/index.ts gen --type legacy --input ../../spec/supabase_dart_v0.yml --output ./docs/reference/dart/v0/generated", "gen:supabase-dart:v1": "npm-run-all gen:supabase-dart:v1:ref", "gen:supabase-dart:v1:ref": "ts-node ./generator/index.ts gen --type legacy --input ../../spec/supabase_dart_v1.yml --output ./docs/reference/dart/generated", + "gen:supabase-csharp:v0": "npm-run-all gen:supabase-dart:v1:ref", + "gen:supabase-csharp:v0:ref": "ts-node ./generator/index.ts gen --type legacy --input ../../spec/supabase_csharp_v1.yml --output ./docs/reference/csharp/generated", "gen:supabase-js:v1": "npm-run-all gen:supabase-js:v1:ref", "gen:supabase-js:v1:ref": "ts-node ./generator/index.ts gen --type legacy --input ../../spec/supabase_js_v1.yml --output ./docs/reference/javascript/v1/generated", "gen:supabase-js:v2": "npm-run-all gen:supabase-js:v2:ref", @@ -42,6 +44,7 @@ "@radix-ui/react-accordion": "^1.0.1", "algoliasearch": "^4.14.2", "babel": "^6.23.0", + "clsx": "^1.2.1", "common": "*", "config": "*", "gray-matter": "^4.0.3", @@ -63,6 +66,7 @@ "react-intersection-observer": "^9.4.0", "react-markdown": "^8.0.3", "react-syntax-highlighter": "^15.3.1", + "rehype-slug": "^5.1.0", "remark": "^14.0.2", "remark-admonitions": "^1.2.1", "remark-gfm": "^3.0.1", @@ -72,10 +76,10 @@ "valtio": "^1.7.6" }, "devDependencies": { - "dotenv": "^16.0.3", "@types/node": "^17.0.12", "@types/react": "17.0.39", "config": "*", + "dotenv": "^16.0.3", "ejs": "^3.1.8", "eslint": "8.9.0", "globby": "^12.0.2", diff --git a/apps/docs/pages/reference/csharp/[...slug].tsx b/apps/docs/pages/reference/csharp/[...slug].tsx new file mode 100644 index 0000000000..04e731b5ae --- /dev/null +++ b/apps/docs/pages/reference/csharp/[...slug].tsx @@ -0,0 +1,21 @@ +import clientLibsCommonSections from '~/../../spec/common-client-libs-sections.json' +// @ts-expect-error +import spec from '~/../../spec/supabase_csharp_v0.yml' assert { type: 'yml' } +import RefSectionHandler from '~/components/reference/RefSectionHandler' +import { flattenSections } from '~/lib/helpers' +import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' +import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' + +const sections = flattenSections(clientLibsCommonSections) + +export default function JSReference(props) { + return +} + +export async function getStaticProps({ params }: { params: { slug: string[] } }) { + return handleRefStaticProps(sections, params, '/csharp', '/csharp') +} + +export function getStaticPaths() { + return handleRefGetStaticPaths() +} diff --git a/apps/docs/pages/reference/csharp/crawlers/[...slug].tsx b/apps/docs/pages/reference/csharp/crawlers/[...slug].tsx new file mode 100644 index 0000000000..c12f3cabbf --- /dev/null +++ b/apps/docs/pages/reference/csharp/crawlers/[...slug].tsx @@ -0,0 +1,43 @@ +import clientLibsCommonSections from '~/../../spec/common-client-libs-sections.json' +import typeSpec from '~/../../spec/enrichments/tsdoc_v2/combined.json' +// @ts-expect-error +import spec from '~/../../spec/supabase_dart_v1.yml' assert { type: 'yml' } +import RefSectionHandler from '~/components/reference/RefSectionHandler' +import { flattenSections } from '~/lib/helpers' +import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' +import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' +import { useRouter } from 'next/router' +import RefSEO from '~/components/reference/RefSEO' + +const sections = flattenSections(clientLibsCommonSections) + +export default function JSReference(props) { + const router = useRouter() + const slug = router.query.slug[0] + const filteredSection = sections.filter((section) => section.id === slug) + + const pageTitle = filteredSection[0]?.title + ? `${filteredSection[0]?.title} | Supabase` + : 'Supabase' + + return ( + <> + + + + + ) +} + +export async function getStaticProps({ params }: { params: { slug: string[] } }) { + return handleRefStaticProps(sections, params, '/dart', '/dart') +} + +export function getStaticPaths() { + return handleRefGetStaticPaths() +} diff --git a/apps/docs/pages/reference/csharp/v0/[...slug].tsx b/apps/docs/pages/reference/csharp/v0/[...slug].tsx new file mode 100644 index 0000000000..a76c3f386b --- /dev/null +++ b/apps/docs/pages/reference/csharp/v0/[...slug].tsx @@ -0,0 +1,21 @@ +import clientLibsCommonSections from '~/../../spec/common-client-libs-sections.json' +// @ts-expect-error +import spec from '~/../../spec/supabase_csharp_v0.yml' assert { type: 'yml' } +import RefSectionHandler from '~/components/reference/RefSectionHandler' +import { flattenSections } from '~/lib/helpers' +import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' +import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' + +const sections = flattenSections(clientLibsCommonSections) + +export default function JSReference(props) { + return +} + +export async function getStaticProps({ params }: { params: { slug: string[] } }) { + return handleRefStaticProps(sections, params, '/csharp/v0', '/csharp/v0') +} + +export function getStaticPaths() { + return handleRefGetStaticPaths() +} diff --git a/apps/docs/pages/reference/csharp/v0/crawlers/[...slug].tsx b/apps/docs/pages/reference/csharp/v0/crawlers/[...slug].tsx new file mode 100644 index 0000000000..4c78342f55 --- /dev/null +++ b/apps/docs/pages/reference/csharp/v0/crawlers/[...slug].tsx @@ -0,0 +1,42 @@ +import clientLibsCommonSections from '~/../../spec/common-client-libs-sections.json' +import typeSpec from '~/../../spec/enrichments/tsdoc_v2/combined.json' +// @ts-expect-error +import spec from '~/../../spec/supabase_csharp_v0.yml' assert { type: 'yml' } +import RefSectionHandler from '~/components/reference/RefSectionHandler' +import { flattenSections } from '~/lib/helpers' +import handleRefGetStaticPaths from '~/lib/mdx/handleRefStaticPaths' +import handleRefStaticProps from '~/lib/mdx/handleRefStaticProps' +import { useRouter } from 'next/router' +import RefSEO from '~/components/reference/RefSEO' + +const sections = flattenSections(clientLibsCommonSections) + +export default function JSReference(props) { + const router = useRouter() + const slug = router.query.slug[0] + const filteredSection = sections.filter((section) => section.id === slug) + + const pageTitle = filteredSection[0]?.title + ? `${filteredSection[0]?.title} | Supabase` + : 'Supabase' + return ( + <> + + + + + ) +} + +export async function getStaticProps({ params }: { params: { slug: string[] } }) { + return handleRefStaticProps(sections, params, '/csharp/v0', '/csharp/v0') +} + +export function getStaticPaths() { + return handleRefGetStaticPaths() +} diff --git a/apps/docs/public/img/icons/csharp.png b/apps/docs/public/img/icons/csharp.png new file mode 100644 index 0000000000000000000000000000000000000000..37f9fd725faa644a840459ea4a92567978984a10 GIT binary patch literal 6935 zcmaiZdpy(a|NqReA#6@lQ}f;&ZZz8*+8l>riX4(C9mY1~w3%~sQ^F){q83r^&ZR<$ zQZZwcbh_^lpORyr>UKz!QhncaA3mS&=kxvj{#E`W_>IRIO%y@}pjS9U}sBQ2i2DQ#mwSXxvVl?6CCD%+>n zf&yaL2~2ECOmr;YHpKy0mTL<>FHKtj*kzK0C|F(740|2LJ$Z>>t7tA~}CckLCZde9#dVONa%DK(zQ*a&}7O z|3SWl{0BKVA}%409}&m>YXSeJ;xG6=7(w^_ca{_;_rDQ)d;h=5V`Bbo8TMkH7+_XeiNA5YzN?nw!dOwyNr3qu|UXj*^s{>Pghsp_&82vG>Gy2 zJzTJ!Zmu>Ys*TNBGU109FmSdYZzLy`&P)KQ$V4zdN#wO;QUJ-y*3!n7L|jX>u_Y3h zB`;Hh^}u2#F#mt_OIeMz2RXdGZ5fgLgt++B<*6U3zKPBI@%H02I&wM3vDoEE+cLwJ z{O$m7fox{N(I{?lcP9zwiRIKk(_F_o{5|QvDj(>3^ zN3cO@|M%J~{;% zbzJj{Rh|v^lJZfj?&>TmM3-Lor>`%oGqUk|m})FnRD0IxU}hngy>%HTpbeYdcOo|(?;!DJDJ};^i}nZ?umcu>^}0| z!R#IXGyJ6Y!i80RPMI62FRw1DH1tO(msfJHfjb6*%LwK}AS#+mLk@DR0u6y^rF+ty z15zq}|HnWY;8B(_+rvM)ko;p;0&TmlDlk)IM z3nF;mCrx4Yh`9>pFty+c9d)N3KkZg(GAY0}f9!py1QBjtftwa@DV*M4TK!rL^^Nt@ z&`vXjCE-5@!TPdiN@@EjbripJAAGR*Rd}!@rGQZfR0XmYqmGiMct|v zk%+K#sAr(!k;B;}^(;Kjb%Sa3(IX6zfN7}Ucgf8}(36QeX7bFin9iXfJhgfaM0A!3 z!UNrlE2f8G5pL*SBN3gcA>OF5An+xZyb3dAj%sGHboR@%syp?7t_a1#lXT%lm`JF) zstt}yM&N%zTiry_(~#@a$RP;^`2~RJ!>)4?8_{~+*vJR8$A^jJ62_B!=W2u>UODTO zf~%ChkCEWgwOKKDL$=V1E~-~mJ(~vvBkiex%p0{0d99EKTr(8SHMO)Oa32hcuQxR+AbQH&{ zsW}bN4Rwy0#E!%>_aW&)CB7ZQp)jBzlhH8*z_9r(W?2;v6^=5rvV7?AtE&PP;P+Hs zr#74Fb)Jw2{E;u$E)b#9-V0lxq3}mL=IpwjysRKXKWw5Fv+t6au-8|1 zWAA5ds)iGHTxXPh=42yxT{abZefNd~H2Z#>c)s-@KuZtCiQhY`;ApG$z&l zI`s7;u6OdKdtQ8S z;soc>wPdwl=#Szj%D?8CD-Aw6=Os6@rVZ$&|hfJS>t#ft8Pk6w*)7OVDhP*O~V zW_SEVLF1yu$`p6awv`q71qpM5jUO!ZV%;@6(kgHT@negWuNLSCccj#svI+g_U26QB zH8#=$Y<^Vyoks)W`mt%J2<|_}rwk`FYntuK z_b#qku{v2`@C)TihNME-q#Yfz8ZdY}@<{I@ghLv;Bj4m{(V20E> zwe9`lq^i9Ij(beG-#9#HKHFe=L;(1umY3cdq{bgJ5gn>O^h@Q$z;~yb-6<3obXVtK zeA&*iA)=D1SiG}m`i^}rCFqQwW_;+DJ+4?Zb`e`)U(?Vr#*Oi#atUEcqF(@Zi-!Zjt`hgA_uG zzw4@`Nd4iU3U*GzyI)sIYl$0FGx};iOKVN;t7P=oK9|;FH>ia5UB4-u)+H zt<~6|%mdFN73DUi@y=NR>2)T+Y6r?C9Q~Upso{lw^JE)LI;q$o@aERS7 zoLHQ^FJ417WR7Y{8Acx^x_BqqIr3ERy{E+_+1v0`JD;?ye3uq7yhMyH*dn^BW4ES+ z0`)Q~p2-Wt>cFsyJXIGoGo~jqNQ#6cNlB0^=&TsN4*mT{aHA^i{|bBA`YV+QSnBJuB zz#WqqCH|0%~Da1lW@?`ln~n0QmM^ZT){lt$U{5!#NdhwNulmTgnwD_f;J zjof?ooMwmF#Wk~=OKxn=dJ1bDIQyFb$EG%a-n!7VePPee13Sk~;B$M?7r#EwZQ7b! zMOC|cuN9eSlD4`Y^9EfvlG8s93vLLgh;F1$tIe%2m&-TPkY@QsO{B_d($ zVx47iDFxb6xIA_Y<-UYm|KY7Ak8NL&nidO}ASVMQlZn^4<2}vwq|X-A`PRElgVZO- zZv?)=Fe`kPO|p1@PwfQZhu7gw$uKhVhx>Y(`Jy7qiy>F))g0li$q<3_57%{U+d$J< zZUmjaldH2-rN|(W?(TG;P<6sL)NtIvcv)0)*A#yH$Zu8}VhR-Ysyzua+-U_;pIcsJ ztz6sz$ge=5*I3PF4ly}>mfQO@hkZ+ifeIV>(b89HG4|iAzwoZwBp0p-e!Zs~m`du5 zCLXi%kW3GU##CLtd&|>ZQi)RQL#!U_E!|@_5cIu+lW|_m@#? z!al?v)xXT0U?}g1=9b>r+T;QjmfVp)3TxnkesG6lcl1W#e5>lrAv=#Jf`ra^uWM1` zHGyC~7B<`dE^96G7>&|is3je_vDvOZJwyDmukOL!)Zwnp5aRMyi#^^t~})ZS)P za^e2qGpXHat2m#+$1m#eFx{=F{Y_4?!PVgnyESA8j1}qV*Rbxl*5hXDcoi*7&4c=% z#MIjlqsI&jODHMBwJP6<kGEuZ1KDBv8JW=8?Vv6CBvzE2=m*-1t_ng zv-R+X)7wdVW;Y)@n=j>&a|0ZMlRGZ8A5N^ipegIZ1U0ey)>!K7%%N^QL{S`?zJQZB ziqAF!-Rj>pWLQkZTWbBD@i6_KQS?&!@7laii3ff>?wj6?fWANE|M_l z4z`Q_JXMM3C2?`yJ5N#Pc}YW^cg(NT<#~1Nb9S7!S+ktQUY!?xJKOGnyQgO`CGTP7 zxM86n*go(6-f^SCu3%awSj8tu7F%aEWl(cK%3KqrAp^|u-QntQHDoU4M%`iGcOzw? z<|YNGCm&+5(%Gx%yI?qBAv^cU^7eQ`&D^C+TyTg`{z zis}PZJ?DyY%UXXi6rR!!*Ib)!TXJW0U`}xvOk`K#aSdOXjT2RjnOC2V3x9M{{+{oX zgN*lwW^@dy$YzqUs^ z&2G<`5Zg>uG7iCx>CsHP6`vF0n4oHfL$DlrG~650k_K(Ls_QHf972zZ`z^k^6*WZF z!BW5q=~3h~?IBp%1(?er;cV3&c}`@aqLl-~9OjodnlfM2zjZQWR$jVKdqQwx zt}@xq%3M{57*9<)mY4SX`(k;CKk|6cx9&;Q8?wE%&4@Uc@alxhzxI3AP)Oq|rzhycW`TmO`$^l+z?7 z#JZT_&O$~VnK{~pomR?XSyy+07anVcr)>R3_4l_LxOf^?cdk>+Zi9*5(S^ULDxZbp zgAq9J=7fOsBqQB>$ixt%V!CmD2%8(>Vj^(Sh-}q(e3(HlAue6PP_tN8ey6PE-E^T{ zCK85vPX1-OXa`+bsjAxsH%vwV;9X7*ig6j`?oN*OG7wc56cliVj;_Zq(6z+vL!{%h z_nJ(WQJaT}OOuT=UU@%*0$#HC;aAFgGN4UrOg!M~836(ZIrbEoaQD?=XM#t1h5LJy7{HR#IiIknT$rRl}ziu9>D|u~&@_sw-`7 zI;fTYsYld;5X=9R&#ho*9jwdt*Lr2YL4KXvp;IQ3#4@Fod0Gs=>@Vg>D=SNo{r4cF h*DSh;0`l{xHOjhYgo#D8s-^!~o^BiImtA)4`yajWjm-c6 literal 0 HcmV?d00001 diff --git a/apps/docs/public/img/icons/menu/c-sharp-icon.svg b/apps/docs/public/img/icons/menu/c-sharp-icon.svg new file mode 100644 index 0000000000..40d0375079 --- /dev/null +++ b/apps/docs/public/img/icons/menu/c-sharp-icon.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/apps/docs/public/img/icons/menu/reference-csharp.svg b/apps/docs/public/img/icons/menu/reference-csharp.svg new file mode 100644 index 0000000000..40d0375079 --- /dev/null +++ b/apps/docs/public/img/icons/menu/reference-csharp.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/package-lock.json b/package-lock.json index a623b4950f..04c9896005 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,6 +49,7 @@ "@radix-ui/react-accordion": "^1.0.1", "algoliasearch": "^4.14.2", "babel": "^6.23.0", + "clsx": "^1.2.1", "common": "*", "config": "*", "gray-matter": "^4.0.3", @@ -70,6 +71,7 @@ "react-intersection-observer": "^9.4.0", "react-markdown": "^8.0.3", "react-syntax-highlighter": "^15.3.1", + "rehype-slug": "^5.1.0", "remark": "^14.0.2", "remark-admonitions": "^1.2.1", "remark-gfm": "^3.0.1", @@ -417,6 +419,14 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "apps/docs/node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "engines": { + "node": ">=6" + } + }, "apps/docs/node_modules/eslint": { "version": "8.9.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.9.0.tgz", @@ -49505,6 +49515,7 @@ "@types/react": "17.0.39", "algoliasearch": "^4.14.2", "babel": "^6.23.0", + "clsx": "*", "common": "*", "config": "*", "dotenv": "^16.0.3", @@ -49534,6 +49545,7 @@ "react-intersection-observer": "^9.4.0", "react-markdown": "^8.0.3", "react-syntax-highlighter": "^15.3.1", + "rehype-slug": "^5.1.0", "remark": "^14.0.2", "remark-admonitions": "^1.2.1", "remark-gfm": "^3.0.1", @@ -49735,6 +49747,11 @@ "uri-js": "^4.2.2" } }, + "clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==" + }, "eslint": { "version": "8.9.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.9.0.tgz", diff --git a/spec/common-client-libs-sections.json b/spec/common-client-libs-sections.json index d80a1e8b3f..9478de69da 100644 --- a/spec/common-client-libs-sections.json +++ b/spec/common-client-libs-sections.json @@ -4,14 +4,14 @@ "id": "introduction", "slug": "introduction", "type": "markdown", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "title": "Installing", "id": "installing", "slug": "installing", "type": "markdown", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "title": "Initializing", @@ -28,7 +28,7 @@ }, { "title": "Database", - "libs": ["js", "js_v1", "dart", "dart_v0"], + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"], "items": [ { "id": "select", @@ -36,7 +36,7 @@ "slug": "select", "product": "database", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "insert", @@ -44,7 +44,7 @@ "slug": "insert", "product": "database", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "update", @@ -52,7 +52,7 @@ "slug": "update", "product": "database", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "upsert", @@ -60,7 +60,7 @@ "slug": "upsert", "product": "database", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "delete", @@ -68,7 +68,7 @@ "slug": "delete", "product": "database", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "rpc", @@ -76,7 +76,7 @@ "slug": "rpc", "product": "database", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "using-filters", @@ -85,7 +85,7 @@ "slug": "using-filters", "product": "database", "type": "function", - "libs": ["js", "dart", "dart_v0"], + "libs": ["js", "dart", "dart_v0", "csharp"], "items": [ { "id": "eq", @@ -94,7 +94,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "neq", @@ -103,7 +103,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "gt", @@ -112,7 +112,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "gte", @@ -121,7 +121,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "lt", @@ -130,7 +130,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "lte", @@ -139,7 +139,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "like", @@ -148,7 +148,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "ilike", @@ -157,7 +157,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "is", @@ -166,7 +166,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "in", @@ -175,7 +175,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "contains", @@ -184,7 +184,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "contained-by", @@ -193,7 +193,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "range-gt", @@ -202,7 +202,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "range-gte", @@ -211,7 +211,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "range-lt", @@ -220,7 +220,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "range-lte", @@ -229,7 +229,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "range-adjacent", @@ -238,7 +238,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "overlaps", @@ -247,7 +247,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "text-search", @@ -256,7 +256,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "match", @@ -265,7 +265,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "not", @@ -274,7 +274,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "or", @@ -283,7 +283,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "filter", @@ -292,7 +292,7 @@ "product": "database", "parent": "filters", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] } ] }, @@ -304,7 +304,7 @@ "product": "database", "parent": "modifiers", "type": "function", - "libs": ["js", "dart", "dart_v0"], + "libs": ["js", "dart", "dart_v0", "csharp"], "items": [ { "id": "db-modifiers-select", @@ -322,7 +322,7 @@ "product": "database", "parent": "modifiers", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "limit", @@ -331,7 +331,7 @@ "product": "database", "parent": "modifiers", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "range", @@ -340,7 +340,7 @@ "product": "database", "parent": "modifiers", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "abort-signal", @@ -358,7 +358,7 @@ "product": "database", "parent": "modifiers", "type": "function", - "libs": ["js", "dart", "dart_v0"] + "libs": ["js", "dart", "dart_v0", "csharp"] }, { "id": "maybe-single", @@ -384,7 +384,7 @@ }, { "title": "Auth", - "libs": ["js", "js_v1", "dart", "dart_v0"], + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"], "items": [ { "id": "auth-api", @@ -399,7 +399,7 @@ "slug": "auth-signup", "product": "auth", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "sign-in", @@ -407,7 +407,7 @@ "slug": "auth-signin", "product": "auth", "type": "function", - "libs": ["js_v1", "dart_v0"] + "libs": ["js_v1", "dart_v0", "csharp"] }, { "id": "sign-in-with-provider", @@ -415,7 +415,7 @@ "slug": "auth-signinwithprovider", "product": "auth", "type": "function", - "libs": ["dart_v0"] + "libs": ["dart_v0", "csharp"] }, { "id": "sign-in-with-password", @@ -559,7 +559,7 @@ "slug": "auth-onauthstatechange", "product": "auth", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "reset-password-for-email", @@ -567,7 +567,7 @@ "slug": "auth-resetpasswordforemail", "product": "auth", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "mfa-enroll", @@ -718,7 +718,7 @@ }, { "title": "Functions", - "libs": ["js", "js_v1", "dart", "dart_v0"], + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"], "items": [ { "id": "invoke", @@ -726,13 +726,13 @@ "slug": "auth-admin-invoke", "product": "functions", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] } ] }, { "title": "Realtime", - "libs": ["js", "js_v1", "dart", "dart_v0"], + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"], "items": [ { "id": "stream", @@ -740,7 +740,7 @@ "slug": "stream", "product": "realtime", "type": "function", - "libs": ["dart", "dart_v0"] + "libs": ["dart", "dart_v0", "csharp"] }, { "id": "subscribe", @@ -748,7 +748,7 @@ "slug": "subscribe", "product": "realtime", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "remove-subscription", @@ -756,7 +756,7 @@ "slug": "removesubscription", "product": "realtime", "type": "function", - "libs": ["dart_v0", "js_v1"] + "libs": ["dart_v0", "csharp", "js_v1"] }, { "id": "remove-all-subscriptions", @@ -803,7 +803,7 @@ }, { "title": "Storage", - "libs": ["js", "js_v1", "dart", "dart_v0"], + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"], "items": [ { "id": "create-bucket", @@ -811,7 +811,7 @@ "slug": "storage-createbucket", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "get-bucket", @@ -819,7 +819,7 @@ "slug": "storage-getbucket", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "list-buckets", @@ -827,7 +827,7 @@ "slug": "storage-listbuckets", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "update-bucket", @@ -835,7 +835,7 @@ "slug": "storage-updatebucket", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "delete-bucket", @@ -843,7 +843,7 @@ "slug": "storage-deletebucket", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "empty-bucket", @@ -851,7 +851,7 @@ "slug": "storage-emptybucket", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "from-upload", @@ -859,7 +859,7 @@ "slug": "storage-from-upload", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "from-download", @@ -867,7 +867,7 @@ "slug": "storage-from-download", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "from-list", @@ -875,7 +875,7 @@ "slug": "storage-from-list", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "from-update", @@ -883,7 +883,7 @@ "slug": "storage-from-update", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "from-move", @@ -891,7 +891,7 @@ "slug": "storage-from-move", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "from-copy", @@ -907,7 +907,7 @@ "slug": "storage-from-remove", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "from-create-signed-url", @@ -915,7 +915,7 @@ "slug": "storage-from-createsignedurl", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] }, { "id": "from-create-signed-urls", @@ -931,7 +931,7 @@ "slug": "storage-from-getpublicurl", "product": "storage", "type": "function", - "libs": ["js", "js_v1", "dart", "dart_v0"] + "libs": ["js", "js_v1", "dart", "dart_v0", "csharp"] } ] }, diff --git a/spec/supabase_csharp_v0.yml b/spec/supabase_csharp_v0.yml new file mode 100644 index 0000000000..f9e6c805d8 --- /dev/null +++ b/spec/supabase_csharp_v0.yml @@ -0,0 +1,2388 @@ +openref: 0.1 + +info: + id: reference/csharp + title: Getting started + description: | + + Supabase C#. + + definition: ../../spec/enrichments/tsdoc_v2/combined.json + slugPrefix: '/' + specUrl: https://github.com/supabase/supabase/edit/master/spec/supabase_csharp_v0.yml + libraries: + - name: 'C#' + id: 'csharp' + version: '0.0.1' + +functions: + - id: sign-up + title: 'SignUp()' + description: | + Creates a new user. + notes: | + - By default, the user needs to verify their email address before logging in. To turn this off, disable **Confirm email** in [your project](https://app.supabase.com/project/_/auth/providers). + - **Confirm email** determines if users need to confirm their email address after signing up. + - If **Confirm email** is enabled, a `user` is returned but `session` is null. + - If **Confirm email** is disabled, both a `user` and a `session` are returned. + - When the user confirms their email address, they are redirected to the [`SITE_URL`](https://supabase.com/docs/reference/auth/config#site_url) by default. You can modify your `SITE_URL` or add additional redirect URLs in [your project](https://app.supabase.com/project/_/auth/url-configuration). + - If SignUp() is called for an existing confirmed user: + - If **Confirm email** is enabled in [your project](https://app.supabase.com/project/_/auth/providers), an obfuscated/fake user object is returned. + - If **Confirm email** is disabled, the error message, `User already registered` is returned. + examples: + - id: sign-up + name: Sign up. + isSpotlight: true + code: | + ```c# + var session = await supabase.Auth.SignUp(email, password); + ``` + - id: sign-in-with-password + title: 'SignIn(email, password)' + description: | + Log in an existing user using email or phone number with password. + notes: | + - Requires either an email and password or a phone number and password. + examples: + - id: sign-in-with-email-and-password + name: Sign in with email and password + isSpotlight: true + code: | + ```c# + var session = await supabase.Auth.SignIn(email, password); + ``` + - id: sign-in-with-phone-and-password + name: Sign in with phone and password + code: | + ```c# + var session = await supabase.Auth.SignIn(SignInType.Phone, phoneNumber, password); + ``` + - id: sign-in-with-otp + title: 'SendMagicLink() and SignIn(SignInType, Phone)' + notes: | + - Requires either an email or phone number. + - This method is used for passwordless sign-ins where a OTP is sent to the user's email or phone number. + - If you're using an email, you can configure whether you want the user to receive a magiclink or a OTP. + - If you're using phone, you can configure whether you want the user to receive a OTP. + - The magic link's destination URL is determined by the [`SITE_URL`](https://supabase.com/docs/reference/auth/config#site_url). You can modify the `SITE_URL` or add additional redirect urls in [your project](https://app.supabase.com/project/_/auth/settings). + examples: + - id: sign-in-with-email + name: Send Magic Link. + isSpotlight: true + description: | + The user will be sent an email which contains either a magiclink or a OTP or both. By default, a given user can only request a OTP once every 60 seconds. + You can pass `emailRedirectTo` with dynamic link to bring the users back to your app after they click on the magic link. + code: | + ```c# + var options = new SignInOptions { RedirectTo = "http://myredirect.example" }; + var didSendMagicLink = await supabase.Auth.SendMagicLink("joseph@supabase.io", options); + ``` + - id: sign-in-with-sms-otp + name: Sign in with SMS OTP. + description: The user will be sent a SMS which contains a OTP. By default, a given user can only request a OTP once every 60 seconds. + code: | + ```c# + await supabase.Auth.SignIn(SignInType.Phone, "+13334445555"); + + // Paired with `VerifyOTP` to get a session + var session = await supabase.Auth.VerifyOTP("+13334445555", TOKEN, MobileOtpType.SMS); + ``` + - id: sign-in-with-oauth + title: 'SignIn(Provider)' + description: | + Signs the user in using third party OAuth providers. + notes: | + - This method is used for signing in using a third-party provider. + - Supabase supports many different [third-party providers](https://supabase.com/docs/guides/auth#providers). + examples: + - id: sign-in-using-a-third-party-provider + name: Sign in using a third-party provider + isSpotlight: true + code: | + ```c# + var signInUrl = supabase.Auth.SignIn(Provider.Github); + ``` + - id: sign-in-with-scopes + name: With scopes + description: | + If you need additional data from an OAuth provider, you can include a space-separated list of scopes in your request to get back an OAuth provider token. + You may also need to specify the scopes in the provider's OAuth app settings, depending on the provider. + code: | + ```c# + var signInUrl = supabase.Auth.SignIn(Provider.Github, 'repo gist notifications'); + + // after user comes back from signin flow + var session = supabase.Auth.GetSessionFromUrl(REDIRECTED_URI); + ``` + - id: sign-out + title: 'SignOut()' + description: | + Signs out the current user, if there is a logged in user. + notes: | + - In order to use the `SignOut()` method, the user needs to be signed in first. + examples: + - id: sign-out + name: Sign out + isSpotlight: true + code: | + ```c# + await supabase.Auth.SignOut(); + ``` + - id: verify-otp + title: 'VerifyOtp()' + notes: | + - The `VerifyOtp` method takes in different verification types. If a phone number is used, the type can either be `sms` or `phone_change`. If an email address is used, the type can be one of the following: `signup`, `magiclink`, `recovery`, `invite` or `email_change`. + - The verification type used should be determined based on the corresponding auth method called before `VerifyOtp` to sign up / sign-in a user. + examples: + - id: verify-sms-one-time-password(otp) + name: Verify Sms One-Time Password (OTP) + isSpotlight: true + code: | + ```c# + var session = await supabase.Auth.VerifyOTP("+13334445555", TOKEN, MobileOtpType.SMS); + ``` + - id: get-session + title: 'CurrentSession' + description: | + Returns the session data, if there is an active session. + examples: + - id: get-the-session-data + name: Get the session data + isSpotlight: true + code: | + ```c# + var session = supabase.Auth.CurrentSession; + ``` + - id: get-user + title: 'CurrentUser' + description: | + Returns the user data, if there is a logged in user. + examples: + - name: Get the logged in user + isSpotlight: true + code: | + ```c# + var user = supabase.Auth.CurrentUser; + ``` + - id: update-user + title: 'UpdateUser()' + description: | + Updates user data, if there is a logged in user. + notes: | + - In order to use the `updateUser()` method, the user needs to be signed in first. + - By Default, email updates sends a confirmation link to both the user's current and new email. + To only send a confirmation link to the user's new email, disable **Secure email change** in your project's [email auth provider settings](https://app.supabase.com/project/_/auth/settings). + examples: + - id: update-the-email-for-an-authenticated-user + name: Update the email for an authenticated user + description: Sends a "Confirm Email Change" email to the new email address. + isSpotlight: true + code: | + ```c# + var attrs = new UserAttributes { Email = "new-email@example.com" }; + var response = await supabase.Auth.Update(attrs); + ``` + - id: update-the-password-for-an-authenticated-user + name: Update the password for an authenticated user + isSpotlight: false + code: | + ```c# + var attrs = new UserAttributes { Password = "***********" }; + var response = await supabase.Auth.Update(attrs); + ``` + - id: update-the-users-metadata + name: Update the user's metadata + isSpotlight: true + code: | + ```c# + var attrs = new UserAttributes + { + Data = new Dictionary { {"example", "data" } } + }; + var response = await supabase.Auth.Update(attrs); + ``` + - id: on-auth-state-change + title: 'StateChanged' + description: | + Receive a notification every time an auth event happens. + notes: | + - Types of auth events: `AuthState.SignedIn`, `AuthState.SignedOut`, `AuthState.UserUpdated`, `AuthState.PasswordRecovery`, `AuthState.TokenRefreshed` + examples: + - id: listen-to-auth-changes + name: Listen to auth changes + isSpotlight: true + code: | + ```c# + supabase.Auth.StateChanged += (sender, ev) => + { + switch (ev.State) + { + case AuthState.SignedIn: + break; + case AuthState.SignedOut: + break; + case AuthState.UserUpdated: + break; + case AuthState.PasswordRecovery: + break; + case AuthState.TokenRefreshed: + break; + } + }; + ``` + - id: auth-reset-password-for-email + title: 'ResetPasswordForEmail()' + description: | + Sends a reset request to an email address. + notes: | + Sends a password reset request to an email address. When the user clicks the reset link in the email they are redirected back to your application. Prompt the user for a new password and call Auth.UpdateUser(): + + examples: + - id: reset-password + name: Reset password for Flutter + isSpotlight: true + code: | + ```c# + await supabase.Auth.ResetPasswordForEmail("joseph@supabase.io"); + ``` + - id: invoke + title: 'invoke()' + description: | + Invokes a Supabase Function. See the [guide](/docs/guides/functions) for details on writing Functions. + notes: | + - Requires an Authorization header. + - Invoke params generally match the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) spec. + examples: + - id: basic-invocation + name: Basic invocation. + isSpotlight: true + code: | + ```c# + var options = new InvokeFunctionOptions + { + Headers = new Dictionary {{ "Authorization", "Bearer 1234" }}, + Body = new Dictionary { { "foo", "bar" } } + }; + + await supabase.Functions.Invoke("hello", options: options); + ``` + - id: modeled-invocation + name: Modeled invocation + code: | + ``` c# + class HelloResponse + { + [JsonProperty("name")] + public string Name { get; set; } + } + + await supabase.Functions.Invoke("hello"); + ``` + - id: select + description: | + Performs vertical filtering with SELECT. + title: 'Fetch data: Select()' + notes: | + - **Column Names must match names in database, not names specified on model properties.** + - By default, Supabase projects will return a maximum of 1,000 rows. This setting can be changed in Project API Settings. It's recommended that you keep it low to limit the payload size of accidental or malicious requests. You can use `range()` queries to paginate through your data. + - `From()` can be combined with [Modifiers](/docs/reference/csharp/using-modifiers) + - `From()` can be combined with [Filters](/docs/reference/csharp/using-filters) + - If using the Supabase hosted platform `apikey` is technically a reserved keyword, since the API gateway will pluck it out for authentication. [It should be avoided as a column name](https://github.com/supabase/supabase/issues/5465). + examples: + - id: getting-your-data + name: Getting your data + isSpotlight: true + code: | + ```c# + var result = await supabase.From().Get(); + var cities = result.Models + ``` + - id: selecting-specific-columns + name: Selecting specific columns + description: You can select specific fields from your tables. + code: | + ```c# + var result = await supabase + .From() + .Select("name, createdAt") + .Get(); + ``` + - id: query-foreign-tables + name: Query foreign tables + description: If your database has relationships, you can query related tables too. + code: | + ```c# + var data = await supabase + .From() + .Select("id, supplier:supplier_id(name), purchaser:purchaser_id(name)") + .Get(); + ``` + - id: filtering-with-inner-joins + name: Filtering with inner joins + description: | + If you want to filter a table based on a child table's values you can use the `!inner()` function. For example, if you wanted + to select all rows in a `message` table which belong to a user with the `username` "Jane": + code: | + ```c# + var result = await supabase + .From() + .Select("*, users!inner(*)") + .Filter("user.username", Operator.Equals, "Jane") + .Get(); + ``` + - id: querying-with-count-option + name: Querying with count option + description: | + You can get the number of rows by using the count option. + Allowed values for count option are [exact](https://postgrest.org/en/stable/api.html#exact-count), [planned](https://postgrest.org/en/stable/api.html#planned-count) and [estimated](https://postgrest.org/en/stable/api.html#estimated-count). + code: | + ```c# + var count = await supabase + .From() + .Select("name") + .Count(CountType.Exact); + ``` + - id: querying-json-data + name: Querying JSON data + description: | + If you have data inside of a JSONB column, you can apply select + and query filters to the data values. Postgres offers a + [number of operators](https://www.postgresql.org/docs/current/functions-json.html) + for querying JSON data. Also see + [PostgREST docs](http://postgrest.org/en/v7.0.0/api.html#json-columns) for more details. + code: | + ```c# + var result = await supabase + .From() + .Select("id, name, address->street") + .Filter("address->postcode", Operator.Equals, 90210) + .Get(); + ``` + + - id: insert + description: | + Performs an INSERT into the table. + title: 'Create data: Insert()' + examples: + - id: create-a-record + name: Create a record + isSpotlight: true + code: | + ```c# + [Table("cities")] + class City : BaseModel + { + [PrimaryKey("id", false)] + public int Id { get; set; } + + [Column("name")] + public string Name { get; set; } + + [Column("country_id")] + public int CountryId { get; set; } + } + + var model = new City + { + Name = "The Shire", + CountryId = 554 + }; + + await supabase.From().Insert(model); + ``` + - id: bulk-create + name: Bulk create + code: | + ```c# + [Table("cities")] + class City : BaseModel + { + [PrimaryKey("id", false)] + public int Id { get; set; } + + [Column("name")] + public string Name { get; set; } + + [Column("country_id")] + public int CountryId { get; set; } + } + + var models = new List + { + new City { Name = "The Shire", CountryId = 554 }, + new City { Name = "Rohan", CountryId = 553 }, + }; + + await supabase.From().Insert(models); + ``` + - id: fetch-inserted-data + name: Fetch inserted record + code: | + ```dart + var result = await supabase + .From() + .Insert(models, new QueryOptions { Returning = ReturnType.Representation }); + ``` + + - id: update + description: | + Performs an UPDATE on the table. + title: 'Modify data: Update()' + notes: | + - `Update()` is typically called using a model as an argument or from a hydrated model. + examples: + - id: updating-your-data + name: Update your data + isSpotlight: true + code: | + ```c# + var model = await supabase + .From() + .Filter("name", Operator.Equals, "Auckland") + .Single(); + + model.Name = "Middle Earth"; + + await model.Update(); + ``` + + - id: upsert + description: | + Performs an UPSERT into the table. + title: 'Upsert data: Upsert()' + notes: | + - Primary keys should be included in the data payload in order for an update to work correctly. + - Primary keys must be natural, not surrogate. There are however, [workarounds](https://github.com/PostgREST/postgrest/issues/1118) for surrogate primary keys. + examples: + - id: upsert-your-data + name: Upsert your data + isSpotlight: true + code: | + ```c# + var model = new City + { + Id = 554, + Name = "Middle Earth" + }; + + await supabase.From().Upsert(model); + ``` + - id: upserting-into-tables-with-constraints + name: Upserting into tables with constraints + description: | + Running the following will cause supabase to upsert data into the `users` table. + If the username 'supabot' already exists, the `onConflict` argument tells supabase to overwrite that row + based on the column passed into `onConflict`. + isSpotlight: true + code: | + ```c# + var model = new City + { + Id = 554, + Name = "Middle Earth" + }; + + await supabase + .From() + .Upsert(model, new QueryOptions { OnConflict = "name" }); + ``` + - id: return-the-exact-number-of-rows + name: Return the exact number of rows + description: | + Allowed values for count option are `exact`, `planned` and `estimated`. + code: | + ```c# + var model = new City + { + Id = 554, + Name = "Middle Earth" + }; + + await supabase + .From() + .Upsert(model, new QueryOptions { Count = QueryOptions.CountType.Exact }); + ``` + + - id: delete + description: | + Performs a DELETE on the table. + title: 'Delete data: Delete()' + notes: | + - `delete()` should always be combined with [Filters](/docs/reference/csharp/using-filters) to target the item(s) you wish to delete. + examples: + - id: delete-records + name: Delete records + isSpotlight: true + code: | + ```c# + await supabase + .From() + .Filter("id", Operator.Equals, 342) + .Delete(); + ``` + + - id: rpc + title: 'Stored Procedures: rpc()' + description: | + You can call stored procedures as a "Remote Procedure Call". + + That's a fancy way of saying that you can put some logic into your database then call it from anywhere. + It's especially useful when the logic rarely changes - like password resets and updates. + examples: + - id: call-a-stored-procedure + name: Call a stored procedure + isSpotlight: true + description: This is an example invoking a stored procedure. + code: | + ```dart + final data = await supabase + .rpc('hello_world'); + ``` + - id: with-parameters + name: With Parameters + code: | + ```dart + final data = await supabase + .rpc('echo_city', params: { 'name': 'The Shire' }); + ``` + + - id: subscribe + description: | + Subscribe to realtime changes in your database. + title: 'on().subscribe()' + notes: | + - Realtime is disabled by default for new Projects for better database performance and security. You can turn it on by [managing replication](/docs/guides/api#managing-realtime). + - If you want to receive the "previous" data for updates and deletes, you will need to set `REPLICA IDENTITY` to `FULL`, like this: `ALTER TABLE your_table REPLICA IDENTITY FULL;` + examples: + - id: listen-to-all-database-changes + name: Listen to all database changes + isSpotlight: true + code: | + ```dart + supabase.channel('*').on( + RealtimeListenTypes.postgresChanges, + ChannelFilter(event: '*', schema: '*'), + (payload, [ref]) { + print('Change received: ${payload.toString()}'); + }, + ).subscribe(); + ``` + - id: listening-to-a-specific-table + name: Listening to a specific table + code: | + ```dart + supabase.channel('public:countries').on( + RealtimeListenTypes.postgresChanges, + ChannelFilter(event: '*', schema: 'public', table: 'countries'), + (payload, [ref]) { + print('Change received: ${payload.toString()}'); + }, + ).subscribe(); + ``` + - id: listening-to-inserts + name: Listening to inserts + code: | + ```dart + supabase.channel('public:countries').on( + RealtimeListenTypes.postgresChanges, + ChannelFilter(event: 'INSERT', schema: 'public', table: 'countries'), + (payload, [ref]) { + print('Change received: ${payload.toString()}'); + }, + ).subscribe(); + ``` + - id: listening-to-updates + name: Listening to updates + description: | + By default, Supabase will send only the updated record. If you want to receive the previous values as well you can + enable full replication for the table you are listening too: + + ```sql + alter table "your_table" replica identity full; + ``` + code: | + ```dart + supabase.channel('public:countries').on( + RealtimeListenTypes.postgresChanges, + ChannelFilter(event: 'UPDATE', schema: 'public', table: 'countries'), + (payload, [ref]) { + print('Change received: ${payload.toString()}'); + }, + ).subscribe(); + ``` + - id: listening-to-deletes + name: Listening to deletes + description: | + By default, Supabase does not send deleted records. If you want to receive the deleted record you can + enable full replication for the table you are listening too: + + ```sql + alter table "your_table" replica identity full; + ``` + code: | + ```dart + supabase.channel('public:countries').on( + RealtimeListenTypes.postgresChanges, + ChannelFilter(event: 'DELETE', schema: 'public', table: 'countries'), + (payload, [ref]) { + print('Change received: ${payload.toString()}'); + }, + ).subscribe(); + ``` + - id: listening-to-multiple-events + name: Listening to multiple events + description: You can chain listeners if you want to listen to multiple events for each table. + code: | + ```dart + supabase.channel('public:countries').on(RealtimeListenTypes.postgresChanges, + ChannelFilter(event: 'INSERT', schema: 'public', table: 'countries'), + (payload, [ref]) { + print('Change received: ${payload.toString()}'); + }).on(RealtimeListenTypes.postgresChanges, + ChannelFilter(event: 'DELETE', schema: 'public', table: 'countries'), + (payload, [ref]) { + print('Change received: ${payload.toString()}'); + }).subscribe(); + ``` + - id: listening-to-row-level-changes + name: Listening to row level changes + description: You can listen to individual rows using the format `{table}:{col}=eq.{val}` - where `{col}` is the column name, and `{val}` is the value which you want to match. + code: | + ```dart + supabase.channel('public:countries:id=eq.200').on( + RealtimeListenTypes.postgresChanges, + ChannelFilter( + event: 'UPDATE', + schema: 'public', + table: 'countries', + filter: 'id=eq.200', + ), (payload, [ref]) { + print('Change received: ${payload.toString()}'); + }).subscribe(); + ``` + + - id: remove-channel + description: | + Unsubscribes and removes Realtime channel from Realtime client. + title: 'removeChannel()' + notes: | + - Removing a channel is a great way to maintain the performance of your project's Realtime service as well as your database if you're listening to Postgres changes. Supabase will automatically handle cleanup 30 seconds after a client is disconnected, but unused channels may cause degradation as more clients are simultaneously subscribed. + examples: + - id: removes-a-channel + name: Remove a channel + isSpotlight: true + code: | + ```dart + final status = await supabase.removeChannel(channel); + ``` + + - id: remove-all-channels + description: | + Unsubscribes and removes all Realtime channels from Realtime client. + title: 'removeAllChannels()' + notes: | + - Removing channels is a great way to maintain the performance of your project's Realtime service as well as your database if you're listening to Postgres changes. Supabase will automatically handle cleanup 30 seconds after a client is disconnected, but unused channels may cause degradation as more clients are simultaneously subscribed. + examples: + - id: remove-all-channels + name: Remove all channels + isSpotlight: true + code: | + ```dart + final statuses = await supabase.removeAllChannels(); + ``` + + - id: get-channels + description: | + Returns all Realtime channels. + title: 'getChannels()' + examples: + - id: get-all-channels + name: Get all channels + isSpotlight: true + code: | + ```dart + final channels = supabase.getChannels(); + ``` + + - id: stream + description: | + Notifies of data at the queried table. + title: 'stream()' + notes: | + - `stream()` will emit the initial data as well as any further change on the database as `Stream` of `List>` by combining Postgrest and Realtime. + - Takes a list of primary key columns as its argument. + examples: + - id: listening-to-a-specific-table + name: Listening to a specific table + isSpotlight: true + code: | + ```dart + supabase.from('countries') + .stream(primaryKey: ['id']) + .listen((List> data) { + // Do something awesome with the data + }); + ``` + - id: listening-to-a-specific-rows-within-a-table + name: Listening to a specific rows within a table + description: | + You can listen to individual rows using the format `{table}:{col}=eq.{val}` - where `{col}` is the column name, and `{val}` is the value which you want to match. + This syntax is the as how you can filter data in Realtime + code: | + ```dart + supabase.from('countries') + .stream(primaryKey: ['id']) + .eq('id', '120') + .listen((List> data) { + // Do something awesome with the data + }); + ``` + - id: with-order + name: With `order()` + code: | + ```dart + supabase.from('countries') + .stream(primaryKey: ['id']) + .order('name', ascending: true) + .listen((List> data) { + // Do something awesome with the data + }); + ``` + - id: with-limit + name: With `limit()` + code: | + ```dart + supabase.from('countries') + .stream(primaryKey: ['id']) + .order('name', ascending: true) + .limit(10) + .listen((List> data) { + // Do something awesome with the data + }); + ``` + - id: using-stream-with-stream-builder + name: Using `stream()` with `StreamBuilder` + description: | + When using `stream()` with a `StreamBuilder` within your Flutter application, make sure to store your stream in a variable to prevent refetching upon rebuilding. + code: | + ```dart + final supabase = Supabase.instance.client; + + class MyWidget extends StatefulWidget { + const MyWidget({Key? key}) : super(key: key); + + @override + State createState() => _MyWidgetState(); + } + + class _MyWidgetState extends State { + // Persist the stream in a local variable to prevent refetching upon rebuilds + final _stream = supabase.from('countries').stream(primaryKey: ['id']); + + @override + Widget build(BuildContext context) { + return StreamBuilder( + stream: _stream, + builder: (context, snapshot) { + // Return your widget with the data from the snapshot + }, + ); + } + } + ``` + + - id: list-buckets + description: | + Retrieves the details of all Storage buckets within an existing product. + title: 'listBuckets()' + $ref: '@supabase/storage-js.packages/StorageBucketApi.default.listBuckets' + notes: | + - Policy permissions required: + - `buckets` permissions: `select` + - `objects` permissions: none + examples: + - id: list-buckets + name: List buckets + isSpotlight: true + code: | + ```dart + final List buckets = await supabase + .storage + .listBuckets(); + ``` + + - id: get-bucket + description: | + Retrieves the details of an existing Storage bucket. + title: 'getBucket()' + $ref: '@supabase/storage-js.packages/StorageBucketApi.default.getBucket' + notes: | + - Policy permissions required: + - `buckets` permissions: `select` + - `objects` permissions: none + examples: + - id: get-bucket + name: Get bucket + isSpotlight: true + code: | + ```dart + final Bucket bucket = await supabase + .storage + .getBucket('avatars'); + ``` + + - id: create-bucket + description: | + Creates a new Storage bucket + title: 'createBucket()' + notes: | + - Policy permissions required: + - `buckets` permissions: `insert` + - `objects` permissions: none + examples: + - id: create-bucket + name: Create bucket + isSpotlight: true + code: | + ```dart + final String bucketId = await supabase + .storage + .createBucket('avatars'); + ``` + + - id: empty-bucket + description: | + Removes all objects inside a single bucket. + title: 'emptyBucket()' + notes: | + - Policy permissions required: + - `buckets` permissions: `select` + - `objects` permissions: `select` and `delete` + examples: + - id: empty-bucket + name: Empty bucket + isSpotlight: true + code: | + ```dart + final String result = await supabase + .storage + .emptyBucket('avatars'); + ``` + - id: update-bucket + description: | + Updates a new Storage bucket + title: 'updateBucket()' + notes: | + - Policy permissions required: + - `buckets` permissions: `update` + - `objects` permissions: none + examples: + - id: update-bucket + name: Update bucket + isSpotlight: true + code: | + ```dart + final res = await supabase + .storage + .updateBucket('avatars', const BucketOptions(public: false)); + ``` + + - id: delete-bucket + description: | + Deletes an existing bucket. A bucket can't be deleted with existing objects inside it. You must first `empty()` the bucket. + title: 'deleteBucket()' + notes: | + - Policy permissions required: + - `buckets` permissions: `select` and `delete` + - `objects` permissions: none + examples: + - id: delete-bucket + name: Delete bucket + isSpotlight: true + code: | + ```dart + final String result = await supabase + .storage + .deleteBucket('avatars'); + ``` + + - id: from-upload + description: | + Uploads a file to an existing bucket. + title: 'from.upload()' + $ref: '@supabase/storage-js.packages/StorageFileApi.default.upload' + notes: | + - Policy permissions required: + - `buckets` permissions: none + - `objects` permissions: `insert` + examples: + - id: upload-file + name: Upload file + isSpotlight: true + code: | + ```dart + final avatarFile = File('path/to/file'); + final String path = await supabase.storage.from('avatars').upload( + 'public/avatar1.png', + avatarFile, + fileOptions: const FileOptions(cacheControl: '3600', upsert: false), + ); + ``` + + - id: from-update + description: | + Replaces an existing file at the specified path with a new one. + title: 'from.update()' + notes: | + - Policy permissions required: + - `buckets` permissions: none + - `objects` permissions: `update` and `select` + examples: + - id: update-file + name: Update file + isSpotlight: true + code: | + ```dart + final avatarFile = File('path/to/local/file'); + final String path = await supabase.storage.from('avatars').update( + 'public/avatar1.png', + avatarFile, + fileOptions: const FileOptions(cacheControl: '3600', upsert: false), + ); + ``` + + - id: from-move + description: | + Moves an existing file, optionally renaming it at the same time. + title: 'from.move()' + notes: | + - Policy permissions required: + - `buckets` permissions: none + - `objects` permissions: `update` and `select` + examples: + - id: move-file + name: Move file + isSpotlight: true + code: | + ```dart + final String result = await supabase + .storage + .from('avatars') + .move('public/avatar1.png', 'private/avatar2.png'); + ``` + + - id: from-create-signed-url + description: | + Create signed url to download file without requiring permissions. This URL can be valid for a set number of seconds. + title: 'from.createSignedUrl()' + notes: | + - Policy permissions required: + - `buckets` permissions: none + - `objects` permissions: `select` + examples: + - id: create-signed-url + name: Create Signed URL + isSpotlight: true + code: | + ```dart + final String signedUrl = await supabase + .storage + .from('avatars') + .createSignedUrl('avatar1.png', 60); + ``` + - id: create-signed-url-with-transform + name: With transform + code: | + ```dart + final String signedUrl = await supabase + .storage + .from('avatars') + .createSignedUrl( + 'avatar1.png', + 60, + transform: TransformOptions( + width: 200, + height: 200, + ), + ); + ``` + + - id: from-get-public-url + description: | + Retrieve URLs for assets in public buckets + title: 'from.getPublicUrl()' + notes: | + - The bucket needs to be set to public, either via [updateBucket()](/docs/reference/javascript/storage-updatebucket) or by going to Storage on [app.supabase.com](https://app.supabase.com), clicking the overflow menu on a bucket and choosing "Make public" + - Policy permissions required: + - `buckets` permissions: none + - `objects` permissions: none + examples: + - id: returns-the-url-for-an-asset-in-a-public-bucket + name: Returns the URL for an asset in a public bucket + isSpotlight: true + code: | + ```dart + final String publicUrl = supabase + .storage + .from('public-bucket') + .getPublicUrl('avatar1.png'); + ``` + - id: returns-the-url-for-an-asset-in-a-public-bucket-with-transform + name: With transform + isSpotlight: true + code: | + ```dart + final String publicUrl = await supabase + .storage + .from('public-bucket') + .getPublicUrl( + 'avatar1.png', + transform: TransformOptions( + width: 200, + height: 200, + ), + ); + ``` + + - id: from-download + description: | + Downloads a file. + title: 'from.download()' + notes: | + - Policy permissions required: + - `buckets` permissions: none + - `objects` permissions: `select` + examples: + - id: download-file + name: Download file + isSpotlight: true + code: | + ```dart + final Uint8List file = await supabase + .storage + .from('avatars') + .download('avatar1.png'); + ``` + - id: download-file-with-transform + name: With transform + isSpotlight: true + code: | + ```dart + final Uint8List file = await supabase + .storage + .from('avatars') + .download( + 'avatar1.png', + transform: TransformOptions( + width: 200, + height: 200, + ), + ); + ``` + + - id: from-remove + description: | + Deletes files within the same bucket + title: 'from.remove()' + notes: | + - Policy permissions required: + - `buckets` permissions: none + - `objects` permissions: `delete` and `select` + examples: + - id: delete-file + name: Delete file + isSpotlight: true + code: | + ```dart + final List objects = await supabase + .storage + .from('avatars') + .remove(['avatar1.png']); + ``` + + - id: from-list + description: | + Lists all the files within a bucket. + title: 'from.list()' + notes: | + - Policy permissions required: + - `buckets` permissions: none + - `objects` permissions: `select` + examples: + - id: list-files-in-a-bucket + name: List files in a bucket + isSpotlight: true + code: | + ```dart + final List objects = await supabase + .storage + .from('avatars') + .list(); + ``` + - id: using-modifiers + title: Using Modifiers + description: | + Filters work on the row level—they allow you to return rows that + only match certain conditions without changing the shape of the rows. + Modifiers are everything that don't fit that definition—allowing you to + change the format of the response (e.g., returning a CSV string). + + Modifiers must be specified after filters. Some modifiers only apply for + queries that return rows (e.g., `select()` or `rpc()` on a function that + returns a table response). + + - id: limit + title: limit() + description: | + Limits the result with the specified count. + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .limit(1); + ``` + - id: with-embedded-resources + name: With embedded resources + code: | + ```dart + final data = await supabase + .from('countries') + .select('name, cities(name)') + .eq('name', 'United States') + .limit(1, foreignTable: 'cities' ); + ``` + + - id: order + title: order() + description: | + Orders the result with the specified column. + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .order('id', ascending: false ); + ``` + - id: with-embedded-resources + name: With embedded resources + code: | + ```dart + final data = await supabase + .from('countries') + .select('name, cities(name)') + .eq('name', 'United States') + .order('name', foreignTable: 'cities'); + ``` + + - id: range + title: range() + description: | + Limits the result to rows within the specified range, inclusive. + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .range(0,3); + ``` + + - id: single + title: single() + description: | + Retrieves only one row from the result. Result must be one row (e.g. using limit), otherwise this will result in an error. + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .single(); + ``` + + - id: using-filters + title: Using Filters + description: | + Filters allow you to only return rows that match certain conditions. + + Filters can be used on `select()`, `update()`, and `delete()` queries. + + If a Database function returns a table response, you can also apply filters. + examples: + - id: applying-filters + name: Applying Filters + description: | + Filters must be applied after any of `select()`, `update()`, `upsert()`, + `delete()`, and `rpc()` and before + [modifiers](/docs/reference/dart/using-modifiers). + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .eq('name', 'The Shire'); // Correct + + final data = await supabase + .from('cities') + .eq('name', 'The Shire') // Incorrect + .select('name, country_id'); + ``` + - id: chaining-filters + name: Chaining Filters + description: | + Filters must be applied after any of `select()`, `update()`, `upsert()`, + `delete()`, and `rpc()` and before + [modifiers](/docs/reference/dart/using-modifiers). + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .eq('name', 'The Shire'); // Correct + + final data = await supabase + .from('cities') + .eq('name', 'The Shire') // Incorrect + .select('name, country_id'); + ``` + - id: conditional-chaining + name: Conditional Chaining + description: | + Filters can be built up one step at a time and then executed. For example: + code: | + ```dart + final data = await supabase + .from('users') + .select() + .eq('address->postcode', 90210); + ``` + - id: filter-by-value-within-json-column + name: Filter by values within a JSON column + description: | + Filters can be built up one step at a time and then executed. For example: + data: + sql: | + ```sql + create table + users ( + id int8 primary key, + name text, + address jsonb + ); + + insert into + users (id, name, address) + values + (1, 'Michael', '{ "postcode": 90210 }'), + (2, 'Jane', null); + ``` + response: | + ```json + { + "data": [ + { + "id": 1, + "name": "Michael", + "address": { + "postcode": 90210 + } + } + ], + "status": 200, + "statusText": "OK" + } + ``` + code: | + ```dart + final data = await supabase + .from('users') + .select() + .eq('address->postcode', 90210); + ``` + - id: filter-foreign-tables + name: Filter Foreign Tables + code: | + ```dart + final data = await supabase + .from('countries') + .select(''' + name, + cities!inner ( + name + ) + ''') + .eq('cities.name', 'Bali'); + ``` + data: + sql: | + ```sql + create table + countries (id int8 primary key, name text); + create table + cities ( + id int8 primary key, + country_id int8 not null references countries, + name text + ); + + insert into + countries (id, name) + values + (1, 'Germany'), + (2, 'Indonesia'); + insert into + cities (id, country_id, name) + values + (1, 2, 'Bali'), + (2, 1, 'Munich'); + ``` + response: | + ```json + { + "data": [ + { + "name": "Indonesia", + "cities": [ + { + "name": "Bali" + } + ] + } + ], + "status": 200, + "statusText": "OK" + } + ``` + - id: or + title: or() + description: | + Finds all rows satisfying at least one of the filters. + notes: | + - `.or()` expects you to use the raw [PostgREST syntax](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows) for the filter names and values. + + ```dart + .or('id.in.(6,7),arraycol.cs.{"a","b"}') // Use Postgres list () and 'in' for in_ filter. Array {} and 'cs' for contains. + .or('id.in.(${mylist.join(',')}),arraycol.cs.{${mylistArray.join(',')}}') // You can insert a Dart list for list or array column. + .or('id.in.(${mylist.join(',')}),rangecol.cs.(${mylistRange.join(',')}]') // You can insert a Dart list for list or range column. + ``` + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .or('id.eq.20,id.eq.30'); + ``` + - id: use-or-with-and + name: Use `or` with `and` + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .or('id.gt.20,and(name.eq.New Zealand,name.eq.France)'); + ``` + + - id: not + title: not() + description: | + Finds all rows which doesn't satisfy the filter. + notes: | + - `.not()` expects you to use the raw [PostgREST syntax](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows) for the filter names and values. + + ```dart + .not('name','eq','Paris') + .not('arraycol','cs','{"a","b"}') // Use Postgres array {} for array column and 'cs' for contains. + .not('rangecol','cs','(1,2]') // Use Postgres range syntax for range column. + .not('id','in','(6,7)') // Use Postgres list () and 'in' for in_ filter. + .not('id','in','(${mylist.join(',')})') // You can insert a Dart list array. + ``` + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .not('name', 'eq', 'Paris'); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('cities') + .update({ 'name': 'Mordor' }) + .not('name', 'eq', 'Paris'); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('cities') + .delete() + .not('name', 'eq', 'Paris'); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_cities) + .not('name', 'eq', 'Paris'); + ``` + + - id: match + title: match() + description: | + Finds all rows whose columns match the specified `query` object. + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .match({'name': 'Beijing', 'country_id': 156}); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('cities') + .update({ 'name': 'Mordor' }) + .match({'name': 'Beijing', 'country_id': 156}); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('cities') + .delete() + .match({'name': 'Beijing', 'country_id': 156}); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_cities') + .match({'name': 'Beijing', 'country_id': 156}); + ``` + + - id: eq + title: eq() + description: | + Finds all rows whose value on the stated `column` exactly matches the specified `value`. + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .eq('name', 'The shire'); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('cities') + .update({ 'name': 'Mordor' }) + .eq('name', 'San Francisco'); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('cities') + .delete() + .eq('name', 'Mordor'); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_cities') + .eq('name', 'San Francisco'); + ``` + + - id: neq + title: neq() + description: | + Finds all rows whose value on the stated `column` doesn't match the specified `value`. + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .neq('name', 'The shire'); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('cities') + .update({ 'name': 'Mordor' }) + .neq('name', 'San Francisco'); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('cities') + .delete() + .neq('name', 'Mordor'); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_cities') + .neq('name', 'Lagos'); + ``` + + - id: gt + title: gt() + description: | + Finds all rows whose value on the stated `column` is greater than the specified `value`. + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .gt('country_id', 250); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('cities') + .update({ 'name': 'Mordor' }) + .gt('country_id', 250); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('cities') + .delete() + .gt('country_id', 250); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_cities') + .gt('country_id', 250); + ``` + + - id: gte + title: gte() + description: | + Finds all rows whose value on the stated `column` is greater than or equal to the specified `value`. + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .gte('country_id', 250); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('cities') + .update({ 'name': 'Mordor' }) + .gte('country_id', 250); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('cities') + .delete() + .gte('country_id', 250); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_cities') + .gte('country_id', 250); + ``` + + - id: lt + title: lt() + description: | + Finds all rows whose value on the stated `column` is less than the specified `value`. + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .lt('country_id', 250); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('cities') + .update({ 'name': 'Mordor' }) + .lt('country_id', 250); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('cities') + .delete() + .lt('country_id', 250); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_cities') + .lt('country_id', 250); + ``` + + - id: lte + title: lte() + description: | + Finds all rows whose value on the stated `column` is less than or equal to the specified `value`. + $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.lte' + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .lte('country_id', 250); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('cities') + .update({ 'name': 'Mordor' }) + .lte('country_id', 250); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('cities') + .delete() + .lte('country_id', 250); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_cities') + .lte('country_id', 250); + ``` + + - id: like + title: like() + description: | + Finds all rows whose value in the stated `column` matches the supplied `pattern` (case sensitive). + $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.lte' + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .like('name', '%la%'); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('cities') + .update({ 'name': 'Mordor' }) + .like('name', '%la%'); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('cities') + .delete() + .like('name', '%la%'); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_cities') + .like('name', '%la%'); + ``` + + - id: ilike + title: ilike() + description: | + Finds all rows whose value in the stated `column` matches the supplied `pattern` (case insensitive). + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .ilike('name', '%la%'); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('cities') + .update({ 'name': 'Mordor' }) + .ilike('name', '%la%'); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('cities') + .delete() + .ilike('name', '%la%'); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_cities') + .ilike('name', '%la%'); + ``` + + - id: is + title: is_() + description: | + A check for exact equality (null, true, false), finds all rows whose value on the stated `column` exactly match the specified `value`. + + `is_` and `in_` filter methods are suffixed with `_` to avoid collisions with reserved keywords. + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .is_('name', null); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('cities') + .update({ 'name': 'Mordor' }) + .is_('name', null); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('cities') + .delete() + .is_('name', null); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_cities') + .is_('name', null); + ``` + + - id: in + title: in_() + description: | + Finds all rows whose value on the stated `column` is found on the specified `values`. + + `is_` and `in_` filter methods are suffixed with `_` to avoid collisions with reserved keywords. + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .in_('name', ['Rio de Janeiro', 'San Francisco']); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('cities') + .update({ 'name': 'Mordor' }) + .in_('name', ['Rio de Janeiro', 'San Francisco']); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('cities') + .delete() + .in_('name', ['Rio de Janeiro', 'San Francisco']); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_cities') + .in_('name', ['Rio de Janeiro', 'San Francisco']); + ``` + + - id: contains + title: contains() + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('countries') + .select('name, id, main_exports') + .contains('main_exports', ['oil']); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('countries') + .update({ 'name': 'Mordor' }) + .contains('main_exports', ['oil']); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('countries') + .delete() + .contains('main_exports', ['oil']); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_countries') + .contains('main_exports', ['oil']); + ``` + + - id: contained-by + title: containedBy() + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('countries') + .select('name, id, main_exports') + .containedBy('main_exports', ['cars', 'food', 'machine']); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('countries') + .update({ 'name': 'Mordor' }) + .containedBy('main_exports', ['orks', 'surveillance', 'evil']); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('countries') + .delete() + .containedBy('main_exports', ['cars', 'food', 'machine']); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_countries') + .containedBy('main_exports', ['cars', 'food', 'machine']); + ``` + + - id: range-lt + title: rangeLt() + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('countries') + .select('name, id, population_range_millions') + .rangeLt('population_range_millions', '[150, 250]'); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('countries') + .update({ 'name': 'Mordor' }) + .rangeLt('population_range_millions', '[150, 250]'); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('countries') + .delete() + .rangeLt('population_range_millions', '[150, 250]'); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_countries') + .rangeLt('population_range_millions', '[150, 250]'); + ``` + + - id: range-gt + title: rangeGt() + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('countries') + .select('name, id, population_range_millions') + .rangeGt('population_range_millions', '[150, 250]'); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('countries') + .update({ 'name': 'Mordor' }) + .rangeGt('population_range_millions', '[150, 250]'); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('countries') + .delete() + .rangeGt('population_range_millions', '[150, 250]'); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_countries') + .rangeGt('population_range_millions', '[150, 250]'); + ``` + + - id: range-gte + title: rangeGte() + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('countries') + .select('name, id, population_range_millions') + .rangeGte('population_range_millions', '[150, 250]'); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('countries') + .update({ 'name': 'Mordor' }) + .rangeGte('population_range_millions', '[150, 250]'); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('countries') + .delete() + .rangeGte('population_range_millions', '[150, 250]'); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_countries') + .rangeGte('population_range_millions', '[150, 250]'); + ``` + + - id: range-lte + title: rangeLte() + $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.rangeLte' + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('countries') + .select('name, id, population_range_millions') + .rangeLte('population_range_millions', '[150, 250]'); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('countries') + .update({ 'name': 'Mordor' }) + .rangeLte('population_range_millions', '[150, 250]'); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('countries') + .delete() + .rangeLte('population_range_millions', '[150, 250]'); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_countries') + .rangeLte('population_range_millions', [150, 250]); + ``` + + - id: range-adjacent + title: rangeAdjacent() + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('countries') + .select('name, id, population_range_millions') + .rangeAdjacent('population_range_millions', '[70, 185]'); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('countries') + .update({ 'name': 'Mordor' }) + .rangeAdjacent('population_range_millions', '[70, 185]'); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('countries') + .delete() + .rangeAdjacent('population_range_millions', '[70, 185]'); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_countries') + .rangeAdjacent('population_range_millions', '[70, 185]'); + ``` + + - id: overlaps + title: overlaps() + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('countries') + .select('name, id, main_exports') + .overlaps('main_exports', ['computers', 'minerals']); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('countries') + .update({ 'name': 'Mordor' }) + .overlaps('main_exports', ['computers', 'minerals']); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('countries') + .delete() + .overlaps('main_exports', ['computers', 'minerals']); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_countries') + .overlaps('main_exports', ['computers', 'minerals']); + ``` + + - id: text-search + title: textSearch() + description: | + Finds all rows whose tsvector value on the stated `column` matches to_tsquery(query). + examples: + - id: text-search + name: Text search + code: | + ```dart + final data = await supabase + .from('quotes') + .select('catchphrase') + .textSearch('catchphrase', "'fat' & 'cat'", + config: 'english' + ); + ``` + - id: basic-normalization + name: Basic normalization + description: Uses PostgreSQL's `plainto_tsquery` function. + code: | + ```dart + final data = await supabase + .from('quotes') + .select('catchphrase') + .textSearch('catchphrase', "'fat' & 'cat'", + type: TextSearchType.plain, + config: 'english' + ); + ``` + - id: full-normalization + name: Full normalization + description: Uses PostgreSQL's `phraseto_tsquery` function. + code: | + ```dart + final data = await supabase + .from('quotes') + .select('catchphrase') + .textSearch('catchphrase', "'fat' & 'cat'", + type: TextSearchType.phrase, + config: 'english' + ); + ``` + - id: web-search + name: Websearch + description: | + Uses PostgreSQL's `websearch_to_tsquery` function. + This function will never raise syntax errors, which makes it possible to use raw user-supplied input for search, and can be used + with advanced operators. + + - `unquoted text`: text not inside quote marks will be converted to terms separated by & operators, as if processed by plainto_tsquery. + - `"quoted text"`: text inside quote marks will be converted to terms separated by <-> operators, as if processed by phraseto_tsquery. + - `OR`: the word “or” will be converted to the | operator. + - `-`: a dash will be converted to the ! operator. + + code: | + ```dart + final data = await supabase + .from('quotes') + .select('catchphrase') + .textSearch('catchphrase', "'fat or cat'", + type: TextSearchType.websearch, + config: 'english' + ); + ``` + + - id: filter + title: filter() + description: | + Finds all rows whose `column` satisfies the filter. + notes: | + - `.filter()` expects you to use the raw [PostgREST syntax](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows) for the filter names and values, so it should only be used as an escape hatch in case other filters don't work. + ```dart + .filter('arraycol','cs','{"a","b"}') // Use Postgres array {} and 'cs' for contains. + .filter('rangecol','cs','(1,2]') // Use Postgres range syntax for range column. + .filter('id','in','(6,7)') // Use Postgres list () and 'in' for in_ filter. + .filter('id','cs','{${mylist.join(',')}}') // You can insert a Dart array list. + ``` + examples: + - id: with-select + name: With `select()` + isSpotlight: true + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, country_id') + .filter('name', 'in', '("Paris","Tokyo")'); + ``` + - id: with-update + name: With `update()` + code: | + ```dart + final data = await supabase + .from('cities') + .update({ 'name': 'Mordor' }) + .filter('name', 'in', '("Paris","Tokyo")'); + ``` + - id: with-delete + name: With `delete()` + code: | + ```dart + final data = await supabase + .from('cities') + .delete() + .filter('name', 'in', '("Paris","Tokyo")'); + ``` + - id: with-rpc + name: With `rpc()` + code: | + ```dart + // Only valid if the Stored Procedure returns a table type. + final data = await supabase + .rpc('echo_all_cities') + .filter('name', 'in', '("Paris","Tokyo")'); + ``` + - id: filter-embedded-resources + name: Filter embedded resources + code: | + ```dart + final data = await supabase + .from('cities') + .select('name, countries ( name )') + .filter('countries.name', 'in', '("France","Japan")'); + ```