diff --git a/apps/docs/components/DocSearch.tsx b/apps/docs/components/DocSearch.tsx index 2a4f56d1e48..7ff1a5ece2a 100644 --- a/apps/docs/components/DocSearch.tsx +++ b/apps/docs/components/DocSearch.tsx @@ -1,4 +1,4 @@ -import { useState, useCallback, useRef, createContext, useContext, useEffect } from 'react' +import { useState, useCallback, useRef, createContext, useContext, useEffect, memo } from 'react' import { createPortal } from 'react-dom' import Link from 'next/link' import Head from 'next/head' @@ -84,7 +84,7 @@ export function SearchProvider({ children }: any) { hitComponent={Hit} transformItems={(items) => { return items.map((item, index) => { - console.log('item', item) + // console.log('item', item) // We transform the absolute URL into a relative URL to // leverage Next's preloading. const a = document.createElement('a') diff --git a/apps/docs/components/Navigation/NavigationMenu/HomeMenu.tsx b/apps/docs/components/Navigation/NavigationMenu/HomeMenu.tsx index ccad3bb7505..9a1f712f859 100644 --- a/apps/docs/components/Navigation/NavigationMenu/HomeMenu.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/HomeMenu.tsx @@ -1,8 +1,7 @@ +import { useTheme } from 'common/Providers' import Image from 'next/image' import Link from 'next/link' import { useRouter } from 'next/router' -import { useMenuLevelId } from '~/hooks/useMenuState' -import { useTheme } from 'common/Providers' import { Fragment } from 'react' const home = [ @@ -113,8 +112,7 @@ const home = [ ], ] -const NavigationMenuHome = () => { - const level = useMenuLevelId() +const NavigationMenuHome = ({ active }) => { const router = useRouter() const { isDarkMode } = useTheme() @@ -122,9 +120,7 @@ const NavigationMenuHome = () => {
- {menu.extras && ( - <> - {' '} - - Resources - - - )} - {menu.extras?.map((x) => { - return ( -
-
  • - - - {x.icon && } - {x.name} - - -
  • -
    - ) - })}
    ) diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideList.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideList.tsx index 32bacbe94b8..b0a5a9c78e1 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideList.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideList.tsx @@ -1,244 +1,38 @@ import * as Accordion from '@radix-ui/react-accordion' -import { useTheme } from 'common/Providers' -import Image from 'next/image' -import Link from 'next/link' import { useRouter } from 'next/router' -import React, { Fragment } from 'react' -import { IconChevronLeft } from '~/../../packages/ui' -import { useMenuLevelId } from '~/hooks/useMenuState' -import * as NavItems from './NavigationMenu.constants' +import React from 'react' +import NavigationMenuGuideListItems from './NavigationMenuGuideListItems' interface Props { id: string - setMenuLevelId?: any - context: 'side' | 'mobile' + active: boolean } -const NavigationMenuGuideList: React.FC = ({ id, setMenuLevelId, context }) => { +const NavigationMenuGuideList: React.FC = ({ id, active }) => { const router = useRouter() - const { isDarkMode } = useTheme() - - const menu = NavItems[id] - - //console.log(id, 'url is:', menu.url) // get url const url = router.asPath // remove the end of the url if a deep link const firstLevelRoute = url?.split('/')?.slice(0, 4)?.join('/') - const level = useMenuLevelId() - return ( -
      - - -
      -
      - -
      -
      - Back to Home -
      - - - - -
      - {menu.icon} - - {menu.title ?? level} - -
      -
      - - - {menu.items.map((x, index) => { - // console.log('1st type of link?', x.items && x.items.length > 0) - // console.log() - return ( -
      - {x.items && x.items.length > 0 ? ( -
      - {x.items.map((subItem, subItemIndex) => { - // console.log('subitem', { subItem }) - // console.log('router', router) - //console.log('subitem url', subItem.url) - let subItemMenuOpen = false - - if (router.asPath.includes(subItem.url)) { - subItemMenuOpen = true - } - - const LinkContainer = (props) => { - return ( - - {props.children} - - ) - } - - return ( - - {subItemIndex === 0 && ( - <> -
      - - {x.name} - - - )} - -
    • - - {subItem.icon && ( - {subItem.name - )} - {subItem.name} - -
    • - - {subItem.items && subItem.items.length > 0 && ( - - {subItem.items.map((subSubItem, subSubItemIndex) => { - return ( -
    • - - - {subSubItem.name} - - -
    • - ) - })} -
      - )} -
      -
      - ) - })} -
      - ) : ( - -
    • - - - {x.icon && ( - {x.icon} - )} - - {x.name} - - -
    • -
      - )} -
      - ) - })} - {menu.extras && ( - <> -
      - - Resources - - - )} - {menu.extras?.map((x) => { - return ( -
      -
    • - - - {x.icon && ( - {x.icon} - )} - {x.name} - - -
    • -
      - ) - })} -
    +
    ) } diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx new file mode 100644 index 00000000000..f298683984d --- /dev/null +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx @@ -0,0 +1,205 @@ +import { useTheme } from 'common/Providers' +import Image from 'next/image' +import Link from 'next/link' +import { useRouter } from 'next/router' +import React from 'react' +import { IconChevronLeft } from '~/../../packages/ui' +import * as NavItems from './NavigationMenu.constants' +import * as Accordion from '@radix-ui/react-accordion' + +interface ImPureProps { + // users: Array +} + +const HeaderImage = React.memo(function HeaderImage(props: any) { + const router = useRouter() + const { isDarkMode } = useTheme() + + return ( + {props.icon} + ) +}) + +const HeaderLink = React.memo(function HeaderLink(props: any) { + const router = useRouter() + + return ( + + {props.title ?? props.id} + + ) +}) + +const ContentAccordionLink = React.memo(function ContentAccordionLink(props: any) { + const router = useRouter() + const { isDarkMode } = useTheme() + + let subItemMenuOpen = false + + if (router.asPath.includes(props.subItem.url)) { + subItemMenuOpen = true + } + + const LinkContainer = (props) => { + return ( + + {props.children} + + ) + } + + return ( + <> + {props.subItemIndex === 0 && ( + <> +
    + + {props.parent.name} + + + )} + +
  • + + {props.subItem.icon && ( + {props.subItem.name + )} + {props.subItem.name} + +
  • + + {props.subItem.items && props.subItem.items.length > 0 && ( + + {props.subItem.items.map((subSubItem) => { + return ( +
  • + + + {subSubItem.name} + + +
  • + ) + })} +
    + )} +
    + + ) +}) + +const ContentLink = React.memo(function ContentLink(props: any) { + const router = useRouter() + + return ( +
  • + + + {props.icon && } + {props.name} + + +
  • + ) +}) + +const Content = (props) => { + const { id } = props + + const menu = NavItems[id] + + return ( +
      + + +
      +
      + +
      +
      + Back to Home +
      + + + + +
      + + +
      +
      + + + {menu.items.map((x, index) => { + return ( +
      + {x.items && x.items.length > 0 ? ( +
      + {x.items.map((subItem, subItemIndex) => { + return ( + + ) + })} +
      + ) : ( + + )} +
      + ) + })} +
    + ) +} + +export default React.memo(Content) diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefList.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefList.tsx index 377973897a7..206a50d2230 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefList.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefList.tsx @@ -1,76 +1,9 @@ -import * as Accordion from '@radix-ui/react-accordion' -import Link from 'next/link' -import { useRouter } from 'next/router' -import { IconChevronLeft } from 'ui' -import * as NavItems from './NavigationMenu.constants' +// import apiCommonSections from '~/../../spec/common-client-libs-sections.json' -import { find } from 'lodash' -import Image from 'next/image' -import { useTheme } from 'common/Providers' - -import RevVersionDropdown from '~/components/RefVersionDropdown' -import { useMenuActiveRefId, useMenuLevelId } from '~/hooks/useMenuState' import { RefIdOptions, RefKeyOptions } from './NavigationMenu' -import { isFuncNotInLibraryOrVersion } from './NavigationMenu.utils' -import { Fragment } from 'react' +import NavigationMenuRefListItems from './NavigationMenuRefListItems' -const FunctionLink = ({ - title, - id, - icon, - library, - slug, -}: { - title: string - name?: string - id: string - icon?: string - product?: string - library: string - slug: string -}) => { - const router = useRouter() - const activeAccordianItem = useMenuActiveRefId() - - // check if we're on a versioned page - let version = '' - if (router.asPath.includes('v1')) { - version = 'v1' - } - - if (router.asPath.includes('v0')) { - version = 'v0' - } - - const active = activeAccordianItem === id - return ( -
  • - - - {icon && {icon}} - {title} - - -
  • - ) -} - -const SideMenuTitle = ({ title }: { title: string }) => { - return ( - - {title} - - ) -} - -const Divider = () => { - return
    -} +import React from 'react' interface INavigationMenuRefList { id: RefIdOptions @@ -80,203 +13,34 @@ interface INavigationMenuRefList { // the keys of menu items that are allowed to be shown on the side menu // if undefined, we show all the menu items allowedClientKeys?: string[] + active: boolean + spec?: any } const NavigationMenuRefList: React.FC = ({ id, lib, commonSections, - allowedClientKeys, + + active, + spec, }) => { - const router = useRouter() - const { isDarkMode } = useTheme() - - let sections = commonSections - - const allowedKeys = allowedClientKeys - - if (!sections) console.error('no common sections imported') - - const menu = NavItems[id] - - const databaseFunctions = find(sections, { title: 'Database' }) - ? find(sections, { title: 'Database' }).items - : [] - - const authFunctions = find(sections, { title: 'Auth' }) - ? find(sections, { title: 'Auth' }).items - : [] - - const filterIds = - databaseFunctions.length > 0 - ? find(databaseFunctions, { - id: 'using-filters', - }) && - find(databaseFunctions, { - id: 'using-filters', - }) - .items.filter((x) => allowedKeys.includes(x.id)) - .map((x) => x.id) - : [] - const modifierIds = - databaseFunctions.length > 0 - ? find(databaseFunctions, { - id: 'using-modifiers', - }) && - find(databaseFunctions, { - id: 'using-modifiers', - }) - .items.filter((x) => allowedKeys.includes(x.id)) - .map((x) => x.id) - : [] - - const authServerIds = - databaseFunctions.length > 0 - ? find(authFunctions, { - id: 'admin-api', - }) && - find(authFunctions, { - id: 'admin-api', - }).items.map((x) => x.id) - : [] - - const level = useMenuLevelId() - return (
    -
    - - -
    -
    - -
    -
    - Back to Main Menu -
    - - -
    - {id} - - {menu.title} - - -
    - {/* )} */} - -
      - {sections.map((fn: any, fnIndex) => { - if (isFuncNotInLibraryOrVersion(fn.id, fn.type, allowedKeys)) { - return - } - - const RenderLink = (props) => { - const activeAccordianItem = useMenuActiveRefId() - let active = false - - const isFilter = - filterIds && filterIds.length > 0 && filterIds.includes(activeAccordianItem) - const isModifier = - modifierIds && modifierIds.length > 0 && modifierIds.includes(activeAccordianItem) - const isAuthServer = - authServerIds && - authServerIds.length > 0 && - authServerIds.includes(activeAccordianItem) - - if ( - (isFilter && !isModifier && !isAuthServer && props.id === 'using-filters') || - (activeAccordianItem === 'using-filters' && props.id === 'using-filters') - ) { - active = true - } else if ( - (isModifier && !isFilter && !isAuthServer && props.id === 'using-modifiers') || - (activeAccordianItem === 'using-modifiers' && props.id === 'using-modifiers') - ) { - active = true - } else if ( - (isAuthServer && !isFilter && !isModifier && props.id === 'admin-api') || - (activeAccordianItem === 'admin-api' && props.id === 'admin-api') - ) { - active = true - } else { - active = false - } - - return ( - - - - - {props.items && - props.items - .filter((item) => allowedKeys.includes(item.id)) - .map((item) => { - return - })} - - - - ) - } - - return fn.id ? ( - - - {fn.items && - fn.items.map((item) => ( - - ))} - - ) : ( - - - - {fn.items && - fn.items.map((item, i) => - isFuncNotInLibraryOrVersion(item.id, item.type, allowedKeys) ? ( - - ) : ( - - ) - )} - - ) - })} -
    -
    +
    ) } -export default NavigationMenuRefList +export default React.memo(NavigationMenuRefList) diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefListItems.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefListItems.tsx new file mode 100644 index 00000000000..fd87508d468 --- /dev/null +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefListItems.tsx @@ -0,0 +1,324 @@ +import * as Accordion from '@radix-ui/react-accordion' +import Link from 'next/link' +import { useRouter } from 'next/router' +import { IconChevronLeft } from 'ui' +import * as NavItems from './NavigationMenu.constants' + +import { find } from 'lodash' +import Image from 'next/image' +import { useTheme } from 'common/Providers' + +import RevVersionDropdown from '~/components/RefVersionDropdown' +import { useMenuActiveRefId } from '~/hooks/useMenuState' +import { RefIdOptions, RefKeyOptions } from './NavigationMenu' + +import React from 'react' +import { generateAllowedClientLibKeys } from '~/lib/refGenerator/helpers' + +const HeaderImage = React.memo(function HeaderImage(props: any) { + const router = useRouter() + const { isDarkMode } = useTheme() + + return ( + {props.icon} + ) +}) + +const HeaderLink = React.memo(function HeaderLink(props: any) { + const router = useRouter() + + return ( + + {props.title ?? props.id} + + ) +}) + +const FunctionLink = React.memo(function FunctionLink({ + title, + id, + icon, + library, + slug, +}: { + title: string + name?: string + id: string + icon?: string + product?: string + library: string + slug: string +}) { + const router = useRouter() + const activeAccordianItem = useMenuActiveRefId() + + // check if we're on a versioned page + let version = '' + if (router.asPath.includes('v1')) { + version = 'v1' + } + + if (router.asPath.includes('v0')) { + version = 'v0' + } + + const active = activeAccordianItem === id + return ( +
  • + + + {icon && {icon}} + {title} + + +
  • + ) +}) + +const RenderLink = React.memo(function RenderLink(props: any) { + const activeAccordianItem = useMenuActiveRefId() + let active = false + + const isFilter = props.filterIds?.includes(activeAccordianItem) + const isModifier = props.modifierIds?.includes(activeAccordianItem) + const isAuthServer = props.authServerIds?.includes(activeAccordianItem) + + if ( + (isFilter && props.id === 'using-filters') || + (activeAccordianItem === 'using-filters' && props.id === 'using-filters') + ) { + active = true + } else if ( + (isModifier && props.id === 'using-modifiers') || + (activeAccordianItem === 'using-modifiers' && props.id === 'using-modifiers') + ) { + active = true + } else if ( + (isAuthServer && props.id === 'admin-api') || + (activeAccordianItem === 'admin-api' && props.id === 'admin-api') + ) { + active = true + } else { + active = false + } + + return ( + + + + + {props.items && + props.items + .filter((item) => props.allowedKeys.includes(item.id)) + .map((item) => { + return ( + + ) + })} + + + + ) +}) + +const SideMenuTitle = ({ title }: { title: string }) => { + return ( + + {title} + + ) +} + +const Divider = () => { + return
    +} + +interface INavigationMenuRefList { + id: RefIdOptions + lib: RefKeyOptions + commonSections: any[] // to do type up + + // the keys of menu items that are allowed to be shown on the side menu + // if undefined, we show all the menu items + allowedClientKeys?: string[] + spec?: any +} + +const Content: React.FC = ({ id, lib, commonSections, spec }) => { + const allowedClientKeys = spec ? generateAllowedClientLibKeys(commonSections, spec) : undefined + + let sections = commonSections + + const allowedKeys = allowedClientKeys + + if (!sections) console.error('no common sections imported') + + const menu = NavItems[id] + + const databaseFunctions = find(sections, { title: 'Database' }) + ? find(sections, { title: 'Database' }).items + : [] + + const authFunctions = find(sections, { title: 'Auth' }) + ? find(sections, { title: 'Auth' }).items + : [] + + const filterIds = + databaseFunctions.length > 0 + ? find(databaseFunctions, { + id: 'using-filters', + }) && + find(databaseFunctions, { + id: 'using-filters', + }) + .items.filter((x) => allowedKeys.includes(x.id)) + .map((x) => x.id) + : [] + const modifierIds = + databaseFunctions.length > 0 + ? find(databaseFunctions, { + id: 'using-modifiers', + }) && + find(databaseFunctions, { + id: 'using-modifiers', + }) + .items.filter((x) => allowedKeys.includes(x.id)) + .map((x) => x.id) + : [] + + const authServerIds = + databaseFunctions.length > 0 + ? find(authFunctions, { + id: 'admin-api', + }) && + find(authFunctions, { + id: 'admin-api', + }).items.map((x) => x.id) + : [] + + return ( +
    + + +
    +
    + +
    +
    + Back to Main Menu +
    + + +
    + + + +
    + +
      + {sections.map((fn: any, fnIndex) => { + // + // check if the link is allowed to be displayed + function isFuncNotInLibraryOrVersion(id, type) { + if (id && allowedKeys && !allowedKeys.includes(id) && type !== 'markdown') { + /* + * Remove this menu link from side bar, as it does not exist for either + * this language, or for this lib version + * + * */ + return true + } else { + return false + } + } + + // run allow check + if (isFuncNotInLibraryOrVersion(fn.id, fn.type)) { + return <> + } + + // handle subtitles with subitems + if (!fn.id) { + return ( + <> + + + {fn.items && + fn.items + //.filter((item) => item.libs && item.libs.includes(lib)) + .map((item) => { + // run allow check + if (isFuncNotInLibraryOrVersion(item.id, item.type)) return <> + return ( + + ) + })} + + ) + } else { + // handle normal links + return ( + <> + + {fn.items && + fn.items + //.filter((item) => item.libs.includes(lib)) + .map((item) => ( + + ))} + + ) + } + })} +
    +
    + ) +} + +export default React.memo(Content) diff --git a/apps/docs/hooks/useMenuState.ts b/apps/docs/hooks/useMenuState.ts index 760796e1244..52977307542 100644 --- a/apps/docs/hooks/useMenuState.ts +++ b/apps/docs/hooks/useMenuState.ts @@ -7,7 +7,7 @@ export const menuState = proxy({ setMenuActiveRefId: (value) => { menuState.menuActiveRefId = value }, - menuLevelId: '', + menuLevelId: 'home', setMenuLevelId: (value) => { menuState.menuMobileOpen = false menuState.menuLevelId = value diff --git a/apps/docs/layouts/SiteLayout.tsx b/apps/docs/layouts/SiteLayout.tsx index ac46ec931fc..9aa8c37d9c0 100644 --- a/apps/docs/layouts/SiteLayout.tsx +++ b/apps/docs/layouts/SiteLayout.tsx @@ -1,18 +1,293 @@ import { useTheme } from 'common/Providers' import Image from 'next/image' import Link from 'next/link' -import { useRouter } from 'next/router' import NavigationMenu from '~/components/Navigation/NavigationMenu/NavigationMenu' import TopNavBarRef from '~/components/Navigation/NavigationMenu/TopNavBarRef' import FooterHelpCallout from '~/components/FooterHelpCallout' -import { menuState, useMenuLevelId, useMenuMobileOpen } from '~/hooks/useMenuState' -import { useEffect } from 'react' +import { memo, useEffect } from 'react' import Footer from '~/components/Navigation/Footer' +import { menuState, useMenuLevelId, useMenuMobileOpen } from '~/hooks/useMenuState' + +const levelsData = { + home: { + icon: '/docs/img/icons/menu/home', + name: 'Home', + }, + gettingstarted: { + icon: '/docs/img/icons/menu/getting-started', + name: 'Getting Started', + }, + database: { + icon: '/docs/img/icons/menu/database', + name: 'Database', + }, + auth: { + icon: '/docs/img/icons/menu/auth', + name: 'Auth', + }, + functions: { + icon: '/docs/img/icons/menu/functions', + name: 'Functions', + }, + realtime: { + icon: '/docs/img/icons/menu/realtime', + name: 'Realtime', + }, + storage: { + icon: '/docs/img/icons/menu/storage', + name: 'Storage', + }, + platform: { + icon: '/docs/img/icons/menu/platform', + name: 'Platform', + }, + resources: { + icon: '/docs/img/icons/menu/resources', + name: 'Resources', + }, + self_hosting: { + icon: '/docs/img/icons/menu/self-hosting', + name: 'Self-Hosting', + }, + integrations: { + icon: '/docs/img/icons/menu/integrations', + name: 'Integrations', + }, + reference_javascript_v1: { + icon: '/docs/img/icons/menu/reference-javascript', + name: 'Javascript Reference v1.0', + }, + reference_javascript_v2: { + icon: '/docs/img/icons/menu/reference-javascript', + name: 'Javascript Reference v2.0', + }, + reference_dart_v0: { + icon: '/docs/img/icons/menu/reference-dart', + name: 'Dart Reference v0.0', + }, + reference_dart_v1: { + icon: '/docs/img/icons/menu/reference-dart', + name: 'Dart Reference v0.0', + }, + reference_cli: { + icon: '/docs/img/icons/menu/reference-cli', + name: 'CLI Reference', + }, + reference_api: { + icon: '/docs/img/icons/menu/reference-api', + name: 'Management API Reference', + }, + reference_self_hosting_auth: { + icon: '/docs/img/icons/menu/reference-auth', + name: 'Auth Server Reference', + }, + reference_self_hosting_storage: { + icon: '/docs/img/icons/menu/reference-storage', + name: 'Storage Server Reference', + }, + reference_self_hosting_realtime: { + icon: '/docs/img/icons/menu/reference-realtime', + name: 'Realtime Server Reference', + }, +} + +const MobileHeader = memo(function MobileHeader() { + const mobileMenuOpen = useMenuMobileOpen() + const menuLevel = useMenuLevelId() + + return ( +
    + +
    + +
    + + {mobileMenuOpen + ? 'Close' + : menuLevel + ? levelsData[menuLevel].name + : levelsData['home'].name} + +
    + ) +}) + +const MobileMenuBackdrop = memo(function MobileMenuBackdrop() { + const mobileMenuOpen = useMenuMobileOpen() + return ( +
    menuState.setMenuMobileOpen(!mobileMenuOpen)} + >
    + ) +}) + +const SideMenu = memo(function SideMenu() { + return ( +
    + +
    + ) +}) + +const HeaderLogo = memo(function HeaderLogo() { + const { isDarkMode } = useTheme() + return ( + + + Supabase Logo + DOCS + + + ) +}) + +const Container = memo(function Container(props) { + const mobileMenuOpen = useMenuMobileOpen() + + return ( +
    +
    {props.children}
    +
    + ) +}) + +const NavContainer = memo(function NavContainer() { + const mobileMenuOpen = useMenuMobileOpen() + + return ( +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    + ) +}) const SiteLayout = ({ children }) => { - const { isDarkMode } = useTheme() + // const mobileMenuOpen = useMenuMobileOpen() useEffect(() => { const key = localStorage.getItem('supabaseDarkMode') @@ -24,275 +299,32 @@ const SiteLayout = ({ children }) => { } }, []) - const menuLevel = useMenuLevelId() - const mobileMenuOpen = useMenuMobileOpen() - - const levelsData = { - home: { - icon: '/docs/img/icons/menu/home', - name: 'Home', - }, - gettingstarted: { - icon: '/docs/img/icons/menu/getting-started', - name: 'Getting Started', - }, - database: { - icon: '/docs/img/icons/menu/database', - name: 'Database', - }, - auth: { - icon: '/docs/img/icons/menu/auth', - name: 'Auth', - }, - functions: { - icon: '/docs/img/icons/menu/functions', - name: 'Functions', - }, - realtime: { - icon: '/docs/img/icons/menu/realtime', - name: 'Realtime', - }, - storage: { - icon: '/docs/img/icons/menu/storage', - name: 'Storage', - }, - platform: { - icon: '/docs/img/icons/menu/platform', - name: 'Platform', - }, - resources: { - icon: '/docs/img/icons/menu/resources', - name: 'Resources', - }, - self_hosting: { - icon: '/docs/img/icons/menu/self-hosting', - name: 'Self-Hosting', - }, - integrations: { - icon: '/docs/img/icons/menu/integrations', - name: 'Integrations', - }, - reference_javascript_v1: { - icon: '/docs/img/icons/menu/reference-javascript', - name: 'Javascript Reference v1.0', - }, - reference_javascript_v2: { - icon: '/docs/img/icons/menu/reference-javascript', - name: 'Javascript Reference v2.0', - }, - reference_dart_v0: { - icon: '/docs/img/icons/menu/reference-dart', - name: 'Dart Reference v0.0', - }, - reference_dart_v1: { - icon: '/docs/img/icons/menu/reference-dart', - name: 'Dart Reference v0.0', - }, - reference_cli: { - icon: '/docs/img/icons/menu/reference-cli', - name: 'CLI Reference', - }, - reference_api: { - icon: '/docs/img/icons/menu/reference-api', - name: 'Management API Reference', - }, - reference_self_hosting_auth: { - icon: '/docs/img/icons/menu/reference-auth', - name: 'Auth Server Reference', - }, - reference_self_hosting_storage: { - icon: '/docs/img/icons/menu/reference-storage', - name: 'Storage Server Reference', - }, - reference_self_hosting_realtime: { - icon: '/docs/img/icons/menu/reference-realtime', - name: 'Realtime Server Reference', - }, - } - return (
    - {/* */} -
    -
    ) diff --git a/apps/docs/lib/refGenerator/helpers.ts b/apps/docs/lib/refGenerator/helpers.ts index 6af5b8eb539..9c14a80167f 100644 --- a/apps/docs/lib/refGenerator/helpers.ts +++ b/apps/docs/lib/refGenerator/helpers.ts @@ -2,6 +2,7 @@ import { TsDoc } from '../../generator/legacy/definitions' import { values, mapValues } from 'lodash' import { OpenAPIV3 } from 'openapi-types' +import { flattenSections } from '../helpers' export function extractTsDocNode(nodeToFind: string, definition: any) { const nodePath = nodeToFind.split('.') @@ -285,3 +286,23 @@ export const toArrayWithKey = (obj: object, keyAs: string) => return value }) ) + +export function generateAllowedClientLibKeys(sections, spec) { + // Filter parent sections first + + const specIds = spec.functions.map((func) => { + return func.id + }) + + const newShape = flattenSections(sections).filter((section) => { + if (specIds.includes(section.id)) { + return section + } + }) + + const final = newShape.map((func) => { + return func.id + }) + + return final +} diff --git a/apps/docs/pages/_app.tsx b/apps/docs/pages/_app.tsx index 52a0b995643..0736cff9c2b 100644 --- a/apps/docs/pages/_app.tsx +++ b/apps/docs/pages/_app.tsx @@ -13,7 +13,6 @@ import '../styles/main.scss?v=1.0.0' import '../styles/new-docs.scss' import '../styles/prism-okaidia.scss' import { post } from '~/lib/fetchWrappers' -import { menuState } from '~/hooks/useMenuState' function MyApp({ Component, pageProps }: AppPropsWithLayout) { const router = useRouter() diff --git a/apps/docs/pages/guides/auth/overview.mdx b/apps/docs/pages/guides/auth/overview.mdx index 85b1fdc96da..97044096e13 100644 --- a/apps/docs/pages/guides/auth/overview.mdx +++ b/apps/docs/pages/guides/auth/overview.mdx @@ -55,7 +55,7 @@ You can enable third-party providers with the click of a button by navigating to ### Redirect URLs and wildcards -When using third-party providers, the [Supabase client library](/docs/reference/javascript/auth-signinwithoauth#sign-in-using-a-third-party-provider-with-redirect) redirects the user to the provider. When the third-party provider successfully authenticates the user, the provider redirects the user to the Supabase Auth callback URL where they are further redirected to the URL specified in the `redirectTo` parameter. This parameter defaults to the [`SITE_URL`](/docs/reference/auth/config#site_url). You can modify the `SITE_URL` or [add additional redirect URLs](https://app.supabase.com/project/_/auth/settings). +When using third-party providers, the [Supabase client library](/docs/reference/javascript/auth-signinwithoauth#sign-in-using-a-third-party-provider-with-redirect) redirects the user to the provider. When the third-party provider successfully authenticates the user, the provider redirects the user to the Supabase Auth callback URL where they are further redirected to the URL specified in the `redirectTo` parameter. This parameter defaults to the [`SITE_URL`](/docs/reference/auth/config#site_url). You can modify the `SITE_URL` or add additional [redirect URLs](https://app.supabase.com/project/_/auth/url-configuration). You can use wildcard match patterns to support preview URLs from providers like Netlify and Vercel. See the [full list of supported patterns](https://pkg.go.dev/github.com/gobwas/glob#Compile). Use [this tool](https://www.digitalocean.com/community/tools/glob?comments=true&glob=http%3A%2F%2Flocalhost%3A3000%2F%2A%2A&matches=false&tests=http%3A%2F%2Flocalhost%3A3000&tests=http%3A%2F%2Flocalhost%3A3000%2F&tests=http%3A%2F%2Flocalhost%3A3000%2F%3Ftest%3Dtest&tests=http%3A%2F%2Flocalhost%3A3000%2Ftest-test%3Ftest%3Dtest&tests=http%3A%2F%2Flocalhost%3A3000%2Ftest%2Ftest%3Ftest%3Dtest) to test your patterns. diff --git a/apps/docs/pages/guides/integrations/prisma.mdx b/apps/docs/pages/guides/integrations/prisma.mdx index 7334621d910..6a80e95fee6 100644 --- a/apps/docs/pages/guides/integrations/prisma.mdx +++ b/apps/docs/pages/guides/integrations/prisma.mdx @@ -63,21 +63,38 @@ This project comes with TypeScript configured and has the following structure. ### Configuring the project to use PostgreSQL -Go ahead and delete the `prisma/dev.db` file because we will be switching to PostgreSQL. -Next, inside the `prisma/.env` file, update the value of the `DATABASE_URL` variable to the connection string you got in **step 1**. The URL might look as follows: +By default, Prisma migrations will try to drop the `postgres` database, which can lead to conflicts with Supabase databases. For this scenario, use [Prisma Shadow Databases](https://www.prisma.io/docs/concepts/components/prisma-migrate/shadow-database#cloud-hosted-shadow-databases-must-be-created-manually). -```env -# prisma/.env -postgres://postgres:[YOUR-PASSWORD]@db.vdbnhqozmlzdsaejdxwr.supabase.co:5432/postgres +Create a shadow database in your PostgreSQL server within the same Supabase project using the `psql` CLI and the `DATABASE_URL` from the previous steps (or use the local database). + +```bash +psql postgresql://postgres:[YOUR-PASSWORD]@db.vdbnhqozmlzdsaejdxwr.supabase.red:5432 ``` -Finally, inside your `schema.prisma` file, change the `provider` from “sqlite” to `“postgresql”`. +After you connect to your project's PostgreSQL instance, create another database (e.g., `postgres_shadow`): + +```bash +postgres=> CREATE DATABASE postgres_shadow; +postgres=> exit +``` + +Go ahead and delete the `prisma/dev.db` file because we will be switching to PostgreSQL. +In the `.env` file, update `DATABASE_URL` and `SHADOW_DATABASE_URL` to the connection string from **step 1**. The `.env` file should look like: + +```env +# .env +DATABASE_URL="postgres://postgres:[YOUR-PASSWORD]@db.vdbnhqozmlzdsaejdxwr.supabase.co:5432/postgres" +SHADOW_DATABASE_URL="postgres://postgres:[YOUR-PASSWORD]@db.vdbnhqozmlzdsaejdxwr.supabase.co:5432/postgres_shadow" +``` + +In the `schema.prisma` file, change the `provider` from "sqlite" to `"postgresql"` and add the `shadowDatabaseUrl` property. This is what your `schema.prisma` file should look like: ```go datasource db { provider = “postgresql” url = env(“DATABASE_URL”) + shadowDatabaseUrl = env("SHADOW_DATABASE_URL") } generator client { provider = “prisma-client-js” @@ -124,11 +141,12 @@ This will create a `prisma/migrations` folder inside your `prisma` directory and If you’re working in a serverless environment (for example Node.js functions hosted on AWS Lambda, Vercel or Netlify Functions), you need to set up [connection pooling](https://www.prisma.io/docs/guides/performance-and-optimization/connection-management#serverless-environments-faas) using a tool like [PgBouncer](https://www.pgbouncer.org/). That’s because every function invocation may result in a [new connection to the database](https://www.prisma.io/docs/guides/performance-and-optimization/connection-management#the-serverless-challenge). Supabase [supports connection management using PgBouncer](https://supabase.io/blog/2021/04/02/supabase-pgbouncer#what-is-connection-pooling) and are enabled by default. Go to the **Database** page from the sidebar in the Supabase dashboard and navigate to **connection pool** settings ![Connection pool settings](/docs/img/guides/integrations/prisma/w0oowg8vq435ob5c3gf0.png) -When running migrations you need to use the non pooled connection URL (like the one we used in **step 1**). However, when deploying your app, you’ll use the pooled connection URL and add the `?pgbouncer=true` flag to the PostgreSQL connection URL. To minimize the number of concurrent connections, setting the `connection_limit` to `1` is also recommended. So the URL might look as follows: +When migrating, you need to use the non-pooled connection URL (like the one used in **step 1**). However, when deploying your app, use the pooled connection URL and add the `?pgbouncer=true` flag to the PostgreSQL connection URL. It's also recommended to minimize the number of concurrent connections by setting the `connection_limit` to `1`. The `.env` file should look like: ```env -# prisma/.env -postgres://postgres:[YOUR-PASSWORD]@db.vdbnhqozmlzdsaejdxwr.supabase.co:6543/postgres?pgbouncer=true&connection_limit=1 +# .env +DATABASE_URL="postgres://postgres:[YOUR-PASSWORD]@db.vdbnhqozmlzdsaejdxwr.supabase.co:6543/postgres?pgbouncer=true&connection_limit=1" +SHADOW_DATABASE_URL="postgres://postgres:[YOUR-PASSWORD]@db.vdbnhqozmlzdsaejdxwr.supabase.co:5432/postgres_shadow" ``` Prisma Migrate uses database transactions to check out the current state of the database and the migrations table. However, the Migration Engine is designed to use a single connection to the database, and does not support connection pooling with PgBouncer. If you attempt to run Prisma Migrate commands in any environment that uses PgBouncer for connection pooling, you might see the following error: diff --git a/apps/www/_blog/2022-08-03-supabase-beta-update-july-2022.mdx b/apps/www/_blog/2022-08-03-supabase-beta-update-july-2022.mdx index 2330e5f8703..5f7812d4c91 100644 --- a/apps/www/_blog/2022-08-03-supabase-beta-update-july-2022.mdx +++ b/apps/www/_blog/2022-08-03-supabase-beta-update-july-2022.mdx @@ -48,7 +48,7 @@ The new hCpatcha integration allows you to implement captcha functionality for a ![supabase-updated-settings-ui-dashboard](/images/blog/2022-july/auth-config.jpeg) -We've started updating our settings UI, starting with the Auth settings. You'll now see updated UI for setting up your Auth providers, Email templates and SMTP config. [Auth settings](https://app.supabase.com/project/_/auth/settings) +We've started updating our settings UI, starting with the Auth settings. You'll now see updated UI for setting up your [Auth providers](https://app.supabase.com/project/_/auth/providers), [Email templates](https://app.supabase.com/project/_/auth/templates), and [SMTP config](https://app.supabase.com/project/_/auth/url-configuration). ## Quick product announcements diff --git a/apps/www/_blog/2022-12-09-launch-week-6-hackathon.mdx b/apps/www/_blog/2022-12-09-launch-week-6-hackathon.mdx index 212e9cce132..5401d567ae6 100644 --- a/apps/www/_blog/2022-12-09-launch-week-6-hackathon.mdx +++ b/apps/www/_blog/2022-12-09-launch-week-6-hackathon.mdx @@ -113,3 +113,16 @@ Don't forget to checkout the new feature's being announced as part of [Launch We - Any intellectual property developed during the hackathon will belong to the team that developed it. We expect that each team will have an agreement between themselves regarding the IP, but this is not required - By making a submission you grant Supabase permission to use screenshots, code-snippets and/or links to your project or content of your README on our Twitter, blog, website, email updates, and in the Supabase discord server. Supabase does not make any claims over your IP. - $1500 prize will be paid by making a GitHub sponsorship to the winning repo, $500/month for 3 months. The goal here is to create a sustainable project that will be continue to be maintained for the duration of the sponsorship period (and hopefully beyond :) ) + +## More Launch Week 6 + +- [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) +- [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) +- [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) +- [Day 4: Supabase Wrappers, a Postgres FDW framework written in Rust](https://supabase.com/blog/postgres-foreign-data-wrappers-rust) +- [Day 5: Supabase Vault is now in Beta](https://supabase.com/blog/vault-now-in-beta) +- [Community Day](https://supabase.com/blog/launch-week-6-community-day) +- [Point in Time Recovery is now available](https://supabase.com/blog/postgres-point-in-time-recovery) +- [Custom Domain Names are now available](https://supabase.com/blog/custom-domain-names) +- [Wrap Up: everything we shipped](https://supabase.com/blog/launch-week-6-wrap-up) + diff --git a/apps/www/_blog/2022-12-10-postgres-crdt.mdx b/apps/www/_blog/2022-12-10-postgres-crdt.mdx index 066544d0003..143a356fee7 100644 --- a/apps/www/_blog/2022-12-10-postgres-crdt.mdx +++ b/apps/www/_blog/2022-12-10-postgres-crdt.mdx @@ -145,3 +145,15 @@ We're likely to discover more (no doubt from a few friendly HN comments). ## Next steps If you want to help with `pg_crdt` the best way is to get involved in the GitHub repo. We have enabled [Discussions](https://github.com/supabase/pg_crdt/discussions) for any and all ideas. If you have experience with CRDTs and you like this approach, don't hesitate to contact one of the team. + +## More Launch Week 6 + +- [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) +- [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) +- [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) +- [Day 4: Supabase Wrappers, a Postgres FDW framework written in Rust](https://supabase.com/blog/postgres-foreign-data-wrappers-rust) +- [Day 5: Supabase Vault is now in Beta](https://supabase.com/blog/vault-now-in-beta) +- [Community Day](https://supabase.com/blog/launch-week-6-community-day) +- [Point in Time Recovery is now available](https://supabase.com/blog/postgres-point-in-time-recovery) +- [Custom Domain Names are now available](https://supabase.com/blog/custom-domain-names) +- [Wrap Up: everything we shipped](https://supabase.com/blog/launch-week-6-wrap-up) diff --git a/apps/www/_blog/2022-12-12-new-supabase-docs-built-with-nextjs.mdx b/apps/www/_blog/2022-12-12-new-supabase-docs-built-with-nextjs.mdx index 41f8ef5ac1e..9f725b9ab84 100644 --- a/apps/www/_blog/2022-12-12-new-supabase-docs-built-with-nextjs.mdx +++ b/apps/www/_blog/2022-12-12-new-supabase-docs-built-with-nextjs.mdx @@ -94,6 +94,12 @@ Docs are more than just the tech behind them. The goal of docs is to give you, t ## More Launch Week 6 -- [Launch Week 6 Hackathon](https://supabase.com/blog/launch-week-6-hackathon) -- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) -- [pg_crdt - an experimental CRDT extension for Postgres](https://supabase.com/blog/postgres-crdt) +- [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) +- [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) +- [Day 4: Supabase Wrappers, a Postgres FDW framework written in Rust](https://supabase.com/blog/postgres-foreign-data-wrappers-rust) +- [Day 5: Supabase Vault is now in Beta](https://supabase.com/blog/vault-now-in-beta) +- [Community Day](https://supabase.com/blog/launch-week-6-community-day) +- [Point in Time Recovery is now available](https://supabase.com/blog/postgres-point-in-time-recovery) +- [Custom Domain Names are now available](https://supabase.com/blog/custom-domain-names) +- [Wrap Up: everything we shipped](https://supabase.com/blog/launch-week-6-wrap-up) + diff --git a/apps/www/_blog/2022-12-13-storage-image-resizing-smart-cdn.mdx b/apps/www/_blog/2022-12-13-storage-image-resizing-smart-cdn.mdx index 00f68ff0f90..deb677996d5 100644 --- a/apps/www/_blog/2022-12-13-storage-image-resizing-smart-cdn.mdx +++ b/apps/www/_blog/2022-12-13-storage-image-resizing-smart-cdn.mdx @@ -205,3 +205,14 @@ A few features to look out for in the future: - Check out the Docs for [Image Resizing](https://supabase.com/docs/guides/storage/image-transformations). - Check out the Docs for the [Storage CDN](https://supabase.com/docs/guides/storage/cdn). - Get Started today with the [JavaScript](https://supabase.com/docs/reference/javascript/storage-from-download) and [Dart](https://supabase.com/docs/reference/dart/storage-from-list) client libraries. + +## More Launch Week 6 + +- [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) +- [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) +- [Day 4: Supabase Wrappers, a Postgres FDW framework written in Rust](https://supabase.com/blog/postgres-foreign-data-wrappers-rust) +- [Day 5: Supabase Vault is now in Beta](https://supabase.com/blog/vault-now-in-beta) +- [Community Day](https://supabase.com/blog/launch-week-6-community-day) +- [Point in Time Recovery is now available](https://supabase.com/blog/postgres-point-in-time-recovery) +- [Custom Domain Names are now available](https://supabase.com/blog/custom-domain-names) +- [Wrap Up: everything we shipped](https://supabase.com/blog/launch-week-6-wrap-up) diff --git a/apps/www/_blog/2022-12-14-mfa-auth-via-rls.mdx b/apps/www/_blog/2022-12-14-mfa-auth-via-rls.mdx index b2b4cbedff0..bfb8e02b25d 100644 --- a/apps/www/_blog/2022-12-14-mfa-auth-via-rls.mdx +++ b/apps/www/_blog/2022-12-14-mfa-auth-via-rls.mdx @@ -128,10 +128,14 @@ For starters, we are looking to support WebAuthn and FIDO2 compliant devices suc We are grateful to our early MFA users for the support and feedback provided throughout this period. In particular, we would like to thank [Fabian Beer](https://madebyfabian.com), [Cogram](https://www.cogram.com), and [Happl](https://happl.com) whose detailed feedback helped to shape our implementation. We would also like to specially thank the community behind the [pquerna/otp](https://github.com/pquerna/otp) and [ajstarks/svgo](https://github.com/ajstarks/svgo) libraries - their work is indispensable to this implementation. + ## More Launch Week 6 - [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) - [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) -- [Launch Week 6 Hackathon](https://supabase.com/blog/launch-week-6-hackathon) -- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) -- [pg_crdt - an experimental CRDT extension for Postgres](https://supabase.com/blog/postgres-crdt) +- [Day 4: Supabase Wrappers, a Postgres FDW framework written in Rust](https://supabase.com/blog/postgres-foreign-data-wrappers-rust) +- [Day 5: Supabase Vault is now in Beta](https://supabase.com/blog/vault-now-in-beta) +- [Community Day](https://supabase.com/blog/launch-week-6-community-day) +- [Point in Time Recovery is now available](https://supabase.com/blog/postgres-point-in-time-recovery) +- [Custom Domain Names are now available](https://supabase.com/blog/custom-domain-names) +- [Wrap Up: everything we shipped](https://supabase.com/blog/launch-week-6-wrap-up) diff --git a/apps/www/_blog/2022-12-15-postgres-foreign-data-wrappers-rust.mdx b/apps/www/_blog/2022-12-15-postgres-foreign-data-wrappers-rust.mdx index c746fd61ba4..62147a24dd0 100644 --- a/apps/www/_blog/2022-12-15-postgres-foreign-data-wrappers-rust.mdx +++ b/apps/www/_blog/2022-12-15-postgres-foreign-data-wrappers-rust.mdx @@ -259,6 +259,8 @@ If you're interested in getting involved or building your own Wrapper, don't hes - [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) - [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) - [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) -- [Launch Week 6 Hackathon](https://supabase.com/blog/launch-week-6-hackathon) -- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) -- [pg_crdt - an experimental CRDT extension for Postgres](https://supabase.com/blog/postgres-crdt) +- [Day 5: Supabase Vault is now in Beta](https://supabase.com/blog/vault-now-in-beta) +- [Community Day](https://supabase.com/blog/launch-week-6-community-day) +- [Point in Time Recovery is now available](https://supabase.com/blog/postgres-point-in-time-recovery) +- [Custom Domain Names are now available](https://supabase.com/blog/custom-domain-names) +- [Wrap Up: everything we shipped](https://supabase.com/blog/launch-week-6-wrap-up) diff --git a/apps/www/_blog/2022-12-16-custom-domain-names.mdx b/apps/www/_blog/2022-12-16-custom-domain-names.mdx index 014255f71a8..79ca54ad805 100644 --- a/apps/www/_blog/2022-12-16-custom-domain-names.mdx +++ b/apps/www/_blog/2022-12-16-custom-domain-names.mdx @@ -62,6 +62,8 @@ We're working hard to fix these limitations, so stay tuned for future updates. - [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) - [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) - [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) -- [Launch Week 6 Hackathon](https://supabase.com/blog/launch-week-6-hackathon) -- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) -- [pg_crdt - an experimental CRDT extension for Postgres](https://supabase.com/blog/postgres-crdt) +- [Day 4: Supabase Wrappers, a Postgres FDW framework written in Rust](https://supabase.com/blog/postgres-foreign-data-wrappers-rust) +- [Day 5: Supabase Vault is now in Beta](https://supabase.com/blog/vault-now-in-beta) +- [Point in Time Recovery is now available](https://supabase.com/blog/postgres-point-in-time-recovery) +- [Custom Domain Names are now available](https://supabase.com/blog/custom-domain-names) +- [Wrap Up: everything we shipped](https://supabase.com/blog/launch-week-6-wrap-up) diff --git a/apps/www/_blog/2022-12-16-launch-week-6-community-day.mdx b/apps/www/_blog/2022-12-16-launch-week-6-community-day.mdx index b0c7f395dc8..81cbbfdf6d7 100644 --- a/apps/www/_blog/2022-12-16-launch-week-6-community-day.mdx +++ b/apps/www/_blog/2022-12-16-launch-week-6-community-day.mdx @@ -237,4 +237,7 @@ We plan to continue our open and collaborative trend. There are many companies w - [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) - [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) - [Day 4: Supabase Wrappers, a Postgres FDW framework written in Rust](https://supabase.com/blog/postgres-foreign-data-wrappers-rust) -- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) +- [Day 5: Supabase Vault is now in Beta](https://supabase.com/blog/vault-now-in-beta) +- [Point in Time Recovery is now available](https://supabase.com/blog/postgres-point-in-time-recovery) +- [Custom Domain Names are now available](https://supabase.com/blog/custom-domain-names) +- [Wrap Up: everything we shipped](https://supabase.com/blog/launch-week-6-wrap-up) diff --git a/apps/www/_blog/2022-12-16-new-in-postgres-15.mdx b/apps/www/_blog/2022-12-16-new-in-postgres-15.mdx index d1b158b5a47..6eb78cee729 100644 --- a/apps/www/_blog/2022-12-16-new-in-postgres-15.mdx +++ b/apps/www/_blog/2022-12-16-new-in-postgres-15.mdx @@ -68,3 +68,15 @@ Before choosing to upgrade, don't forget to check the list of rare cases that ne - If you're self-hosting, upgrading between major PostgreSQL is easily done with [pg_upgrade](https://www.postgresql.org/docs/current/pgupgrade.html) utility or a set of recommended practices in the [official docs](https://www.postgresql.org/docs/current/upgrading.html). - If you're starting a new project on Supabase, you'll already be on PG15. - If you want to upgrade an existing project, check out our [Upgrading](https://supabase.com/docs/guides/platform/migrating-and-upgrading-projects#upgrade-your-project) documentation. + +## More Launch Week 6 + +- [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) +- [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) +- [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) +- [Day 4: Supabase Wrappers, a Postgres FDW framework written in Rust](https://supabase.com/blog/postgres-foreign-data-wrappers-rust) +- [Day 5: Supabase Vault is now in Beta](https://supabase.com/blog/vault-now-in-beta) +- [Community Day](https://supabase.com/blog/launch-week-6-community-day) +- [Point in Time Recovery is now available](https://supabase.com/blog/postgres-point-in-time-recovery) +- [Custom Domain Names are now available](https://supabase.com/blog/custom-domain-names) +- [Wrap Up: everything we shipped](https://supabase.com/blog/launch-week-6-wrap-up) diff --git a/apps/www/_blog/2022-12-16-pg-graphql-v1.mdx b/apps/www/_blog/2022-12-16-pg-graphql-v1.mdx index 30c6c59d777..d72dcdfd1d4 100644 --- a/apps/www/_blog/2022-12-16-pg-graphql-v1.mdx +++ b/apps/www/_blog/2022-12-16-pg-graphql-v1.mdx @@ -98,6 +98,9 @@ Longer term we look forward to experimenting with more ambitions features like a - [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) - [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) - [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) -- [Launch Week 6 Hackathon](https://supabase.com/blog/launch-week-6-hackathon) -- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) -- [pg_crdt - an experimental CRDT extension for Postgres](https://supabase.com/blog/postgres-crdt) +- [Day 4: Supabase Wrappers, a Postgres FDW framework written in Rust](https://supabase.com/blog/postgres-foreign-data-wrappers-rust) +- [Day 5: Supabase Vault is now in Beta](https://supabase.com/blog/vault-now-in-beta) +- [Community Day](https://supabase.com/blog/launch-week-6-community-day) +- [Point in Time Recovery is now available](https://supabase.com/blog/postgres-point-in-time-recovery) +- [Custom Domain Names are now available](https://supabase.com/blog/custom-domain-names) +- [Wrap Up: everything we shipped](https://supabase.com/blog/launch-week-6-wrap-up) diff --git a/apps/www/_blog/2022-12-16-postgres-point-in-time-recovery.mdx b/apps/www/_blog/2022-12-16-postgres-point-in-time-recovery.mdx index 243adfdb0e1..3e9007dbe0b 100644 --- a/apps/www/_blog/2022-12-16-postgres-point-in-time-recovery.mdx +++ b/apps/www/_blog/2022-12-16-postgres-point-in-time-recovery.mdx @@ -45,6 +45,8 @@ Enabling Point in Time Recovery could be done [in the Dashboard](https://app.sup - [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) - [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) - [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) -- [Launch Week 6 Hackathon](https://supabase.com/blog/launch-week-6-hackathon) -- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) -- [pg_crdt - an experimental CRDT extension for Postgres](https://supabase.com/blog/postgres-crdt) +- [Day 4: Supabase Wrappers, a Postgres FDW framework written in Rust](https://supabase.com/blog/postgres-foreign-data-wrappers-rust) +- [Day 5: Supabase Vault is now in Beta](https://supabase.com/blog/vault-now-in-beta) +- [Community Day](https://supabase.com/blog/launch-week-6-community-day) +- [Custom Domain Names are now available](https://supabase.com/blog/custom-domain-names) +- [Wrap Up: everything we shipped](https://supabase.com/blog/launch-week-6-wrap-up) diff --git a/apps/www/_blog/2022-12-16-postgrest-11-prerelease.mdx b/apps/www/_blog/2022-12-16-postgrest-11-prerelease.mdx index bbef228a26d..138a576eefc 100644 --- a/apps/www/_blog/2022-12-16-postgrest-11-prerelease.mdx +++ b/apps/www/_blog/2022-12-16-postgrest-11-prerelease.mdx @@ -224,3 +224,15 @@ $ supabase start ``` Please try it and report any bugs, suggestions or ideas! + +## More Launch Week 6 + +- [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) +- [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) +- [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) +- [Day 4: Supabase Wrappers, a Postgres FDW framework written in Rust](https://supabase.com/blog/postgres-foreign-data-wrappers-rust) +- [Day 5: Supabase Vault is now in Beta](https://supabase.com/blog/vault-now-in-beta) +- [Community Day](https://supabase.com/blog/launch-week-6-community-day) +- [Point in Time Recovery is now available](https://supabase.com/blog/postgres-point-in-time-recovery) +- [Custom Domain Names are now available](https://supabase.com/blog/custom-domain-names) +- [Wrap Up: everything we shipped](https://supabase.com/blog/launch-week-6-wrap-up) diff --git a/apps/www/_blog/2022-12-16-vault-now-in-beta.mdx b/apps/www/_blog/2022-12-16-vault-now-in-beta.mdx index 3d1418be10d..141e75ed838 100644 --- a/apps/www/_blog/2022-12-16-vault-now-in-beta.mdx +++ b/apps/www/_blog/2022-12-16-vault-now-in-beta.mdx @@ -91,6 +91,8 @@ You'll see the Vault appear in the Dashboard over the next month. If you want to - [Day 1: New Supabase Docs, built with Next.js](https://supabase.com/blog/new-supabase-docs-built-with-nextjs) - [Day 2: Supabase Storage v2: Image resizing and Smart CDN](https://supabase.com/blog/storage-image-resizing-smart-cdn) - [Day 3: Multi-factor Authentication via Row Level Security Enforcement](https://supabase.com/blog/mfa-auth-via-rls) -- [Launch Week 6 Hackathon](https://supabase.com/blog/launch-week-6-hackathon) -- [Who We Hire at Supabase](https://supabase.com/blog/who-we-hire) -- [pg_crdt - an experimental CRDT extension for Postgres](https://supabase.com/blog/postgres-crdt) +- [Day 4: Supabase Wrappers, a Postgres FDW framework written in Rust](https://supabase.com/blog/postgres-foreign-data-wrappers-rust) +- [Community Day](https://supabase.com/blog/launch-week-6-community-day) +- [Point in Time Recovery is now available](https://supabase.com/blog/postgres-point-in-time-recovery) +- [Custom Domain Names are now available](https://supabase.com/blog/custom-domain-names) +- [Wrap Up: everything we shipped](https://supabase.com/blog/launch-week-6-wrap-up) diff --git a/i18n/README.es.md b/i18n/README.es.md index a653d1b2492..602393663a2 100644 --- a/i18n/README.es.md +++ b/i18n/README.es.md @@ -71,17 +71,134 @@ Supabase es una [plataforma alojada](https://app.supabase.com). Te puedes regist Nuestra librería de cliente es modular. Cada sub-librería es una implementación independiente para cada sistema externo. Esta es una de las formas de apoyar las herramientas existentes. -- **`supabase-{lang}`**: Combina librerías y agrega mejoras. - - `postgrest-{lang}`: Librería de cliente para trabajar con [PostgREST](https://github.com/postgrest/postgrest) - - `realtime-{lang}`: Librería de cliente para trabajar con [Realtime](https://github.com/supabase/realtime) - - `gotrue-{lang}`: Librería de cliente para trabajar con [GoTrue](https://github.com/netlify/gotrue) - -| Repositorio | Oficial | Comunidad | -| --------------------- | ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **`supabase-{lang}`** | [`JS`](https://github.com/supabase/supabase-js) | [`C#`](https://github.com/supabase/supabase-csharp) \| [`Flutter`](https://github.com/supabase/supabase-flutter) \| [`Python`](https://github.com/supabase/supabase-py) \| `Rust` | -| `postgrest-{lang}` | [`JS`](https://github.com/supabase/postgrest-js) | [`C#`](https://github.com/supabase/postgrest-csharp) \| [`Dart`](https://github.com/supabase/postgrest-dart) \| [`Python`](https://github.com/supabase/postgrest-py) \| [`Rust`](https://github.com/supabase/postgrest-rs) | -| `realtime-{lang}` | [`JS`](https://github.com/supabase/realtime-js) | [`C#`](https://github.com/supabase/realtime-csharp) \| [`Dart`](https://github.com/supabase/realtime-dart) \| [`Python`](https://github.com/supabase/realtime-py) \| `Rust` | -| `gotrue-{lang}` | [`JS`](https://github.com/supabase/gotrue-js) | [`C#`](https://github.com/supabase/gotrue-csharp) \| [`Dart`](https://github.com/supabase/gotrue-dart) \| [`Python`](https://github.com/supabase/gotrue-py) \| `Rust` | + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    LenguajeClienteCaracterĂ­stica - Clientes (incluido en el cliente de Supabase)
    SupabasePostgRESTGoTrueRealtimeStorageFunctions
    ⚡️ Oficial ⚡️
    JavaScript (TypeScript)supabase-jspostgrest-jsgotrue-jsrealtime-jsstorage-jsfunctions-js
    Fluttersupabase-flutterpostgrest-dartgotrue-dartrealtime-dartstorage-dartfunctions-dart
    đź’š Comunidad đź’š
    C#supabase-csharppostgrest-csharpgotrue-csharprealtime-csharpstorage-csharpfunctions-csharp
    Go-postgrest-gogotrue-go-storage-gofunctions-go
    Java--gotrue-java-storage-java-
    Kotlinsupabase-ktpostgrest-ktgotrue-ktrealtime-ktstorage-ktfunctions-kt
    Pythonsupabase-pypostgrest-pygotrue-pyrealtime-pystorage-pyfunctions-py
    Rubysupabase-rbpostgrest-rb----
    Rust-postgrest-rs----
    Swiftsupabase-swiftpostgrest-swiftgotrue-swiftrealtime-swiftstorage-swiftfunctions-swift
    Godot Engine (GDScript)supabase-gdscriptpostgrest-gdscriptgotrue-gdscriptrealtime-gdscriptstorage-gdscriptfunctions-gdscript
    diff --git a/spec/common-client-libs-sections.json b/spec/common-client-libs-sections.json index f1afe0b46b5..d80a1e8b3fb 100644 --- a/spec/common-client-libs-sections.json +++ b/spec/common-client-libs-sections.json @@ -616,107 +616,103 @@ "product": "auth", "type": "function", "libs": ["js"] - } - ] - }, - { - "title": "Auth Admin", - "libs": ["js", "js_v1"], - "items": [ + }, { "id": "admin-api", - "title": "Overview", + "title": "Auth Admin", "slug": "admin-api", "libs": ["js", "js_v1"], - "type": "function" - }, - { - "id": "get-user-by-id", - "title": "Retrieve a user", - "slug": "auth-admin-getuserbyid", - "product": "auth-admin", "type": "function", - "libs": ["js"] - }, - { - "id": "list-users", - "title": "List all users", - "slug": "auth-admin-listusers", - "product": "auth-admin", - "type": "function", - "libs": ["js", "js_v1"] - }, - { - "id": "create-user", - "title": "Create a user", - "slug": "auth-admin-createuser", - "product": "auth-admin", - "type": "function", - "libs": ["js", "js_v1"] - }, - { - "id": "delete-user", - "title": "Delete a user", - "slug": "auth-admin-deleteuser", - "product": "auth-admin", - "type": "function", - "libs": ["js", "js_v1"] - }, - { - "id": "invite-user-by-email", - "title": "Send an email invite link", - "slug": "auth-admin-inviteuserbyemail", - "product": "auth-admin", - "type": "function", - "libs": ["js", "js_v1"] - }, - { - "id": "reset-password-for-email", - "title": "Send a password reset request", - "slug": "auth-admin-resetpasswordforemail", - "product": "auth-admin", - "type": "function", - "libs": ["js"] - }, - { - "id": "generate-link", - "title": "Generate an email link", - "slug": "auth-admin-generatelink", - "product": "auth-admin", - "type": "function", - "libs": ["js"] - }, - { - "id": "send-mobile-otp", - "title": "Send a one-time passcode", - "slug": "auth-api-sendmobileotp", - "product": "auth-server", - "type": "function", - "libs": ["js_v1"] - }, - { - "id": "update-user-by-id", - "title": "Update a user", - "slug": "auth-admin-updateuserbyid", - "product": "auth-admin", - "type": "function", - "libs": ["js", "js_v1"] - }, - { - "id": "mfa-list-factors", - "title": "List all factors for a user", - "slug": "auth-admin-mfa-listfactors", - "product": "auth-admin", - "type": "function", - "libs": ["js"] - }, - { - "id": "mfa-delete-factor", - "title": "Delete a factor for a user", - "slug": "auth-admin-mfa-deletefactor", - "product": "auth-admin", - "type": "function", - "libs": ["js"] + "items": [ + { + "id": "get-user-by-id", + "title": "Retrieve a user", + "slug": "auth-admin-getuserbyid", + "product": "auth-admin", + "type": "function", + "libs": ["js"] + }, + { + "id": "list-users", + "title": "List all users", + "slug": "auth-admin-listusers", + "product": "auth-admin", + "type": "function", + "libs": ["js", "js_v1"] + }, + { + "id": "create-user", + "title": "Create a user", + "slug": "auth-admin-createuser", + "product": "auth-admin", + "type": "function", + "libs": ["js", "js_v1"] + }, + { + "id": "delete-user", + "title": "Delete a user", + "slug": "auth-admin-deleteuser", + "product": "auth-admin", + "type": "function", + "libs": ["js", "js_v1"] + }, + { + "id": "invite-user-by-email", + "title": "Send an email invite link", + "slug": "auth-admin-inviteuserbyemail", + "product": "auth-admin", + "type": "function", + "libs": ["js", "js_v1"] + }, + { + "id": "reset-password-for-email", + "title": "Send a password reset request", + "slug": "auth-admin-resetpasswordforemail", + "product": "auth-admin", + "type": "function", + "libs": ["js"] + }, + { + "id": "generate-link", + "title": "Generate an email link", + "slug": "auth-admin-generatelink", + "product": "auth-admin", + "type": "function", + "libs": ["js"] + }, + { + "id": "send-mobile-otp", + "title": "Send a one-time passcode", + "slug": "auth-api-sendmobileotp", + "product": "auth-server", + "type": "function", + "libs": ["js_v1"] + }, + { + "id": "update-user-by-id", + "title": "Update a user", + "slug": "auth-admin-updateuserbyid", + "product": "auth-admin", + "type": "function", + "libs": ["js", "js_v1"] + }, + { + "id": "mfa-list-factors", + "title": "List all factors for a user", + "slug": "auth-admin-mfa-listfactors", + "product": "auth-admin", + "type": "function", + "libs": ["js"] + }, + { + "id": "mfa-delete-factor", + "title": "Delete a factor for a user", + "slug": "auth-admin-mfa-deletefactor", + "product": "auth-admin", + "type": "function", + "libs": ["js"] + } + ] } ] }, diff --git a/spec/examples/examples.yml b/spec/examples/examples.yml index d2bc4403b6e..393fc81e279 100644 --- a/spec/examples/examples.yml +++ b/spec/examples/examples.yml @@ -114,13 +114,13 @@ functions: title: 'signUp()' $ref: '@supabase/gotrue-js.GoTrueClient.signUp' 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/settings). + - 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/settings). + - By default, when the user confirms their email address, they are redirected to the [`SITE_URL`](https://supabase.com/docs/reference/auth/config#site_url). 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/settings), an obfuscated/fake user object is returned. + - 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. - To fetch the currently logged-in user, refer to [`getUser()`](/docs/reference/javascript/auth-getuser). examples: @@ -192,7 +192,7 @@ functions: - 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). + - 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/url-configuration). examples: - id: sign-in-with-email. name: Sign in with email. @@ -236,7 +236,7 @@ functions: isSpotlight: false description: | When the third-party provider successfully authenticates the user, the provider will redirect the user to the URL specified in the `redirectTo` parameter. This parameter defaults to the [`SITE_URL`](https://supabase.com/docs/reference/auth/config#site_url). It does not redirect the user immediately after invoking this method. - You can modify the `SITE_URL` or add additional redirect urls in [your project](https://app.supabase.com/project/_/auth/settings). + You can modify the `SITE_URL` or add additional redirect URLs in [your project](https://app.supabase.com/project/_/auth/url-configuration). js: | ```js const { data, error } = await supabase.auth.signInWithOAuth({ @@ -334,7 +334,7 @@ functions: 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). + 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/providers). examples: - id: update-the-email-for-an-authenticated-user name: Update the email for an authenticated user diff --git a/spec/supabase_dart_v0--old.yml b/spec/supabase_dart_v0--old.yml deleted file mode 100644 index 90dab81a758..00000000000 --- a/spec/supabase_dart_v0--old.yml +++ /dev/null @@ -1,2183 +0,0 @@ -openref: 0.1 - -info: - id: reference/dart - title: Getting started - description: | - - Supabase Dart. - - definition: ../../spec/enrichments/tsdoc_v1/combined.json - slugPrefix: '/' - specUrl: https://github.com/supabase/supabase/edit/master/spec/supabase_dart_v0.yml - libraries: - - name: 'Dart' - id: 'dart' - version: '0.0.1' - -pages: - Installing: - description: | - ## Dart - - Dart libraries are built and supported by the community. - - ```bash - dart pub add supabase - ``` - - Find the source code on [GitHub](https://github.com/supabase/supabase-dart). - - ## Flutter - - For Flutter project, you can use [supabase_flutter](https://github.com/supabase/supabase-flutter). - - ```bash - flutter pub add supabase_flutter - ``` - - `supabase_flutter` plugin uses `supabase` plugin internally, and it adds some Flutter specific functionality such as handling deeplinks coming back from magic link verifications. - If you are creating a Flutter application, we recommend using `supabase_flutter` instead of `supabase`. - - For the most part `supabase_flutter` shares the same API as `supabase` with few exceptions such as initialization or OAuth sign in. - - Initializing: - description: | - ## Dart - You can initialize a new Supabase client using the `SupabaseClient()` method. - - The Supabase client is your entrypoint to the rest of the Supabase functionality - and is the easiest way to interact with everything we offer within the Supabase ecosystem. - - - ## Flutter - - For `supabase_flutter`, you will be using the static `initialize()` method on `Supabase` class. - - examples: - - name: Dart SupabaseClient() - dart: | - ```dart - final supabase = SupabaseClient('https://xyzcompany.supabase.co', 'public-anon-key'); - ``` - - name: Flutter initialize() - dart: | - ```dart title="main.dart" - Future main() async { - await Supabase.initialize(url: 'https://xyzcompany.supabase.co', anonKey: 'public-anon-key'); - runApp(MyApp()); - } - ``` - - auth.signUp(): - description: | - Creates a new user. - notes: | - - By default, the user will need to verify their email address before logging in. If you would like to change this, you can disable "Email Confirmations" by going to Authentication -> Settings on [app.supabase.com](https://app.supabase.com) - - If "Email Confirmations" is turned on, a user is returned but session will be null - - If "Email Confirmations" is turned off, both a `user` and a `session` will be returned - - When the user confirms their email address, they will be redirected to localhost:3000 by default. To change this, you can go to Authentication -> Settings on [app.supabase.com](https://app.supabase.com) - examples: - - name: Sign up. - isSpotlight: true - dart: | - ```dart - final res = await supabase.auth.signUp('example@email.com', 'example-password'); - - final user = res.data?.user; - final error = res.error; - ``` - - name: Sign up with third-party providers. - hideCodeBlock: true - description: | - If you are using Flutter, you can sign up with OAuth providers using the [`signInWithProvider()`](/docs/reference/dart/v0/auth-signinwithprovider) method available on `supabase_flutter`. - - auth.signIn(): - description: | - Log in an existing user, or login via a third-party provider. - notes: | - - A user can sign up via email, phone number. - - If you provide `email` without a `password`, the user will be sent a magic link. - - The magic link's destination URL is determined by the SITE_URL config variable. To change this, you can go to Authentication -> Settings on [app.supabase.com](https://app.supabase.com) - - Similarly, if you provide `phone` without a `password`, the user will be sent a one time password. - - If you are looking to sign users in with OAuth in Flutter apps, go to [`signInWithProvider()`](/docs/reference/dart/v0/auth-signinwithprovider). - examples: - - name: Sign in with email. - isSpotlight: true - dart: | - ```dart - final res = await supabase.auth.signIn(email: 'example@email.com', password: 'example-password'); - - final user = res.data?.user; - final error = res.error; - ``` - - name: Sign in with magic link. - description: If email is provided, but no password is provided, the user will be sent a "magic link" to their email address, which they can click to open your application with a valid session. By default, a given user can only request a Magic Link once every 60 seconds. - dart: | - ```dart - final res = await supabase.auth.signIn(email: 'example@email.com'); - - final error = res.error; - ``` - - name: Get OAuth sign in URL. - description: | - Passing provider parameter to `signIn()` will return a URL to sign your user in via OAuth. - If you are looking to sign in a user via OAuth on Flutter app, go to [`signInWithProvider()`](/docs/reference/dart/v0/auth-signinwithprovider). - dart: | - ```dart - final res = await supabase.auth.signIn(provider: Provider.github); - - final url = res.data?.url; - final error = res.error; - ``` - auth.signInWithProvider(): - description: | - Signs the user in using third party OAuth providers. - notes: | - - `auth.signInWithProvider()` is only available on `supabase_flutter` - - It will open the browser to the relevant login page. - examples: - - name: Sign in with provider. - isSpotlight: true - dart: | - ```dart - final res = await supabase.auth.signInWithProvider(Provider.github); - - final error = res.error; - ``` - - name: With `redirectTo` - description: | - Specify the redirect link to bring back the user via deeplink. - Note that `redirectTo` should be null for Flutter Web. - dart: | - ```dart - final res = await supabase.auth.signInWithProvider( - Provider.github, - options: AuthOptions( - redirectTo: kIsWeb - ? null - : 'io.supabase.flutter://reset-callback/'), - ); - - final error = res.error; - ``` - - 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. - dart: | - ```dart - const { user, session, error } = await supabase.auth.signIn({ - provider: 'github' - }, { - scopes: 'repo gist notifications' - }) - const oAuthToken = session.provider_token // use to access provider API - ``` - auth.signOut(): - description: | - Signs out the current user, if there is a logged in user. - examples: - - name: Sign out - isSpotlight: true - dart: | - ```dart - final res = await supabase.auth.signOut(); - - final error = res.error; - ``` - - auth.session(): - description: | - Returns the session data, if there is an active session. - examples: - - name: Get the session data - isSpotlight: true - dart: | - ```dart - final session = supabase.auth.session(); - ``` - - auth.user(): - description: | - Returns the user data, if there is a logged in user. - examples: - - name: Get the logged in user - isSpotlight: true - dart: | - ```dart - final user = supabase.auth.user(); - ``` - - auth.update(): - description: | - Updates user data, if there is a logged in user. - notes: | - It's generally better to store user data in a table inside your public schema (i.e. `public.users`). - Use the `update()` method if you have data which rarely changes or is specific only to the logged in user. - examples: - - name: Update a user's metadata. - isSpotlight: true - dart: | - ```dart - final res = await supabase.auth.update( - UserAttributes(data: {'hello': 'world'}) - ); - - final error = res.error; - ``` - - auth.onAuthStateChange(): - description: | - Receive a notification every time an auth event happens. - examples: - - name: Listen to auth changes - isSpotlight: true - dart: | - ```dart - final subscription = supabase.auth.onAuthStateChange((event, session) { - print(session?.user?.id); - // handle auth state change - }); - ``` - - Reset Password (Email): - description: | - Sends a reset request to an email address. - notes: | - Sends a reset request to an email address. - - When the user clicks the reset link in the email they will be forwarded to: - - `#access_token=x&refresh_token=y&expires_in=z&token_type=bearer&type=recovery` - - Your app must detect `type=recovery` in the fragment and display a password reset form to the user. - - You should then use the access_token in the url and new password to update the user as follows: - - ```dart - final res = await supabase.auth.api.updateUser( - accessToken, - UserAttributes(password: 'NEW_PASSWORD'), - ); - ``` - examples: - - name: Reset password - isSpotlight: true - dart: | - ```dart - final res = await supabase.auth.api.resetPasswordForEmail('user@example.com'); - - final error = res.error; - ``` - - name: Reset password for Flutter - isSpotlight: true - dart: | - You can pass `redirectTo` to open the app via deeplink when user opens the password reset email. - ```dart - final res = await supabase.auth.api.resetPasswordForEmail( - 'user@example.com', - options: AuthOptions(redirectTo: kIsWeb - ? null - : 'io.supabase.flutter://reset-callback/'), - ); - - final error = res.error; - ``` - 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: - - name: Basic invocation. - isSpotlight: true - dart: | - ```dart - final res = await supabaseClient.functions.invoke('hello', body: {'foo': 'baa'}); - final data = res.data; - final error = res.error; - ``` - - name: Specifying response type. - description: | - By default, `invoke()` will parse the response as JSON. You can parse the response in the following formats: `json`, `blob`, `text`, and `arrayBuffer`. - isSpotlight: true - dart: | - ```dart - final res = await supabaseClient.functions.invoke( - 'hello', - body: {'foo': 'baa'}, - responseType: ResponseType.text, - ); - final data = res.data; - final error = res.error; - ``` - - name: Parsing custom headers. - description: | - Any `headers` will be passed through to the function. A common pattern is to pass a logged-in user's JWT token as an Authorization header. - isSpotlight: true - dart: | - ```dart - final res = await supabaseClient.functions.invoke( - 'hello', - body: {'foo': 'baa'}, - headers: { - 'Authorization': 'Bearer ${supabase.auth.session()?.access_token}' - }, - ); - ``` - select(): - description: | - Performs vertical filtering with SELECT. - title: 'Fetch data: select()' - notes: | - - 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. - - `select()` can be combined with [Modifiers](/docs/reference/dart/using-modifiers) - - `select()` can be combined with [Filters](/docs/reference/dart/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: - - name: Getting your data - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select() - .execute(); - - final data = res.data; - final error = res.error; - ``` - - name: Selecting specific columns - description: You can select specific fields from your tables. - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name') - .execute(); - ``` - - name: Query foreign tables - description: If your database has relationships, you can query related tables too. - dart: | - ```dart - final res = await supabase - .from('countries') - .select(''' - name, - cities ( - name - ) - ''') - .execute(); - ``` - - name: Query the same foreign table multiple times - description: | - Sometimes you will need to query the same foreign table twice. - In this case, you can use the name of the joined column to identify - which join you intend to use. For convenience, you can also give an - alias for each column. For example, if we had a shop of products, - and we wanted to get the supplier and the purchaser at the same time - (both in the users) table: - dart: | - ```dart - final res = await supabase - .from('products') - .select(''' - id, - supplier:supplier_id ( name ), - purchaser:purchaser_id ( name ) - ''') - .execute(); - ``` - - 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": - dart: | - ```dart - final res = await supabase - .from('messages') - .select('*, users!inner(*)') - .eq('users.username', 'Jane') - .execute(); - ``` - - 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). - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name') - .execute(count: CountOption.exact); - - final count = res.count; - ``` - - 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. - dart: | - ```dart - final res = await supabase - .from('users') - .select(''' - id, name, - address->street - ''') - .eq('address->postcode', 90210) - .execute(); - ``` - - name: Return data as CSV - description: | - By default the data is returned in JSON format, however you can also request for it to be returned as Comma Separated Values. - dart: | - ```dart - final res = await supabase - .from('users') - .select() - .csv() - .execute(); - ``` - - insert(): - description: | - Performs an INSERT into the table. - title: 'Create data: insert()' - notes: | - - By default, every time you run `insert()`, the client library will make a `select` to return the full record. - This is convenient, but it can also cause problems if your Policies are not configured to allow the `select` operation. - If you are using Row Level Security and you are encountering problems, try setting the `returning` param to `minimal`. - examples: - - name: Create a record - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .insert([ - {'name': 'The Shire', 'country_id': 554} - ]).execute(); - ``` - - name: Bulk create - dart: | - ```dart - final res = await supabase - .from('cities') - .insert([ - {'name': 'The Shire', 'country_id': 554}, - {'name': 'Rohan', 'country_id': 555}, - ]).execute(); - ``` - - update(): - description: | - Performs an UPDATE on the table. - title: 'Modify data: update()' - notes: | - - `update()` should always be combined with [Filters](/docs/reference/dart/using-filters) to target the item(s) you wish to update. - examples: - - name: Updating your data - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Middle Earth' }) - .match({ 'name': 'Auckland' }) - .execute(); - ``` - - name: Updating JSON data - description: | - Postgres offers a - [number of operators](https://www.postgresql.org/docs/current/functions-json.html) - for working with JSON data. Right now it is only possible to update an entire JSON document, - but we are [working on ideas](https://github.com/PostgREST/postgrest/issues/465) for updating individual keys. - dart: | - ```dart - final res = await supabase - .from('users') - .update({ - 'address': { - 'street': 'Melrose Place', - 'postcode': 90210 - } - }) - .eq('address->postcode', 90210) - .execute(); - ``` - - 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: - - name: Upsert your data - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('messages') - .upsert({ 'id': 3, 'message': 'foo', 'username': 'supabot' }) - .execute(); - ``` - - 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 - dart: | - ```dart - final res = await supabase - .from('users') - .upsert({ 'username': 'supabot' }, { 'onConflict': 'username' }) - .execute(); - ``` - - name: Return the exact number of rows - description: | - Allowed values for count option are `exact`, `planned` and `estimated`. - dart: | - ```dart - final res = await supabase - .from('users') - .upsert({ - 'id': 3, - 'message': 'foo', - 'username': 'supabot' - }) - .execute(count: CountOption.exact); - ``` - - delete(): - description: | - Performs a DELETE on the table. - title: 'Delete data: delete()' - notes: | - - `delete()` should always be combined with [Filters](/docs/reference/dart/using-filters) to target the item(s) you wish to delete. - examples: - - name: Delete records - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .match({ 'id': 666 }) - .execute(); - ``` - - 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: - - name: Call a stored procedure - isSpotlight: true - description: This is an example invoking a stored procedure. - dart: | - ```dart - final res = await supabase - .rpc('hello_world') - .execute(); - ``` - - name: With Parameters - dart: | - ```dart - final res = await supabase - .rpc('echo_city', params: { 'name': 'The Shire' }) - .execute(); - ``` - - name: With count option - description: | - You can specify a count option to get the row count along with your data. - Allowed values for count option are `exact`, `planned` and `estimated`. - dart: | - ```dart - final res = await supabase - .rpc('hello_world') - .execute(count: CountOption.exact); - ``` - - 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: - - name: Listen to all database changes - isSpotlight: true - dart: | - ```dart - final mySubscription = supabase - .from('countries') - .on(SupabaseEventTypes.all, (payload) { - // Handle realtime payload - }) - .subscribe(); - ``` - - name: Listening to a specific table - dart: | - ```dart - final mySubscription = supabase - .from('countries') - .on(SupabaseEventTypes.all, (payload) { - // Handle realtime payload - }) - .subscribe(); - ``` - - name: Listening to inserts - dart: | - ```dart - final mySubscription = supabase - .from('countries') - .on(SupabaseEventTypes.insert, (payload) { - // Handle realtime payload - }) - .subscribe(); - ``` - - 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; - ``` - dart: | - ```dart - final mySubscription = supabase - .from('countries') - .on(SupabaseEventTypes.update, (payload) { - // Handle realtime payload - }) - .subscribe(); - ``` - - 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; - ``` - dart: | - ```dart - final mySubscription = supabase - .from('countries') - .on(SupabaseEventTypes.delete, (payload) { - // Handle realtime payload - }) - .subscribe(); - ``` - - name: Listening to multiple events - description: You can chain listeners if you want to listen to multiple events for each table. - dart: | - ```dart - final mySubscription = supabase - .from('countries') - .on(SupabaseEventTypes.insert, handleInsert) - .on(SupabaseEventTypes.delete, handleDelete) - .subscribe(); - ``` - - 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. - dart: | - ```dart - final mySubscription = supabase - .from('countries:id=eq.200') - .on(SupabaseEventTypes.update, handleRecordUpdated) - .subscribe(); - ``` - - removeSubscription(): - description: | - Removes an active subscription and returns the number of open connections. - title: 'removeSubscription()' - notes: | - - Removing subscriptions is a great way to maintain the performance of your project's database. Supabase will automatically handle cleanup 30 seconds after a user is disconnected, but unused subscriptions may cause degradation as more users are simultaneously subscribed. - examples: - - name: Remove a subscription - isSpotlight: true - dart: | - ```dart - supabase.removeSubscription(mySubscription); - ``` - - getSubscriptions(): - description: | - Returns an array of all your subscriptions. - title: 'getSubscriptions()' - examples: - - name: Get all subscriptions - isSpotlight: true - dart: | - ```dart - final subscriptions = supabase.getSubscriptions(); - ``` - - 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: - - name: Listening to a specific table - isSpotlight: true - dart: | - ```dart - supabase - .from('countries') - .stream(['id']) - .execute(); - ``` - - 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 - dart: | - ```dart - supabase - .from('countries:id=eq.120') - .stream(['id']) - .execute(); - ``` - - name: With `order()` - dart: | - ```dart - supabase - .from('countries') - .stream(['id']) - .order('name', ascending: false) - .execute(); - ``` - - name: With `limit()` - dart: | - ```dart - supabase - .from('countries') - .stream(['id']) - .order('name', ascending: false) - .limit(10) - .execute(); - ``` - - storage.listBuckets(): - description: | - Retrieves the details of all Storage buckets within an existing product. - title: 'listBuckets()' - $ref: '@supabase/storage-js."lib/StorageBucketApi".StorageBucketApi.listBuckets' - notes: | - - Policy permissions required: - - `buckets` permissions: `select` - - `objects` permissions: none - examples: - - name: List buckets - isSpotlight: true - dart: | - ```dart - final res = await supabase - .storage - .listBuckets() - ``` - - storage.getBucket(): - description: | - Retrieves the details of an existing Storage bucket. - title: 'getBucket()' - $ref: '@supabase/storage-js."lib/StorageBucketApi".StorageBucketApi.getBucket' - notes: | - - Policy permissions required: - - `buckets` permissions: `select` - - `objects` permissions: none - examples: - - name: Get bucket - isSpotlight: true - dart: | - ```dart - final res = await supabase - .storage - .getBucket('avatars') - ``` - - storage.createBucket(): - description: | - Creates a new Storage bucket - title: 'createBucket()' - notes: | - - Policy permissions required: - - `buckets` permissions: `insert` - - `objects` permissions: none - examples: - - name: Create bucket - isSpotlight: true - dart: | - ```dart - final res = await supabase - .storage - .createBucket('avatars'); - ``` - - storage.emptyBucket(): - description: | - Removes all objects inside a single bucket. - title: 'emptyBucket()' - notes: | - - Policy permissions required: - - `buckets` permissions: `select` - - `objects` permissions: `select` and `delete` - examples: - - name: Empty bucket - isSpotlight: true - dart: | - ```dart - final res = await supabase - .storage - .emptyBucket('avatars'); - ``` - storage.updateBucket(): - description: | - Updates a new Storage bucket - title: 'updateBucket()' - notes: | - - Policy permissions required: - - `buckets` permissions: `update` - - `objects` permissions: none - examples: - - name: Update bucket - isSpotlight: true - dart: | - ```dart - final res = await supabase - .storage - .updateBucket('avatars', { public: false }); - ``` - - storage.deleteBucket(): - 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: - - name: Delete bucket - isSpotlight: true - dart: | - ```dart - final res = await supabase - .storage - .deleteBucket('avatars'); - ``` - - storage.from.upload(): - description: | - Uploads a file to an existing bucket. - title: 'from.upload()' - $ref: '@supabase/storage-js."lib/StorageFileApi".StorageFileApi.upload' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `insert` - examples: - - name: Upload file - isSpotlight: true - dart: | - ```dart - final avatarFile = File('path/to/file'); - final res = await supabase - .storage - .from('avatars') - .upload('public/avatar1.png', avatarFile, fileOptions: FileOptions( - cacheControl: '3600', - upsert: false - )); - ``` - - storage.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: - - name: Update file - isSpotlight: true - dart: | - ```dart - final avatarFile = File('path/to/file'); - final res = await supabase - .storage - .from('avatars') - .update('public/avatar1.png', avatarFile, fileOptions: FileOptions( - cacheControl: '3600', - upsert: false - )); - ``` - - storage.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: - - name: Move file - isSpotlight: true - dart: | - ```dart - final res = await supabase - .storage - .from('avatars') - .move('public/avatar1.png', 'private/avatar2.png'); - ``` - - storage.from.createSignedUrl(): - 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: - - name: Create Signed URL - isSpotlight: true - dart: | - ```dart - final res = await supabase - .storage - .from('avatars') - .createSignedUrl('avatar1.png', 60); - - final signedURL = res.data; - ``` - - storage.from.getPublicUrl(): - 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: - - name: Returns the URL for an asset in a public bucket - isSpotlight: true - dart: | - ```dart - final res = supabase - .storage - .from('public-bucket') - .getPublicUrl('avatar1.png'); - - final publicURL = res.data; - ``` - - storage.from.download(): - description: | - Downloads a file. - title: 'from.download()' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `select` - examples: - - name: Download file - isSpotlight: true - dart: | - ```dart - final res = await supabase - .storage - .from('avatars') - .download('avatar1.png'); - ``` - - storage.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: - - name: Delete file - isSpotlight: true - dart: | - ```dart - final res = await supabase - .storage - .from('avatars') - .remove(['avatar1.png']); - ``` - - storage.from.list(): - description: | - Lists all the files within a bucket. - title: 'from.list()' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `select` - examples: - - name: List files in a bucket - isSpotlight: true - dart: | - ```dart - final res = await supabase - .storage - .from('avatars') - .list(); - ``` - Using Modifiers: - description: | - Modifiers can be used on `select()` queries. - - If a Stored Procedure returns a table response, you can also apply modifiers to the `rpc()` function. - - limit(): - description: | - Limits the result with the specified count. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .limit(1) - .execute(); - ``` - - name: With embedded resources - dart: | - ```dart - final res = await supabase - .from('countries') - .select('name, cities(name)') - .eq('name', 'United States') - .limit(1, foreignTable: 'cities' ) - .execute(); - ``` - - order(): - description: | - Orders the result with the specified column. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .order('id', ascending: false ) - .execute(); - ``` - - name: With embedded resources - dart: | - ```dart - final res = await supabase - .from('countries') - .select('name, cities(name)') - .eq('name', 'United States') - .order('name', foreignTable: 'cities') - .execute(); - ``` - - range(): - description: | - Limits the result to rows within the specified range, inclusive. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .range(0,3) - .execute(); - ``` - - 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: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .single() - .execute(); - ``` - - Using Filters: - description: | - Filters can be used on `select()`, `update()`, and `delete()` queries. - - If a Stored Procedure returns a table response, you can also apply filters. - - ### Applying Filters - - You must apply your filters to the end of your query. For example: - - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .eq('name', 'The Shire') // Correct - .execute(); - - final res = await supabase - .from('cities') - .eq('name', 'The Shire') // Incorrect - .select('name, country_id') - .execute(); - ``` - - ### Chaining - - Filters can be chained together to produce advanced queries. For example: - - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .gte('population', 1000) - .lt('population', 10000) - .execute(); - ``` - - .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: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .or('id.eq.20,id.eq.30') - .execute(); - ``` - - name: Use `or` with `and` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .or('id.gt.20,and(name.eq.New Zealand,name.eq.France)') - .execute(); - ``` - # TODO Not available at the moment, so would have to fix the bug on postgrest-dart first - # - name: Use `or` on foreign tables - # isSpotlight: true - # dart: | - # ```dart - # final res = await supabase - # .from('countries') - # .select('id, cities(*)') - # .or('name.eq.Wellington,name.eq.Paris', { foreignTable: "cities" }) - # ``` - - .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: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .not('name', 'eq', 'Paris') - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .not('name', 'eq', 'Paris') - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .not('name', 'eq', 'Paris') - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_cities) - .not('name', 'eq', 'Paris') - .execute(); - ``` - - .match(): - description: | - Finds all rows whose columns match the specified `query` object. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .match({'name': 'Beijing', 'country_id': 156}) - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .match({'name': 'Beijing', 'country_id': 156}) - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .match({'name': 'Beijing', 'country_id': 156}) - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_cities') - .match({'name': 'Beijing', 'country_id': 156}) - .execute(); - ``` - - .eq(): - description: | - Finds all rows whose value on the stated `column` exactly matches the specified `value`. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .eq('name', 'The shire') - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .eq('name', 'San Francisco') - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .eq('name', 'Mordor') - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_cities') - .eq('name', 'San Francisco') - .execute(); - ``` - - .neq(): - description: | - Finds all rows whose value on the stated `column` doesn't match the specified `value`. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .neq('name', 'The shire') - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .neq('name', 'San Francisco') - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .neq('name', 'Mordor') - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_cities') - .neq('name', 'Lagos') - .execute(); - ``` - - .gt(): - description: | - Finds all rows whose value on the stated `column` is greater than the specified `value`. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .gt('country_id', 250) - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .gt('country_id', 250) - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .gt('country_id', 250) - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_cities') - .gt('country_id', 250) - .execute(); - ``` - - .gte(): - description: | - Finds all rows whose value on the stated `column` is greater than or equal to the specified `value`. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .gte('country_id', 250) - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .gte('country_id', 250) - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .gte('country_id', 250) - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_cities') - .gte('country_id', 250) - .execute(); - ``` - - .lt(): - description: | - Finds all rows whose value on the stated `column` is less than the specified `value`. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .lt('country_id', 250) - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .lt('country_id', 250) - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .lt('country_id', 250) - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_cities') - .lt('country_id', 250) - .execute(); - ``` - - .lte(): - description: | - Finds all rows whose value on the stated `column` is less than or equal to the specified `value`. - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.lte' - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .lte('country_id', 250) - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .lte('country_id', 250) - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .lte('country_id', 250) - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_cities') - .lte('country_id', 250) - .execute(); - ``` - - .like(): - description: | - Finds all rows whose value in the stated `column` matches the supplied `pattern` (case sensitive). - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.like' - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .like('name', '%la%') - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .like('name', '%la%') - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .like('name', '%la%') - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_cities') - .like('name', '%la%') - .execute(); - ``` - - .ilike(): - description: | - Finds all rows whose value in the stated `column` matches the supplied `pattern` (case insensitive). - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .ilike('name', '%la%') - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .ilike('name', '%la%') - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .ilike('name', '%la%') - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_cities') - .ilike('name', '%la%') - .execute(); - ``` - - .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: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .is_('name', null) - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .is_('name', null) - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .is_('name', null) - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_cities') - .is_('name', null) - .execute(); - ``` - - .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: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .in_('name', ['Rio de Janeiro', 'San Francisco']) - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .in_('name', ['Rio de Janeiro', 'San Francisco']) - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .in_('name', ['Rio de Janeiro', 'San Francisco']) - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_cities') - .in_('name', ['Rio de Janeiro', 'San Francisco']) - .execute(); - ``` - - .contains(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('countries') - .select('name, id, main_exports') - .contains('main_exports', ['oil']) - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .contains('main_exports', ['oil']) - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('countries') - .delete() - .contains('main_exports', ['oil']) - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_countries') - .contains('main_exports', ['oil']) - .execute(); - ``` - - .containedBy(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('countries') - .select('name, id, main_exports') - .containedBy('main_exports', ['cars', 'food', 'machine']) - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .containedBy('main_exports', ['orks', 'surveillance', 'evil']) - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('countries') - .delete() - .containedBy('main_exports', ['cars', 'food', 'machine']) - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_countries') - .containedBy('main_exports', ['cars', 'food', 'machine']) - .execute(); - ``` - - .rangeLt(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeLt('population_range_millions', '[150, 250]') - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .rangeLt('population_range_millions', '[150, 250]') - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('countries') - .delete() - .rangeLt('population_range_millions', '[150, 250]') - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_countries') - .rangeLt('population_range_millions', '[150, 250]') - .execute(); - ``` - - .rangeGt(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeGt('population_range_millions', '[150, 250]') - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .rangeGt('population_range_millions', '[150, 250]') - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('countries') - .delete() - .rangeGt('population_range_millions', '[150, 250]') - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_countries') - .rangeGt('population_range_millions', '[150, 250]') - .execute(); - ``` - - .rangeGte(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeGte('population_range_millions', '[150, 250]') - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .rangeGte('population_range_millions', '[150, 250]') - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('countries') - .delete() - .rangeGte('population_range_millions', '[150, 250]') - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_countries') - .rangeGte('population_range_millions', '[150, 250]') - .execute(); - ``` - - .rangeLte(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.rangeLte' - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeLte('population_range_millions', '[150, 250]') - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .rangeLte('population_range_millions', '[150, 250]') - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('countries') - .delete() - .rangeLte('population_range_millions', '[150, 250]') - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_countries') - .rangeLte('population_range_millions', [150, 250]) - .execute(); - ``` - - .rangeAdjacent(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeAdjacent('population_range_millions', '[70, 185]') - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .rangeAdjacent('population_range_millions', '[70, 185]') - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('countries') - .delete() - .rangeAdjacent('population_range_millions', '[70, 185]') - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_countries') - .rangeAdjacent('population_range_millions', '[70, 185]') - .execute(); - ``` - - .overlaps(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('countries') - .select('name, id, main_exports') - .overlaps('main_exports', ['computers', 'minerals']) - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .overlaps('main_exports', ['computers', 'minerals']) - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('countries') - .delete() - .overlaps('main_exports', ['computers', 'minerals']) - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_countries') - .overlaps('main_exports', ['computers', 'minerals']) - .execute(); - ``` - - .textSearch(): - description: | - Finds all rows whose tsvector value on the stated `column` matches to_tsquery(query). - examples: - - name: Text search - dart: | - ```dart - final res = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', "'fat' & 'cat'", - config: 'english' - ) - .execute(); - ``` - - name: Basic normalization - description: Uses PostgreSQL's `plainto_tsquery` function. - dart: | - ```dart - final res = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', "'fat' & 'cat'", - type: TextSearchType.plain, - config: 'english' - ) - .execute(); - ``` - - name: Full normalization - description: Uses PostgreSQL's `phraseto_tsquery` function. - dart: | - ```dart - final res = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', "'fat' & 'cat'", - type: TextSearchType.phrase, - config: 'english' - ) - .execute(); - ``` - - name: Full normalization - 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. - - dart: | - ```dart - final res = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', "'fat or cat'", - type: TextSearchType.websearch, - config: 'english' - ) - .execute(); - ``` - - .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: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, country_id') - .filter('name', 'in', '("Paris","Tokyo")') - .execute(); - ``` - - name: With `update()` - dart: | - ```dart - final res = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .filter('name', 'in', '("Paris","Tokyo")') - .execute(); - ``` - - name: With `delete()` - dart: | - ```dart - final res = await supabase - .from('cities') - .delete() - .filter('name', 'in', '("Paris","Tokyo")') - .execute(); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final res = await supabase - .rpc('echo_all_cities') - .filter('name', 'in', '("Paris","Tokyo")') - ``` - - name: Filter embedded resources - dart: | - ```dart - final res = await supabase - .from('cities') - .select('name, countries ( name )') - .filter('countries.name', 'in', '("France","Japan")') - .execute(); - ``` diff --git a/spec/supabase_dart_v1--old.yml b/spec/supabase_dart_v1--old.yml deleted file mode 100644 index 6f3ef71a653..00000000000 --- a/spec/supabase_dart_v1--old.yml +++ /dev/null @@ -1,2280 +0,0 @@ -openref: 0.1 - -info: - id: reference/dart - title: Getting started - description: | - - Supabase Dart. - - definition: ../../spec/enrichments/tsdoc_v2/combined.json - slugPrefix: '/' - specUrl: https://github.com/supabase/supabase/edit/master/spec/supabase_dart_v1.yml - libraries: - - name: 'Dart' - id: 'dart' - version: '0.0.1' - -pages: - auth.signUp(): - 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/settings). - - **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/settings). - - If signUp() is called for an existing confirmed user: - - If **Confirm email** is enabled in [your project](https://app.supabase.com/project/_/auth/settings), an obfuscated/fake user object is returned. - - If **Confirm email** is disabled, the error message, `User already registered` is returned. - examples: - - name: Sign up. - isSpotlight: true - dart: | - ```dart - final AuthResponse res = await supabase.auth.signUp( - email: 'example@email.com', - password: 'example-password', - ); - final Session? session = res.session; - final User? user = res.user; - ``` - - name: Sign up with third-party providers. - hideCodeBlock: true - description: | - If you are using Flutter, you can sign up with OAuth providers using the [`signInWithOAuth()`](/docs/reference/dart/auth-signinwithoauth) method available on `supabase_flutter`. - - auth.signInWithPassword(): - title: 'signInWithPassword()' - 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: - - name: Sign in with email and password - isSpotlight: true - dart: | - ```dart - final AuthResponse res = await supabase.auth.signInWithPassword( - email: 'example@email.com', - password: 'example-password', - ); - final Session? session = res.session; - final User? user = res.user; - ``` - - name: Sign in with phone and password - dart: | - ```dart - final AuthResponse res = await supabase.auth.signInWithPassword( - phone: '+13334445555', - password: 'example-password', - ); - final Session? session = res.session; - final User? user = res.user; - ``` - auth.signInWithOtp(): - title: 'signInWithOtp()' - 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: - - name: Sign in with email. - 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. - dart: | - ```dart - await supabase.auth.signInWithOtp( - email: 'example@email.com', - emailRedirectTo: kIsWeb ? null : 'io.supabase.flutter://signin-callback/', - ); - ``` - - 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. - dart: | - ```dart - await supabase.auth.signInWithOtp( - phone: '+13334445555', - ); - ``` - auth.signInWithOAuth(): - title: 'signInWithOAuth()' - 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: - - name: Sign in using a third-party provider - isSpotlight: true - dart: | - ```dart - await supabase.auth.signInWithOAuth(Provider.github); - ``` - - name: With `redirectTo` - description: | - Specify the redirect link to bring back the user via deeplink. - Note that `redirectTo` should be null for Flutter Web. - dart: | - ```dart - await supabase.auth.signInWithOAuth( - Provider.github, - redirectTo: kIsWeb ? null : 'io.supabase.flutter://reset-callback/', - ); - ``` - - 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. - dart: | - ```dart - await supabase.auth.signInWithOAuth( - Provider.github, - scopes: 'repo gist notifications' - ); - ... - // after user comes back from signin flow - - final Session? session = supabase.auth.currentSession; - final String? oAuthToken = session?.providerToken; - ``` - auth.signOut(): - 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: - - name: Sign out - isSpotlight: true - dart: | - ```dart - await supabase.auth.signOut(); - ``` - auth.verifyOtp(): - 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: - - name: Verify Sms One-Time Password (OTP) - isSpotlight: true - dart: | - ```dart - final AuthResponse res = await supabase.auth.verifyOTP( - type: OtpType.sms, - token: '111111', - phone: '+13334445555', - ); - final Session? session = res.session; - final User? user = res.user; - ``` - - name: Verify Signup One-Time Password (OTP) - isSpotlight: false - dart: | - ```dart - final AuthResponse res = await supabase.auth.verifyOTP( - type: OtpType.signup, - token: token, - phone: '+13334445555', - ); - final Session? session = res.session; - final User? user = res.user; - ``` - auth.currentSession: - title: 'currentSession' - description: | - Returns the session data, if there is an active session. - examples: - - name: Get the session data - isSpotlight: true - dart: | - ```dart - final Session? session = supabase.auth.currentSession; - ``` - auth.currentUser: - title: 'currentUser' - description: | - Returns the user data, if there is a logged in user. - examples: - - name: Get the logged in user - isSpotlight: true - dart: | - ```dart - final User? user = supabase.auth.currentUser; - ``` - auth.updateUser(): - 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: - - name: Update the email for an authenticated user - description: Sends a "Confirm Email Change" email to the new email address. - isSpotlight: true - dart: | - ```dart - final UserResponse res = await supabase.auth.updateUser( - UserAttributes( - email: 'example@email.com', - ), - ); - final User? updatedUser = res.user; - ``` - - name: Update the password for an authenticated user - isSpotlight: false - dart: | - ```dart - final UserResponse res = await supabase.auth.updateUser( - UserAttributes( - password: 'new password', - ), - ); - final User? updatedUser = res.user; - ``` - - name: Update the user's metadata - isSpotlight: true - dart: | - ```dart - final UserResponse res = await supabase.auth.updateUser( - UserAttributes( - data: { 'hello': 'world' }, - ), - ); - final User? updatedUser = res.user; - ``` - auth.onAuthStateChange(): - title: 'onAuthStateChange()' - description: | - Receive a notification every time an auth event happens. - notes: | - - Types of auth events: `AuthChangeEvent.passwordRecovery`, `AuthChangeEvent.signedIn`, `AuthChangeEvent.signedOut`, `AuthChangeEvent.tokenRefreshed`, `AuthChangeEvent.userUpdated`and `AuthChangeEvent.userDeleted` - examples: - - name: Listen to auth changes - isSpotlight: true - dart: | - ```dart - final authSubscription = supabase.auth.onAuthStateChange.listen((data) { - final AuthChangeEvent event = data.event; - final Session? session = data.session; - }); - ``` - - name: Listen to a specific event - dart: | - ```dart - final authSubscription = supabase.auth.onAuthStateChange.listen((data) { - final AuthChangeEvent event = data.event; - if (event == AuthChangeEvent.signedIn) { - // handle signIn - } - }); - ``` - - name: Unsubscribe from auth subscription - dart: | - ```dart - final authSubscription = supabase.auth.onAuthStateChange((event, session) {}); - - authSubscription.cancel(); - ``` - auth.resetPasswordForEmail: - 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(): - - ```dart - await supabase.auth.resetPasswordForEmail( - 'sample@email.com', - redirectTo: kIsWeb ? null : 'io.supabase.flutter://reset-callback/', - ); - ``` - examples: - - name: Reset password for Flutter - isSpotlight: true - dart: | - `redirectTo` is used to open the app via deeplink when user opens the password reset email. - ```dart - await supabase.auth.resetPasswordForEmail( - 'sample@email.com', - redirectTo: kIsWeb ? null : 'io.supabase.flutter://reset-callback/', - ); - ``` - 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: - - name: Basic invocation. - isSpotlight: true - dart: | - ```dart - final res = await supabase.functions.invoke('hello', body: {'foo': 'baa'}); - final data = res.data; - ``` - - name: Specifying response type. - description: | - By default, `invoke()` will parse the response as JSON. You can parse the response in the following formats: `json`, `blob`, `text`, and `arrayBuffer`. - isSpotlight: true - dart: | - ```dart - final res = await supabase.functions.invoke( - 'hello', - body: {'foo': 'baa'}, - responseType: ResponseType.text, - ); - final data = res.data; - ``` - - name: Parsing custom headers. - description: | - Any `headers` will be passed through to the function. A common pattern is to pass a logged-in user's JWT token as an Authorization header. - isSpotlight: true - dart: | - ```dart - final res = await supabase.functions.invoke( - 'hello', - body: {'foo': 'baa'}, - headers: { - 'Authorization': 'Bearer ${supabase.auth.currentSession?.accessToken}' - }, - ); - ``` - select(): - description: | - Performs vertical filtering with SELECT. - title: 'Fetch data: select()' - notes: | - - 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. - - `select()` can be combined with [Modifiers](/docs/reference/dart/using-modifiers) - - `select()` can be combined with [Filters](/docs/reference/dart/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: - - name: Getting your data - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name'); - ``` - - name: Selecting specific columns - description: You can select specific fields from your tables. - dart: | - ```dart - final data = await supabase - .from('countries') - .select(''' - name, - cities ( - name - ) - '''); - ``` - - name: Query foreign tables - description: If your database has relationships, you can query related tables too. - dart: | - ```dart - final data = await supabase - .from('products') - .select(''' - id, - supplier:supplier_id ( name ), - purchaser:purchaser_id ( name ) - '''); - ``` - - name: Query the same foreign table multiple times - description: | - Sometimes you will need to query the same foreign table twice. - In this case, you can use the name of the joined column to identify - which join you intend to use. For convenience, you can also give an - alias for each column. For example, if we had a shop of products, - and we wanted to get the supplier and the purchaser at the same time - (both in the users) table: - dart: | - ```dart - final data = await supabase - .from('messages') - .select('*, users!inner(*)') - .eq('users.username', 'Jane'); - ``` - - 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": - dart: | - ```dart - final data = await supabase - .from('messages') - .select('*, users!inner(*)') - .eq('users.username', 'Jane'); - ``` - - 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). - dart: | - ```dart - final res = await supabase.from('cities').select( - 'name', - const FetchOptions( - count: CountOption.exact, - ), - ); - - final count = res.count; - ``` - - 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. - dart: | - ```dart - final data = await supabase - .from('users') - .select(''' - id, name, - address->street - ''') - .eq('address->postcode', 90210); - ``` - - name: Return data as CSV - description: | - By default the data is returned in JSON format, however you can also request for it to be returned as Comma Separated Values. - dart: | - ```dart - final data = await supabase - .from('users') - .select() - .csv(); - ``` - - insert(): - description: | - Performs an INSERT into the table. - title: 'Create data: insert()' - examples: - - name: Create a record - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .insert({'name': 'The Shire', 'country_id': 554}); - ``` - - name: Bulk create - dart: | - ```dart - final res = await supabase.from('cities').insert([ - {'name': 'The Shire', 'country_id': 554}, - {'name': 'Rohan', 'country_id': 555}, - ]); - ``` - - update(): - description: | - Performs an UPDATE on the table. - title: 'Modify data: update()' - notes: | - - `update()` should always be combined with [Filters](/docs/reference/dart/using-filters) to target the item(s) you wish to update. - examples: - - name: Updating your data - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Middle Earth' }) - .match({ 'name': 'Auckland' }); - ``` - - name: Updating JSON data - description: | - Postgres offers a - [number of operators](https://www.postgresql.org/docs/current/functions-json.html) - for working with JSON data. Right now it is only possible to update an entire JSON document, - but we are [working on ideas](https://github.com/PostgREST/postgrest/issues/465) for updating individual keys. - dart: | - ```dart - final data = await supabase - .from('users') - .update({ - 'address': { - 'street': 'Melrose Place', - 'postcode': 90210 - } - }) - .eq('address->postcode', 90210); - ``` - - 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: - - name: Upsert your data - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('messages') - .upsert({ 'id': 3, 'message': 'foo', 'username': 'supabot' }); - ``` - - 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 - dart: | - ```dart - final data = await supabase - .from('users') - .upsert({ 'username': 'supabot' }, { 'onConflict': 'username' }); - ``` - - name: Return the exact number of rows - description: | - Allowed values for count option are `exact`, `planned` and `estimated`. - dart: | - ```dart - final res = await supabase.from('users').upsert( - {'id': 3, 'message': 'foo', 'username': 'supabot'}, - options: const FetchOptions(count: CountOption.exact), - ); - - final data = res.data; - final count = res.count; - ``` - - delete(): - description: | - Performs a DELETE on the table. - title: 'Delete data: delete()' - notes: | - - `delete()` should always be combined with [Filters](/docs/reference/dart/using-filters) to target the item(s) you wish to delete. - examples: - - name: Delete records - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .match({ 'id': 666 }); - ``` - - 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: - - name: Call a stored procedure - isSpotlight: true - description: This is an example invoking a stored procedure. - dart: | - ```dart - final data = await supabase - .rpc('hello_world'); - ``` - - name: With Parameters - dart: | - ```dart - final data = await supabase - .rpc('echo_city', params: { 'name': 'The Shire' }); - ``` - - 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: - - name: Listen to all database changes - isSpotlight: true - dart: | - ```dart - supabase.channel('*').on( - RealtimeListenTypes.postgresChanges, - ChannelFilter(event: '*', schema: '*'), - (payload, [ref]) { - print('Change received: ${payload.toString()}'); - }, - ).subscribe(); - ``` - - name: Listening to a specific table - dart: | - ```dart - supabase.channel('public:countries').on( - RealtimeListenTypes.postgresChanges, - ChannelFilter(event: '*', schema: 'public', table: 'countries'), - (payload, [ref]) { - print('Change received: ${payload.toString()}'); - }, - ).subscribe(); - ``` - - name: Listening to inserts - dart: | - ```dart - supabase.channel('public:countries').on( - RealtimeListenTypes.postgresChanges, - ChannelFilter(event: 'INSERT', schema: 'public', table: 'countries'), - (payload, [ref]) { - print('Change received: ${payload.toString()}'); - }, - ).subscribe(); - ``` - - 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; - ``` - dart: | - ```dart - supabase.channel('public:countries').on( - RealtimeListenTypes.postgresChanges, - ChannelFilter(event: 'UPDATE', schema: 'public', table: 'countries'), - (payload, [ref]) { - print('Change received: ${payload.toString()}'); - }, - ).subscribe(); - ``` - - 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; - ``` - dart: | - ```dart - supabase.channel('public:countries').on( - RealtimeListenTypes.postgresChanges, - ChannelFilter(event: 'DELETE', schema: 'public', table: 'countries'), - (payload, [ref]) { - print('Change received: ${payload.toString()}'); - }, - ).subscribe(); - ``` - - name: Listening to multiple events - description: You can chain listeners if you want to listen to multiple events for each table. - dart: | - ```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(); - ``` - - 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. - dart: | - ```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(); - ``` - - removeChannel(): - 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: - - name: Remove a channel - isSpotlight: true - dart: | - ```dart - final status = await supabase.removeChannel(channel); - ``` - - removeAllChannels(): - 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: - - name: Remove all channels - isSpotlight: true - dart: | - ```dart - final statuses = await supabase.removeAllChannels(); - ``` - - getChannels(): - description: | - Returns all Realtime channels. - title: 'getChannels()' - examples: - - name: Get all channels - isSpotlight: true - dart: | - ```dart - final channels = supabase.getChannels(); - ``` - - 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: - - name: Listening to a specific table - isSpotlight: true - dart: | - ```dart - supabase.from('countries') - .stream(primaryKey: ['id']) - .listen((List> data) { - // Do something awesome with the data - }); - ``` - - 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 - dart: | - ```dart - supabase.from('countries') - .stream(primaryKey: ['id']) - .eq('id', '120') - .listen((List> data) { - // Do something awesome with the data - }); - ``` - - name: With `order()` - dart: | - ```dart - supabase.from('countries') - .stream(primaryKey: ['id']) - .order('name', ascending: true) - .listen((List> data) { - // Do something awesome with the data - }); - ``` - - name: With `limit()` - dart: | - ```dart - supabase.from('countries') - .stream(primaryKey: ['id']) - .order('name', ascending: true) - .limit(10) - .listen((List> data) { - // Do something awesome with the data - }); - ``` - - 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. - dart: | - ```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 - }, - ); - } - } - ``` - - storage.listBuckets(): - description: | - Retrieves the details of all Storage buckets within an existing product. - title: 'listBuckets()' - notes: | - - Policy permissions required: - - `buckets` permissions: `select` - - `objects` permissions: none - examples: - - name: List buckets - isSpotlight: true - dart: | - ```dart - final List buckets = await supabase - .storage - .listBuckets(); - ``` - - storage.getBucket(): - description: | - Retrieves the details of an existing Storage bucket. - title: 'getBucket()' - notes: | - - Policy permissions required: - - `buckets` permissions: `select` - - `objects` permissions: none - examples: - - name: Get bucket - isSpotlight: true - dart: | - ```dart - final Bucket bucket = await supabase - .storage - .getBucket('avatars'); - ``` - - storage.createBucket(): - description: | - Creates a new Storage bucket - title: 'createBucket()' - notes: | - - Policy permissions required: - - `buckets` permissions: `insert` - - `objects` permissions: none - examples: - - name: Create bucket - isSpotlight: true - dart: | - ```dart - final String bucketId = await supabase - .storage - .createBucket('avatars'); - ``` - - storage.emptyBucket(): - description: | - Removes all objects inside a single bucket. - title: 'emptyBucket()' - notes: | - - Policy permissions required: - - `buckets` permissions: `select` - - `objects` permissions: `select` and `delete` - examples: - - name: Empty bucket - isSpotlight: true - dart: | - ```dart - final String result = await supabase - .storage - .emptyBucket('avatars'); - ``` - storage.updateBucket(): - description: | - Updates a new Storage bucket - title: 'updateBucket()' - notes: | - - Policy permissions required: - - `buckets` permissions: `update` - - `objects` permissions: none - examples: - - name: Update bucket - isSpotlight: true - dart: | - ```dart - final res = await supabase - .storage - .updateBucket('avatars', const BucketOptions(public: false)); - ``` - - storage.deleteBucket(): - 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: - - name: Delete bucket - isSpotlight: true - dart: | - ```dart - final String result = await supabase - .storage - .deleteBucket('avatars'); - ``` - - storage.from.upload(): - description: | - Uploads a file to an existing bucket. - title: 'from.upload()' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `insert` - examples: - - name: Upload file - isSpotlight: true - dart: | - ```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), - ); - ``` - - storage.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: - - name: Update file - isSpotlight: true - dart: | - ```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), - ); - ``` - - storage.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: - - name: Move file - isSpotlight: true - dart: | - ```dart - final String result = await supabase - .storage - .from('avatars') - .move('public/avatar1.png', 'private/avatar2.png'); - ``` - - storage.from.createSignedUrl(): - 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: - - name: Create Signed URL - isSpotlight: true - dart: | - ```dart - final String signedUrl = await supabase - .storage - .from('avatars') - .createSignedUrl('avatar1.png', 60); - ``` - - storage.from.createSignedUrls(): - title: 'from.createSignedUrls()' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: none - - `objects` table permissions: `select` - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: Create Signed URLs - isSpotlight: true - dart: | - ```dart - final List signedUrls = await supabase - .storage - .from('avatars') - .createSignedUrls(['folder/avatar1.png', 'folder/avatar2.png'], 60); - ``` - - storage.from.getPublicUrl(): - 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: - - name: Returns the URL for an asset in a public bucket - isSpotlight: true - dart: | - ```dart - final String publicUrl = supabase - .storage - .from('public-bucket') - .getPublicUrl('avatar1.png'); - ``` - - storage.from.download(): - description: | - Downloads a file. - title: 'from.download()' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `select` - examples: - - name: Download file - isSpotlight: true - dart: | - ```dart - final Uint8List file = await supabase - .storage - .from('avatars') - .download('avatar1.png'); - ``` - - storage.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: - - name: Delete file - isSpotlight: true - dart: | - ```dart - final List objects = await supabase - .storage - .from('avatars') - .remove(['avatar1.png']); - ``` - - storage.from.list(): - description: | - Lists all the files within a bucket. - title: 'from.list()' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `select` - examples: - - name: List files in a bucket - isSpotlight: true - dart: | - ```dart - final List objects = await supabase - .storage - .from('avatars') - .list(); - ``` - 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). - - limit(): - description: | - Limits the result with the specified count. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .limit(1); - ``` - - name: With embedded resources - dart: | - ```dart - final data = await supabase - .from('countries') - .select('name, cities(name)') - .eq('name', 'United States') - .limit(1, foreignTable: 'cities' ); - ``` - - order(): - description: | - Orders the result with the specified column. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .order('id', ascending: false ); - ``` - - name: With embedded resources - dart: | - ```dart - final data = await supabase - .from('countries') - .select('name, cities(name)') - .eq('name', 'United States') - .order('name', foreignTable: 'cities'); - ``` - - range(): - description: | - Limits the result to rows within the specified range, inclusive. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .range(0,3); - ``` - - 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: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .single(); - ``` - - 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. - - ### Applying Filters - - Filters must be applied after any of `select()`, `update()`, `upsert()`, - `delete()`, and `rpc()` and before - [modifiers](/docs/reference/dart/using-modifiers). - - ```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'); - ``` - - ### Chaining - - Filters can be chained together to produce advanced queries. For example, - to query cities with population between 1,000 and 10,000: - - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .gte('population', 1000) - .lt('population', 10000); - ``` - - ### Conditional Chaining - - Filters can be built up one step at a time and then executed. For example: - - ```dart - final filterByName = null; - final filterPopLow = 1000; - final filterPopHigh = 10000; - - var query = supabase - .from('cities') - .select('name, country_id'); - - if (filterByName != null) { query = query.eq('name', filterByName); } - if (filterPopLow != null) { query = query.gte('population', filterPopLow); } - if (filterPopHigh != null) { query = query.lt('population', filterPopHigh); } - - final data = await query; - ``` - - ### Filter by values within a JSON column - - - - - ```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); - ``` - - - - - ```dart - final data = await supabase - .from('users') - .select() - .eq('address->postcode', 90210); - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Michael", - "address": { - "postcode": 90210 - } - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - - ### Filter Foreign Tables - - You can filter on foreign tables in your `select()` query using dot - notation: - - - - - ```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'); - ``` - - - - - ```dart - final data = await supabase - .from('countries') - .select(''' - name, - cities!inner ( - name - ) - ''') - .eq('cities.name', 'Bali'); - ``` - - - - - ```json - { - "data": [ - { - "name": "Indonesia", - "cities": [ - { - "name": "Bali" - } - ] - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - - .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: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .or('id.eq.20,id.eq.30'); - ``` - - name: Use `or` with `and` - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .or('id.gt.20,and(name.eq.New Zealand,name.eq.France)'); - ``` - - .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: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .not('name', 'eq', 'Paris'); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .not('name', 'eq', 'Paris'); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .not('name', 'eq', 'Paris'); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final data = await supabase - .rpc('echo_all_cities) - .not('name', 'eq', 'Paris'); - ``` - - .match(): - description: | - Finds all rows whose columns match the specified `query` object. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .match({'name': 'Beijing', 'country_id': 156}); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .match({'name': 'Beijing', 'country_id': 156}); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .match({'name': 'Beijing', 'country_id': 156}); - ``` - - name: With `rpc()` - dart: | - ```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}); - ``` - - .eq(): - description: | - Finds all rows whose value on the stated `column` exactly matches the specified `value`. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .eq('name', 'The shire'); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .eq('name', 'San Francisco'); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .eq('name', 'Mordor'); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final data = await supabase - .rpc('echo_all_cities') - .eq('name', 'San Francisco'); - ``` - - .neq(): - description: | - Finds all rows whose value on the stated `column` doesn't match the specified `value`. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .neq('name', 'The shire'); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .neq('name', 'San Francisco'); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .neq('name', 'Mordor'); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final data = await supabase - .rpc('echo_all_cities') - .neq('name', 'Lagos'); - ``` - - .gt(): - description: | - Finds all rows whose value on the stated `column` is greater than the specified `value`. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .gt('country_id', 250); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .gt('country_id', 250); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .gt('country_id', 250); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final data = await supabase - .rpc('echo_all_cities') - .gt('country_id', 250); - ``` - - .gte(): - description: | - Finds all rows whose value on the stated `column` is greater than or equal to the specified `value`. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .gte('country_id', 250); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .gte('country_id', 250); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .gte('country_id', 250); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final data = await supabase - .rpc('echo_all_cities') - .gte('country_id', 250); - ``` - - .lt(): - description: | - Finds all rows whose value on the stated `column` is less than the specified `value`. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .lt('country_id', 250); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .lt('country_id', 250); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .lt('country_id', 250); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final data = await supabase - .rpc('echo_all_cities') - .lt('country_id', 250); - ``` - - .lte(): - description: | - Finds all rows whose value on the stated `column` is less than or equal to the specified `value`. - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .lte('country_id', 250); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .lte('country_id', 250); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .lte('country_id', 250); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final data = await supabase - .rpc('echo_all_cities') - .lte('country_id', 250); - ``` - - .like(): - description: | - Finds all rows whose value in the stated `column` matches the supplied `pattern` (case sensitive). - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .like('name', '%la%'); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .like('name', '%la%'); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .like('name', '%la%'); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final data = await supabase - .rpc('echo_all_cities') - .like('name', '%la%'); - ``` - - .ilike(): - description: | - Finds all rows whose value in the stated `column` matches the supplied `pattern` (case insensitive). - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .ilike('name', '%la%'); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .ilike('name', '%la%'); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .ilike('name', '%la%'); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final data = await supabase - .rpc('echo_all_cities') - .ilike('name', '%la%'); - ``` - - .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: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .is_('name', null); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .is_('name', null); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .is_('name', null); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final data = await supabase - .rpc('echo_all_cities') - .is_('name', null); - ``` - - .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: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .in_('name', ['Rio de Janeiro', 'San Francisco']); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .in_('name', ['Rio de Janeiro', 'San Francisco']); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .in_('name', ['Rio de Janeiro', 'San Francisco']); - ``` - - name: With `rpc()` - dart: | - ```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']); - ``` - - .contains(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('countries') - .select('name, id, main_exports') - .contains('main_exports', ['oil']); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .contains('main_exports', ['oil']); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('countries') - .delete() - .contains('main_exports', ['oil']); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final data = await supabase - .rpc('echo_all_countries') - .contains('main_exports', ['oil']); - ``` - - .containedBy(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('countries') - .select('name, id, main_exports') - .containedBy('main_exports', ['cars', 'food', 'machine']); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .containedBy('main_exports', ['orks', 'surveillance', 'evil']); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('countries') - .delete() - .containedBy('main_exports', ['cars', 'food', 'machine']); - ``` - - name: With `rpc()` - dart: | - ```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']); - ``` - - .rangeLt(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeLt('population_range_millions', '[150, 250]'); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .rangeLt('population_range_millions', '[150, 250]'); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('countries') - .delete() - .rangeLt('population_range_millions', '[150, 250]'); - ``` - - name: With `rpc()` - dart: | - ```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]'); - ``` - - .rangeGt(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeGt('population_range_millions', '[150, 250]'); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .rangeGt('population_range_millions', '[150, 250]'); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('countries') - .delete() - .rangeGt('population_range_millions', '[150, 250]'); - ``` - - name: With `rpc()` - dart: | - ```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]'); - ``` - - .rangeGte(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeGte('population_range_millions', '[150, 250]'); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .rangeGte('population_range_millions', '[150, 250]'); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('countries') - .delete() - .rangeGte('population_range_millions', '[150, 250]'); - ``` - - name: With `rpc()` - dart: | - ```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]'); - ``` - - .rangeLte(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeLte('population_range_millions', '[150, 250]'); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .rangeLte('population_range_millions', '[150, 250]'); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('countries') - .delete() - .rangeLte('population_range_millions', '[150, 250]'); - ``` - - name: With `rpc()` - dart: | - ```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]); - ``` - - .rangeAdjacent(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeAdjacent('population_range_millions', '[70, 185]'); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .rangeAdjacent('population_range_millions', '[70, 185]'); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('countries') - .delete() - .rangeAdjacent('population_range_millions', '[70, 185]'); - ``` - - name: With `rpc()` - dart: | - ```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]'); - ``` - - .overlaps(): - examples: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('countries') - .select('name, id, main_exports') - .overlaps('main_exports', ['computers', 'minerals']); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('countries') - .update({ 'name': 'Mordor' }) - .overlaps('main_exports', ['computers', 'minerals']); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('countries') - .delete() - .overlaps('main_exports', ['computers', 'minerals']); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final data = await supabase - .rpc('echo_all_countries') - .overlaps('main_exports', ['computers', 'minerals']); - ``` - - .textSearch(): - description: | - Finds all rows whose tsvector value on the stated `column` matches to_tsquery(query). - examples: - - name: Text search - dart: | - ```dart - final data = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', "'fat' & 'cat'", - config: 'english' - ); - ``` - - name: Basic normalization - description: Uses PostgreSQL's `plainto_tsquery` function. - dart: | - ```dart - final data = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', "'fat' & 'cat'", - type: TextSearchType.plain, - config: 'english' - ); - ``` - - name: Full normalization - description: Uses PostgreSQL's `phraseto_tsquery` function. - dart: | - ```dart - final data = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', "'fat' & 'cat'", - type: TextSearchType.phrase, - config: 'english' - ); - ``` - - name: Full normalization - 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. - - dart: | - ```dart - final data = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', "'fat or cat'", - type: TextSearchType.websearch, - config: 'english' - ); - ``` - - .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: - - name: With `select()` - isSpotlight: true - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, country_id') - .filter('name', 'in', '("Paris","Tokyo")'); - ``` - - name: With `update()` - dart: | - ```dart - final data = await supabase - .from('cities') - .update({ 'name': 'Mordor' }) - .filter('name', 'in', '("Paris","Tokyo")'); - ``` - - name: With `delete()` - dart: | - ```dart - final data = await supabase - .from('cities') - .delete() - .filter('name', 'in', '("Paris","Tokyo")'); - ``` - - name: With `rpc()` - dart: | - ```dart - // Only valid if the Stored Procedure returns a table type. - final data = await supabase - .rpc('echo_all_cities') - .filter('name', 'in', '("Paris","Tokyo")'); - ``` - - name: Filter embedded resources - dart: | - ```dart - final data = await supabase - .from('cities') - .select('name, countries ( name )') - .filter('countries.name', 'in', '("France","Japan")'); - ``` diff --git a/spec/supabase_dart_v1.yml b/spec/supabase_dart_v1.yml index 073ec4d6f10..9c61cc1ee20 100644 --- a/spec/supabase_dart_v1.yml +++ b/spec/supabase_dart_v1.yml @@ -21,13 +21,13 @@ functions: 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/settings). + - 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/settings). + - 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/settings), an obfuscated/fake user object is returned. + - 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 @@ -85,7 +85,7 @@ functions: - 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). + - 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/url-configuration). examples: - id: sign-in-with-email name: Sign in with email. @@ -229,7 +229,7 @@ functions: 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). + 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/providers). examples: - id: update-the-email-for-an-authenticated-user name: Update the email for an authenticated user diff --git a/spec/supabase_js_v1--old.yml b/spec/supabase_js_v1--old.yml deleted file mode 100644 index 0daa83daa92..00000000000 --- a/spec/supabase_js_v1--old.yml +++ /dev/null @@ -1,2533 +0,0 @@ -openref: 0.1 - -info: - id: reference/supabase-js - title: Supabase Client - description: | - - Supabase JavaScript. - - definition: ../../spec/enrichments/tsdoc_v1/combined.json - specUrl: https://github.com/supabase/supabase/edit/master/spec/supabase_js_v1.yml - slugPrefix: '/' - libraries: - - name: 'JavaScript' - id: 'js' - version: '0.0.1' - -pages: - auth.signUp(): - title: 'signUp()' - $ref: '@supabase/gotrue-js.GoTrueClient.signUp' - notes: | - - By default, the user will need to verify their email address before logging in. If you would like to change this, you can disable "Email Confirmations" by going to Authentication -> Settings on [app.supabase.com](https://app.supabase.com) - - If "Email Confirmations" is turned on, a `user` is returned but `session` will be null - - If "Email Confirmations" is turned off, both a `user` and a `session` will be returned - - When the user confirms their email address, they will be redirected to localhost:3000 by default. To change this, you can go to Authentication -> Settings on [app.supabase.com](https://app.supabase.com) - - If signUp() is called for an existing confirmed user: - - If "Enable email confirmations" is enabled on the "Authentication" -> "Settings" page, an obfuscated / fake user object will be returned. - - If "Enable email confirmations" is disabled, an error with a message "User already registered" will be returned. - - To check if a user already exists, refer to getUser(). - examples: - - name: Sign up. - isSpotlight: true - js: | - ```js - const { user, session, error } = await supabase.auth.signUp({ - email: 'example@email.com', - password: 'example-password', - }) - ``` - - name: Sign up with additional user meta data. - isSpotlight: true - js: | - ```js - const { user, session, error } = await supabase.auth.signUp( - { - email: 'example@email.com', - password: 'example-password', - }, - { - data: { - first_name: 'John', - age: 27, - } - } - ) - ``` - - name: Sign up with third-party providers. - hideCodeBlock: true - description: | - You can sign up with OAuth providers using the [`signIn()`](/docs/reference/javascript/v1/auth-signin#sign-in-using-third-party-providers) method. - - name: Sign up with Phone. - description: | - Supabase supports Phone Auth. After a user has verified their number, they can use the [`signIn()`](/docs/reference/javascript/v1/auth-signin#sign-in-using-phone) method. - js: | - ```js - const { user, session, error } = await supabase.auth.signUp({ - phone: '+13334445555', - password: 'some-password', - }) - - // After receiving an SMS with One Time Password. - let { session, error } = await supabase.auth.verifyOTP({ - phone: '+13334445555', - token: '123456', - }) - ``` - - auth.signIn(): - title: 'signIn()' - $ref: '@supabase/gotrue-js.GoTrueClient.signIn' - notes: | - - A user can sign up either via email or OAuth. - - If you provide `email` without a `password`, the user will be sent a magic link. - - The magic link's destination URL is determined by the SITE_URL config variable. To change this, you can go to Authentication -> Settings on [app.supabase.com](https://app.supabase.com) - - Specifying a `provider` will open the browser to the relevant login page. - examples: - - name: Sign in with email. - isSpotlight: true - js: | - ```js - const { user, session, error } = await supabase.auth.signIn({ - email: 'example@email.com', - password: 'example-password', - }) - ``` - - name: Sign in with magic link. - description: If no password is provided, the user will be sent a "magic link" to their email address, which they can click to open your application with a valid session. By default, a given user can only request a Magic Link once every 60 seconds. - js: | - ```js - const { user, session, error } = await supabase.auth.signIn({ - email: 'example@email.com' - }) - ``` - - name: Sign in using third-party providers. - description: Supabase supports many different [third-party providers](https://supabase.com/docs/guides/auth#providers). - js: | - ```js - const { user, session, error } = await supabase.auth.signIn({ - // provider can be 'github', 'google', 'gitlab', and more - provider: 'github' - }) - ``` - - name: Sign in with Phone. - description: Supabase supports Phone Auth. - js: | - ```js - const { user, session, error } = await supabase.auth.signIn({ - phone: '+13334445555', - password: 'some-password', - }) - ``` - - name: Sign in with redirect. - description: | - Note that the `redirectTo` param is only relevant for OAuth logins, where the login flow is managed by - the Auth server. If you are using email/phone logins you should set up your own redirects (within the email/sms template). - - Sometimes you want to control where the user is redirected to after they are logged in. Supabase supports this for - any URL path on your website (the URL must either be on the same domain as your Site URL [see Auth>Settings in dashboard], or must match one of the Additional Redirect URLs [also in Auth>Settings]). - js: | - ```js - const { user, session, error } = await supabase.auth.signIn({ - provider: 'github' - }, { - redirectTo: 'https://example.com/welcome' - }) - ``` - - name: Sign in 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. - js: | - ```js - const { user, session, error } = await supabase.auth.signIn({ - provider: 'github' - }, { - scopes: 'repo gist notifications' - }) - const oAuthToken = session.provider_token // use to access provider API - ``` - - name: Sign in using a refresh token (e.g. in React Native). - description: | - If you are completing a sign up or login in a React Native app you can pass the refresh token obtained from the provider to obtain a session. - js: | - ```js - // An example using Expo's `AuthSession` - const redirectUri = AuthSession.makeRedirectUri({ useProxy: false }); - const provider = 'google'; - - AuthSession.startAsync({ - authUrl: `https://MYSUPABASEAPP.supabase.co/auth/v1/authorize?provider=${provider}&redirect_to=${redirectUri}`, - returnUrl: redirectUri, - }).then(async (response: any) => { - if (!response) return; - const { user, session, error } = await supabase.auth.signIn({ - refreshToken: response.params?.refresh_token, - }); - }); - ``` - - auth.signOut(): - title: 'signOut()' - $ref: '@supabase/gotrue-js.GoTrueClient.signOut' - examples: - - name: Sign out - isSpotlight: true - js: | - ```js - const { error } = await supabase.auth.signOut() - ``` - - auth.session(): - title: 'session()' - $ref: '@supabase/gotrue-js.GoTrueClient.session' - examples: - - name: Get the session data - isSpotlight: true - js: | - ```js - const session = supabase.auth.session() - ``` - - auth.user(): - title: 'user()' - $ref: '@supabase/gotrue-js.GoTrueClient.user' - notes: | - This method gets the user object from memory. - examples: - - name: Get the logged in user - isSpotlight: true - js: | - ```js - const user = supabase.auth.user() - ``` - - auth.update(): - title: 'update()' - $ref: '@supabase/gotrue-js.GoTrueClient.update' - notes: | - User email: 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). - - User metadata: It's generally better to store user data in a table within your public schema (i.e., `public.users`). - Use the `update()` method if you have data which rarely changes or is specific only to the logged in user. - examples: - - name: Update the email for an authenticated user - description: Sends a "Confirm Email Change" email to the new email address. - isSpotlight: true - js: | - ```js - const { user, error } = await supabase.auth.update({email: 'new@email.com'}) - ``` - - name: Update the password for an authenticated user - isSpotlight: true - js: | - ```js - const { user, error } = await supabase.auth.update({password: 'new password'}) - ``` - - name: Update the user's metadata - isSpotlight: true - js: | - ```js - const { user, error } = await supabase.auth.update({ - data: { hello: 'world' } - }) - ``` - - auth.setAuth(): - title: 'setAuth()' - $ref: '@supabase/gotrue-js.GoTrueClient.setAuth' - examples: - - name: Basic example. - description: This is most useful on server-side functions where you cannot log the user in, but have access to the user's access token. - isSpotlight: true - js: | - ```js - function apiFunction(req, res) { - // Assuming the access token was sent as a header "X-Supabase-Auth" - const { access_token } = req.get('X-Supabase-Auth') - - // You can now use it within a Supabase Client - const supabase = createClient("https://xyzcompany.supabase.co", "public-anon-key") - const { user, error } = supabase.auth.setAuth(access_token) - - // This client will now send requests as this user - const { data } = await supabase.from('your_table').select() - } - ``` - - name: With Express. - isSpotlight: true - js: | - ```js - - /** - * Make a request from the client to your server function - */ - async function makeApiRequest() { - const token = newClient.session()?.access_token - - await fetch('https://example.com/withAuth', { - method: 'GET', - withCredentials: true, - credentials: 'include', - headers: { - 'Content-Type': 'application/json', - 'Authorization': bearer, // Your own auth - 'X-Supabase-Auth': token, // Set the Supabase user - } - }) - } - - /** - * Use the Auth token in your server-side function. - */ - async function apiFunction(req, res) { - const { access_token } = req.get('X-Supabase-Auth') - - // You can now use it within a Supabase Client - const supabase = createClient("https://xyzcompany.supabase.co", "public-anon-key") - const { user, error } = supabase.auth.setAuth(access_token) - - // This client will now send requests as this user - const { data } = await supabase.from('your_table').select() - } - ``` - - auth.onAuthStateChange(): - title: 'onAuthStateChange()' - $ref: '@supabase/gotrue-js.GoTrueClient.onAuthStateChange' - examples: - - name: Listen to auth changes - isSpotlight: true - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - console.log(event, session) - }) - ``` - - name: Listen to sign in - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - if (event == 'SIGNED_IN') console.log('SIGNED_IN', session) - }) - ``` - - name: Listen to sign out - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - if (event == 'SIGNED_OUT') console.log('SIGNED_OUT', session) - }) - ``` - - name: Listen to token refresh - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - if (event == 'TOKEN_REFRESHED') console.log('TOKEN_REFRESHED', session) - }) - ``` - - name: Listen to user updates - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - if (event == 'USER_UPDATED') console.log('USER_UPDATED', session) - }) - ``` - - name: Listen to user deleted - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - if (event == 'USER_DELETED') console.log('USER_DELETED', session) - }) - ``` - - name: Listen to password recovery events - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - if (event == 'PASSWORD_RECOVERY') console.log('PASSWORD_RECOVERY', session) - }) - ``` - auth.api.getUser(): - title: 'getUser()' - $ref: '@supabase/gotrue-js.GoTrueApi.getUser' - notes: | - - Fetches the user object from the database instead of local storage. - - Note that user() fetches the user object from local storage which might not be the most updated. - - Requires the user's access_token. - examples: - - name: Fetch the user object using the access_token jwt. - isSpotlight: true - js: | - ```js - const { user, error } = await supabase.auth.api.getUser( - 'ACCESS_TOKEN_JWT', - ) - ``` - - auth.api.listUsers(): - title: 'listUsers()' - $ref: '@supabase/gotrue-js.GoTrueApi.listUsers' - notes: | - - Requires a `service_role` key. - - This function should be called on a server. Never expose your `service_role` key in the browser. - examples: - - name: Get a full list of users. - isSpotlight: true - js: | - ```js - const { data: user, error } = await supabase.auth.api.listUsers() - ``` - - auth.api.createUser(): - title: 'createUser()' - $ref: '@supabase/gotrue-js.GoTrueApi.createUser' - notes: | - - Requires a `service_role` key. - - This function should be called on a server. Never expose your `service_role` key in the browser. - - If you do not provide the `email_confirm` and `phone_confirm` options to this function, both will default to false. - examples: - - name: Create a new user. - isSpotlight: true - js: | - ```js - const { data: user, error } = await supabase.auth.api.createUser({ - email: 'user@email.com', - password: 'password', - user_metadata: { name: 'Yoda' } - }) - ``` - - name: Auto-confirm email. - isSpotlight: true - js: | - ```js - const { data: user, error } = await supabase.auth.api.createUser({ - email: 'user@email.com', - email_confirm: true - }) - ``` - - name: Auto-confirm phone. - isSpotlight: true - js: | - ```js - const { data: user, error } = await supabase.auth.api.createUser({ - phone: '1234567890', - phone_confirm: true - }) - ``` - - auth.api.deleteUser(): - title: 'deleteUser()' - $ref: '@supabase/gotrue-js.GoTrueApi.deleteUser' - notes: | - - Requires a `service_role` key. - - This function should be called on a server. Never expose your `service_role` key in the browser. - examples: - - name: Remove a user completely. - isSpotlight: true - js: | - ```js - const { data: user, error } = await supabase.auth.api.deleteUser( - '715ed5db-f090-4b8c-a067-640ecee36aa0' - ) - ``` - - auth.api.inviteUserByEmail(): - title: 'inviteUserByEmail()' - $ref: '@supabase/gotrue-js.GoTrueApi.inviteUserByEmail' - notes: | - - Requires a `service_role` key. - - This function should only be called on a server. Never expose your `service_role` key in the browser. - examples: - - name: Basic example. - isSpotlight: false - js: | - ```js - const { data: user, error } = await supabase.auth - .api - .inviteUserByEmail('email@example.com') - ``` - - auth.api.sendMobileOTP(): - title: 'sendMobileOTP()' - $ref: '@supabase/gotrue-js.GoTrueApi.sendMobileOTP' - notes: | - - Requires a `service_role` key. - - This function should only be called on a server. Never expose your `service_role` key in the browser. - examples: - - name: Basic example. - isSpotlight: false - js: | - ```js - const { data: user, error } = await supabase.auth - .api - .sendMobileOTP('12345879') - ``` - - auth.api.resetPasswordForEmail(): - title: 'resetPasswordForEmail()' - $ref: '@supabase/gotrue-js.GoTrueApi.resetPasswordForEmail' - 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.update()`: - ```js - const { data, error } = await supabase.auth.update({ - password: new_password, - }) - ``` - examples: - - name: Reset password - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.auth.api.resetPasswordForEmail( - 'user@email.com' - ) - ``` - - name: Reset password (React) - isSpotlight: true - js: | - ```js - /** - * Step 1: Send the user an email to get a password reset token. - * This email contains a link which sends the user back to your application. - */ - const { data, error } = await supabase.auth.api.resetPasswordForEmail( - 'user@email.com' - ) - - /** - * Step 2: Once the user is redirected back to your application, - * ask the user to reset their password. - */ - useEffect(() => { - supabase.auth.onAuthStateChange(async (event, session) => { - if (event == "PASSWORD_RECOVERY") { - const newPassword = prompt("What would you like your new password to be?"); - const { data, error } = await supabase.auth.update({ - password: newPassword, - }) - - if (data) alert("Password updated successfully!") - if (error) alert("There was an error updating your password.") - } - }) - }, []) - ``` - - auth.api.generateLink(): - title: 'generateLink()' - $ref: '@supabase/gotrue-js.GoTrueApi.generateLink' - notes: | - - Requires a `service_role` key. - - This function should only be called on a server. Never expose your `service_role` key in the browser. - examples: - - name: Generate an invite link - isSpotlight: false - js: | - ```js - const { data: user, error } = await supabase.auth.api.generateLink( - 'invite', - 'email@example.com' - ) - ``` - - auth.api.updateUserById(): - title: 'updateUserById()' - $ref: '@supabase/gotrue-js.GoTrueApi.updateUserById' - notes: | - - Requires a `service_role` key. - - This function should only be called on a server. Never expose your `service_role` key in the browser. - examples: - - name: Updates a user's email. - isSpotlight: true - js: | - ```js - const { data: user, error } = await supabase.auth.api.updateUserById( - '6aa5d0d4-2a9f-4483-b6c8-0cf4c6c98ac4', - { email: 'new@email.com' } - ) - ``` - - name: Updates a user's password. - isSpotlight: true - js: | - ```js - const { data: user, error } = await supabase.auth.api.updateUserById( - '6aa5d0d4-2a9f-4483-b6c8-0cf4c6c98ac4', - { password: 'new_password' } - ) - ``` - - name: Updates a user's metadata. - isSpotlight: true - js: | - ```js - const { data: user, error } = await supabase.auth.api.updateUserById( - '6aa5d0d4-2a9f-4483-b6c8-0cf4c6c98ac4', - { user_metadata: { hello: 'world' } } - ) - ``` - - name: Updates a user's app_metadata. - isSpotlight: true - js: | - ```js - const { data: user, error } = await supabase.auth.api.updateUserById( - '6aa5d0d4-2a9f-4483-b6c8-0cf4c6c98ac4', - { app_metadata: { plan: 'trial' } } - ) - ``` - - name: Confirms a user's email address. - isSpotlight: true - js: | - ```js - const { data: user, error } = await supabase.auth.api.updateUserById( - '6aa5d0d4-2a9f-4483-b6c8-0cf4c6c98ac4', - { email_confirm: true } - ) - ``` - - name: Confirms a user's phone number. - isSpotlight: true - js: | - ```js - const { data: user, error } = await supabase.auth.api.updateUserById( - '6aa5d0d4-2a9f-4483-b6c8-0cf4c6c98ac4', - { phone_confirm: true } - ) - ``` - invoke(): - title: 'invoke()' - description: | - Invokes a Supabase Function. - $ref: '@supabase/functions-js.FunctionsClient.invoke' - 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: - - name: Basic invocation. - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.functions.invoke('hello', { - body: JSON.stringify({ foo: 'bar' }) - }) - ``` - - name: Specifying response type. - description: | - By default, `invoke()` will parse the response as JSON. You can parse the response in the following formats: `json`, `blob`, `text`, and `arrayBuffer`. - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.functions.invoke('hello', { - responseType: 'text', - body: JSON.stringify({ foo: 'bar' }) - }) - ``` - - name: Parsing custom headers. - description: | - You can pass custom headers to your function. Note: supabase-js automatically passes the `Authorization` header with the signed in user's JWT. - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.functions.invoke('hello', { - headers: { - "my-custom-header": 'my-custom-header-value' - }, - body: JSON.stringify({ foo: 'bar' }) - }) - ``` - - select(): - title: 'Fetch data: select()' - $ref: '@supabase/postgrest-js."lib/PostgrestQueryBuilder".PostgrestQueryBuilder.select' - notes: | - - 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. - - `select()` can be combined with [Modifiers](/docs/reference/javascript/using-modifiers) - - `select()` can be combined with [Filters](/docs/reference/javascript/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: - - name: Getting your data - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select() - ``` - - name: Selecting specific columns - description: You can select specific fields from your tables. - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name') - ``` - - name: Query foreign tables - description: If your database has foreign key relationships, you can query related tables too. - js: | - ```js - const { data, error } = await supabase - .from('countries') - .select(` - name, - cities ( - name - ) - `) - ``` - note: | - What about join tables - If you're in a situation where your tables are **NOT** directly related, but instead are joined by a _join table_, - you can still use the `select()` method to query the related data. The PostgREST engine detects the relationship automatically. - For more details, [follow the link](https://postgrest.org/en/latest/api.html#embedding-through-join-tables). - - name: Query the same foreign table multiple times - description: | - Sometimes you will need to query the same foreign table twice. - In this case, you can use the name of the joined column to identify - which join you intend to use. For convenience, you can also give an - alias for each column. For example, if we had a shop of products, - and we wanted to get the supplier and the purchaser at the same time - (both in the users) table: - js: | - ```js - const { data, error } = await supabase - .from('products') - .select(` - id, - supplier:supplier_id ( name ), - purchaser:purchaser_id ( name ) - `) - ``` - - 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": - js: | - ```js - const { data, error } = await supabase - .from('messages') - .select('*, users!inner(*)') - .eq('users.username', 'Jane') - ``` - - name: Querying with count option - description: | - You can get the number of rows by using the count option. - Allowed values for count option are `null`, [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). - js: | - ```js - const { data, error, count } = await supabase - .from('cities') - .select('name', { count: 'exact' }) // if you don't want to return any rows, you can use { count: 'exact', head: true } - ``` - - 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. - js: | - ```js - const { data, error } = await supabase - .from('users') - .select(` - id, name, - address->street - `) - .eq('address->postcode', 90210) - ``` - - name: Return data as CSV - description: | - By default the data is returned in JSON format, however you can also request for it to be returned as Comma Separated Values. - js: | - ```js - const { data, error } = await supabase - .from('users') - .select() - .csv() - ``` - - name: Aborting requests in-flight - description: | - You can use an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) to abort requests. Note that `status` and `statusText` doesn't mean anything for aborted requests, since the request wasn't actually fulfilled. - js: | - ```js - const ac = new AbortController() - supabase - .from('very_big_table') - .select() - .abortSignal(ac.signal) - .then(console.log) - ac.abort() - // { - // error: { - // message: 'FetchError: The user aborted a request.', - // details: '', - // hint: '', - // code: '' - // }, - // data: null, - // body: null, - // count: null, - // status: 400, - // statusText: 'Bad Request' - // } - ``` - - insert(): - title: 'Create data: insert()' - $ref: '@supabase/postgrest-js."lib/PostgrestQueryBuilder".PostgrestQueryBuilder.insert' - notes: | - - By default, every time you run `insert()`, the client library will make a `select` to return the full record. - This is convenient, but it can also cause problems if your Policies are not configured to allow the `select` operation. - If you are using Row Level Security and you are encountering problems, try setting the `returning` param to `minimal`. - examples: - - name: Create a record - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .insert([ - { name: 'The Shire', country_id: 554 } - ]) - ``` - - name: Bulk create - description: | - When running a bulk create, the operation is handled in a single transaction. If any of the inserts fail, all other operations are - rolled back. - js: | - ```js - const { data, error } = await supabase - .from('cities') - .insert([ - { name: 'The Shire', country_id: 554 }, - { name: 'Rohan', country_id: 555 }, - ]) - ``` - - name: Upsert - description: | - For upsert, if set to true, primary key columns would need to be included - in the data parameter in order for an update to properly happen. Also, primary keys - used must be natural, not surrogate. There are however, - [workarounds](https://github.com/PostgREST/postgrest/issues/1118) - for surrogate primary keys. - js: | - ```js - const { data, error } = await supabase - .from('cities') - .insert( - [ - { name: 'The Shire', country_id: 554 }, - { name: 'Rohan', country_id: 555 }, - { name: 'City by the Bay', country_id:840} - ], - { upsert: true }) - ``` - - update(): - title: 'Modify data: update()' - $ref: '@supabase/postgrest-js."lib/PostgrestQueryBuilder".PostgrestQueryBuilder.update' - notes: | - - `update()` should always be combined with [Filters](/docs/reference/javascript/using-filters) to target the item(s) you wish to update. - examples: - - name: Updating your data - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Middle Earth' }) - .match({ name: 'Auckland' }) - ``` - - name: Updating JSON data - description: | - Postgres offers a - [number of operators](https://www.postgresql.org/docs/current/functions-json.html) - for working with JSON data. Right now it is only possible to update an entire JSON document, - but we are [working on ideas](https://github.com/PostgREST/postgrest/issues/465) for updating individual keys. - js: | - ```js - const { data, error } = await supabase - .from('users') - .update(` - address: { - street: 'Melrose Place', - postcode: 90210 - } - `) - .eq('address->postcode', 90210) - ``` - - upsert(): - title: 'Upsert data: upsert()' - $ref: '@supabase/postgrest-js."lib/PostgrestQueryBuilder".PostgrestQueryBuilder.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. - - If you need to insert new data and update existing data at the same time, use [Postgres triggers](https://github.com/supabase/postgrest-js/issues/173#issuecomment-825124550). - examples: - - name: Upsert your data - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('messages') - .upsert({ id: 3, message: 'foo', username: 'supabot' }) - ``` - - name: Bulk Upsert your data - isSpotlight: false - js: | - ```js - const { data, error } = await supabase - .from('messages') - .upsert([ - { id: 3, message: 'foo', username: 'supabot' }, - { id: 4, message: 'bar', username: 'supabot' } - ]) - ``` - - 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 - js: | - ```js - const { data, error } = await supabase - .from('users') - .upsert({ username: 'supabot' }, { onConflict: 'username' }) - ``` - - name: Return the exact number of rows - isSpotlight: true - js: | - ```js - const { data, error, count } = await supabase - .from('users') - .upsert({ - id: 3, message: 'foo', - username: 'supabot' - }, { - count: 'exact' - }) - ``` - - delete(): - title: 'Delete data: delete()' - $ref: '@supabase/postgrest-js."lib/PostgrestQueryBuilder".PostgrestQueryBuilder.delete' - notes: | - - `delete()` should always be combined with [filters](/docs/reference/javascript/using-filters) to target the item(s) you wish to delete. - - If you use `delete()` with filters and you have - [RLS](/docs/learn/auth-deep-dive/auth-row-level-security) enabled, only - rows visible through `SELECT` policies are deleted. Note that by default - no rows are visible, so you need at least one `SELECT`/`ALL` policy that - makes the rows visible. - examples: - - name: Delete records - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .match({ id: 666 }) - ``` - - rpc(): - title: 'Postgres functions: rpc()' - description: | - You can call Postgres functions as _Remote Procedure Calls_, logic in your database that you can execute from anywhere. - Functions are useful when the logic rarely changes—like for password resets and updates. - - ```sql - create or replace function hello_world() returns text as $$ - select 'Hello world'; - $$ language sql; - ``` - $ref: '@supabase/postgrest-js."lib/PostgrestRpcBuilder".PostgrestRpcBuilder.rpc' - examples: - - name: Call a Postgres function without arguments - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .rpc('hello_world') - ``` - - name: Call a Postgres function with arguments - js: | - ```js - const { data, error } = await supabase - .rpc('echo_city', { name: 'The Shire' }) - ``` - - name: Bulk processing - description: You can process large payloads at once using [array parameters](https://postgrest.org/en/stable/api.html#calling-functions-with-array-parameters). - js: | - ```js - const { data, error } = await postgrest - .rpc('echo_cities', { names: ['The Shire', 'Mordor'] }) - ``` - - name: Call a Postgres function with filters - description: | - Postgres functions that return tables can also be combined with - [Modifiers](/docs/reference/javascript/using-modifiers) and - [Filters](/docs/reference/javascript/using-filters). - js: | - ```js - const { data, error } = await supabase - .rpc('echo_all_cities') - .select('name, population') - .eq('name', 'The Shire') - ``` - - name: Call a Postgres function with a count option - description: | - You can specify a count option to get the row count along with your data. - Allowed values for count option are `null`, `exact`, `planned` and `estimated`. - js: | - ```js - const { data, error, count } = await supabase - .rpc('hello_world', {}, { count: 'exact' }) - ``` - - subscribe(): - title: 'on().subscribe()' - $ref: '@supabase/supabase-js.lib/SupabaseQueryBuilder.SupabaseQueryBuilder.on' - 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: - - name: Listen to all database changes - isSpotlight: true - js: | - ```js - const mySubscription = supabase - .from('*') - .on('*', payload => { - console.log('Change received!', payload) - }) - .subscribe() - ``` - - name: Listening to a specific table - js: | - ```js - const mySubscription = supabase - .from('countries') - .on('*', payload => { - console.log('Change received!', payload) - }) - .subscribe() - ``` - - name: Listening to inserts - js: | - ```js - const mySubscription = supabase - .from('countries') - .on('INSERT', payload => { - console.log('Change received!', payload) - }) - .subscribe() - ``` - - 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; - ``` - js: | - ```js - const mySubscription = supabase - .from('countries') - .on('UPDATE', payload => { - console.log('Change received!', payload) - }) - .subscribe() - ``` - - 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; - ``` - js: | - ```js - const mySubscription = supabase - .from('countries') - .on('DELETE', payload => { - console.log('Change received!', payload) - }) - .subscribe() - ``` - - name: Listening to multiple events - description: You can chain listeners if you want to listen to multiple events for each table. - js: | - ```js - const mySubscription = supabase - .from('countries') - .on('INSERT', handleRecordInserted) - .on('DELETE', handleRecordDeleted) - .subscribe() - ``` - - 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. - notes: | - - ``eq`` filter works with all database types as under the hood, it's casting both the filter value and the database value to the correct type and then comparing them. - js: | - ```js - const mySubscription = supabase - .from('countries:id=eq.200') - .on('UPDATE', handleRecordUpdated) - .subscribe() - ``` - - removeSubscription(): - title: 'removeSubscription()' - $ref: '@supabase/supabase-js.index.SupabaseClient.removeSubscription' - notes: | - - Removing subscriptions is a great way to maintain the performance of your project's database. Supabase will automatically handle cleanup 30 seconds after a user is disconnected, but unused subscriptions may cause degradation as more users are simultaneously subscribed. - examples: - - name: Remove a subscription - isSpotlight: true - js: | - ```js - supabase.removeSubscription(mySubscription) - ``` - - removeAllSubscriptions(): - title: 'removeAllSubscriptions()' - $ref: '@supabase/supabase-js.index.SupabaseClient.removeAllSubscriptions' - notes: | - - Removing subscriptions is a great way to maintain the performance of your project's database. Supabase will automatically handle cleanup 30 seconds after a user is disconnected, but unused subscriptions may cause degradation as more users are simultaneously subscribed. - examples: - - name: Removes all subscriptions - isSpotlight: true - js: | - ```js - supabase.removeAllSubscriptions() - ``` - - getSubscriptions(): - title: 'getSubscriptions()' - $ref: '@supabase/supabase-js.index.SupabaseClient.getSubscriptions' - examples: - - name: Get all subscriptions - isSpotlight: true - js: | - ```js - const subscriptions = supabase.getSubscriptions() - ``` - - storage.listBuckets(): - title: 'listBuckets()' - $ref: '@supabase/storage-js."lib/StorageBucketApi".StorageBucketApi.listBuckets' - notes: | - - Policy permissions required: - - `buckets` permissions: `select` - - `objects` permissions: none - examples: - - name: List buckets - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .listBuckets() - ``` - - storage.getBucket(): - title: 'getBucket()' - $ref: '@supabase/storage-js."lib/StorageBucketApi".StorageBucketApi.getBucket' - notes: | - - Policy permissions required: - - `buckets` permissions: `select` - - `objects` permissions: none - examples: - - name: Get bucket - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .getBucket('avatars') - ``` - - storage.createBucket(): - title: 'createBucket()' - $ref: '@supabase/storage-js."lib/StorageBucketApi".StorageBucketApi.createBucket' - notes: | - - Policy permissions required: - - `buckets` permissions: `insert` - - `objects` permissions: none - examples: - - name: Create bucket - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .createBucket('avatars', { public: false }) - ``` - - storage.emptyBucket(): - title: 'emptyBucket()' - $ref: '@supabase/storage-js."lib/StorageBucketApi".StorageBucketApi.emptyBucket' - notes: | - - Policy permissions required: - - `buckets` permissions: `select` - - `objects` permissions: `select` and `delete` - examples: - - name: Empty bucket - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .emptyBucket('avatars') - ``` - storage.updateBucket(): - title: 'updateBucket()' - $ref: '@supabase/storage-js."lib/StorageBucketApi".StorageBucketApi.updateBucket' - notes: | - - Policy permissions required: - - `buckets` permissions: `update` - - `objects` permissions: none - examples: - - name: Update bucket - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .updateBucket('avatars', { public: false }) - ``` - - storage.deleteBucket(): - title: 'deleteBucket()' - $ref: '@supabase/storage-js."lib/StorageBucketApi".StorageBucketApi.deleteBucket' - notes: | - - Policy permissions required: - - `buckets` permissions: `select` and `delete` - - `objects` permissions: none - examples: - - name: Delete bucket - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .deleteBucket('avatars') - ``` - - storage.from.upload(): - title: 'from.upload()' - $ref: '@supabase/storage-js."lib/StorageFileApi".StorageFileApi.upload' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `insert` - - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Upload file using `ArrayBuffer` from base64 file data instead, see example below. - examples: - - name: Upload file - isSpotlight: true - js: | - ```js - const avatarFile = event.target.files[0] - const { data, error } = await supabase - .storage - .from('avatars') - .upload('public/avatar1.png', avatarFile, { - cacheControl: '3600', - upsert: false - }) - ``` - - name: Upload file using `ArrayBuffer` from base64 file data - js: | - ```js - import { decode } from 'base64-arraybuffer' - - const { data, error } = await supabase - .storage - .from('avatars') - .upload('public/avatar1.png', decode('base64FileData'), { - contentType: 'image/png' - }) - ``` - - storage.from.update(): - title: 'from.update()' - $ref: '@supabase/storage-js."lib/StorageFileApi".StorageFileApi.update' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `update` and `select` - - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Update file using `ArrayBuffer` from base64 file data instead, see example below. - examples: - - name: Update file - isSpotlight: true - js: | - ```js - const avatarFile = event.target.files[0] - const { data, error } = await supabase - .storage - .from('avatars') - .update('public/avatar1.png', avatarFile, { - cacheControl: '3600', - upsert: false - }) - ``` - - name: Update file using `ArrayBuffer` from base64 file data - js: | - ```js - import {decode} from 'base64-arraybuffer' - - const { data, error } = await supabase - .storage - .from('avatars') - .update('public/avatar1.png', decode('base64FileData'), { - contentType: 'image/png' - }) - ``` - - storage.from.move(): - title: 'from.move()' - $ref: '@supabase/storage-js."lib/StorageFileApi".StorageFileApi.move' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `update` and `select` - examples: - - name: Move file - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .move('public/avatar1.png', 'private/avatar2.png') - ``` - - storage.from.copy(): - title: 'from.copy()' - $ref: '@supabase/storage-js."lib/StorageFileApi".StorageFileApi.copy' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `insert` and `select` - examples: - - name: Copy file - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .copy('public/avatar1.png', 'private/avatar2.png') - ``` - - storage.from.createSignedUrl(): - title: 'from.createSignedUrl()' - $ref: '@supabase/storage-js."lib/StorageFileApi".StorageFileApi.createSignedUrl' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `select` - examples: - - name: Create Signed URL - isSpotlight: true - js: | - ```js - const { signedURL, error } = await supabase - .storage - .from('avatars') - .createSignedUrl('folder/avatar1.png', 60) - ``` - - storage.from.createSignedUrls(): - title: 'from.createSignedUrls()' - $ref: '@supabase/storage-js."lib/StorageFileApi".StorageFileApi.createSignedUrls' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `select` - examples: - - name: Create Signed URLs - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .createSignedUrls(['folder/avatar1.png', 'folder/avatar2.png'], 60) - ``` - - storage.from.getPublicUrl(): - title: 'from.getPublicUrl()' - $ref: '@supabase/storage-js."lib/StorageFileApi".StorageFileApi.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: - - name: Returns the URL for an asset in a public bucket - isSpotlight: true - js: | - ```js - const { publicURL, error } = supabase - .storage - .from('public-bucket') - .getPublicUrl('folder/avatar1.png') - ``` - - storage.from.download(): - title: 'from.download()' - $ref: '@supabase/storage-js."lib/StorageFileApi".StorageFileApi.download' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `select` - examples: - - name: Download file - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .download('folder/avatar1.png') - ``` - - storage.from.remove(): - title: 'from.remove()' - $ref: '@supabase/storage-js."lib/StorageFileApi".StorageFileApi.remove' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `delete` and `select` - examples: - - name: Delete file - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .remove(['folder/avatar1.png']) - ``` - - storage.from.list(): - title: 'from.list()' - $ref: '@supabase/storage-js."lib/StorageFileApi".StorageFileApi.list' - notes: | - - Policy permissions required: - - `buckets` permissions: none - - `objects` permissions: `select` - examples: - - name: List files in a bucket - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .list('folder', { - limit: 100, - offset: 0, - sortBy: { column: 'name', order: 'asc' }, - }) - ``` - - name: Search files in a bucket - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .list('folder', { - limit: 100, - offset: 0, - sortBy: { column: 'name', order: 'asc' }, - search: 'jon' - }) - ``` - - Using Modifiers: - description: | - Modifiers can be used on `select()` queries. - - If a Postgres function returns a table response, you can also apply modifiers to the `rpc()` function. - - limit(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.limit' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .limit(1) - ``` - - name: With embedded resources - js: | - ```js - const { data, error } = await supabase - .from('countries') - .select('name, cities(name)') - .eq('name', 'United States') - .limit(1, { foreignTable: 'cities' }) - ``` - - order(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.order' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .order('id', { ascending: false }) - ``` - - name: With embedded resources - js: | - ```js - const { data, error } = await supabase - .from('countries') - .select('name, cities(name)') - .eq('name', 'United States') - .order('name', {foreignTable: 'cities'}) - ``` - - name: Ordering multiple columns - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name', 'country_id') - .order('country_id', { ascending: false }) - .order('name', { ascending: false }) - ``` - range(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.range' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .range(0,3) - ``` - - single(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.single' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .limit(1) - .single() - ``` - - maybeSingle(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.maybeSingle' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .eq('name', 'Singapore') - .maybeSingle() - ``` - - Using Filters: - description: | - Filters can be used on `select()`, `update()`, and `delete()` queries. - - If a Postgres function returns a table response, you can also apply filters. - - ### Applying Filters - - You must apply your filters to the end of your query. For example: - - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .eq('name', 'The Shire') // Correct - - const { data, error } = await supabase - .from('cities') - .eq('name', 'The Shire') // Incorrect - .select('name, country_id') - ``` - - ### Chaining - - Filters can be chained together to produce advanced queries. For example: - - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .gte('population', 1000) - .lt('population', 10000) - ``` - - ### Conditional Chaining - - Filters can be built up one step at a time and then executed. For example: - - ```js - const filterByName = null - const filterPopLow = 1000 - const filterPopHigh = 10000 - - let query = supabase - .from('cities') - .select('name, country_id') - - if (filterByName) { query = query.eq('name', filterByName) } - if (filterPopLow) { query = query.gte('population', filterPopLow) } - if (filterPopHigh) { query = query.lt('population', filterPopHigh) } - - const { data, error } = await query - ``` - - .or(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.or' - 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. - - ```js - .or('id.in.(6,7), arraycol.cs.{"a","b"}') // Use Postgres list () for in filter. Array {} for array column and 'cs' for contains. - .or(`id.in.(${arrList}),arraycol.cs.{${arr}}`) // You can insert a javascipt array for list or array on array column. - .or(`id.in.(${arrList}),rangecol.cs.[${arrRange})`) // You can insert a javascipt array for list or range on a range column. - ``` - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .or('id.eq.20,id.eq.30') - ``` - - name: Use `or` with `and` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .or('id.gt.20,and(name.eq.New Zealand,name.eq.France)') - ``` - - name: Use `or` on foreign tables - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('countries') - .select('id, cities(*)') - .or('name.eq.Wellington,name.eq.Paris', { foreignTable: "cities" }) - ``` - - .not(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.not' - 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. - - ```js - .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 () for in filter. - .not('id','in',`(${arr})`) // You can insert a javascript array. - ``` - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .not('name', 'eq', 'Paris') - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Mordor' }) - .not('name', 'eq', 'Paris') - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .not('name', 'eq', 'Paris') - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_cities') - .not('name', 'eq', 'Paris') - ``` - - .match(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.match' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .match({name: 'Beijing', country_id: 156}) - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Mordor' }) - .match({name: 'Beijing', country_id: 156}) - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .match({name: 'Beijing', country_id: 156}) - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_cities') - .match({name: 'Beijing', country_id: 156}) - ``` - - .eq(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.eq' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .eq('name', 'The shire') - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Mordor' }) - .eq('name', 'San Francisco') - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .eq('name', 'Mordor') - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_cities') - .eq('name', 'San Francisco') - ``` - - .neq(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.neq' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .neq('name', 'The shire') - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Mordor' }) - .neq('name', 'San Francisco') - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .neq('name', 'Mordor') - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_cities') - .neq('name', 'Lagos') - ``` - - .gt(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.gt' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .gt('country_id', 250) - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Mordor' }) - .gt('country_id', 250) - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .gt('country_id', 250) - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_cities') - .gt('country_id', 250) - ``` - - .gte(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.gte' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .gte('country_id', 250) - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Mordor' }) - .gte('country_id', 250) - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .gte('country_id', 250) - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_cities') - .gte('country_id', 250) - ``` - - .lt(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.lt' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .lt('country_id', 250) - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Mordor' }) - .lt('country_id', 250) - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .lt('country_id', 250) - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_cities') - .lt('country_id', 250) - ``` - - .lte(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.lte' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .lte('country_id', 250) - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Mordor' }) - .lte('country_id', 250) - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .lte('country_id', 250) - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_cities') - .lte('country_id', 250) - ``` - - .like(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.like' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .like('name', '%la%') - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Mordor' }) - .like('name', '%la%') - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .like('name', '%la%') - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_cities') - .like('name', '%la%') - ``` - - .ilike(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.ilike' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .ilike('name', '%la%') - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Mordor' }) - .ilike('name', '%la%') - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .ilike('name', '%la%') - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_cities') - .ilike('name', '%la%') - ``` - - .is(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.is' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .is('name', null) - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Mordor' }) - .is('name', null) - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .is('name', null) - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_cities') - .is('name', null) - ``` - - .in(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.in' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .in('name', ['Rio de Janeiro', 'San Francisco']) - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Mordor' }) - .in('name', ['Rio de Janeiro', 'San Francisco']) - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .in('name', ['Rio de Janeiro', 'San Francisco']) - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_cities') - .in('name', ['Rio de Janeiro', 'San Francisco']) - ``` - - .contains(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.contains' - notes: | - - `.contains()` can work on array columns or range columns. - It is very useful for finding rows where a tag array contains all the values in the filter array. - - ```js - .contains('arraycol',["a","b"]) // You can use a javascript array for an array column - .contains('arraycol','{"a","b"}') // You can use a string with Postgres array {} for array column. - .contains('rangecol','(1,2]') // Use Postgres range syntax for range column. - .contains('rangecol',`(${arr}]`) // You can insert an array into a string. - ``` - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('countries') - .select('name, id, main_exports') - .contains('main_exports', ['oil']) - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .update({ name: 'Mordor' }) - .contains('main_exports', ['oil']) - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .delete() - .contains('main_exports', ['oil']) - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_countries') - .contains('main_exports', ['oil']) - ``` - - .containedBy(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.containedBy' - notes: | - - `.containedBy()` can work on array columns or range columns. - - ```js - .containedBy('arraycol',["a","b"]) // You can use a javascript array for an array column - .containedBy('arraycol','{"a","b"}') // You can use a string with Postgres array {} for array column. - .containedBy('rangecol','(1,2]') // Use Postgres range syntax for range column. - .containedBy('rangecol',`(${arr}]`) // You can insert an array into a string. - ``` - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('countries') - .select('name, id, main_exports') - .containedBy('main_exports', ['cars', 'food', 'machine']) - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .update({ name: 'Mordor' }) - .containedBy('main_exports', ['orks', 'surveillance', 'evil']) - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .delete() - .containedBy('main_exports', ['cars', 'food', 'machine']) - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_countries') - .containedBy('main_exports', ['cars', 'food', 'machine']) - ``` - - .rangeLt(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.rangeLt' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeLt('population_range_millions', '[150, 250]') - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .update({ name: 'Mordor' }) - .rangeLt('population_range_millions', '[150, 250]') - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .delete() - .rangeLt('population_range_millions', '[150, 250]') - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_countries') - .rangeLt('population_range_millions', '[150, 250]') - ``` - - .rangeGt(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.rangeGt' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeGt('population_range_millions', '[150, 250]') - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .update({ name: 'Mordor' }) - .rangeGt('population_range_millions', '[150, 250]') - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .delete() - .rangeGt('population_range_millions', '[150, 250]') - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_countries') - .rangeGt('population_range_millions', '[150, 250]') - ``` - - .rangeGte(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.rangeGte' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeGte('population_range_millions', '[150, 250]') - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .update({ name: 'Mordor' }) - .rangeGte('population_range_millions', '[150, 250]') - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .delete() - .rangeGte('population_range_millions', '[150, 250]') - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_countries') - .rangeGte('population_range_millions', '[150, 250]') - ``` - - .rangeLte(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.rangeLte' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeLte('population_range_millions', '[150, 250]') - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .update({ name: 'Mordor' }) - .rangeLte('population_range_millions', '[150, 250]') - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .delete() - .rangeLte('population_range_millions', '[150, 250]') - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_countries') - .rangeLte('population_range_millions', '[150, 250]') - ``` - - .rangeAdjacent(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.rangeAdjacent' - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('countries') - .select('name, id, population_range_millions') - .rangeAdjacent('population_range_millions', '[70, 185]') - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .update({ name: 'Mordor' }) - .rangeAdjacent('population_range_millions', '[70, 185]') - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .delete() - .rangeAdjacent('population_range_millions', '[70, 185]') - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_countries') - .rangeAdjacent('population_range_millions', '[70, 185]') - ``` - - .overlaps(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.overlaps' - notes: | - - `.overlaps()` can work on array columns or range columns. - - ```js - .overlaps('arraycol',["a","b"]) // You can use a javascript array for an array column - .overlaps('arraycol','{"a","b"}') // You can use a string with Postgres array {} for array column. - .overlaps('rangecol','(1,2]') // Use Postgres range syntax for range column. - .overlaps('rangecol',`(${arr}]`) // You can insert an array into a string. - ``` - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('countries') - .select('name, id, main_exports') - .overlaps('main_exports', ['computers', 'minerals']) - ``` - - name: With `update()` - js: | - ```js - let countries = await supabase - .from('countries') - .update({ name: 'Mordor' }) - .overlaps('main_exports', ['computers', 'minerals']) - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('countries') - .delete() - .overlaps('main_exports', ['computers', 'minerals']) - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_countries') - .overlaps('main_exports', ['computers', 'minerals']) - ``` - - .textSearch(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.textSearch' - examples: - - name: Text search - js: | - ```js - const { data, error } = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', `'fat' & 'cat'`, { - config: 'english' - }) - ``` - - name: Basic normalization - description: Uses PostgreSQL's `plainto_tsquery` function. - js: | - ```js - const { data, error } = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', `'fat' & 'cat'`, { - type: 'plain', - config: 'english' - }) - ``` - - name: Full normalization - description: Uses PostgreSQL's `phraseto_tsquery` function. - js: | - ```js - const { data, error } = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', `'fat' & 'cat'`, { - type: 'phrase', - config: 'english' - }) - ``` - - 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. - - js: | - ```js - const { data, error } = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', `'fat or cat'`, { - type: 'websearch', - config: 'english' - }) - ``` - - .filter(): - $ref: '@supabase/postgrest-js."lib/PostgrestFilterBuilder".PostgrestFilterBuilder.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. - ```js - .filter('arraycol','cs','{"a","b"}') // Use Postgres array {} for array column and 'cs' for contains. - .filter('rangecol','cs','(1,2]') // Use Postgres range syntax for range column. - .filter('id','in','(6,7)') // Use Postgres list () for in filter. - .filter('id','in',`(${arr})`) // You can insert a javascript array. - ``` - examples: - - name: With `select()` - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .filter('name', 'in', '("Paris","Tokyo")') - ``` - - name: With `update()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .update({ name: 'Mordor' }) - .filter('name', 'in', '("Paris","Tokyo")') - ``` - - name: With `delete()` - js: | - ```js - const { data, error } = await supabase - .from('cities') - .delete() - .filter('name', 'in', '("Paris","Tokyo")') - ``` - - name: With `rpc()` - js: | - ```js - // Only valid if the Postgres function returns a table type. - const { data, error } = await supabase - .rpc('echo_all_cities') - .filter('name', 'in', '("Paris","Tokyo")') - ``` - - name: Filter embedded resources - js: | - ```js - const { data, error } = await supabase - .from('cities') - .select('name, countries ( name )') - .filter('countries.name', 'in', '("France","Japan")') - ``` diff --git a/spec/supabase_js_v1.yml b/spec/supabase_js_v1.yml index b56b1390eac..810e46d2036 100644 --- a/spec/supabase_js_v1.yml +++ b/spec/supabase_js_v1.yml @@ -285,7 +285,7 @@ functions: $ref: '@supabase/gotrue-js.GoTrueClient.update' notes: | User email: 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). + 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/providers). User metadata: It's generally better to store user data in a table within your public schema (i.e., `public.users`). Use the `update()` method if you have data which rarely changes or is specific only to the logged in user. diff --git a/spec/supabase_js_v2--old.yml b/spec/supabase_js_v2--old.yml deleted file mode 100644 index f245467e26c..00000000000 --- a/spec/supabase_js_v2--old.yml +++ /dev/null @@ -1,5390 +0,0 @@ -openref: 0.1 - -info: - id: reference/supabase-js - title: Supabase Client - description: | - - Supabase JavaScript. - - definition: ../../spec/enrichments/tsdoc_v2/combined.json - specUrl: https://github.com/supabase/supabase/edit/master/spec/supabase_js_v2.yml - slugPrefix: '/' - libraries: - - name: 'JavaScript' - id: 'js' - version: '0.0.1' - -pages: - Initializing: - $ref: '@supabase/supabase-js.index.SupabaseClient.constructor' - description: | - You can initialize a new Supabase client using the `createClient()` method. - - The Supabase client is your entrypoint to the rest of the Supabase functionality - and is the easiest way to interact with everything we offer within the Supabase ecosystem. - - examples: - - name: createClient() - js: | - ```js - import { createClient } from '@supabase/supabase-js' - - // Create a single supabase client for interacting with your database - const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key') - ``` - - name: With additional parameters - js: | - ```js - import { createClient } from '@supabase/supabase-js' - - const options = { - db: { - schema: 'public', - }, - auth: { - autoRefreshToken: true, - persistSession: true, - detectSessionInUrl: true - }, - global: { - headers: { 'x-my-custom-header': 'my-app-name' }, - }, - } - const supabase = createClient("https://xyzcompany.supabase.co", "public-anon-key", options) - ``` - - name: API schemas - js: | - ```js - import { createClient } from '@supabase/supabase-js' - - // Provide a custom schema. Defaults to "public". - const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key', { - db: { schema: 'other_schema' } - }) - ``` - - By default the API server points to the `public` schema. You can enable other database schemas within the Dashboard. - Go to `Settings > API > Schema` and add the schema which you want to expose to the API. - - Note: each client connection can only access a single schema, so the code above can access the `other_schema` schema but cannot access the `public` schema. - - name: Custom `fetch` implementation - js: | - ```js - import { createClient } from '@supabase/supabase-js' - - const supabase = createClient('https://xyzcompany.supabase.co', 'public-anon-key', { - global: { fetch: fetch.bind(globalThis) } - }) - ``` - - `supabase-js` uses the [`cross-fetch`](https://www.npmjs.com/package/cross-fetch) library to make HTTP requests, - but an alternative `fetch` implementation can be provided as an option. - This is most useful in environments where `cross-fetch` is not compatible (for instance Cloudflare Workers). - - name: React Native options - js: | - ```js - import { createClient } from '@supabase/supabase-js' - import AsyncStorage from "@react-native-async-storage/async-storage"; - - const supabase = createClient("https://xyzcompany.supabase.co", "public-anon-key", { - auth: { - storage: AsyncStorage, - autoRefreshToken: true, - persistSession: true, - detectSessionInUrl: false, - }, - }); - ``` - - For React Native we recommend using `AsyncStorage` as the storage implementation for Supabase Auth. - auth.signUp(): - title: 'signUp()' - $ref: '@supabase/gotrue-js.GoTrueClient.signUp' - 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/settings). - - **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/settings). - - If signUp() is called for an existing confirmed user: - - If **Confirm email** is enabled in [your project](https://app.supabase.com/project/_/auth/settings), an obfuscated/fake user object is returned. - - If **Confirm email** is disabled, the error message, `User already registered` is returned. - - To fetch the currently logged-in user, refer to [`getUser()`](/docs/reference/javascript/auth-getuser). - examples: - - name: Sign up. - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.auth.signUp({ - email: 'example@email.com', - password: 'example-password', - }) - ``` - - name: Sign up with additional user metadata. - isSpotlight: false - js: | - ```js - const { data, error } = await supabase.auth.signUp( - { - email: 'example@email.com', - password: 'example-password', - options: { - data: { - first_name: 'John', - age: 27, - } - } - } - ) - ``` - auth.signInWithPassword(): - title: 'signInWithPassword()' - $ref: '@supabase/gotrue-js.GoTrueClient.signInWithPassword' - notes: | - - Requires either an email and password or a phone number and password. - examples: - - name: Sign in with email and password - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.auth.signInWithPassword({ - email: 'example@email.com', - password: 'example-password', - }) - ``` - - name: Sign in with phone and password - isSpotlight: false - js: | - ```js - const { data, error } = await supabase.auth.signInWithPassword({ - phone: '+13334445555', - password: 'some-password', - }) - - // After receiving a SMS with a OTP. - const { data, error } = await supabase.auth.verifyOtp({ - phone: '+13334445555', - token: '123456', - }) - ``` - auth.signInWithOtp(): - title: 'signInWithOtp()' - $ref: '@supabase/gotrue-js.GoTrueClient.signInWithOtp' - 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: - - name: Sign in with email. - 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. - js: | - ```js - const { data, error } = await supabase.auth.signInWithOtp({ - email: 'example@email.com', - }) - ``` - - name: Sign in with SMS OTP. - isSpotlight: false - 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. - js: | - ```js - const { data, error } = await supabase.auth.signInWithOtp({ - phone: '+13334445555', - }) - ``` - auth.signInWithOAuth(): - title: 'signInWithOAuth()' - $ref: '@supabase/gotrue-js.GoTrueClient.signInWithOAuth' - 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: - - name: Sign in using a third-party provider - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.auth.signInWithOAuth({ - provider: 'github' - }) - ``` - - name: Sign in using a third-party provider with redirect - isSpotlight: false - description: | - When the third-party provider successfully authenticates the user, the provider redirects the user to the Supabase Auth callback URL where they are further redirected to the URL specified in the `redirectTo` parameter. This parameter defaults to the [`SITE_URL`](/docs/reference/auth/config#site_url). - You can modify the `SITE_URL` or [add additional redirect URLs](https://app.supabase.com/project/_/auth/settings). You can use [wildcard match patterns](/docs/guides/auth#redirect-urls-and-wildcards) to support preview URLs from providers like Netlify and Vercel. - js: | - ```js - const { data, error } = await supabase.auth.signInWithOAuth({ - provider: 'github' - options: { - redirectTo: 'https://example.com/welcome' - } - } - ``` - - name: Sign in with scopes - isSpotlight: false - 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. The list of scopes will be documented by the third-party provider you are using and specifying scopes will enable you to use the OAuth provider token to call additional APIs supported by the third-party provider to get more information. - js: | - ```js - const { data, error } = await supabase.auth.signInWithOAuth({ - provider: 'github' - options: { - scopes: 'repo gist notifications' - } - }) - const oAuthToken = data.session.provider_token // use to access provider API - ``` - auth.signOut(): - title: 'signOut()' - $ref: '@supabase/gotrue-js.GoTrueClient.signOut' - notes: | - - In order to use the `signOut()` method, the user needs to be signed in first. - examples: - - name: Sign out - isSpotlight: true - js: | - ```js - const { error } = await supabase.auth.signOut() - ``` - auth.verifyOtp(): - title: 'verifyOtp()' - $ref: '@supabase/gotrue-js.GoTrueClient.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: - - name: Verify Sms One-Time Password (OTP) - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.auth.verifyOtp({ phone, token, type: 'sms'}) - ``` - - name: Verify Signup One-Time Password (OTP) - isSpotlight: false - js: | - ```js - const { data, error } = await supabase.auth.verifyOtp({ email, token, type: 'signup'}) - ``` - auth.getSession(): - title: 'getSession()' - $ref: '@supabase/gotrue-js.GoTrueClient.getSession' - examples: - - name: Get the session data - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.auth.getSession() - ``` - auth.getUser(): - title: 'getUser()' - $ref: '@supabase/gotrue-js.GoTrueClient.getUser' - notes: | - - This method gets the user object from the current session. - - Fetches the user object from the database instead of local session. - examples: - - name: Get the logged in user with the current existing session - isSpotlight: true - js: | - ```js - const { data: { user } } = await supabase.auth.getUser() - ``` - - name: Get the logged in user with a custom access token jwt. - isSpotlight: false - js: | - ```js - const { data: { user } } = await supabase.auth.getUser(jwt) - ``` - auth.updateUser(): - title: 'updateUser()' - $ref: '@supabase/gotrue-js.GoTrueClient.updateUser' - 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: - - name: Update the email for an authenticated user - description: Sends a "Confirm Email Change" email to the new email address. - isSpotlight: false - js: | - ```js - const { data, error } = await supabase.auth.updateUser({email: 'new@email.com'}) - ``` - - name: Update the password for an authenticated user - isSpotlight: false - js: | - ```js - const { data, error } = await supabase.auth.updateUser({password: 'new password'}) - ``` - - name: Update the user's metadata - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.auth.updateUser({ - data: { hello: 'world' } - }) - ``` - auth.setSession(): - title: 'setSession()' - $ref: '@supabase/gotrue-js.GoTrueClient.setSession' - notes: | - - `setSession()` takes in a refresh token and access token to get a new session. - - The refresh token can only be used once to obtain a new session. - - [Refresh token rotation](/docs/reference/auth/config#refresh_token_rotation_enabled) is enabled by default on all projects to guard against replay attacks. - - You can configure the [`REFRESH_TOKEN_REUSE_INTERVAL`](https://supabase.com/docs/reference/auth/config#refresh_token_reuse_interval) which provides a short window in which the same refresh token can be used multiple times in the event of concurrency or offline issues. - - If you are using React Native, you will need to install a Buffer polyfill via a library such as [rn-nodeify](https://github.com/tradle/rn-nodeify) to properly use the library. - examples: - - name: Set the session - description: Sets the session data from a `refresh_token` and `access_token` and returns the current session or an error if the tokens are invalid. - isSpotlight: true - js: | - ```js - const { data, error } = supabase.auth.setSession({refresh_token, access_token}) - ``` - auth.refreshSession(): - title: 'refreshSession()' - $ref: '@supabase/gotrue-js.GoTrueClient.refreshSession' - notes: | - - This method will refresh the session whether the current one is expired or not. - - Both examples destructure `user` and `session` from `data`. This is not required; so `const { data, error } =` is also valid. - examples: - - name: Refresh session using the current session - isSpotlight: true - js: | - ```js - const { data: { user, session }, error } = await supabase.auth.refreshSession() - ``` - - name: Refresh session using a passed-in session - isSpotlight: true - js: | - ```js - const { data: { user, session }, error } = await supabase.auth.refreshSession({ refresh_token }) - ``` - auth.onAuthStateChange(): - title: 'onAuthStateChange()' - $ref: '@supabase/gotrue-js.GoTrueClient.onAuthStateChange' - notes: | - - Types of auth events: `SIGNED_IN`, `SIGNED_OUT`, `TOKEN_REFRESHED`, `USER_UPDATED`, `USER_DELETED`, `PASSWORD_RECOVERY` - examples: - - name: Listen to auth changes - isSpotlight: true - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - console.log(event, session) - }) - ``` - - name: Listen to sign in - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - if (event == 'SIGNED_IN') console.log('SIGNED_IN', session) - }) - ``` - - name: Listen to sign out - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - if (event == 'SIGNED_OUT') console.log('SIGNED_OUT', session) - }) - ``` - - name: Listen to token refresh - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - if (event == 'TOKEN_REFRESHED') console.log('TOKEN_REFRESHED', session) - }) - ``` - - name: Listen to user updates - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - if (event == 'USER_UPDATED') console.log('USER_UPDATED', session) - }) - ``` - - name: Listen to user deleted - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - if (event == 'USER_DELETED') console.log('USER_DELETED', session) - }) - ``` - - name: Listen to password recovery events - js: | - ```js - supabase.auth.onAuthStateChange((event, session) => { - if (event == 'PASSWORD_RECOVERY') console.log('PASSWORD_RECOVERY', session) - }) - ``` - Supabase Auth Admin Api: - title: 'Overview' - notes: | - - Any method under the `supabase.auth.admin` namespace requires a `service_role` key. - - These methods are considered admin methods and should be called on a trusted server. Never expose your `service_role` key in the browser. - - auth.admin.getUserById(): - title: 'getUserById()' - $ref: '@supabase/gotrue-js.GoTrueAdminApi.getUserById' - notes: | - - Fetches the user object from the database based on the user's id. - - The `getUserById()` method requires the user's id which maps to the `auth.users.id` column. - examples: - - name: Fetch the user object using the access_token jwt. - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.auth.admin.getUserById(1) - ``` - - auth.admin.listUsers(): - title: 'listUsers()' - $ref: '@supabase/gotrue-js.GoTrueAdminApi.listUsers' - examples: - - name: Get a full list of users. - isSpotlight: true - js: | - ```js - const { data: { users }, error } = await supabase.auth.admin.listUsers() - ``` - auth.admin.createUser(): - title: 'createUser()' - $ref: '@supabase/gotrue-js.GoTrueAdminApi.createUser' - notes: | - - To confirm the user's email address or phone number, set `email_confirm` or `phone_confirm` to true. Both arguments default to false. - examples: - - name: Create a new user with custom user metadata - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.auth.admin.createUser({ - email: 'user@email.com', - password: 'password', - user_metadata: { name: 'Yoda' } - }) - ``` - - name: Auto-confirm the user's email - js: | - ```js - const { data, error } = await supabase.auth.admin.createUser({ - email: 'user@email.com', - email_confirm: true - }) - ``` - - name: Auto-confirm the user's phone number - js: | - ```js - const { data, error } = await supabase.auth.admin.createUser({ - phone: '1234567890', - phone_confirm: true - }) - ``` - auth.admin.deleteUser(): - title: 'deleteUser()' - $ref: '@supabase/gotrue-js.GoTrueAdminApi.deleteUser' - notes: | - - The `deleteUser()` method requires the user's ID, which maps to the `auth.users.id` column. - examples: - - name: Removes a user - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.auth.admin.deleteUser( - '715ed5db-f090-4b8c-a067-640ecee36aa0' - ) - ``` - - auth.admin.inviteUserByEmail(): - title: 'inviteUserByEmail()' - $ref: '@supabase/gotrue-js.GoTrueAdminApi.inviteUserByEmail' - notes: | - - Sends an invite link to the user's email address. - examples: - - name: Invite a user - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.auth.admin.inviteUserByEmail('email@example.com') - ``` - - auth.resetPasswordForEmail(): - title: 'resetPasswordForEmail()' - $ref: '@supabase/gotrue-js.GoTrueClient.resetPasswordForEmail' - 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()`: - ```js - const { data, error } = await supabase.auth - .updateUser({ password: new_password }) - ``` - examples: - - name: Reset password - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.auth.resetPasswordForEmail(email, { - redirectTo: 'https://example.com/update-password', - }) - ``` - - name: Reset password (React) - isSpotlight: true - js: | - ```js - /** - * Step 1: Send the user an email to get a password reset token. - * This email contains a link which sends the user back to your application. - */ - const { data, error } = await supabase.auth - .resetPasswordForEmail('user@email.com') - - /** - * Step 2: Once the user is redirected back to your application, - * ask the user to reset their password. - */ - useEffect(() => { - supabase.auth.onAuthStateChange(async (event, session) => { - if (event == "PASSWORD_RECOVERY") { - const newPassword = prompt("What would you like your new password to be?"); - const { data, error } = await supabase.auth - .updateUser({ password: newPassword }) - - if (data) alert("Password updated successfully!") - if (error) alert("There was an error updating your password.") - } - }) - }, []) - ``` - - auth.admin.generateLink(): - title: 'generateLink()' - $ref: '@supabase/gotrue-js.GoTrueAdminApi.generateLink' - examples: - - name: Generate a signup link - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.auth.admin.generateLink({ - type: 'signup', - email: 'email@example.com', - options: { - 'password': 'secret' - } - }) - ``` - - name: Generate an invite link - isSpotlight: false - js: | - ```js - const { data, error } = await supabase.auth.admin.generateLink({ - type: 'invite', - email: 'email@example.com' - }) - ``` - - name: Generate a magic link - isSpotlight: false - js: | - ```js - const { data, error } = await supabase.auth.admin.generateLink({ - type: 'magiclink', - email: 'email@example.com' - }) - ``` - - name: Generate a recovery link - isSpotlight: false - js: | - ```js - const { data, error } = await supabase.auth.admin.generateLink({ - type: 'recovery', - email: 'email@example.com' - }) - ``` - - name: Generate links to change current email address - isSpotlight: false - js: | - ```js - // generate an email change link to be sent to the current email address - const { data, error } = await supabase.auth.admin.generateLink({ - type: 'email_change_current', - email: 'current.email@example.com', - newEmail: 'new.email@example.com' - }) - - // generate an email change link to be sent to the new email address - const { data, error } = await supabase.auth.admin.generateLink({ - type: 'email_change_new', - email: 'current.email@example.com', - newEmail: 'new.email@example.com' - }) - ``` - - auth.admin.updateUserById(): - title: 'updateUserById()' - $ref: '@supabase/gotrue-js.GoTrueAdminApi.updateUserById' - examples: - - name: Updates a user's email. - isSpotlight: false - js: | - ```js - const { data: user, error } = await supabase.auth.admin.updateUserById( - '6aa5d0d4-2a9f-4483-b6c8-0cf4c6c98ac4', - { email: 'new@email.com' } - ) - ``` - - name: Updates a user's password. - isSpotlight: false - js: | - ```js - const { data: user, error } = await supabase.auth.admin.updateUserById( - '6aa5d0d4-2a9f-4483-b6c8-0cf4c6c98ac4', - { password: 'new_password' } - ) - ``` - - name: Updates a user's metadata. - isSpotlight: true - js: | - ```js - const { data: user, error } = await supabase.auth.admin.updateUserById( - '6aa5d0d4-2a9f-4483-b6c8-0cf4c6c98ac4', - { user_metadata: { hello: 'world' } } - ) - ``` - - name: Updates a user's app_metadata. - isSpotlight: false - js: | - ```js - const { data: user, error } = await supabase.auth.admin.updateUserById( - '6aa5d0d4-2a9f-4483-b6c8-0cf4c6c98ac4', - { app_metadata: { plan: 'trial' } } - ) - ``` - - name: Confirms a user's email address. - isSpotlight: false - js: | - ```js - const { data: user, error } = await supabase.auth.admin.updateUserById( - '6aa5d0d4-2a9f-4483-b6c8-0cf4c6c98ac4', - { email_confirm: true } - ) - ``` - - name: Confirms a user's phone number. - isSpotlight: false - js: | - ```js - const { data: user, error } = await supabase.auth.admin.updateUserById( - '6aa5d0d4-2a9f-4483-b6c8-0cf4c6c98ac4', - { phone_confirm: true } - ) - ``` - - select(): - title: 'Fetch data: select()' - $ref: '@supabase/postgrest-js.PostgrestQueryBuilder.select' - notes: | - - By default, Supabase projects return a maximum of 1,000 rows. This setting can be changed in your project's [API settings](https://app.supabase.com/project/_/settings/api). 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. - - `select()` can be combined with [Filters](/docs/reference/javascript/using-filters) - - `select()` can be combined with [Modifiers](/docs/reference/javascript/using-modifiers) - - `apikey` is a reserved keyword if you're using the [Supabase Platform](/docs/guides/platform) and should be avoided as a column name](https://github.com/supabase/supabase/issues/5465). - examples: - - name: Getting your data - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Afghanistan" - }, - { - "id": 2, - "name": "Albania" - }, - { - "id": 3, - "name": "Algeria" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - ``` - - name: Selecting specific columns - description: | - You can select specific fields from your tables. - - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select('name') - ``` - - - - - ```json - { - "data": [ - { - "name": "Afghanistan" - }, - { - "name": "Albania" - }, - { - "name": "Algeria" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - name: Query foreign tables - description: | - If your database has foreign key relationships, you can query related tables too. - - - - - ```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'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select(` - name, - cities ( - name - ) - `) - ``` - - - - - ```json - { - "data": [ - { - "name": "Germany", - "cities": [ - { - "name": "Munich" - } - ] - }, - { - "name": "Indonesia", - "cities": [ - { - "name": "Bali" - } - ] - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - name: Query foreign tables through a join table - description: | - If you're in a situation where your tables are **NOT** directly - related, but instead are joined by a _join table_, you can still use - the `select()` method to query the related data. The join table needs - to have the foreign keys as part of its composite primary key. - - - - - ```sql - create table - users ( - id int8 primary key, - name text - ); - create table - teams ( - id int8 primary key, - name text - ); - -- join table - create table - users_teams ( - user_id int8 not null references users, - team_id int8 not null references teams, - -- both foreign keys must be part of a composite primary key - primary key (user_id, team_id) - ); - - insert into - users (id, name) - values - (1, 'Kiran'), - (2, 'Evan'); - insert into - teams (id, name) - values - (1, 'Green'), - (2, 'Blue'); - insert into - users_teams (user_id, team_id) - values - (1, 1), - (1, 2), - (2, 2); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('users') - .select(` - name, - teams ( - name - ) - `) - ``` - - - - - ```json - { - "data": [ - { - "name": "Kiran", - "teams": [ - { - "name": "Green" - }, - { - "name": "Blue" - } - ] - }, - { - "name": "Evan", - "teams": [ - { - "name": "Blue" - } - ] - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - name: Query the same foreign table multiple times - description: | - If you need to query the same foreign table twice, use the name of the - joined column to identify which join to use. You can also give each - column an alias. - - - - - ```sql - create table - users (id int8 primary key, name text); - - create table - messages ( - sender_id int8 not null references users, - receiver_id int8 not null references users, - content text - ); - - insert into - users (id, name) - values - (1, 'Kiran'), - (2, 'Evan'); - - insert into - messages (sender_id, receiver_id, content) - values - (1, 2, '👋'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('messages') - .select(` - content, - from:sender_id(name), - to:receiver_id(name) - `) - ``` - - - - - ```json - { - "data": [ - { - "content": "👋", - "from": { - "name": "Kiran" - }, - "to": { - "name": "Evan" - } - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - name: Filtering through foreign tables - description: | - If the filter on a foreign table's column is not satisfied, the foreign - table returns `[]` or `null` but the parent table is not filtered out. - - - - - ```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'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('cities') - .select('name, countries(*)') - .eq('countries.name', 'Estonia') - ``` - - - - - ```json - { - "data": [ - { - "name": "Bali", - "countries": null - }, - { - "name": "Munich", - "countries": null - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - - If you want to filter out the parent table rows, use the `!inner` hint: - - - - - ```ts - const { data, error } = await supabase - .from('cities') - .select('name, countries!inner(*)') - .eq('countries.name', 'Estonia') - ``` - - - - - ```json - { - "data": [], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - name: Querying with count option - description: | - You can get the number of rows by using the - [count](/docs/reference/javascript/select#parameters) option. For - example, to get the table count without returning all rows: - - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { count, error } = await supabase - .from('countries') - .select('*', { count: 'exact', head: true }) - ``` - - - - - ```json - { - "count": 3, - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - name: Querying JSON data - description: | - You can select and filter data inside of - [JSON](/docs/guides/database/json) columns. Postgres offers some - [operators](/docs/guides/database/json#query-the-jsonb-data) for - querying JSON data. - - - - - ```sql - create table - users ( - id int8 primary key, - name text, - address jsonb - ); - - insert into - users (id, name, address) - values - (1, 'Avdotya', '{"city":"Saint Petersburg"}'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('users') - .select(` - id, name, - address->city - `) - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Avdotya", - "city": "Saint Petersburg" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - insert(): - title: 'Create data: insert()' - $ref: '@supabase/postgrest-js.PostgrestQueryBuilder.insert' - examples: - - name: Create a record - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - ``` - - - - - ```ts - const { error } = await supabase - .from('countries') - .insert({ id: 1, name: 'Denmark' }) - ``` - - - - - ```json - { - "status": 201, - "statusText": "Created" - } - ``` - - - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Denmark" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { error } = await supabase - .from('countries') - .insert({ id: 1, name: 'Denmark' }) - ``` - - name: Create a record and return it - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .insert({ id: 1, name: 'Denmark' }) - .select() - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Denmark" - } - ], - "status": 201, - "statusText": "Created" - } - ``` - - - - hideCodeBlock: true - - name: Bulk create - description: | - A bulk create operation is handled in a single transaction. - If any of the inserts fail, none of the rows are inserted. - - - - - ```sql - create table - countries (id int8 primary key, name text); - ``` - - - - - ```ts - const { error } = await supabase - .from('countries') - .insert([ - { id: 1, name: 'Nepal' }, - { id: 1, name: 'Vietnam' }, - ]) - ``` - - - - - ```json - { - "error": { - "code": "23505", - "details": "Key (id)=(1) already exists.", - "hint": null, - "message": "duplicate key value violates unique constraint \"countries_pkey\"" - }, - "status": 409, - "statusText": "Conflict" - } - ``` - - - - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - ``` - - - - - ```json - { - "data": [], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - update(): - title: 'Modify data: update()' - $ref: '@supabase/postgrest-js.PostgrestQueryBuilder.update' - notes: | - - `update()` should always be combined with [Filters](/docs/reference/javascript/using-filters) to target the item(s) you wish to update. - examples: - - name: Updating your data - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Taiwan'); - ``` - - - - - ```ts - const { error } = await supabase - .from('countries') - .update({ name: 'Australia' }) - .eq('id', 1) - ``` - - - - - ```json - { - "status": 204, - "statusText": "No Content" - } - ``` - - - - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Australia" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { error } = await supabase - .from('countries') - .update({ name: 'Australia' }) - .eq('id', 1) - ``` - - name: Update a record and return it - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Taiwan'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .update({ name: 'Australia' }) - .eq('id', 1) - .select() - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Australia" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - name: Updating JSON data - description: | - Postgres offers some - [operators](/docs/guides/database/json#query-the-jsonb-data) for - working with JSON data. - - - - - ```sql - create table - users ( - id int8 primary key, - name text, - address jsonb - ); - - insert into - users (id, name, address) - values - (1, 'Michael', '{ "postcode": 90210 }'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('users') - .update({ - address: { - street: 'Melrose Place', - postcode: 90210 - } - }) - .eq('address->postcode', 90210) - .select() - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Michael", - "address": { - "street": "Melrose Place", - "postcode": 90210 - } - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - - Currently, it is only possible to update the entire JSON document. - hideCodeBlock: true - - upsert(): - title: 'Upsert data: upsert()' - $ref: '@supabase/postgrest-js.PostgrestQueryBuilder.upsert' - notes: | - - Primary keys must be included in `values` to use upsert. - examples: - - name: Upsert your data - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .upsert({ id: 1, name: 'Albania' }) - .select() - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Albania" - } - ], - "status": 201, - "statusText": "Created" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .upsert({ id: 1, name: 'Albania' }) - .select() - ``` - - name: Bulk Upsert your data - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .upsert([ - { id: 1, name: 'Albania' }, - { id: 2, name: 'Algeria' }, - ]) - .select() - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Albania" - }, - { - "id": 2, - "name": "Algeria" - } - ], - "status": 201, - "statusText": "Created" - } - ``` - - - - hideCodeBlock: true - - name: Upserting into tables with constraints - description: | - In the following query, `upsert()` implicitly uses the `id` - (primary key) column to determine conflicts. If there is no existing - row with the same `id`, `upsert()` inserts a new row, which - will fail in this case as there is already a row with `handle` `"saoirse"`. - - - - - ```sql - create table - users ( - id int8 generated by default as identity primary key, - handle text not null unique, - display_name text - ); - - insert into - users (id, handle, display_name) - values - (1, 'saoirse', null); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('users') - .upsert({ id: 42, handle: 'saoirse', display_name: 'Saoirse' }) - .select() - ``` - - - - - ```json - { - "error": { - "code": "23505", - "details": "Key (handle)=(saoirse) already exists.", - "hint": null, - "message": "duplicate key value violates unique constraint \"users_handle_key\"" - }, - "status": 409, - "statusText": "Conflict" - } - ``` - - - - - Using the `onConflict` option, you can instruct `upsert()` to use - another column with a unique constraint to determine conflicts: - - - - - ```ts - await supabase - .from('users') - .upsert( - { id: 42, handle: 'saoirse', display_name: 'Saoirse' }, - { onConflict: 'handle' }, - ) - const { data, error } = await supabase - .from('users') - .select() - ``` - - - - - ```json - { - "data": [ - { - "id": 42, - "handle": "saoirse", - "display_name": "Saoirse" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - delete(): - title: 'Delete data: delete()' - $ref: '@supabase/postgrest-js.PostgrestQueryBuilder.delete' - notes: | - - `delete()` should always be combined with [filters](/docs/reference/javascript/using-filters) to target the item(s) you wish to delete. - - If you use `delete()` with filters and you have - [RLS](/docs/learn/auth-deep-dive/auth-row-level-security) enabled, only - rows visible through `SELECT` policies are deleted. Note that by default - no rows are visible, so you need at least one `SELECT`/`ALL` policy that - makes the rows visible. - examples: - - name: Delete records - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Spain'); - ``` - - - - - ```ts - const { error } = await supabase - .from('countries') - .delete() - .eq('id', 1) - ``` - - - - - ```json - { - "status": 204, - "statusText": "No Content" - } - ``` - - - - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - ``` - - - - - ```json - { - "data": [], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { error } = await supabase - .from('countries') - .delete() - .eq('id', 1) - ``` - - rpc(): - title: 'Postgres functions: rpc()' - description: | - You can call Postgres functions as _Remote Procedure Calls_, logic in your database that you can execute from anywhere. - Functions are useful when the logic rarely changes—like for password resets and updates. - - ```sql - create or replace function hello_world() returns text as $$ - select 'Hello world'; - $$ language sql; - ``` - $ref: '@supabase/postgrest-js.PostgrestClient.rpc' - examples: - - name: Call a Postgres function without arguments - description: | - - - - ```sql - create function hello_world() returns text as $$ - select 'Hello world'; - $$ language sql; - ``` - - - - - ```ts - const { data, error } = await supabase.rpc('hello_world') - ``` - - - - - ```json - { - "data": "Hello world", - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase.rpc('hello_world') - ``` - - name: Call a Postgres function with arguments - description: | - - - - ```sql - create function echo(say text) returns text as $$ - select say; - $$ language sql; - ``` - - - - - ```ts - const { data, error } = await supabase.rpc('echo', { say: '👋' }) - ``` - - - - - ```json - { - "data": "👋", - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - name: Bulk processing - description: | - You can process large payloads by passing in an array as an argument: - - - - - ```sql - create function add_one_each(arr int[]) returns int[] as $$ - select array_agg(n + 1) from unnest(arr) as n; - $$ language sql; - ``` - - - - - ```ts - const { data, error } = await supabase.rpc('add_one_each', { arr: [1, 2, 3] }) - ``` - - - - - ```json - { - "data": [ - 2, - 3, - 4 - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - name: Call a Postgres function with filters - description: | - Postgres functions that return tables can also be combined with - [Filters](/docs/reference/javascript/using-filters) and - [Modifiers](/docs/reference/javascript/using-modifiers). - - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'France'), - (2, 'United Kingdom'); - - create function list_stored_countries() returns setof countries as $$ - select * from countries; - $$ language sql; - ``` - - - - - ```ts - const { data, error } = await supabase - .rpc('list_stored_countries') - .eq('id', 1) - .single() - ``` - - - - - ```json - { - "data": { - "id": 1, - "name": "France" - }, - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - Using Filters: - description: | - Filters allow you to only return rows that match certain conditions. - - Filters can be used on `select()`, `update()`, `upsert()`, and `delete()` queries. - - If a Postgres function returns a table response, you can also apply filters. - - ### Applying Filters - - Filters must be applied after any of `select()`, `update()`, `upsert()`, - `delete()`, and `rpc()` and before - [modifiers](/docs/reference/javascript/using-modifiers). - - ```ts - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .eq('name', 'The Shire') // Correct - - const { data, error } = await supabase - .from('cities') - .eq('name', 'The Shire') // Incorrect - .select('name, country_id') - ``` - - ### Chaining - - Filters can be chained together to produce advanced queries. For example, - to query cities with population between 1,000 and 10,000: - - ```ts - const { data, error } = await supabase - .from('cities') - .select('name, country_id') - .gte('population', 1000) - .lt('population', 10000) - ``` - - ### Conditional Chaining - - Filters can be built up one step at a time and then executed. For example: - - ```ts - const filterByName = null - const filterPopLow = 1000 - const filterPopHigh = 10000 - - let query = supabase - .from('cities') - .select('name, country_id') - - if (filterByName) { query = query.eq('name', filterByName) } - if (filterPopLow) { query = query.gte('population', filterPopLow) } - if (filterPopHigh) { query = query.lt('population', filterPopHigh) } - - const { data, error } = await query - ``` - - ### Filter by values within a JSON column - - - - - ```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); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('users') - .select() - .eq('address->postcode', 90210) - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Michael", - "address": { - "postcode": 90210 - } - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - - ### Filter Foreign Tables - - You can filter on foreign tables in your `select()` query using dot - notation: - - - - - ```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'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select(` - name, - cities!inner ( - name - ) - `) - .eq('cities.name', 'Bali') - ``` - - - - - ```json - { - "data": [ - { - "name": "Indonesia", - "cities": [ - { - "name": "Bali" - } - ] - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - - eq(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.eq' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .eq('name', 'Albania') - ``` - - - - - ```json - { - "data": [ - { - "id": 2, - "name": "Albania" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .eq('name', 'Albania') - ``` - - neq(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.neq' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .neq('name', 'Albania') - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Afghanistan" - }, - { - "id": 3, - "name": "Algeria" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .neq('name', 'Albania') - ``` - - gt(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.gt' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .gt('id', 2) - ``` - - - - - ```json - { - "data": [ - { - "id": 3, - "name": "Algeria" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .gt('id', 2) - ``` - - gte(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.gte' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .gte('id', 2) - ``` - - - - - ```json - { - "data": [ - { - "id": 2, - "name": "Albania" - }, - { - "id": 3, - "name": "Algeria" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .gte('id', 2) - ``` - - lt(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.lt' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .lt('id', 2) - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Afghanistan" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .lt('id', 2) - ``` - - lte(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.lte' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .lte('id', 2) - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Afghanistan" - }, - { - "id": 2, - "name": "Albania" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .lte('id', 2) - ``` - - like(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.like' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .like('name', '%Alba%') - ``` - - - - - ```json - { - "data": [ - { - "id": 2, - "name": "Albania" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .like('name', '%Alba%') - ``` - - ilike(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.ilike' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .ilike('name', '%alba%') - ``` - - - - - ```json - { - "data": [ - { - "id": 2, - "name": "Albania" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .ilike('name', '%alba%') - ``` - - is(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.is' - examples: - - name: Checking nullness - description: | - Using the `eq()` filter doesn't work when filtering for `null`: - - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'null'), - (2, null); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .eq('name', null) - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "null" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - - Instead, you need to use `is()`: - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .is('name', null) - ``` - - - - - ```json - { - "data": [ - { - "id": 2, - "name": null - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .is('name', null) - ``` - - in(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.in' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .in('name', ['Albania', 'Algeria']) - ``` - - - - - ```json - { - "data": [ - { - "id": 2, - "name": "Albania" - }, - { - "id": 3, - "name": "Algeria" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .in('name', ['Albania', 'Algeria']) - ``` - - contains(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.contains' - examples: - - name: On array columns - description: | - - - - ```sql - create table - issues ( - id int8 primary key, - title text, - tags text[] - ); - - insert into - issues (id, title, tags) - values - (1, 'Cache invalidation is not working', array['is:open', 'severity:high', 'priority:low']), - (2, 'Use better names', array['is:open', 'severity:low', 'priority:medium']); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('issues') - .select('title') - .contains('tags', ['is:open', 'severity:high']) - ``` - - - - - ```json - { - "data": [ - { - "title": "Cache invalidation is not working" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('users') - .select() - .contains('name', ['is:online', 'faction:red']) - ``` - - name: On range columns - description: | - Postgres supports a number of [range - types](https://www.postgresql.org/docs/current/rangetypes.html). You - can filter on range columns using the string representation of range - values. - - - - - ```sql - create table - reservations ( - id int8 primary key, - room_name text, - during tsrange - ); - - insert into - reservations (id, room_name, during) - values - (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), - (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('reservations') - .select() - .contains('during', '[2000-01-01 13:00, 2000-01-01 13:30)') - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "room_name": "Emerald", - "during": "[\"2000-01-01 13:00:00\",\"2000-01-01 15:00:00\")" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - name: On `jsonb` columns - description: | - - - - ```sql - create table - users ( - id int8 primary key, - name text, - address jsonb - ); - - insert into - users (id, name, address) - values - (1, 'Michael', '{ "postcode": 90210, "street": "Melrose Place" }'), - (2, 'Jane', '{}'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('users') - .select('name') - .contains('address', { postcode: 90210 }) - ``` - - - - - ```json - { - "data": [ - { - "name": "Michael" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - containedBy(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.containedBy' - examples: - - name: On array columns - description: | - - - - ```sql - create table - classes ( - id int8 primary key, - name text, - days text[] - ); - - insert into - classes (id, name, days) - values - (1, 'Chemistry', array['monday', 'friday']), - (2, 'History', array['monday', 'wednesday', 'thursday']); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('classes') - .select('name') - .containedBy('days', ['monday', 'tuesday', 'wednesday', 'friday']) - ``` - - - - - ```json - { - "data": [ - { - "name": "Chemistry" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('classes') - .select('name') - .containedBy('days', ['monday', 'tuesday', 'wednesday', 'friday']) - ``` - - name: On range columns - description: | - Postgres supports a number of [range - types](https://www.postgresql.org/docs/current/rangetypes.html). You - can filter on range columns using the string representation of range - values. - - - - - ```sql - create table - reservations ( - id int8 primary key, - room_name text, - during tsrange - ); - - insert into - reservations (id, room_name, during) - values - (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), - (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('reservations') - .select() - .containedBy('during', '[2000-01-01 00:00, 2000-01-01 23:59)') - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "room_name": "Emerald", - "during": "[\"2000-01-01 13:00:00\",\"2000-01-01 15:00:00\")" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - name: On `jsonb` columns - description: | - - - - ```sql - create table - users ( - id int8 primary key, - name text, - address jsonb - ); - - insert into - users (id, name, address) - values - (1, 'Michael', '{ "postcode": 90210, "street": "Melrose Place" }'), - (2, 'Jane', '{}'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('users') - .select('name') - .containedBy('address', {}) - ``` - - - - - ```json - { - "data": [ - { - "name": "Jane" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - rangeGt(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.rangeGt' - examples: - - name: With `select()` - description: | - Postgres supports a number of [range - types](https://www.postgresql.org/docs/current/rangetypes.html). You - can filter on range columns using the string representation of range - values. - - - - - ```sql - create table - reservations ( - id int8 primary key, - room_name text, - during tsrange - ); - - insert into - reservations (id, room_name, during) - values - (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), - (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('reservations') - .select() - .rangeGt('during', '[2000-01-02 08:00, 2000-01-02 09:00)') - ``` - - - - - ```json - { - "data": [ - { - "id": 2, - "room_name": "Topaz", - "during": "[\"2000-01-02 09:00:00\",\"2000-01-02 10:00:00\")" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('reservations') - .select() - .rangeGt('during', '[2000-01-02 08:00, 2000-01-02 09:00)') - ``` - - rangeGte(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.rangeGte' - examples: - - name: With `select()` - description: | - Postgres supports a number of [range - types](https://www.postgresql.org/docs/current/rangetypes.html). You - can filter on range columns using the string representation of range - values. - - - - - ```sql - create table - reservations ( - id int8 primary key, - room_name text, - during tsrange - ); - - insert into - reservations (id, room_name, during) - values - (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), - (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('reservations') - .select() - .rangeGte('during', '[2000-01-02 08:30, 2000-01-02 09:30)') - ``` - - - - - ```json - { - "data": [ - { - "id": 2, - "room_name": "Topaz", - "during": "[\"2000-01-02 09:00:00\",\"2000-01-02 10:00:00\")" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('reservations') - .select() - .rangeGte('during', '[2000-01-02 08:30, 2000-01-02 09:30)') - ``` - - rangeLt(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.rangeLt' - examples: - - name: With `select()` - description: | - Postgres supports a number of [range - types](https://www.postgresql.org/docs/current/rangetypes.html). You - can filter on range columns using the string representation of range - values. - - - - - ```sql - create table - reservations ( - id int8 primary key, - room_name text, - during tsrange - ); - - insert into - reservations (id, room_name, during) - values - (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), - (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('reservations') - .select() - .rangeLt('during', '[2000-01-01 15:00, 2000-01-01 16:00)') - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "room_name": "Emerald", - "during": "[\"2000-01-01 13:00:00\",\"2000-01-01 15:00:00\")" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('reservations') - .select() - .rangeLt('during', '[2000-01-01 15:00, 2000-01-01 16:00)') - ``` - - rangeLte(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.rangeLte' - examples: - - name: With `select()` - description: | - Postgres supports a number of [range - types](https://www.postgresql.org/docs/current/rangetypes.html). You - can filter on range columns using the string representation of range - values. - - - - - ```sql - create table - reservations ( - id int8 primary key, - room_name text, - during tsrange - ); - - insert into - reservations (id, room_name, during) - values - (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), - (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('reservations') - .select() - .rangeLte('during', '[2000-01-01 14:00, 2000-01-01 16:00)') - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "room_name": "Emerald", - "during": "[\"2000-01-01 13:00:00\",\"2000-01-01 15:00:00\")" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('reservations') - .select() - .rangeLte('during', '[2000-01-01 14:00, 2000-01-01 16:00)') - ``` - - rangeAdjacent(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.rangeAdjacent' - examples: - - name: With `select()` - description: | - Postgres supports a number of [range - types](https://www.postgresql.org/docs/current/rangetypes.html). You - can filter on range columns using the string representation of range - values. - - - - - ```sql - create table - reservations ( - id int8 primary key, - room_name text, - during tsrange - ); - - insert into - reservations (id, room_name, during) - values - (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), - (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('reservations') - .select() - .rangeAdjacent('during', '[2000-01-01 12:00, 2000-01-01 13:00)') - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "room_name": "Emerald", - "during": "[\"2000-01-01 13:00:00\",\"2000-01-01 15:00:00\")" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('reservations') - .select() - .rangeAdjacent('during', '[2000-01-01 12:00, 2000-01-01 13:00)') - ``` - - overlaps(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.overlaps' - examples: - - name: On array columns - description: | - - - - ```sql - create table - issues ( - id int8 primary key, - title text, - tags text[] - ); - - insert into - issues (id, title, tags) - values - (1, 'Cache invalidation is not working', array['is:open', 'severity:high', 'priority:low']), - (2, 'Use better names', array['is:open', 'severity:low', 'priority:medium']); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('issues') - .select('title') - .overlaps('tags', ['is:closed', 'severity:high']) - ``` - - - - - ```json - { - "data": [ - { - "title": "Cache invalidation is not working" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('issues') - .select('title') - .overlaps('tags', ['is:closed', 'severity:high']) - ``` - - name: On range columns - description: | - Postgres supports a number of [range - types](https://www.postgresql.org/docs/current/rangetypes.html). You - can filter on range columns using the string representation of range - values. - - - - - ```sql - create table - reservations ( - id int8 primary key, - room_name text, - during tsrange - ); - - insert into - reservations (id, room_name, during) - values - (1, 'Emerald', '[2000-01-01 13:00, 2000-01-01 15:00)'), - (2, 'Topaz', '[2000-01-02 09:00, 2000-01-02 10:00)'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('reservations') - .select() - .overlaps('during', '[2000-01-01 12:45, 2000-01-01 13:15)') - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "room_name": "Emerald", - "during": "[\"2000-01-01 13:00:00\",\"2000-01-01 15:00:00\")" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - # TODO: schema & result - textSearch(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.textSearch' - notes: - - For more information, see [Postgres full text search](/docs/guides/database/full-text-search). - examples: - - name: Text search - js: | - ```ts - const { data, error } = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', `'fat' & 'cat'`, { - config: 'english' - }) - ``` - - name: Basic normalization - description: Uses PostgreSQL's `plainto_tsquery` function. - js: | - ```ts - const { data, error } = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', `'fat' & 'cat'`, { - type: 'plain', - config: 'english' - }) - ``` - - name: Full normalization - description: Uses PostgreSQL's `phraseto_tsquery` function. - js: | - ```ts - const { data, error } = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', `'fat' & 'cat'`, { - type: 'phrase', - config: 'english' - }) - ``` - - 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. - - js: | - ```ts - const { data, error } = await supabase - .from('quotes') - .select('catchphrase') - .textSearch('catchphrase', `'fat or cat'`, { - type: 'websearch', - config: 'english' - }) - ``` - - match(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.match' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select('name') - .match({ id: 2, name: 'Albania' }) - ``` - - - - - ```json - { - "data": [ - { - "name": "Albania" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select('name') - .match({ id: 2, name: 'Albania' }) - ``` - - not(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.not' - notes: | - not() expects you to use the raw PostgREST syntax for the filter values. - - ```ts - .not('id', 'in', '(5,6,7)') // Use `()` for `in` filter - .not('arraycol', 'cs', '{"a","b"}') // Use `cs` for `contains()`, `{}` for array values - ``` - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'null'), - (2, null); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .not('name', 'is', null) - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "null" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .not('name', 'is', null) - ``` - - or(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.or' - notes: | - or() expects you to use the raw PostgREST syntax for the filter names and values. - - ```ts - .or('id.in.(5,6,7), arraycol.cs.{"a","b"}') // Use `()` for `in` filter, `{}` for array values and `cs` for `contains()`. - .or('id.in.(5,6,7), arraycol.cd.{"a","b"}') // Use `cd` for `containedBy()` - ``` - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select('name') - .or('id.eq.2,name.eq.Algeria') - ``` - - - - - ```json - { - "data": [ - { - "name": "Albania" - }, - { - "name": "Algeria" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select('name') - .or('id.eq.2,name.eq.Algeria') - ``` - - name: Use `or` with `and` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select('name') - .or('id.gt.3,and(id.eq.1,name.eq.Afghanistan)') - ``` - - - - - - ```json - { - "data": [ - { - "name": "Afghanistan" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - name: Use `or` on foreign tables - description: | - - - - ```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'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select(` - name, - cities!inner ( - name - ) - `) - .or('country_id.eq.1,name.eq.Beijing', { foreignTable: 'cities' }) - ``` - - - - - ```json - { - "data": [ - { - "name": "Germany", - "cities": [ - { - "name": "Munich" - } - ] - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - filter(): - $ref: '@supabase/postgrest-js.PostgrestFilterBuilder.filter' - notes: | - filter() expects you to use the raw PostgREST syntax for the filter values. - - ```ts - .filter('id', 'in', '(5,6,7)') // Use `()` for `in` filter - .filter('arraycol', 'cs', '{"a","b"}') // Use `cs` for `contains()`, `{}` for array values - ``` - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .filter('name', 'in', '("Algeria","Japan")') - ``` - - - - - ```json - { - "data": [ - { - "id": 3, - "name": "Algeria" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .filter('name', 'in', '("Algeria","Japan")') - ``` - - name: On a foreign table - description: | - - - - ```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'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select(` - name, - cities!inner ( - name - ) - `) - .filter('cities.name', 'eq', 'Bali') - ``` - - - - - ```json - { - "data": [ - { - "name": "Indonesia", - "cities": [ - { - "name": "Bali" - } - ] - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select(` - name, - cities!inner ( - name - ) - `) - .filter('cities.name', 'eq', 'Bali') - ``` - - Using Modifiers: - description: | - Filters work on the row level—they allows 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). - - db.modifiers.select(): - $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.select' - title: select() - examples: - - name: With `upsert()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .upsert({ id: 1, name: 'Albania' }) - ``` - - - - - ```json - { - "status": 201, - "statusText": "Created" - } - ``` - - - - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .upsert({ id: 1, name: 'Algeria' }) - .select() - ``` - - - - - ```json - { - "data": [ - { - "id": 1, - "name": "Algeria" - } - ], - "status": 201, - "statusText": "Created" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .upsert({ id: 1, name: 'Algeria' }) - .select() - ``` - - order(): - $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.order' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .order('name', { ascending: false }) - ``` - - - - - ```json - { - "data": [ - { - "id": 3, - "name": "Algeria" - }, - { - "id": 2, - "name": "Albania" - }, - { - "id": 1, - "name": "Afghanistan" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('cities') - .select('name', 'country_id') - .order('id', { ascending: false }) - ``` - - name: On a foreign table - description: | - Ordering on foreign tables doesn't affect the ordering of - the parent table. - - - - - ```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, 'United States'), - (2, 'Vanuatu'); - insert into - cities (id, country_id, name) - values - (1, 1, 'Atlanta'), - (2, 1, 'New York City'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select(` - name, - cities ( - name - ) - `) - .order('name', { foreignTable: 'cities', ascending: false }) - ``` - - - - - ```json - { - "data": [ - { - "name": "United States", - "cities": [ - { - "name": "New York City" - }, - { - "name": "Atlanta" - } - ] - }, - { - "name": "Vanuatu", - "cities": [] - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - limit(): - $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.limit' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select('name') - .limit(1) - ``` - - - - - ```json - { - "data": [ - { - "name": "Afghanistan" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select('name') - .limit(1) - ``` - - name: On a foreign table - description: | - - - - ```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, 'United States'); - insert into - cities (id, country_id, name) - values - (1, 1, 'Atlanta'), - (2, 1, 'New York City'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select(` - name, - cities ( - name - ) - `) - .limit(1, { foreignTable: 'cities' }) - ``` - - - - - ```json - { - "data": [ - { - "name": "United States", - "cities": [ - { - "name": "Atlanta" - } - ] - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - - range(): - $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.range' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select('name') - .range(0, 1) - ``` - - - - - ```json - { - "data": [ - { - "name": "Afghanistan" - }, - { - "name": "Albania" - } - ], - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select('name') - .range(0, 1) - ``` - - db.abortSignal(): - $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.abortSignal' - title: abortSignal() - examples: - - name: Aborting requests in-flight - description: | - You can use an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) to abort requests. Note that `status` and `statusText` don't mean anything for aborted requests as the request wasn't fulfilled. - - - - - ```ts - const ac = new AbortController() - ac.abort() - const { data, error } = await supabase - .from('very_big_table') - .select() - .abortSignal(ac.signal) - ``` - - - - - ```json - { - "error": { - "message": "FetchError: The user aborted a request.", - "details": "", - "hint": "", - "code": "" - }, - "status": 400, - "statusText": "Bad Request" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const ac = new AbortController() - ac.abort() - const { data, error } = await supabase - .from('very_big_table') - .select() - .abortSignal(ac.signal) - ``` - - single(): - $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.single' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select('name') - .limit(1) - .single() - ``` - - - - - ```json - { - "data": { - "name": "Afghanistan" - }, - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select('name') - .limit(1) - .single() - ``` - - maybeSingle(): - $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.maybeSingle' - examples: - - name: With `select()` - description: | - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .eq('name', 'Singapore') - .maybeSingle() - ``` - - - - - ```json - { - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .eq('name', 'Singapore') - .maybeSingle() - ``` - - db.csv(): - $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.csv' - title: csv() - examples: - - name: Return data as CSV - description: | - By default, the data is returned in JSON format, but can also be returned as Comma Separated Values. - - - - - ```sql - create table - countries (id int8 primary key, name text); - - insert into - countries (id, name) - values - (1, 'Afghanistan'), - (2, 'Albania'), - (3, 'Algeria'); - ``` - - - - - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .csv() - ``` - - - - - ```json - { - "data": "id,name\n1,Afghanistan\n2,Albania\n3,Algeria", - "status": 200, - "statusText": "OK" - } - ``` - - - - hideCodeBlock: true - isSpotlight: true - js: | - ```ts - const { data, error } = await supabase - .from('countries') - .select() - .csv() - ``` - - # NOTE: Not available on currently deployed PostgREST - # db.geojson(): - # $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.geojson' - # title: geojson() - - # NOTE: Not available on currently deployed PostgREST - # db.explain(): - # $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.explain' - # title: explain() - - # NOTE: Not available on currently deployed PostgREST - # db.rollback(): - # $ref: '@supabase/postgrest-js.PostgrestTransformBuilder.rollback' - # title: rollback() - # examples: - # - name: With `delete()` - # description: | - #
    - # Schema - - # ```sql - # create table - # countries (id int8 primary key, name text); - - # insert into - # countries (id, name) - # values - # (1, 'Spain'); - # ``` - #
    - - # ```ts - # const { error } = await supabase - # .from('countries') - # .delete() - # .eq('id', 1) - # .rollback() - # ``` - - #
    - # Result - - # ```json - # { - # "status": 204, - # "statusText": "No Content" - # } - # ``` - #
    - - # ```ts - # const { data, error } = await supabase - # .from('countries') - # .select() - # ``` - - #
    - # Result - - # ```json - # { - # "data": [ - # { - # "id": 1, - # "name": "Spain" - # } - # ], - # "status": 200, - # "statusText": "OK" - # } - # ``` - #
    - # hideCodeBlock: true - # isSpotlight: true - # js: | - # ```ts - # const { error } = await supabase - # .from('countries') - # .delete() - # .eq('id', 1) - # ``` - - invoke(): - title: 'invoke()' - description: | - Invoke a Supabase Function. - $ref: '@supabase/functions-js.FunctionsClient.invoke' - notes: | - - Requires an Authorization header. - - Invoke params generally match the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) spec. - - When you pass in a body to your function, we automatically attach the Content-Type header for `Blob`, `ArrayBuffer`, `File`, `FormData` and `String`. If it doesn't match any of these types we assume the payload is `json`, serialise it and attach the `Content-Type` header as `application/json`. You can override this behaviour by passing in a `Content-Type` header of your own. - - Responses are automatically parsed as `json`, `blob` and `form-data` depending on the `Content-Type` header sent by your function. Responses are parsed as `text` by default. - examples: - - name: Basic invocation. - description: - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.functions.invoke('hello', { - body: { foo: 'bar' } - }) - ``` - - name: Error handling. - description: | - A `FunctionsHttpError` error is returned if your function throws an error, `FunctionsRelayError` if the Supabase Relay has an error processing your function and `FunctionsFetchError` if there is a network error in calling your function. - isSpotlight: true - js: | - ```js - import { FunctionsHttpError, FunctionsRelayError, FunctionsFetchError } from "@supabase/supabase-js"; - - const { data, error } = await supabase.functions.invoke('hello', { - headers: { - "my-custom-header": 'my-custom-header-value' - }, - body: { foo: 'bar' } - }) - - if (error instanceof FunctionsHttpError) { - console.log('Function returned an error', error.message) - } else if (error instanceof FunctionsRelayError) { - console.log('Relay error:', error.message) - } else if (error instanceof FunctionsFetchError) { - console.log('Fetch error:', error.message) - } - ``` - - name: Passing custom headers. - description: | - You can pass custom headers to your function. Note: supabase-js automatically passes the `Authorization` header with the signed in user's JWT. - isSpotlight: true - js: | - ```js - const { data, error } = await supabase.functions.invoke('hello', { - headers: { - "my-custom-header": 'my-custom-header-value' - }, - body: { foo: 'bar' } - }) - ``` - - subscribe(): - title: 'on().subscribe()' - $ref: '@supabase/realtime-js.RealtimeChannel.on' - 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). - - Row level security is not applied to delete statements. - - 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;` - - When a delete occurs, the contents of old_record will be broadcast to all subscribers to that table so ensure that each table's replica identity only contains information that is safe to expose publicly. - - The channel name must exactly match the schema/table/filter you want to listen to separated by colons. See below examples for additional context. - examples: - - name: Listen to all database changes - isSpotlight: true - js: | - ```js - supabase - .channel('*') - .on('postgres_changes', { event: '*', schema: '*' }, payload => { - console.log('Change received!', payload) - }) - .subscribe() - ``` - - name: Listening to a specific table - js: | - ```js - supabase - .channel('public:countries') - .on('postgres_changes', { event: '*', schema: 'public', table: 'countries' }, payload => { - console.log('Change received!', payload) - }) - .subscribe() - ``` - - name: Listening to inserts - js: | - ```js - supabase - .channel('public:countries') - .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'countries' }, payload => { - console.log('Change received!', payload) - }) - .subscribe() - ``` - - 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 to: - - ```sql - alter table "your_table" replica identity full; - ``` - js: | - ```js - supabase - .channel('public:countries') - .on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'countries' }, payload => { - console.log('Change received!', payload) - }) - .subscribe() - ``` - - 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; - ``` - js: | - ```js - supabase - .channel('public:countries') - .on('postgres_changes', { event: 'DELETE', schema: 'public', table: 'countries' }, payload => { - console.log('Change received!', payload) - }) - .subscribe() - ``` - - name: Listening to multiple events - description: You can chain listeners if you want to listen to multiple events for each table. - js: | - ```js - supabase - .channel('public:countries') - .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'countries' }, handleRecordInserted) - .on('postgres_changes', { event: 'DELETE', schema: 'public', table: 'countries' }, handleRecordDeleted) - .subscribe() - ``` - - 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. - notes: | - - ``eq`` filter works with all database types as under the hood, it's casting both the filter value and the database value to the correct type and then comparing them. - js: | - ```js - supabase - .channel('public:countries:id=eq.200') - .on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'countries', filter: 'id=eq.200' }, handleRecordUpdated) - .subscribe() - ``` - - getChannels(): - title: 'getChannels()' - $ref: '@supabase/supabase-js.index.SupabaseClient.getChannels' - examples: - - name: Get all channels - isSpotlight: true - js: | - ```js - const channels = supabase.getChannels() - ``` - - removeChannel(): - title: 'removeChannel()' - $ref: '@supabase/supabase-js.index.SupabaseClient.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: - - name: Removes a channel - isSpotlight: true - js: | - ```js - supabase.removeChannel(myChannel) - ``` - - removeAllChannels(): - title: 'removeAllChannels()' - $ref: '@supabase/supabase-js.index.SupabaseClient.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: - - name: Remove all channels - isSpotlight: true - js: | - ```js - supabase.removeAllChannels() - ``` - - storage.listBuckets(): - title: 'listBuckets()' - $ref: '@supabase/storage-js.packages/StorageBucketApi.default.listBuckets' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: `select` - - `objects` table permissions: none - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: List buckets - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .listBuckets() - ``` - - storage.getBucket(): - title: 'getBucket()' - $ref: '@supabase/storage-js.packages/StorageBucketApi.default.getBucket' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: `select` - - `objects` table permissions: none - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: Get bucket - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .getBucket('avatars') - ``` - - storage.createBucket(): - title: 'createBucket()' - $ref: '@supabase/storage-js.packages/StorageBucketApi.default.createBucket' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: `insert` - - `objects` table permissions: none - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: Create bucket - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .createBucket('avatars', { public: false }) - ``` - - storage.emptyBucket(): - title: 'emptyBucket()' - $ref: '@supabase/storage-js.packages/StorageBucketApi.default.emptyBucket' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: `select` - - `objects` table permissions: `select` and `delete` - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: Empty bucket - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .emptyBucket('avatars') - ``` - storage.updateBucket(): - title: 'updateBucket()' - $ref: '@supabase/storage-js.packages/StorageBucketApi.default.updateBucket' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: `update` - - `objects` table permissions: none - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: Update bucket - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .updateBucket('avatars', { public: false }) - ``` - - storage.deleteBucket(): - title: 'deleteBucket()' - $ref: '@supabase/storage-js.packages/StorageBucketApi.default.deleteBucket' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: `select` and `delete` - - `objects` table permissions: none - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: Delete bucket - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .deleteBucket('avatars') - ``` - - storage.from.upload(): - title: 'from.upload()' - $ref: '@supabase/storage-js.packages/StorageFileApi.default.upload' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: none - - `objects` table permissions: `insert` - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Upload file using `ArrayBuffer` from base64 file data instead, see example below. - examples: - - name: Upload file - isSpotlight: true - js: | - ```js - const avatarFile = event.target.files[0] - const { data, error } = await supabase - .storage - .from('avatars') - .upload('public/avatar1.png', avatarFile, { - cacheControl: '3600', - upsert: false - }) - ``` - - name: Upload file using `ArrayBuffer` from base64 file data - js: | - ```js - import { decode } from 'base64-arraybuffer' - - const { data, error } = await supabase - .storage - .from('avatars') - .upload('public/avatar1.png', decode('base64FileData'), { - contentType: 'image/png' - }) - ``` - - storage.from.update(): - title: 'from.update()' - $ref: '@supabase/storage-js.packages/StorageFileApi.default.update' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: none - - `objects` table permissions: `update` and `select` - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - - For React Native, using either `Blob`, `File` or `FormData` does not work as intended. Update file using `ArrayBuffer` from base64 file data instead, see example below. - examples: - - name: Update file - isSpotlight: true - js: | - ```js - const avatarFile = event.target.files[0] - const { data, error } = await supabase - .storage - .from('avatars') - .update('public/avatar1.png', avatarFile, { - cacheControl: '3600', - upsert: false - }) - ``` - - name: Update file using `ArrayBuffer` from base64 file data - js: | - ```js - import {decode} from 'base64-arraybuffer' - - const { data, error } = await supabase - .storage - .from('avatars') - .update('public/avatar1.png', decode('base64FileData'), { - contentType: 'image/png' - }) - ``` - - storage.from.move(): - title: 'from.move()' - $ref: '@supabase/storage-js.packages/StorageFileApi.default.move' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: none - - `objects` table permissions: `update` and `select` - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: Move file - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .move('public/avatar1.png', 'private/avatar2.png') - ``` - - storage.from.copy(): - title: 'from.copy()' - $ref: '@supabase/storage-js.packages/StorageFileApi.default.copy' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: none - - `objects` table permissions: `insert` and `select` - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: Copy file - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .copy('public/avatar1.png', 'private/avatar2.png') - ``` - - storage.from.createSignedUrl(): - title: 'from.createSignedUrl()' - $ref: '@supabase/storage-js.packages/StorageFileApi.default.createSignedUrl' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: none - - `objects` table permissions: `select` - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: Create Signed URL - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .createSignedUrl('folder/avatar1.png', 60) - ``` - - storage.from.createSignedUrls(): - title: 'from.createSignedUrls()' - $ref: '@supabase/storage-js.packages/StorageFileApi.default.createSignedUrls' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: none - - `objects` table permissions: `select` - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: Create Signed URLs - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .createSignedUrls(['folder/avatar1.png', 'folder/avatar2.png'], 60) - ``` - - storage.from.getPublicUrl(): - title: 'from.getPublicUrl()' - $ref: '@supabase/storage-js.packages/StorageFileApi.default.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" - - RLS policy permissions required: - - `buckets` table permissions: none - - `objects` table permissions: none - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: Returns the URL for an asset in a public bucket - isSpotlight: true - js: | - ```js - const { data } = supabase - .storage - .from('public-bucket') - .getPublicUrl('folder/avatar1.png') - ``` - - storage.from.download(): - title: 'from.download()' - $ref: '@supabase/storage-js.packages/StorageFileApi.default.download' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: none - - `objects` table permissions: `select` - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: Download file - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .download('folder/avatar1.png') - ``` - - storage.from.remove(): - title: 'from.remove()' - $ref: '@supabase/storage-js.packages/StorageFileApi.default.remove' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: none - - `objects` table permissions: `delete` and `select` - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: Delete file - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .remove(['folder/avatar1.png']) - ``` - - storage.from.list(): - title: 'from.list()' - $ref: '@supabase/storage-js.packages/StorageFileApi.default.list' - notes: | - - RLS policy permissions required: - - `buckets` table permissions: none - - `objects` table permissions: `select` - - Refer to the [Storage guide](/docs/guides/storage#access-control) on how access control works - examples: - - name: List files in a bucket - isSpotlight: true - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .list('folder', { - limit: 100, - offset: 0, - sortBy: { column: 'name', order: 'asc' }, - }) - ``` - - name: Search files in a bucket - js: | - ```js - const { data, error } = await supabase - .storage - .from('avatars') - .list('folder', { - limit: 100, - offset: 0, - sortBy: { column: 'name', order: 'asc' }, - search: 'jon' - }) - ``` diff --git a/spec/supabase_js_v2.yml b/spec/supabase_js_v2.yml index 237b0a3b729..908c389b6ea 100644 --- a/spec/supabase_js_v2.yml +++ b/spec/supabase_js_v2.yml @@ -136,13 +136,13 @@ functions: title: 'signUp()' $ref: '@supabase/gotrue-js.GoTrueClient.signUp' 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/settings). + - 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/settings). + - 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/settings), an obfuscated/fake user object is returned. + - 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. - To fetch the currently logged-in user, refer to [`getUser()`](/docs/reference/javascript/auth-getuser). examples: @@ -360,7 +360,7 @@ functions: 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). + 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/providers). examples: - id: update-the-email-for-an-authenticated-user name: Update the email for an authenticated user diff --git a/studio/components/interfaces/Billing/Billing.utils.ts b/studio/components/interfaces/Billing/Billing.utils.ts index 67f98f93e7b..4bad6ed40a7 100644 --- a/studio/components/interfaces/Billing/Billing.utils.ts +++ b/studio/components/interfaces/Billing/Billing.utils.ts @@ -52,8 +52,7 @@ export const formSubscriptionUpdatePayload = ( }, nonChangeableAddons: SubscriptionAddon[], selectedPaymentMethod: string, - region: string, - hcaptchaToken: string | undefined + region: string ) => { const { computeSize, pitrDuration, customDomains } = selectedAddons @@ -78,8 +77,7 @@ export const formSubscriptionUpdatePayload = ( ...(tierPriceId && { tier: tierPriceId.id }), addons, proration_date, - payment_method: selectedPaymentMethod, - hcaptchaToken + payment_method: selectedPaymentMethod } } diff --git a/studio/components/interfaces/Billing/EnterpriseUpdate.tsx b/studio/components/interfaces/Billing/EnterpriseUpdate.tsx index 254d83275c7..969b5d58993 100644 --- a/studio/components/interfaces/Billing/EnterpriseUpdate.tsx +++ b/studio/components/interfaces/Billing/EnterpriseUpdate.tsx @@ -114,8 +114,7 @@ const EnterpriseUpdate: FC = ({ selectedAddons, nonChangeableAddons, selectedPaymentMethodId, - projectRegion, - undefined + projectRegion ), tier: currentSubscription.tier.price_id, } @@ -178,8 +177,7 @@ const EnterpriseUpdate: FC = ({ selectedAddons, nonChangeableAddons, selectedPaymentMethodId, - projectRegion, - token ?? undefined + projectRegion ), tier: currentSubscription.tier.price_id, } diff --git a/studio/components/interfaces/Billing/ExitSurvey/ExitSurvey.tsx b/studio/components/interfaces/Billing/ExitSurvey/ExitSurvey.tsx index 439f5edc6f3..9cda2b5aa30 100644 --- a/studio/components/interfaces/Billing/ExitSurvey/ExitSurvey.tsx +++ b/studio/components/interfaces/Billing/ExitSurvey/ExitSurvey.tsx @@ -109,7 +109,7 @@ const ExitSurvey: FC = ({ freeTier, subscription, onSelectBack }) => { setMessage(values.message) return setShowConfirmModal(true) } else { - downgradeProject(values, token as string) + downgradeProject(values) } } @@ -118,7 +118,7 @@ const ExitSurvey: FC = ({ freeTier, subscription, onSelectBack }) => { captchaRef.current?.resetCaptcha() } - const downgradeProject = async (values?: any, hcaptchaToken?: string) => { + const downgradeProject = async (values?: any) => { const downgradeMessage = values?.message ?? message try { @@ -132,7 +132,6 @@ const ExitSurvey: FC = ({ freeTier, subscription, onSelectBack }) => { tier, addons, proration_date, - hcaptchaToken: captchaToken ?? hcaptchaToken, }) resetCaptcha() diff --git a/studio/components/interfaces/Billing/ProUpgrade.tsx b/studio/components/interfaces/Billing/ProUpgrade.tsx index 2f05f9a8844..b4cf2635051 100644 --- a/studio/components/interfaces/Billing/ProUpgrade.tsx +++ b/studio/components/interfaces/Billing/ProUpgrade.tsx @@ -137,8 +137,7 @@ const ProUpgrade: FC = ({ selectedAddons, nonChangeableAddons, selectedPaymentMethodId, - projectRegion, - undefined + projectRegion ) setIsRefreshingPreview(true) @@ -184,8 +183,7 @@ const ProUpgrade: FC = ({ selectedAddons, nonChangeableAddons, selectedPaymentMethodId, - projectRegion, - captchaToken ?? undefined + projectRegion ) const res = await patch(`${API_URL}/projects/${projectRef}/subscription`, payload) resetCaptcha() diff --git a/supabase/.gitignore b/supabase/.gitignore new file mode 100644 index 00000000000..773c7c3e0a1 --- /dev/null +++ b/supabase/.gitignore @@ -0,0 +1,3 @@ +# Supabase +.branches +.temp diff --git a/supabase/functions/og-images/README.md b/supabase/functions/og-images/README.md new file mode 100644 index 00000000000..886b9f69b9e --- /dev/null +++ b/supabase/functions/og-images/README.md @@ -0,0 +1,40 @@ +# Open Graph (OG) Image Generator + +Generate OG Images for the sites at supabase. + +## How to use + +To use the og image generator, you will need to visit the site with the following parameters: + +`site`: indicating which site you want to generate an image for. Currently, the only available option is docs. + +`title`: representing the title of the image you want to generate. + +`description`: representing the description of the image you want to generate. + +`type` (optional): indicating the type of image you want to generate. This is optional and is only used for the docs site. + +`icon` (optional): indicating the icon you want to use for the image. This is optional and is only used for the docs site. + +If any of the required parameters are missing, you will receive a 404 response with a message indicating that some parameters are missing. If the site parameter is not recognized, you will receive a 404 response with a message indicating that the site was not found. + +Here is an example link that you can use to test the website: + +https://obuldanrptloktxcffvn.functions.supabase.co/og-images?site=docs&title=Example%20Title&description=Example%20Description&type=Auth&icon=google + +This link will generate an image for the docs site with the title "Example Title", the description "Example Description", the Auth type, and the Google icon. + +## Run locally + +First we need to start up supabase using the [supabase cli](https://supabase.com/docs/reference/cli/introduction) + +```bash +supabase start +``` + +Then run the function +```bash +supabase functions serve og-images +``` + +Now we can visit [localhost:54321/functions/v1/og-images/?site=docs&title=Title&description=Description&type=Auth](http://localhost:54321/functions/v1/og-images/?site=docs&title=Title&description=Description&type=Auth) to see your changes localy. diff --git a/supabase/functions/og-images/component/Docs.tsx b/supabase/functions/og-images/component/Docs.tsx new file mode 100644 index 00000000000..eef40786d56 --- /dev/null +++ b/supabase/functions/og-images/component/Docs.tsx @@ -0,0 +1,57 @@ +import React from 'https://esm.sh/react@18.2.0?deno-std=0.140.0' + +type Props = { + type?: string | null + title: string + description: string + icon?: string | null +} + +const Docs = (props: Props) => { + const { type, title, description, icon } = props + + return ( +
    +
    + {icon && ( + + )} + {type && icon && ( +
    + )} + {type && ( + <> +
    + +
    + {type} + + )} +
    +
    +
    +

    {title}

    +

    {description}

    +
    +
    + + DOCS +
    +
    +
    + ) +} + +export default Docs \ No newline at end of file diff --git a/supabase/functions/og-images/handler.tsx b/supabase/functions/og-images/handler.tsx new file mode 100644 index 00000000000..1e7b9ae98bf --- /dev/null +++ b/supabase/functions/og-images/handler.tsx @@ -0,0 +1,59 @@ +import React from 'https://esm.sh/react@18.2.0?deno-std=0.140.0' +import { ImageResponse } from 'https://deno.land/x/og_edge@0.0.4/mod.ts' +import Docs from './component/Docs.tsx' + +const corsHeaders = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', + 'Content-Type': 'application/json' +} + +// Load custom font +const FONT_URL = 'https://obuldanrptloktxcffvn.supabase.co/storage/v1/object/public/images/lw6/CircularStd-Book.otf' +const font = fetch(new URL(FONT_URL, import.meta.url)).then((res) => res.arrayBuffer()) +const fontData = await font + +export async function handler(req: Request) { + const url = new URL(req.url) + const site = url.searchParams.get('site')?.toLowerCase() ?? url.searchParams.get('amp;site')?.toLowerCase() + const icon = url.searchParams.get('icon')?.toLowerCase() ?? url.searchParams.get('amp;icon')?.toLowerCase() + const type = url.searchParams.get('type') ?? url.searchParams.get('amp;type') + const title = url.searchParams.get('title') ?? url.searchParams.get('amp;title') + const description = url.searchParams.get('description') ?? url.searchParams.get('amp;description') + + if(!site || !title || !description) { + return new Response(JSON.stringify({ message: 'missing params' }), { + headers: { ...corsHeaders }, + status: 404, + }) + } + + switch (site) { + case 'docs': + return new ImageResponse(( ), + { + width: 1200, + height: 630, + fonts: [ + { + name: 'Circular', + data: fontData, + style: 'normal', + }, + ], + headers: { + 'content-type': 'image/png', + 'cache-control': 'public, max-age=31536000, s-maxage=31536000, no-transform, immutable', + 'cdn-cache-control': 'max-age=31536000', + }, + }) + break; + + default: + return new Response(JSON.stringify({message: 'site not found'}), { + headers: { ...corsHeaders }, + status: 404, + }) + break; + } +} diff --git a/supabase/functions/og-images/index.ts b/supabase/functions/og-images/index.ts new file mode 100644 index 00000000000..ebf53f34dce --- /dev/null +++ b/supabase/functions/og-images/index.ts @@ -0,0 +1,4 @@ +import { serve } from 'https://deno.land/std@0.170.0/http/server.ts' +import { handler } from './handler.tsx' + +serve(handler)