@idb-orm/react-query 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > ## THIS PACKAGE IS BRAND-NEW AND UNSTABLE. DO NOT USE
4
4
 
5
- A React adapter for [Tanstack's Query library](https://tanstack.com/query/latest) for @idb-orm. It essentially offers easy to use shortcuts to manage querying idb-orm data and caching.
5
+ A React adapter for [Tanstack's Query library](https://tanstack.com/query/latest) for @idb-orm. It essentially offers easy to use shortcuts to manage querying idb-orm data and caching. This package is an extension of `@idb-orm/react`.
6
6
 
7
7
  ## Example
8
8
 
@@ -36,18 +36,30 @@ npm i @idb-orm/react-query
36
36
 
37
37
  ## Getting Started
38
38
 
39
- Define your @idb-orm schema in any file. Then, create the provider and client object like so:
39
+ Define your @idb-orm schema in any file. Then, call the factory function. This function will create a React Context, a Provider component for the context, and a series of hooks used to access the context's value.
40
40
 
41
41
  ```tsx
42
42
  // idb-query.ts
43
43
 
44
- import { createIDBClient } from "@idb-orm/react-query";
45
-
46
- // File that creates the @idb-orm database client
47
- import { client } from "./db-client";
48
-
49
- const { queryClient, Provider, stores } = createIDBQueryClient(client);
50
- export { queryClient, Provider, stores };
44
+ import { queryClientProviderFactory } from "@idb-orm/react-query";
45
+
46
+ // File that creates the @idb-orm database
47
+ import { db } from "./db";
48
+
49
+ export const {
50
+ // Primitive React Context object
51
+ Context,
52
+ // Hook to acquire the IDB-ORM client object
53
+ useDbClient,
54
+ // Hook to acquire the Tanstack-Query QueryClient object
55
+ useQueryClient,
56
+ // Hook to acquire the auto-generated query functions.
57
+ useQueryInterface,
58
+ // Hook to acquire the contents of the 3 hooks above in one.
59
+ useIDBQuery,
60
+ // Provider that will allow the above hooks to function and populate the context.
61
+ DbClientProvider,
62
+ } = queryClientProviderFactory(db);
51
63
  ```
52
64
 
53
65
  Then, in your project's root, wrap your application in the provider:
@@ -55,52 +67,62 @@ Then, in your project's root, wrap your application in the provider:
55
67
  ```tsx
56
68
  // App.tsx
57
69
 
58
- import { Provider, queryClient } from "./idb-query";
70
+ import { DbClientProvider } from "./idb-query";
59
71
 
60
72
  function App(){
61
73
  return (
62
- <Provider client={queryClient}>
74
+ <DbClientProvider version={2} fallback={<>Waiting for client creation...</>}>
63
75
  {/* Appliation */}
64
- <Provider>
76
+ <DbClientProvider>
65
77
  )
66
78
  }
67
79
  ```
68
80
 
81
+ The fallback prop is an optional prop you can give to the provider to render while the client is building. Building the `@idb-orm` client is an asynchronous operation, so while that is being done its children are not rendered. This may be changed in a future update.
82
+
69
83
  ## Usage
70
84
 
71
85
  Anywhere inside a component, you can call one of three hooks for each store:
72
86
 
73
87
  ```ts
74
- // Will find all documents that matches the filter/selector
75
- stores.users.useFind({
76
- query: {
77
- /* Selector Object */
78
- },
79
- /* Additional options */
80
- });
81
-
82
- // Will find the first document that matches the filter/selector
83
- stores.users.useFindFirst({
84
- query: {
85
- /* Selector Object */
86
- },
87
- /* Additional options */
88
- });
88
+ import { useQueryInterface } from "./idb-query";
89
+
90
+ function MyComponent(){
91
+ const stores = useQueryInterface();
92
+
93
+ // Will find all documents that matches the filter/selector
94
+ stores.users.useFind({
95
+ query: {
96
+ /* Selector Object */
97
+ },
98
+ /* Additional options */
99
+ });
100
+
101
+ // Will find the first document that matches the filter/selector
102
+ stores.users.useFindFirst({
103
+ query: {
104
+ /* Selector Object */
105
+ },
106
+ /* Additional options */
107
+ });
108
+
109
+ // Will find the first document that matches the filter/selector
110
+ stores.users.useGet({
111
+ key: /* Primary Key */
112
+ /* Additional options */
113
+ });
114
+
115
+ return <>My Favorite Component</>
116
+ }
89
117
 
90
- // Will find the first document that matches the filter/selector
91
- stores.users.useGet({
92
- key: /* Primary Key */
93
- /* Additional options */
94
- });
95
118
  ```
96
119
 
97
120
  These hooks return the same type as the result of the Tanstack [useQuery](https://tanstack.com/query/latest/docs/framework/react/reference/useQuery) hook. Check out their documentation for more information as well as additional options.
98
121
 
99
122
  Some things to note:
100
123
 
101
- - Fields passed into the `query` key of a hook input will be used to determine query invalidation. These query objects are serialized into JSON by Tanstack, so any TS/JS types that are not serializable into JSON (functions, files, undefined) will be omitted from the serialized representation. So if any of these types of values change, the query will **NOT** be automatically invalidated.
102
- - The `stores` field should be exported for use throughout your app. That is what provides the shortcut functions for each store.
103
- - The provider component already has the Tanstack `QueryClientProvider` included!
124
+ - Fields passed into the `query` key of a hook input will be used to determine query invalidation. These query objects are serialized into JSON by Tanstack, so any TS/JS types that are not serializable into JSON (functions, files, undefined) will be omitted from the serialized representation. So if any of these types of values change, the query will **NOT** be automatically invalidated.
125
+ - The `DbClientProvider` component already has the Tanstack `QueryClientProvider` included, you do not need to add another!
104
126
 
105
127
  ## Disclaimer
106
128
 
package/dist/index.cjs.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@tanstack/react-query"),t=require("react");class r extends e.QueryClient{constructor(e,t){super(t),this.db=e}createInterface(r){const n={},i=this.db.getStoreNames(),o=this.db.stores;for(const t of i)n[t]={useFind:(r,n=[])=>e.useQuery({...r,queryKey:[t,"find",r.query,...n],queryFn:()=>o[t].find(r.query)}),useFindFirst:(r,n=[])=>e.useQuery({...r,queryKey:[t,"findFirst",r.query,...n],queryFn:()=>o[t].findFirst(r.query)}),useGet:(r,n=[])=>{e.useQuery({...r,queryKey:[t,"get",r.key,...n],queryFn:()=>o[t].get(r.key)})}};return{...n,useClient:()=>{const e=t.useContext(r);if(!e)throw new Error("Query Context Not Found. Make sure you wrap your application in the <Provider/> Component.");return e}}}}exports.createIDBQueryClient=function(n,i){const o=new r(n,i),u=t.createContext({});return{queryClient:o,context:u,Provider:({client:r,children:n})=>{const i=t.useMemo(()=>{function e(e){return{invalidate:()=>r.invalidateQueries({queryKey:e})}}const t=e([]),n=r.db.getStoreNames();for(const r of n)"invalidate"===r&&console.warn("Model name 'invalidate' causes the invalidate() function of useClient() to not work. Please fix by renaming the model."),t[r]={...e([r]),get:e([r,"get"]),find:e([r,"find"]),findFirst:e([r,"findFirst"])};return t},[r]);return t.createElement(e.QueryClientProvider,{client:r},t.createElement(u.Provider,{value:i},n))},stores:o.createInterface(u)}};
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@tanstack/react-query"),t=require("react"),r="Query Client Context not found. Please ensure this component is wrapped in a <DbClientProvider /> component.";class n extends e.QueryClient{constructor(e,t){super(t),this.db=e}createInterface(r){const n={},o=this.db.getStoreNames(),i=this.db.stores;for(const t of o)n[t]={useFind:(r,n=[])=>e.useQuery({...r,queryKey:[t,"find",r.query,...n],queryFn:()=>i[t].find(r.query)}),useFindFirst:(r,n=[])=>e.useQuery({...r,queryKey:[t,"findFirst",r.query,...n],queryFn:()=>i[t].findFirst(r.query)}),useGet:(r,n=[])=>{e.useQuery({...r,queryKey:[t,"get",r.key,...n],queryFn:()=>i[t].get(r.key)})}};return{...n,useClient:()=>{const e=t.useContext(r);if(!e)throw new Error("Query Context Not Found. Make sure you wrap your application in the <Provider/> Component.");return e}}}}exports.IDBQueryClient=n,exports.queryClientProviderFactory=function(o,i){const u=t.createContext(null);return{Context:u,useDbClient:()=>{const e=t.useContext(u);if(!e)throw new Error(r);return e.client},useQueryClient:()=>{const e=t.useContext(u);if(!e)throw new Error(r);return e.queryClient},useQueryInterface:()=>{const e=t.useContext(u);if(!e)throw new Error(r);return e.stores},useIDBQuery:()=>{const e=t.useContext(u);if(!e)throw new Error(r);return e},DbClientProvider:({fallback:r,children:s,version:a})=>{const[c,l]=t.useState(null);return t.useEffect(()=>{o.createClientAsync(a).then(e=>{const t=new n(e,i);function r(e){return{invalidate:()=>t.invalidateQueries({queryKey:e})}}const o=r([]),u=t.db.getStoreNames();for(const n of u)"invalidate"===n&&console.warn("Model name 'invalidate' causes the invalidate() function of useClient() to not work. Please fix by renaming the model."),o[n]={...r([n]),get:r([n,"get"]),find:r([n,"find"]),findFirst:r([n,"findFirst"])};l({client:e,queryClient:t,stores:o})}).catch(e=>{throw new Error(`@idb-orm Query Client Creation Failed: ${e}`)})},[a]),c?t.createElement(e.QueryClientProvider,{client:c.queryClient},t.createElement(u.Provider,{value:c},s)):r}}};
package/dist/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { core, Model } from '@idb-orm/core';
2
2
  import { QueryClient, DefinedUseQueryResult, UndefinedInitialDataOptions, QueryClientConfig } from '@tanstack/react-query';
3
- import { default as React } from 'react';
4
- interface QueryOptions<O> extends Omit<UndefinedInitialDataOptions<O>, "queryFn" | "queryKey"> {
3
+ import { default as React, Context, PropsWithChildren, ReactNode } from 'react';
4
+ import { ClientProviderProps } from '@idb-orm/react';
5
+ export interface QueryOptions<O> extends Omit<UndefinedInitialDataOptions<O>, "queryFn" | "queryKey"> {
5
6
  }
6
- interface ModelQueryInterface<Name extends Names, Names extends string, Models extends core.CollectionObject<Names>> {
7
+ export interface ModelQueryInterface<Name extends Names, Names extends string, Models extends core.CollectionObject<Names>> {
7
8
  /**
8
9
  * Query instance on a particular primary key. This query will acquire **only** the given document and no related documents.
9
10
  */
@@ -17,7 +18,7 @@ interface ModelQueryInterface<Name extends Names, Names extends string, Models e
17
18
  query: I;
18
19
  }, deps?: React.DependencyList) => DefinedUseQueryResult<O | undefined>;
19
20
  }
20
- interface ModelQueryClient {
21
+ export interface ModelQueryClient {
21
22
  invalidate(): Promise<void>;
22
23
  }
23
24
  type IDBClientInterface<Names extends string, _Models extends core.CollectionObject<Names>> = core.Simplify<{
@@ -27,21 +28,21 @@ type IDBClientInterface<Names extends string, _Models extends core.CollectionObj
27
28
  find: ModelQueryClient;
28
29
  } & core.Simplify<ModelQueryClient>;
29
30
  } & ModelQueryClient>;
30
- export declare function createIDBQueryClient<Names extends string, Models extends core.CollectionObject<Names>>(client: core.DbClient<string, Names, Models>, config?: QueryClientConfig): {
31
- queryClient: IDBQueryClient<Names, Models>;
32
- context: React.Context<{ [K_1 in Names]: {
33
- get: ModelQueryClient;
34
- findFirst: ModelQueryClient;
35
- find: ModelQueryClient;
36
- } & {
37
- invalidate: () => Promise<void>;
38
- }; } & ModelQueryClient extends infer T ? { [K in keyof T]: T[K]; } : never>;
39
- Provider: ({ client, children, }: React.PropsWithChildren<{
40
- client: IDBQueryClient<Names, Models>;
41
- }>) => React.JSX.Element;
42
- stores: IDBQueryInterface<Names, Models>;
43
- };
44
- declare class IDBQueryClient<Names extends string, Models extends core.CollectionObject<Names>> extends QueryClient {
31
+ export interface UseQueryClientReturn<Name extends string, ModelNames extends string, Models extends core.CollectionObject<ModelNames>> {
32
+ client: core.DbClient<Name, ModelNames, Models>;
33
+ queryClient: IDBQueryClient<ModelNames, Models>;
34
+ stores: IDBClientInterface<ModelNames, Models>;
35
+ }
36
+ export interface QueryClientProviderFactoryReturn<Name extends string, ModelNames extends string, Models extends core.CollectionObject<ModelNames>> {
37
+ Context: Context<UseQueryClientReturn<Name, ModelNames, Models> | null>;
38
+ useDbClient: () => core.DbClient<Name, ModelNames, Models>;
39
+ useQueryClient: () => IDBQueryClient<ModelNames, Models>;
40
+ useQueryInterface: () => IDBClientInterface<ModelNames, Models>;
41
+ useIDBQuery: () => UseQueryClientReturn<Name, ModelNames, Models>;
42
+ DbClientProvider: (props: PropsWithChildren<ClientProviderProps>) => ReactNode;
43
+ }
44
+ export declare function queryClientProviderFactory<Name extends string, ModelNames extends string, Models extends core.CollectionObject<ModelNames>>(db: core.CompiledDb<Name, ModelNames, Models>, config?: QueryClientConfig): QueryClientProviderFactoryReturn<Name, ModelNames, Models>;
45
+ export declare class IDBQueryClient<Names extends string, Models extends core.CollectionObject<Names>> extends QueryClient {
45
46
  readonly db: core.DbClient<string, Names, Models>;
46
47
  constructor(db: core.DbClient<string, Names, Models>, config?: QueryClientConfig);
47
48
  createInterface(context: React.Context<IDBClientInterface<Names, Models>>): IDBQueryInterface<Names, Models>;
package/dist/index.es.js CHANGED
@@ -1,2 +1 @@
1
- import{QueryClientProvider as e,QueryClient as t,useQuery as r}from"@tanstack/react-query";import n from"react";function o(t,r){const o=new i(t,r),s=n.createContext({});return{queryClient:o,context:s,Provider:({client:t,children:r})=>{const o=n.useMemo(()=>{function e(e){return{invalidate:()=>t.invalidateQueries({queryKey:e})}}const r=e([]),n=t.db.getStoreNames();for(const t of n)"invalidate"===t&&console.warn("Model name 'invalidate' causes the invalidate() function of useClient() to not work. Please fix by renaming the model."),r[t]={...e([t]),get:e([t,"get"]),find:e([t,"find"]),findFirst:e([t,"findFirst"])};return r},[t]);/* @__PURE__ */
2
- return n.createElement(e,{client:t},/* @__PURE__ */n.createElement(s.Provider,{value:o},r))},stores:o.createInterface(s)}}class i extends t{constructor(e,t){super(t),this.db=e}createInterface(e){const t={},o=this.db.getStoreNames(),i=this.db.stores;for(const n of o)t[n]={useFind:(e,t=[])=>r({...e,queryKey:[n,"find",e.query,...t],queryFn:()=>i[n].find(e.query)}),useFindFirst:(e,t=[])=>r({...e,queryKey:[n,"findFirst",e.query,...t],queryFn:()=>i[n].findFirst(e.query)}),useGet:(e,t=[])=>{r({...e,queryKey:[n,"get",e.key,...t],queryFn:()=>i[n].get(e.key)})}};return{...t,useClient:()=>{const t=n.useContext(e);if(!t)throw new Error("Query Context Not Found. Make sure you wrap your application in the <Provider/> Component.");return t}}}}export{o as createIDBQueryClient};
1
+ import{QueryClientProvider as e,QueryClient as r,useQuery as t}from"@tanstack/react-query";import n,{createContext as o,useState as i,useEffect as s,useContext as u}from"react";const a="Query Client Context not found. Please ensure this component is wrapped in a <DbClientProvider /> component.";function c(r,t){const c=o(null);return{Context:c,useDbClient:()=>{const e=u(c);if(!e)throw new Error(a);return e.client},useQueryClient:()=>{const e=u(c);if(!e)throw new Error(a);return e.queryClient},useQueryInterface:()=>{const e=u(c);if(!e)throw new Error(a);return e.stores},useIDBQuery:()=>{const e=u(c);if(!e)throw new Error(a);return e},DbClientProvider:({fallback:o,children:u,version:a})=>{const[d,y]=i(null);return s(()=>{r.createClientAsync(a).then(e=>{const r=new l(e,t);function n(e){return{invalidate:()=>r.invalidateQueries({queryKey:e})}}const o=n([]),i=r.db.getStoreNames();for(const t of i)"invalidate"===t&&console.warn("Model name 'invalidate' causes the invalidate() function of useClient() to not work. Please fix by renaming the model."),o[t]={...n([t]),get:n([t,"get"]),find:n([t,"find"]),findFirst:n([t,"findFirst"])};y({client:e,queryClient:r,stores:o})}).catch(e=>{throw new Error(`@idb-orm Query Client Creation Failed: ${e}`)})},[a]),d?/* @__PURE__ */n.createElement(e,{client:d.queryClient},/* @__PURE__ */n.createElement(c.Provider,{value:d},u)):o}}}class l extends r{constructor(e,r){super(r),this.db=e}createInterface(e){const r={},o=this.db.getStoreNames(),i=this.db.stores;for(const n of o)r[n]={useFind:(e,r=[])=>t({...e,queryKey:[n,"find",e.query,...r],queryFn:()=>i[n].find(e.query)}),useFindFirst:(e,r=[])=>t({...e,queryKey:[n,"findFirst",e.query,...r],queryFn:()=>i[n].findFirst(e.query)}),useGet:(e,r=[])=>{t({...e,queryKey:[n,"get",e.key,...r],queryFn:()=>i[n].get(e.key)})}};return{...r,useClient:()=>{const r=n.useContext(e);if(!r)throw new Error("Query Context Not Found. Make sure you wrap your application in the <Provider/> Component.");return r}}}}export{l as IDBQueryClient,c as queryClientProviderFactory};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idb-orm/react-query",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "An adapter for the Tanstack React-Query library for @idb-orm",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -25,6 +25,7 @@
25
25
  "peerDependencies": {
26
26
  "@idb-orm/core": "^1.0.7",
27
27
  "@tanstack/react-query": "^5.90.11",
28
+ "@idb-orm/react": "^0.0.1",
28
29
  "react": "^19.2.0"
29
30
  },
30
31
  "devDependencies": {