@electric-sql/pglite-react
Version:
Hooks for using PGlite
1 lines • 8.63 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts","../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["export * from './provider'\nexport * from './hooks'\n","import React, { createContext, useContext } from 'react'\nimport { PGliteWithLive } from '@electric-sql/pglite/live'\n\ninterface Props<T extends PGliteWithLive> {\n children?: React.ReactNode\n db?: T\n}\n\ntype PGliteProvider<T extends PGliteWithLive> = (\n props: Props<T>,\n) => React.JSX.Element\ntype UsePGlite<T extends PGliteWithLive> = (db?: T) => T\n\ninterface PGliteProviderSet<T extends PGliteWithLive> {\n PGliteProvider: PGliteProvider<T>\n usePGlite: UsePGlite<T>\n}\n\n/**\n * Create a typed set of {@link PGliteProvider} and {@link usePGlite}.\n */\nfunction makePGliteProvider<T extends PGliteWithLive>(): PGliteProviderSet<T> {\n const ctx = createContext<T | undefined>(undefined)\n return {\n usePGlite: ((db?: T) => {\n const dbProvided = useContext(ctx)\n\n // allow providing a db explicitly\n if (db !== undefined) return db\n\n if (!dbProvided)\n throw new Error(\n 'No PGlite instance found, use PGliteProvider to provide one',\n )\n\n return dbProvided\n }) as UsePGlite<T>,\n PGliteProvider: ({ children, db }: Props<T>) => {\n return <ctx.Provider value={db}>{children}</ctx.Provider>\n },\n }\n}\n\nconst { PGliteProvider, usePGlite } = makePGliteProvider<PGliteWithLive>()\n\nexport { makePGliteProvider, PGliteProvider, usePGlite }\n","import type { LiveQuery, LiveQueryResults } from '@electric-sql/pglite/live'\nimport { query as buildQuery } from '@electric-sql/pglite/template'\nimport { useEffect, useRef, useState } from 'react'\nimport { usePGlite } from './provider'\n\nfunction paramsEqual(\n a1: unknown[] | undefined | null,\n a2: unknown[] | undefined | null,\n) {\n if (!a1 && !a2) return true\n if (a1?.length !== a2?.length) return false\n for (let i = 0; i < a1!.length; i++) {\n if (!Object.is(a1![i], a2![i])) {\n return false\n }\n }\n return true\n}\n\nfunction useLiveQueryImpl<T = { [key: string]: unknown }>(\n query: string | LiveQuery<T> | Promise<LiveQuery<T>>,\n params: unknown[] | undefined | null,\n key?: string,\n): Omit<LiveQueryResults<T>, 'affectedRows'> | undefined {\n const db = usePGlite()\n const paramsRef = useRef(params)\n const liveQueryRef = useRef<LiveQuery<T> | undefined>(undefined)\n let liveQuery: LiveQuery<T> | undefined\n let liveQueryChanged = false\n if (!(typeof query === 'string') && !(query instanceof Promise)) {\n liveQuery = query\n liveQueryChanged = liveQueryRef.current !== liveQuery\n liveQueryRef.current = liveQuery\n }\n const [results, setResults] = useState<LiveQueryResults<T> | undefined>(\n liveQuery?.initialResults,\n )\n\n let currentParams = paramsRef.current\n if (!paramsEqual(paramsRef.current, params)) {\n paramsRef.current = params\n currentParams = params\n }\n\n /* eslint-disable @eslint-react/hooks-extra/no-direct-set-state-in-use-effect */\n useEffect(() => {\n let cancelled = false\n const cb = (results: LiveQueryResults<T>) => {\n if (cancelled) return\n setResults(results)\n }\n if (typeof query === 'string') {\n const ret =\n key !== undefined\n ? db.live.incrementalQuery<T>(query, currentParams, key, cb)\n : db.live.query<T>(query, currentParams, cb)\n\n return () => {\n cancelled = true\n ret.then(({ unsubscribe }) => unsubscribe())\n }\n } else if (query instanceof Promise) {\n query.then((liveQuery) => {\n if (cancelled) return\n liveQueryRef.current = liveQuery\n setResults(liveQuery.initialResults)\n liveQuery.subscribe(cb)\n })\n return () => {\n cancelled = true\n liveQueryRef.current?.unsubscribe(cb)\n }\n } else if (liveQuery) {\n setResults(liveQuery.initialResults)\n liveQuery.subscribe(cb)\n return () => {\n cancelled = true\n liveQuery.unsubscribe(cb)\n }\n } else {\n throw new Error('Should never happen')\n }\n }, [db, key, query, currentParams, liveQuery])\n /* eslint-enable @eslint-react/hooks-extra/no-direct-set-state-in-use-effect */\n\n if (liveQueryChanged && liveQuery) {\n return liveQuery.initialResults\n }\n\n return (\n results && {\n rows: results.rows,\n fields: results.fields,\n totalCount: results.totalCount,\n offset: results.offset,\n limit: results.limit,\n }\n )\n}\n\nexport function useLiveQuery<T = { [key: string]: unknown }>(\n query: string,\n params?: unknown[] | null,\n): LiveQueryResults<T> | undefined\n\nexport function useLiveQuery<T = { [key: string]: unknown }>(\n liveQuery: LiveQuery<T>,\n): LiveQueryResults<T>\n\nexport function useLiveQuery<T = { [key: string]: unknown }>(\n liveQueryPromise: Promise<LiveQuery<T>>,\n): LiveQueryResults<T> | undefined\n\nexport function useLiveQuery<T = { [key: string]: unknown }>(\n query: string | LiveQuery<T> | Promise<LiveQuery<T>>,\n params?: unknown[] | null,\n): LiveQueryResults<T> | undefined {\n return useLiveQueryImpl<T>(query, params)\n}\n\nuseLiveQuery.sql = function <T = { [key: string]: unknown }>(\n strings: TemplateStringsArray,\n ...values: any[]\n): LiveQueryResults<T> | undefined {\n const { query, params } = buildQuery(strings, ...values)\n // eslint-disable-next-line react-compiler/react-compiler\n // eslint-disable-next-line react-hooks/rules-of-hooks\n return useLiveQueryImpl<T>(query, params)\n}\n\nexport function useLiveIncrementalQuery<T = { [key: string]: unknown }>(\n query: string,\n params: unknown[] | undefined | null,\n key: string,\n): LiveQueryResults<T> | undefined {\n return useLiveQueryImpl<T>(query, params, key)\n}\n"],"mappings":"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","names":["src_exports","__export","PGliteProvider","makePGliteProvider","useLiveIncrementalQuery","useLiveQuery","usePGlite","__toCommonJS","import_react","import_jsx_runtime","makePGliteProvider","ctx","db","dbProvided","children","PGliteProvider","usePGlite","import_template","import_react","paramsEqual","a1","a2","i","useLiveQueryImpl","query","params","key","db","usePGlite","paramsRef","liveQueryRef","liveQuery","liveQueryChanged","results","setResults","currentParams","cancelled","cb","ret","unsubscribe","useLiveQuery","strings","values","buildQuery","useLiveIncrementalQuery"]}