From 8e9b9cd4a77e07b8e214aaedea66ec64b01904ee Mon Sep 17 00:00:00 2001 From: Jonathan Summers-Muir Date: Thu, 8 Dec 2022 00:19:56 +0800 Subject: [PATCH] updated common and sidebars for filters and modifiers --- .../NavigationMenu/NavigationMenu.Context.tsx | 37 ++ .../NavigationMenu/NavigationMenu.tsx | 5 +- .../NavigationMenu/NavigationMenuRefList.tsx | 254 ++++++--- apps/docs/hooks/useIsMounted.ts | 12 + apps/docs/hooks/useMenuState.ts | 14 + apps/docs/hooks/useWindowLocation.ts | 55 ++ apps/docs/layouts/SiteRefLayout.tsx | 15 +- apps/docs/layouts/ref/RefSubLayout.tsx | 31 +- apps/docs/package.json | 3 +- .../pages/reference/javascript/[...slug].tsx | 399 +++++++------- package-lock.json | 141 ++--- spec/common-client-libs-sections.json | 505 +++++++++--------- 12 files changed, 859 insertions(+), 612 deletions(-) create mode 100644 apps/docs/components/Navigation/NavigationMenu/NavigationMenu.Context.tsx create mode 100644 apps/docs/hooks/useIsMounted.ts create mode 100644 apps/docs/hooks/useMenuState.ts create mode 100644 apps/docs/hooks/useWindowLocation.ts diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.Context.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.Context.tsx new file mode 100644 index 00000000000..f4fb58904cf --- /dev/null +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.Context.tsx @@ -0,0 +1,37 @@ +import { createContext, useContext } from 'react' + +interface ContextProps { + activeRefItem: string + setActiveRefItem: (x: string) => void +} + +interface Provider extends ContextProps { + children?: React.ReactNode +} + +// Make sure the shape of the default value passed to +// createContext matches the shape that the consumers expect! +const NavMenuContext = createContext({ + activeRefItem: undefined, + setActiveRefItem: undefined, +}) + +export const NavigationMenuContextProvider = (props: Provider) => { + const { activeRefItem, setActiveRefItem } = props + + const value = { + activeRefItem, + setActiveRefItem, + } + + return {props.children} +} + +// context helper to avoid using a consumer component +export const useNavigationMenuContext = () => { + const context = useContext(NavMenuContext) + if (context === undefined) { + throw new Error(`useFormContextOnChange must be used within a FormContextProvider.`) + } + return context +} diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx index b933ceb99aa..6ef79e6770a 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.tsx @@ -2,10 +2,11 @@ import { useTheme } from 'common/Providers' import Image from 'next/image' import Link from 'next/link' import { useRouter } from 'next/router' -import { useEffect, useState } from 'react' +import { useEffect, useState, memo } from 'react' import NavigationMenuCliList from './NavigationMenuCliList' import NavigationMenuGuideList from './NavigationMenuGuideList' import NavigationMenuRefList from './NavigationMenuRefList' +import { NavigationMenuContextProvider } from './NavigationMenu.Context' // @ts-expect-error import jsSpecNEW from '~/../../spec/supabase_js_v2_temp_new_shape.yml' assert { type: 'yml' } @@ -305,4 +306,4 @@ const SideNav = () => { ) } -export default SideNav +export default memo(SideNav) diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefList.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefList.tsx index 0fd8b37a41f..f05e91699e4 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefList.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuRefList.tsx @@ -2,13 +2,75 @@ import Link from 'next/link' import { useRouter } from 'next/router' import { IconChevronLeft } from 'ui' import * as NavItems from './NavigationMenu.constants' +import * as Accordion from '@radix-ui/react-accordion' import Image from 'next/image' import clientLibsCommonSections from '~/../../spec/common-client-libs-sections.json' +import { useEffect, useState, memo } from 'react' +import useWindowLocation from '~/hooks/useWindowLocation' +import { useNavigationMenuContext } from './NavigationMenu.Context' +import { find } from 'lodash' +import { useMenuActiveRefId } from '~/hooks/useMenuState' const allFunctions = Object.values(clientLibsCommonSections.sections.functions) +const FunctionLink = ({ + title, + id, + icon, + product, + library, + slug, +}: { + title: string + name?: string + id: string + icon?: string + product?: string + library: string + slug: string +}) => { + const router = useRouter() + // const { activeRefItem } = useNavigationMenuContext() + const activeAccordianItem = useMenuActiveRefId() + + const active = activeAccordianItem === id + return ( +
  • + + + {icon && } + {title} + + +
  • + ) +} + +const SideMenuTitle = ({ title }: { title: string }) => { + return ( + + {title} + + ) +} + +const Divider = () => { + return
    +} + const NavigationMenuRefList = ({ currentLevel, setLevel, id, lib }) => { + const router = useRouter() + // const { activeRefItem } = useNavigationMenuContext() + // const [activeAccordianItem, setActiveAccordianItem] = useState('') + + // const activeRefItem = useMenuActiveRefId() + // Get only the functions with references in the current librarry // ie: if the lib === dart, only get the dart functions const allCurrentFunctions = allFunctions @@ -18,49 +80,53 @@ const NavigationMenuRefList = ({ currentLevel, setLevel, id, lib }) => { .filter((item) => item) const introItems = Object.values(clientLibsCommonSections.sections.intro[lib].items) - const router = useRouter() const menu = NavItems[id] - const FunctionLink = ({ - title, - id, - icon, - product, - library, - slug, - }: { - title: string - name?: string - id: string - icon?: string - product?: string - library: string - slug: string - }) => { - return ( -
  • - - - {icon && } - {title} - - -
  • - ) - } + const url = router.asPath - const SideMenuTitle = ({ title }: { title: string }) => { - return ( - - {title} - - ) - } + const firstLevelRoute = url?.split('/')?.slice(0, 4)?.join('/') - const Divider = () => { - return
    - } + const path = useWindowLocation() + + useEffect(() => { + console.log('path', path) + }, [path]) + + // console.log('firstLevelRoute', firstLevelRoute) + + // console.log('allFunctions', allFunctions) + + const databaseFunctions = find(allFunctions, { title: 'Database' }).items + + const filterIds = find(databaseFunctions, { + id: 'using-filters', + }).items.map((x) => x.id) + + const modifierIds = find(databaseFunctions, { + id: 'using-modifiers', + }).items.map((x) => x.id) + + // console.log(filterIds, modifierIds) + + // console.log(filterIds.includes(activeRefItem) ? 'test IS FILTER' : 'test NOT FIlTER') + + // useEffect(() => { + // console.log('activeAccordianItem in USEEFFECT', activeAccordianItem) + + // if (filterIds.includes(activeRefItem) || activeRefItem === 'using-filters') { + // console.log('FILTERS') + // setActiveAccordianItem('using-filters') + // } else if (modifierIds.includes(activeRefItem) || activeRefItem === 'using-modifiers') { + // console.log('MODIFIERS') + // setActiveAccordianItem('using-modifiers') + // } else { + // setActiveAccordianItem('') + // } + // }, [activeRefItem]) + + // console.log('filterIds', filterIds) + // console.log('modifierIds', modifierIds) return (
    { currentLevel !== id ? 'opacity-0 invisible absolute' : '', ].join(' ')} > + + + + + + + +

    hello world

    +
    +
    +
    +
    {/* {process.env.NEXT_PUBLIC_EXPERIMENTAL_REF !== 'true' && ( */} @@ -124,53 +202,65 @@ const NavigationMenuRefList = ({ currentLevel, setLevel, id, lib }) => { const toplevelItems = fn.items.filter((item) => !item.parent) toplevelItems.map((item) =>
  • {item.title}
  • ) - // Database has Filters and Modifiers sub-items - if (fn.title === 'Database') { - const filters = fn.items.filter( - (item) => item.parent === 'filters' && item.libs.includes(lib) - ) - const modifiers = fn.items.filter( - (item) => item.parent === 'modifiers' && item.libs.includes(lib) - ) + const RenderLink = (props) => { + const activeAccordianItem = useMenuActiveRefId() + let active = false + + console.log('render link id', props.id) + + const isFilter = filterIds.includes(activeAccordianItem) + const isModifier = modifierIds.includes(activeAccordianItem) + + if ( + (isFilter && !isModifier && props.id === 'using-filters') || + activeAccordianItem === 'using-filters' + ) { + active = true + } else if ( + (isModifier && !isFilter && props.id === 'using-modifiers') || + activeAccordianItem === 'using-modifiers' + ) { + active = true + } else { + active = false + } return ( - <> - - - {toplevelItems.map((item) => ( - - ))} - -
    - - {filters.map((item) => ( - - ))} -
    - -
    - - {modifiers.map((item) => ( - - ))} -
    - - ) - } else { - // Only database has subitems (Filters & Modifiers) - // so output the rest directly - return ( - <> - - - {fn.items - .filter((item) => item.libs.includes(lib)) - .map((item) => ( - - ))} - + + + + + {props.items && + props.items + .filter((item) => item.libs.includes(lib)) + .map((item) => { + return + })} + + + ) } + + return ( + <> + + + {fn.items + .filter((item) => item.libs.includes(lib)) + .map((item) => ( + + ))} + + ) })} {menu.extras && ( @@ -207,4 +297,4 @@ const NavigationMenuRefList = ({ currentLevel, setLevel, id, lib }) => { ) } -export default NavigationMenuRefList +export default memo(NavigationMenuRefList) diff --git a/apps/docs/hooks/useIsMounted.ts b/apps/docs/hooks/useIsMounted.ts new file mode 100644 index 00000000000..d1ff05f505f --- /dev/null +++ b/apps/docs/hooks/useIsMounted.ts @@ -0,0 +1,12 @@ +import { useState, useEffect } from 'react' + +const useIsMounted = (): boolean => { + const [isMounted, setIsMounted] = useState(false) + useEffect(() => { + setIsMounted(() => true) + }, []) + + return isMounted +} + +export default useIsMounted diff --git a/apps/docs/hooks/useMenuState.ts b/apps/docs/hooks/useMenuState.ts new file mode 100644 index 00000000000..9d3209683b5 --- /dev/null +++ b/apps/docs/hooks/useMenuState.ts @@ -0,0 +1,14 @@ +import { proxy, useSnapshot } from 'valtio' + +export const menuState = proxy({ + // values + menuActiveRefId: '', + // set states + setMenuActiveRefId: (value) => { + menuState.menuActiveRefId = value + }, +}) + +export const useMenuActiveRefId = () => { + return useSnapshot(menuState).menuActiveRefId +} diff --git a/apps/docs/hooks/useWindowLocation.ts b/apps/docs/hooks/useWindowLocation.ts new file mode 100644 index 00000000000..7c9e26a451f --- /dev/null +++ b/apps/docs/hooks/useWindowLocation.ts @@ -0,0 +1,55 @@ +import useIsMounted from './useIsMounted' +import { useEffect, useState } from 'react' + +const useWindowLocation = (): Location | void => { + const isMounted = useIsMounted() + const [location, setLocation] = useState(isMounted ? window.location : undefined) + + const setWindowLocation = (location) => { + setLocation(location) + } + + useEffect(() => { + console.log('HOOK USEEFFECT FOR WINDOWWW') + if (!isMounted) return + console.log('I AM MOUNTED') + + if (!location) { + setWindowLocation(window.location) + } + + const handler = () => { + console.log('handlinggg...') + console.log(window.location) + setWindowLocation(window.location) + } + + window.addEventListener('popstate', handler) + + return () => { + window.removeEventListener('popstate', handler) + } + }, [isMounted]) + + useEffect(() => { + console.log('location, in hook useffect', location) + }, [location]) + + return location +} + +// const useWindowLocation = (): any => { +// const [location, setLocation] = useState((window && window.location) ?? undefined) +// const setWindowLocation = () => { +// console.log('Hello', window.location) +// setLocation(window.location) +// } +// useEffect(() => { +// window.addEventListener('popstate', setWindowLocation) +// return () => { +// window.removeEventListener('popstate', setWindowLocation) +// } +// }, []) +// return location +// } +export default useWindowLocation diff --git a/apps/docs/layouts/SiteRefLayout.tsx b/apps/docs/layouts/SiteRefLayout.tsx index 24a3f3c3512..4009ef1e418 100644 --- a/apps/docs/layouts/SiteRefLayout.tsx +++ b/apps/docs/layouts/SiteRefLayout.tsx @@ -6,9 +6,10 @@ import TopNavBarRef from '~/components/Navigation/NavigationMenu/TopNavBarRef' import { useTheme } from 'common/Providers' import RefSwitcher from '~/components/Navigation/RefSwitcher' -import { useEffect, useState } from 'react' +import { useEffect, useState, memo } from 'react' import FooterHelpCallout from '~/components/FooterHelpCallout' +import { NavigationMenuContextProvider } from '~/components/Navigation/NavigationMenu/NavigationMenu.Context' const SiteRefLayout = ({ children }) => { const router = useRouter() @@ -16,12 +17,14 @@ const SiteRefLayout = ({ children }) => { const [mobileMenuOpen, setMobileMenuOpen] = useState(false) - useEffect(() => { - setMobileMenuOpen(false) - }, [router.asPath]) + // const [activeRefItem, setActiveRefItem] = useState('') + + // useEffect(() => { + // setMobileMenuOpen(false) + // }, [router.asPath]) return ( - <> + {}}>
    {/* {
    - + ) } diff --git a/apps/docs/layouts/ref/RefSubLayout.tsx b/apps/docs/layouts/ref/RefSubLayout.tsx index d0c89058641..6a0d9542213 100644 --- a/apps/docs/layouts/ref/RefSubLayout.tsx +++ b/apps/docs/layouts/ref/RefSubLayout.tsx @@ -1,6 +1,10 @@ import { useInView } from 'react-intersection-observer' import { FC } from 'react' import { highlightSelectedNavItem } from '~/components/CustomHTMLElements/CustomHTMLElements.utils' +import { useRouter } from 'next/router' +import { useNavigationMenuContext } from '~/components/Navigation/NavigationMenu/NavigationMenu.Context' +import { route } from 'next/dist/server/router' +import { menuState } from '~/hooks/useMenuState' interface ISectionContainer { id: string @@ -27,19 +31,13 @@ type StickyHeader = { type RefSubLayoutType = {} const RefSubLayout: FC & RefSubLayoutSubComponents = (props) => { - return ( -
    -
    -
    {props.children}
    -
    -
    - ) + return
    {props.children}
    } const Section: FC = (props) => { - console.log({ props }) + // console.log({ props }) return ( -
    +
    {props.children}
    @@ -47,12 +45,22 @@ const Section: FC = (props) => { } const StickyHeader: FC = (props) => { + const router = useRouter() + const { setActiveRefItem } = useNavigationMenuContext() + const { ref } = useInView({ threshold: 1, rootMargin: '30% 0% -35% 0px', onChange: (inView, entry) => { - if (inView && window) highlightSelectedNavItem(entry.target.id) - if (props.scrollSpyHeader) window.history.pushState(null, '', entry.target.id) + if (inView && window) highlightSelectedNavItem(entry.target.attributes['data-ref-id'].value) + if (inView && props.scrollSpyHeader) { + window.history.replaceState(null, '', entry.target.id) + // if (setActiveRefItem) setActiveRefItem(entry.target.attributes['data-ref-id'].value) + menuState.setMenuActiveRefId(entry.target.attributes['data-ref-id'].value) + // router.push(`/reference/javascript/${entry.target.attributes['data-ref-id'].value}`, null, { + // shallow: true, + // }) + } }, }) @@ -60,6 +68,7 @@ const StickyHeader: FC = (props) => {

    fn.items) .flat(2) +console.log('allFunctions', allFunctions) + +interface ICommonFunc { + id: string + title: string + slug: string + product: string + libs: string + items: ICommonFunc[] +} + +interface IFunctionSection { + funcData: any + commonFuncData: ICommonFunc +} + +const FunctionSection: React.FC = (props) => { + const item = jsSpec.functions.find((x) => x.id === props.funcData.id) + const hasTsRef = item['$ref'] || null + const tsDefinition = hasTsRef && extractTsDocNode(hasTsRef, jsTypeSpec) + const parameters = hasTsRef ? generateParameters(tsDefinition) : '' + const shortText = hasTsRef ? tsDefinition.signatures[0].comment.shortText : '' + + return ( + <> + + + <> +
    + {shortText && {shortText}} +
    + + {item.description && ( +
    + {item.description} +
    + )} + {/* {functionMarkdownContent && ( +
    + +
    + )} */} + {item.notes && ( +
    + {item.notes} +
    + )} + {/* // parameters */} + {parameters && ( +
    +
    Parameters
    +
      + {parameters.map((param) => { + // grab override params from yaml file + const overrideParams = item.overrideParams + + // params from the yaml file can override the params from parameters if it matches the name + const overide = overrideParams?.filter((x) => { + return param.name === x.name + }) + + const paramItem = overide?.length > 0 ? overide[0] : param + + return ( + + {paramItem.subContent && ( +
      + + {param.subContent.map((param) => { + return + })} + +
      + )} + + ) + })} +
    +
    + )} + +
    + + {item.examples && ( + <> + + {item.examples && + item.examples.map((example, exampleIndex) => { + const exampleString = ` +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') +` + const currentExampleId = example.id + const staticExample = item.examples[exampleIndex] + + const response = staticExample.response + const sql = staticExample?.data?.sql + const tables = staticExample?.data?.tables + + return ( + + {((tables && tables.length > 0) || sql) && ( + + <> + {tables && + tables.length > 0 && + tables.map((table) => { + return ( +
    +
    +
    +
    + +
    +
    {table.name}
    +
    +
    +
    + ) + })} + {sql && ( + + {sql} + + )} + +
    + )} + + + {exampleString + + (example.code && + example.code.replace('```', '').replace('js', '').replace('```', ''))} + + {response && ( + + + {response.replace('```', '').replace('json', '').replace('```', '')} + + + )} +
    + ) + })} +
    + + )} +
    +
    + + ) +} + export default function JSReference(props) { console.log('docs', props.docs) const router = useRouter() @@ -72,7 +262,7 @@ export default function JSReference(props) { return ( <> -
    ~~~Preamble pages~~~
    + {/*
    ~~~Preamble pages~~~
    */} {props.docs .filter((doc) => doc.introPage) .map((item) => ( @@ -88,209 +278,22 @@ export default function JSReference(props) { ))} -
    -
    - - {/* jsSpec.functions.map((item, itemIndex) => { */} {props.docs .filter((doc) => !doc.introPage) - .map((doc, itemIndex) => { - const item = jsSpec.functions.find((x) => x.id === doc.id) - const hasTsRef = item['$ref'] || null - const tsDefinition = hasTsRef && extractTsDocNode(hasTsRef, jsTypeSpec) - const parameters = hasTsRef ? generateParameters(tsDefinition) : '' - // const functionMarkdownContent = props?.docs[itemIndex]?.content - // ? props?.docs[itemIndex]?.content - // : null - const shortText = hasTsRef ? tsDefinition.signatures[0].comment.shortText : '' - - // const introFileMarkdownContent = - //console.log('props.docs', props.docs) - // if (item.id !== 'db-modifiers-select') return <> - + .map((func, itemIndex) => { + const commonFuncData = allFunctions.find((fn) => fn.id === func.id) return ( <> - fn.id === item.id).slug} - scrollSpyHeader={true} - > - - <> -
    - {shortText && ( - {shortText} - )} -
    + + {commonFuncData.items && + commonFuncData.items.map((_commonFuncData) => { + const rawFuncData = jsSpec.functions.find((x) => x.id === _commonFuncData.id) - {item.description && ( -
    - {item.description} -
    - )} - {/* {functionMarkdownContent && ( -
    - -
    - )} */} - {item.notes && ( -
    - {item.notes} -
    - )} - {/* // parameters */} - {parameters && ( -
    -
    Parameters
    -
      - {parameters.map((param) => { - // grab override params from yaml file - const overrideParams = item.overrideParams - - // params from the yaml file can override the params from parameters if it matches the name - const overide = overrideParams?.filter((x) => { - return param.name === x.name - }) - - const paramItem = overide?.length > 0 ? overide[0] : param - - return ( - - {paramItem.subContent && ( -
      - - {param.subContent.map((param) => { - return - })} - -
      - )} - - ) - })} -
    -
    - )} - -
    - - {item.examples && ( - <> - - {item.examples && - item.examples.map((example, exampleIndex) => { - const exampleString = ` -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') -` - const currentExampleId = example.id - const staticExample = item.examples[exampleIndex] - - const response = staticExample.response - const sql = staticExample?.data?.sql - const tables = staticExample?.data?.tables - - return ( - - {((tables && tables.length > 0) || sql) && ( - - <> - {tables && - tables.length > 0 && - tables.map((table) => { - return ( -
    -
    -
    -
    - -
    -
    - {table.name} -
    -
    -
    -
    - ) - })} - {sql && ( - - {sql} - - )} - -
    - )} - - - {exampleString + - (example.code && - example.code - .replace('```', '') - .replace('js', '') - .replace('```', ''))} - - {response && ( - - - {response - .replace('```', '') - .replace('json', '') - .replace('```', '')} - - - )} -
    - ) - })} -
    - - )} -
    -
    + return ( + + ) + })} ) })} diff --git a/package-lock.json b/package-lock.json index 256ac677995..0a4c9c9e2ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -86,7 +86,8 @@ "remark-mdx": "^2.0.0-rc.2", "remark-prism": "^1.3.6", "remark-slug": "^7.0.1", - "ui": "*" + "ui": "*", + "valtio": "^1.7.6" }, "devDependencies": { "@types/node": "^17.0.12", @@ -432,6 +433,11 @@ "unist-util-visit": "^4.1.0" } }, + "apps/docs/node_modules/proxy-compare": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.3.0.tgz", + "integrity": "sha512-c3L2CcAi7f7pvlD0D7xsF+2CQIW8C3HaYx2Pfgq8eA4HAl3GAH6/dVYsyBbYF/0XJs2ziGLrzmz5fmzPm6A0pQ==" + }, "apps/docs/node_modules/remark-parse": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", @@ -534,6 +540,46 @@ "url": "https://opencollective.com/unified" } }, + "apps/docs/node_modules/valtio": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.7.6.tgz", + "integrity": "sha512-zsGrCCYOIpy8egQxftduFyJusF/BMu3CganhHKUOE/I6t6V6yA1MDfZZkrYoWYCGkC3rSBYcIHEEsoYQM9lV2w==", + "dependencies": { + "proxy-compare": "2.3.0", + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@babel/helper-module-imports": ">=7.12", + "@babel/types": ">=7.13", + "aslemammad-vite-plugin-macro": ">=1.0.0-alpha.1", + "babel-plugin-macros": ">=3.0", + "react": ">=16.8", + "vite": ">=2.8.6" + }, + "peerDependenciesMeta": { + "@babel/helper-module-imports": { + "optional": true + }, + "@babel/types": { + "optional": true + }, + "aslemammad-vite-plugin-macro": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + }, + "react": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, "apps/docs/node_modules/vfile": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", @@ -10223,7 +10269,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "devOptional": true }, "node_modules/@types/parse-numeric-range": { "version": "0.0.1", @@ -12223,7 +12269,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, + "devOptional": true, "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -13812,7 +13858,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dev": true, + "devOptional": true, "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -16100,7 +16146,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, + "devOptional": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -19937,7 +19983,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "devOptional": true }, "node_modules/is-bigint": { "version": "1.0.4", @@ -22570,7 +22616,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "devOptional": true }, "node_modules/json-schema-traverse": { "version": "0.4.1", @@ -22816,7 +22862,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "devOptional": true }, "node_modules/list-item": { "version": "1.1.1", @@ -26809,7 +26855,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, + "devOptional": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -37988,36 +38034,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/@next/swc-android-arm-eabi": { - "version": "12.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.6.tgz", - "integrity": "sha512-dDo8Dxz/+v7gM7y0GwKunl4iMyoXDJV4xhH3zsO2yYReK+WL/KTJxRMzxtRJIiH9XFHHzdxnL935067r4hs1+A==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-freebsd-x64": { - "version": "12.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.6.tgz", - "integrity": "sha512-p8TU7HCNjFEf7pLrKG0fAtuHKbIk8XWLCFvn0n54RvGAnQmwo0kzghU0I8RFzcl/XFbVhxg5oX9Npx/GBlPgcw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } } }, "dependencies": { @@ -45082,7 +45098,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "devOptional": true }, "@types/parse-numeric-range": { "version": "0.0.1", @@ -46652,7 +46668,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dev": true, + "devOptional": true, "requires": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", @@ -47926,7 +47942,7 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dev": true, + "devOptional": true, "requires": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -49501,7 +49517,7 @@ "@mdx-js/react": "^1.6.22", "@next/mdx": "^12.0.4", "@radix-ui/react-accordion": "^1.0.1", - "@radix-ui/react-collapsible": "*", + "@radix-ui/react-collapsible": "^1.0.1", "@tailwindcss/typography": "^0.4.1", "@types/node": "^17.0.12", "@types/react": "17.0.39", @@ -49551,7 +49567,8 @@ "ts-node": "^10.9.1", "tsconfig": "*", "typescript": "^4.5.3", - "ui": "*" + "ui": "*", + "valtio": "*" }, "dependencies": { "@babel/core": { @@ -49791,6 +49808,11 @@ "integrity": "sha512-zshJVTyepNE8Sjrj7Hv1UyDq3UwJVnwKsHGuDBYM4jixsofrC2j9wj2sXQ3PnlryFxLm9pU9ctqiGQgbxYXLjg==", "requires": {} }, + "proxy-compare": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-2.3.0.tgz", + "integrity": "sha512-c3L2CcAi7f7pvlD0D7xsF+2CQIW8C3HaYx2Pfgq8eA4HAl3GAH6/dVYsyBbYF/0XJs2ziGLrzmz5fmzPm6A0pQ==" + }, "remark-parse": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz", @@ -49863,6 +49885,15 @@ "@types/unist": "^2.0.2" } }, + "valtio": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/valtio/-/valtio-1.7.6.tgz", + "integrity": "sha512-zsGrCCYOIpy8egQxftduFyJusF/BMu3CganhHKUOE/I6t6V6yA1MDfZZkrYoWYCGkC3rSBYcIHEEsoYQM9lV2w==", + "requires": { + "proxy-compare": "2.3.0", + "use-sync-external-store": "1.2.0" + } + }, "vfile": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.1.tgz", @@ -50167,7 +50198,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, + "devOptional": true, "requires": { "is-arrayish": "^0.2.1" } @@ -53055,7 +53086,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "devOptional": true }, "is-bigint": { "version": "1.0.4", @@ -55142,7 +55173,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "devOptional": true }, "json-schema-traverse": { "version": "0.4.1", @@ -55339,7 +55370,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "devOptional": true }, "list-item": { "version": "1.1.1", @@ -58265,7 +58296,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, + "devOptional": true, "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -66651,18 +66682,6 @@ "version": "4.4.2", "resolved": "https://registry.npmjs.org/zxcvbn/-/zxcvbn-4.4.2.tgz", "integrity": "sha512-Bq0B+ixT/DMyG8kgX2xWcI5jUvCwqrMxSFam7m0lAf78nf04hv6lNCsyLYdyYTrCVMqNDY/206K7eExYCeSyUQ==" - }, - "@next/swc-android-arm-eabi": { - "version": "12.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.2.6.tgz", - "integrity": "sha512-dDo8Dxz/+v7gM7y0GwKunl4iMyoXDJV4xhH3zsO2yYReK+WL/KTJxRMzxtRJIiH9XFHHzdxnL935067r4hs1+A==", - "optional": true - }, - "@next/swc-freebsd-x64": { - "version": "12.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.2.6.tgz", - "integrity": "sha512-p8TU7HCNjFEf7pLrKG0fAtuHKbIk8XWLCFvn0n54RvGAnQmwo0kzghU0I8RFzcl/XFbVhxg5oX9Npx/GBlPgcw==", - "optional": true } } } diff --git a/spec/common-client-libs-sections.json b/spec/common-client-libs-sections.json index fe8afeda67c..e4f7544e944 100644 --- a/spec/common-client-libs-sections.json +++ b/spec/common-client-libs-sections.json @@ -98,192 +98,193 @@ "title": "Using filters", "slug": "using-filters", "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "eq", - "title": "Column is equal to a value", - "slug": "eq", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "neq", - "title": "Column is not equal to a value", - "slug": "neq", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "gt", - "title": "Column is greater than a value", - "slug": "gt", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "gte", - "title": "Column is greater than or equal to a value", - "slug": "gte", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "lt", - "title": "Column is less than a value", - "slug": "lt", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "lte", - "title": "Column is less than or equal to a value", - "slug": "lte", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "like", - "title": "Column matches a pattern", - "slug": "like", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "ilike", - "title": "Column matches a case-insensitive pattern", - "slug": "ilike", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "is", - "title": "Column is a value", - "slug": "is", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "in", - "title": "Column is in an array", - "slug": "in", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "contains", - "title": "Column contains every element in a value", - "slug": "contains", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "contained-by", - "title": "Contained by value", - "slug": "containedby", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "range-gt", - "title": "Greater than a range", - "slug": "rangegt", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "range-gte", - "title": "Greater than or equal to a range", - "slug": "rangegte", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "range-lt", - "title": "Less than a range", - "slug": "rangelt", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "range-lte", - "title": "Less than or equal to a range", - "slug": "rangelte", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "range-adjacent", - "title": "Mutually exclusive to a range", - "slug": "rangeadjacent", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "overlaps", - "title": "With a common element", - "slug": "overlaps", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "text-search", - "title": "Match a string", - "slug": "textsearch", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "match", - "title": "Match an associated value", - "slug": "match", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "not", - "title": "Don't match the filter", - "slug": "not", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "or", - "title": "Match at least one filter", - "slug": "or", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "filter", - "title": "Match the filter", - "slug": "filter", - "product": "database", - "parent": "filters", - "libs": ["js", "js_v4", "dart", "dart_v0"] + "libs": ["js", "js_v4", "dart", "dart_v0"], + "items": [ + { + "id": "eq", + "title": "Column is equal to a value", + "slug": "eq", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "neq", + "title": "Column is not equal to a value", + "slug": "neq", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "gt", + "title": "Column is greater than a value", + "slug": "gt", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "gte", + "title": "Column is greater than or equal to a value", + "slug": "gte", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "lt", + "title": "Column is less than a value", + "slug": "lt", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "lte", + "title": "Column is less than or equal to a value", + "slug": "lte", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "like", + "title": "Column matches a pattern", + "slug": "like", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "ilike", + "title": "Column matches a case-insensitive pattern", + "slug": "ilike", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "is", + "title": "Column is a value", + "slug": "is", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "in", + "title": "Column is in an array", + "slug": "in", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "contains", + "title": "Column contains every element in a value", + "slug": "contains", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "contained-by", + "title": "Contained by value", + "slug": "containedby", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "range-gt", + "title": "Greater than a range", + "slug": "rangegt", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "range-gte", + "title": "Greater than or equal to a range", + "slug": "rangegte", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "range-lt", + "title": "Less than a range", + "slug": "rangelt", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "range-lte", + "title": "Less than or equal to a range", + "slug": "rangelte", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "range-adjacent", + "title": "Mutually exclusive to a range", + "slug": "rangeadjacent", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "overlaps", + "title": "With a common element", + "slug": "overlaps", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "text-search", + "title": "Match a string", + "slug": "textsearch", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "match", + "title": "Match an associated value", + "slug": "match", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "not", + "title": "Don't match the filter", + "slug": "not", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "or", + "title": "Match at least one filter", + "slug": "or", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "filter", + "title": "Match the filter", + "slug": "filter", + "product": "database", + "parent": "filters", + "libs": ["js", "js_v4", "dart", "dart_v0"] + } + ] }, { "id": "using-modifiers", @@ -291,71 +292,73 @@ "slug": "using-modifiers", "product": "database", "parent": "modifiers", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "db-modifiers-select", - "title": "Select the query", - "slug": "db-modifiers-select", - "product": "database", - "parent": "modifiers", - "libs": ["js", "js_v4"] - }, - { - "id": "order", - "title": "Order the query", - "slug": "order", - "product": "database", - "parent": "modifiers", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "limit", - "title": "Limit the query", - "slug": "limit", - "product": "database", - "parent": "modifiers", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "range", - "title": "Limit the query to a range", - "slug": "range", - "product": "database", - "parent": "modifiers", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "abort-signal", - "title": "Set an abort signal", - "slug": "db-abortsignal", - "product": "database", - "parent": "modifiers", - "libs": ["js", "js_v4"] - }, - { - "id": "single", - "title": "Retrieve the query as one row", - "slug": "single", - "product": "database", - "parent": "modifiers", - "libs": ["js", "js_v4", "dart", "dart_v0"] - }, - { - "id": "maybe-single", - "title": "Retrieve the query as 0-1 rows", - "slug": "maybesingle", - "product": "database", - "parent": "modifiers", - "libs": ["js", "js_v4"] - }, - { - "id": "csv", - "title": "Retrieve the query as a CSV string", - "slug": "db-csv", - "product": "database", - "parent": "modifiers", - "libs": ["js", "js_v4"] + "libs": ["js", "js_v4", "dart", "dart_v0"], + "items": [ + { + "id": "db-modifiers-select", + "title": "Select the query", + "slug": "db-modifiers-select", + "product": "database", + "parent": "modifiers", + "libs": ["js", "js_v4"] + }, + { + "id": "order", + "title": "Order the query", + "slug": "order", + "product": "database", + "parent": "modifiers", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "limit", + "title": "Limit the query", + "slug": "limit", + "product": "database", + "parent": "modifiers", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "range", + "title": "Limit the query to a range", + "slug": "range", + "product": "database", + "parent": "modifiers", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "abort-signal", + "title": "Set an abort signal", + "slug": "db-abortsignal", + "product": "database", + "parent": "modifiers", + "libs": ["js", "js_v4"] + }, + { + "id": "single", + "title": "Retrieve the query as one row", + "slug": "single", + "product": "database", + "parent": "modifiers", + "libs": ["js", "js_v4", "dart", "dart_v0"] + }, + { + "id": "maybe-single", + "title": "Retrieve the query as 0-1 rows", + "slug": "maybesingle", + "product": "database", + "parent": "modifiers", + "libs": ["js", "js_v4"] + }, + { + "id": "csv", + "title": "Retrieve the query as a CSV string", + "slug": "db-csv", + "product": "database", + "parent": "modifiers", + "libs": ["js", "js_v4"] + } + ] } ] },