asasvirtuais 1.1.1 → 2.0.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "asasvirtuais",
3
3
  "type": "module",
4
- "version": "1.1.1",
4
+ "version": "2.0.0",
5
5
  "description": "React form and action management utilities",
6
6
  "directories": {
7
7
  "packages": "./packages"
@@ -80,7 +80,7 @@ export function useIndex<T>(value: Record<string, any>) {
80
80
  }))
81
81
  }, [])
82
82
 
83
- const remove = useCallback((...params: readable[]) => {
83
+ const unset = useCallback((...params: readable[]) => {
84
84
  setIndex(prev => {
85
85
  const newState = { ...prev }
86
86
  for (const data of params) {
@@ -97,7 +97,7 @@ export function useIndex<T>(value: Record<string, any>) {
97
97
  array,
98
98
  set,
99
99
  setIndex,
100
- remove,
100
+ unset,
101
101
  }
102
102
  }
103
103
 
@@ -8,12 +8,14 @@ export interface TableInterface<Readable, Writable = Readable> {
8
8
  list (props: ListProps<Readable>) : Promise<Readable[]>
9
9
  }
10
10
 
11
- export function tableInterface<Schema extends DatabaseInterface, Table extends keyof Schema & string>(schema: Schema, table?: Table | null, tableInterface?: TableInterface<z.infer<Schema[Table]['readable']>, z.infer<Schema[Table]['writable']>>) {
11
+ export function tableInterface<Schema extends DatabaseSchema, Table extends keyof Schema & string>(schema: Schema, table?: Table | null, tableInterface?: TableInterface<z.infer<Schema[Table]['readable']>, z.infer<Schema[Table]['writable']>>) {
12
12
  return tableInterface
13
13
  }
14
14
 
15
- export interface DatabaseInterface {
16
- [T: string]: { readable: z.ZodObject<z.ZodRawShape>, writable: z.ZodObject<z.ZodRawShape> }
15
+ export interface TableSchema { readable: z.ZodObject<z.ZodRawShape>, writable: z.ZodObject<z.ZodRawShape> }
16
+
17
+ export interface DatabaseSchema {
18
+ [T: string]: TableSchema
17
19
  }
18
20
 
19
21
  export type BasicOperators<T, K extends keyof T> = {
@@ -1,394 +1,315 @@
1
- import { z } from 'zod'
2
- import {
3
- useState,
4
- useCallback,
5
- useEffect,
6
- useMemo,
7
- createContext,
8
- useContext,
9
- } from 'react'
10
- import { useAction as useAsyncAction, useIndex } from './hooks'
1
+ import z from 'zod'
2
+ import { DatabaseSchema, ListProps, TableInterface, TableSchema } from './interface'
3
+ import { createContextFromHook, useAction as useAsyncAction, useIndex } from './hooks'
4
+ import { createContext, PropsWithChildren, useCallback, useContext, useEffect, useState } from 'react'
11
5
  import { ActionProvider, useAction, useActionProvider } from './action'
12
- import { TableInterface, ListProps, DatabaseInterface } from './interface'
13
6
  import { FieldsProvider, useFields } from './fields'
14
7
 
15
- export function reactInterface<
16
- Database extends DatabaseInterface>(
17
- database: Database,
18
- {
19
- find,
20
- create,
21
- update,
22
- remove,
23
- list,
24
- }: TableInterface<
25
- z.infer<Database[keyof Database]['readable']>,
26
- z.infer<Database[keyof Database]['writable']>
27
- >
28
- ) {
29
- type TableKey = keyof Database & string
30
-
31
- type TableProviderProps<Table extends TableKey> = {
32
- table: Table
33
- asAbove?: Record<string, z.infer<Database[Table]["readable"]>>
34
- }
35
-
36
- function useTableProvider<Table extends TableKey>({
37
- table,
38
- asAbove,
39
- }: TableProviderProps<Table>) {
40
- type Readable = z.infer<Database[Table]['readable']>
41
- type Writable = z.infer<Database[Table]['writable']>
42
-
43
- const index = useIndex<Readable>({ ...(asAbove ?? {}) })
8
+ export function useDatabaseProvider() {
44
9
 
45
- const array = useMemo(
46
- () => Object.values(index.index) as Readable[],
47
- [index.index]
48
- )
49
-
50
- useEffect(function soBelow() {
51
- index.setIndex((prev) => ({ ...prev, ...asAbove }))
52
- }, [])
53
-
54
- const methods = { find, create, update, remove, list } as TableInterface<
55
- Readable,
56
- Writable
57
- >
10
+ const [database, setDatabase] = useState<Record<string, ReturnType<typeof useInterface<any>>>>({})
58
11
 
59
12
  return {
60
- ...index,
61
- array,
62
- find: useAsyncAction(((props) => methods.find({ ...props, table }).then(res => {
63
- index.set(res)
64
- return res
65
- })) as typeof find),
66
- create: useAsyncAction(((props) => create({ ...props, table }).then(res => {
67
- index.set(res)
68
- return res
69
- })) as typeof create),
70
- update: useAsyncAction(((props) => update({ ...props, table }).then(res => {
71
- index.set(res)
72
- return res
73
- })) as typeof update),
74
- remove: useAsyncAction(((props) => remove({ ...props, table }).then(res => {
75
- index.remove(res)
76
- return res
77
- })) as typeof remove),
78
- list: useAsyncAction(((props) => list({ ...props, table }).then(arr => {
79
- index.set(...arr)
80
- return arr
81
- })) as typeof list),
13
+ database,
14
+ setDatabase,
82
15
  }
83
- }
84
-
85
- function useDatabaseProvider(tables: { [T in TableKey]: Record<string, z.infer<Database[T]['readable']>> }): {
86
- [T in TableKey]: ReturnType<typeof useTableProvider<T>>
87
- } {
88
- return Object.fromEntries(
89
- Object.entries(tables).map(([table, value]) => [
90
- table, useTableProvider({ table: table as TableKey, asAbove: value })
91
- ])
92
- ) as {
93
- [T in TableKey]: ReturnType<typeof useTableProvider<T>>
94
- }
95
- }
96
- // Create a separate context for each table dynamically
97
- const tableContexts = new Map<TableKey, React.Context<ReturnType<typeof useTableProvider<any>> | undefined>>();
98
-
99
- function getTableContext<T extends TableKey>(table: T) {
100
- if (!tableContexts.has(table)) {
101
- tableContexts.set(table, createContext<ReturnType<typeof useTableProvider<T>> | undefined>(undefined));
102
- }
103
- return tableContexts.get(table)!;
104
- }
16
+ }
105
17
 
106
- function TableProvider<Table extends TableKey>({ children, ...props }: TableProviderProps<Table> & {
107
- children: React.ReactNode | ((props: ReturnType<typeof useTableProvider<Table>>) => React.ReactNode)
108
- }) {
109
- const context = useTableProvider(props);
110
- const TableContext = getTableContext(props.table);
18
+ export const [DatabaseProvider, useDatabase] = createContextFromHook(useDatabaseProvider)
111
19
 
112
- return (
113
- <TableContext.Provider value={context}>
114
- {typeof children === 'function' ? children(context) : children}
115
- </TableContext.Provider>
116
- )
117
- }
20
+ export function useDatabaseTable<TSchema extends TableSchema>(table: string) {
21
+ const { database } = useDatabase()
118
22
 
119
- function DatabaseProvider({
120
- children,
121
- ...tables
122
- }: React.PropsWithChildren<{
123
- [T in TableKey]?: Record<string, z.infer<Database[T]['readable']>>
124
- }>) {
125
- return Object.entries(tables).reduce(
126
- (prev, [table, asAbove]) => {
127
- return (
128
- <TableProvider table={table as TableKey} asAbove={asAbove}>
129
- {prev}
130
- </TableProvider>
131
- );
132
- },
133
- children as React.ReactNode
134
- )
135
- }
23
+ const tableMethods = database[table] as ReturnType<typeof useInterface<TSchema>> | undefined
136
24
 
137
- function useTable<T extends TableKey>(name: T) {
138
- const TableContext = getTableContext(name);
139
- const context = useContext(TableContext);
25
+ if (!tableMethods)
26
+ throw new Error(`Table "${table}" is not defined in the database schema.`)
140
27
 
141
- if (!context) {
142
- throw new Error(`useTable("${String(name)}") must be used within a TableProvider or DatabaseProvider with table="${String(name)}"`);
143
- }
28
+ return tableMethods
29
+ }
144
30
 
145
- return context as ReturnType<typeof useTableProvider<T>>;
146
- }
31
+ export type TableProviderProps<TSchema extends TableSchema> = {
32
+ table: string
33
+ schema: TSchema
34
+ interface: TableInterface<z.infer<TSchema['readable']>, z.infer<TSchema['writable']>>
35
+ asAbove?: Record<string, z.infer<TSchema['readable']>>
36
+ }
147
37
 
148
- function useSingleProvider<Table extends TableKey>({
149
- id,
150
- table,
151
- }: {
152
- id: string
153
- table: Table
154
- }) {
155
- const { index, find } = useTable(table)
156
- const [single, setSingle] = useState<z.infer<Database[Table]['readable']>>(
157
- () => index[id]
158
- )
159
- useEffect(() => {
160
- if (!single) find.trigger({ id }).then(setSingle)
161
- }, [])
162
- useEffect(() => {
163
- setSingle(index[id])
164
- }, [index[id]])
38
+ export function useInterface<TSchema extends TableSchema>(table: string, {
39
+ find, create, update, remove, list
40
+ }: TableInterface<z.infer<TSchema['readable']>, z.infer<TSchema['writable']>>, index: ReturnType<typeof useIndex<z.infer<TSchema['readable']>>>) {
165
41
  return {
166
- id,
167
- single,
168
- setSingle,
169
- loading: find.loading,
42
+ index,
43
+ find: useAsyncAction(((props) => find({ ...props, table }).then(res => {
44
+ index.set(res)
45
+ return res
46
+ })) as typeof find),
47
+ create: useAsyncAction(((props) => create({ ...props, table }).then(res => {
48
+ index.set(res)
49
+ return res
50
+ })) as typeof create),
51
+ update: useAsyncAction(((props) => update({ ...props, table }).then(res => {
52
+ index.set(res)
53
+ return res
54
+ })) as typeof update),
55
+ remove: useAsyncAction(((props) => remove({ ...props, table }).then(res => {
56
+ index.unset(res)
57
+ return res
58
+ })) as typeof remove),
59
+ list: useAsyncAction(((props) => list({ ...props, table }).then(arr => {
60
+ index.set(...arr)
61
+ return arr
62
+ })) as typeof list),
170
63
  }
171
- }
64
+ }
172
65
 
173
- const SingleContext = createContext<
174
- ReturnType<typeof useSingleProvider<any>> | undefined
175
- >(undefined)
66
+ export function useTableProvider<TSchema extends TableSchema>({
67
+ table,
68
+ schema,
69
+ interface: tableInterface,
70
+ asAbove,
71
+ }: TableProviderProps<TSchema>) {
176
72
 
177
- function SingleProvider<Table extends TableKey>({
178
- children,
179
- ...props
180
- }: {
181
- id: string
182
- table: Table
183
- children: React.ReactNode | ((props: ReturnType<typeof useSingleProvider<Table>>) => React.ReactNode)
184
- }) {
185
- const value = useSingleProvider(props)
186
- if (!value.single) return null
187
- return (
188
- <SingleContext.Provider value={value}>
189
- {typeof children === 'function' ? (
190
- children(value)
191
- ) : (
192
- children
193
- )}
194
- </SingleContext.Provider>
195
- )
196
- }
73
+ type Readable = z.infer<TableSchema['readable']>
197
74
 
198
- const useSingle = <Table extends TableKey>(table: Table) =>
199
- useContext(SingleContext) as ReturnType<typeof useSingleProvider<Table>>
75
+ const index = useIndex<Readable>({ ...(asAbove ?? {}) })
200
76
 
201
- function CreateForm<
202
- T extends TableKey
203
- >({
204
- table,
205
- defaults,
206
- onSuccess,
207
- children,
208
- }: {
209
- table: T
210
- defaults?: Partial<z.infer<Database[T]['writable']>>
211
- onSuccess?: (result: z.infer<Database[T]['readable']>) => void
77
+ useEffect(function soBelow() {
78
+ index.setIndex((prev) => ({ ...prev, ...asAbove }))
79
+ }, [])
80
+
81
+ return useInterface<TSchema>(table, tableInterface, index)
82
+ }
83
+
84
+ export const [TableContextProvider, useTableContext] = createContextFromHook(useTableProvider<any>)
85
+
86
+ export function TableProvider<TSchema extends TableSchema>({ children, ...props }: PropsWithChildren<TableProviderProps<TSchema>>) {
87
+ return <TableContextProvider {...props}>{children}</TableContextProvider>
88
+ }
89
+
90
+ export function useTable<TSchema extends TableSchema>() {
91
+ return useTableContext() as ReturnType<typeof useTableProvider<TSchema>>
92
+ }
93
+
94
+ export function CreateForm<TSchema extends TableSchema>({ table, defaults, onSuccess, children }: {
95
+ table: string
96
+ schema: TSchema
97
+ defaults?: Partial<z.infer<TSchema['writable']>>
98
+ onSuccess?: (result: z.infer<TSchema['readable']>) => void
212
99
  children: React.ReactNode | (
213
- ( props: ReturnType<typeof useActionProvider<z.infer<Database[T]['writable']>, z.infer<Database[T]['readable']>>>
214
- & ReturnType<typeof useFields<z.infer<Database[T]['writable']>>>
215
- ) => React.ReactNode
100
+ (props: ReturnType<typeof useActionProvider<z.infer<TSchema['writable']>, z.infer<TSchema['readable']>>>
101
+ & ReturnType<typeof useFields<z.infer<TSchema['writable']>>>
102
+ ) => React.ReactNode
216
103
  )
217
- }) {
218
- type Readable = z.infer<Database[T]['readable']>
219
- type Writable = z.infer<Database[T]['writable']>
104
+ }) {
105
+ type Readable = z.infer<TSchema['readable']>
106
+ type Writable = z.infer<TSchema['writable']>
220
107
 
221
- const { create } = useTable(table)
108
+ const { create } = useDatabaseTable(table)
222
109
 
223
110
  const callback = useCallback(
224
- async (fields: Writable) => {
225
- const result = await create.trigger({ data: fields })
226
- if (onSuccess) onSuccess(result as Readable)
227
- return result
228
- },
229
- [create, onSuccess]
111
+ async (fields: Writable) => {
112
+ const result = await create.trigger({ data: fields })
113
+ if (onSuccess) onSuccess(result as Readable)
114
+ return result
115
+ },
116
+ [create, onSuccess]
230
117
  )
231
118
 
232
119
  return (
233
- <FieldsProvider<Writable> defaults={defaults || ({} as Writable)}>
234
- {fields => (
235
- <ActionProvider<Writable, Readable> action={callback} params={fields.fields}>
236
- {typeof children === 'function' ? (
237
- form => children({ ...form, ...fields })
238
- ) : (
239
- children
120
+ <FieldsProvider<Writable> defaults={defaults || ({} as Writable)}>
121
+ {fields => (
122
+ <ActionProvider<Writable, Readable> action={callback} params={fields.fields}>
123
+ {typeof children === 'function' ? (
124
+ form => children({ ...form, ...fields })
125
+ ) : (
126
+ children
127
+ )}
128
+ </ActionProvider>
240
129
  )}
241
- </ActionProvider>
242
- )}
243
- </FieldsProvider>
130
+ </FieldsProvider>
244
131
  )
245
- }
132
+ }
246
133
 
247
- function UpdateForm<T extends TableKey>({
134
+ export function UpdateForm<TSchema extends TableSchema>({
135
+ schema,
248
136
  table,
249
137
  id,
250
138
  defaults,
251
139
  onSuccess,
252
140
  children,
253
- }: {
254
- table: T
141
+ }: {
142
+ schema: TSchema
143
+ table: string
255
144
  id: string
256
- defaults?: Partial<z.infer<Database[T]['writable']>>
257
- onSuccess?: (result: z.infer<Database[T]['readable']>) => void
145
+ defaults?: Partial<z.infer<TSchema['writable']>>
146
+ onSuccess?: (result: z.infer<TSchema['readable']>) => void
258
147
  children: React.ReactNode | (
259
- (props: ReturnType<typeof useActionProvider<Partial<z.infer<Database[T]['writable']>>, z.infer<Database[T]['readable']>>>
260
- & ReturnType<typeof useFields<z.infer<Database[T]['writable']>>>
261
- ) => React.ReactNode
148
+ (props: ReturnType<typeof useActionProvider<Partial<z.infer<TSchema['writable']>>, z.infer<TSchema['readable']>>>
149
+ & ReturnType<typeof useFields<z.infer<TSchema['writable']>>>
150
+ ) => React.ReactNode
262
151
  )
263
- }) {
264
- type Readable = z.infer<Database[T]['readable']>
265
- type Writable = z.infer<Database[T]['writable']>
152
+ }) {
153
+ type Readable = z.infer<TSchema['readable']>
154
+ type Writable = z.infer<TSchema['writable']>
266
155
 
267
- const { update } = useTable(table)
156
+ const { update } = useDatabaseTable(table)
268
157
 
269
158
  const callback = useCallback(
270
- async (fields: Partial<Writable>) => {
271
- const result = await update.trigger({ id, data: fields })
272
- if (onSuccess) onSuccess(result as Readable)
273
- return result
274
- },
275
- [update, id, onSuccess]
159
+ async (fields: Partial<Writable>) => {
160
+ const result = await update.trigger({ id, data: fields })
161
+ if (onSuccess) onSuccess(result as Readable)
162
+ return result
163
+ },
164
+ [update, id, onSuccess]
276
165
  )
277
166
 
278
167
  return (
279
- <FieldsProvider<Writable>
280
- defaults={defaults || ({} as Partial<Writable>)}
281
- >
282
- {fields => (
283
- <ActionProvider<Partial<Writable>, Readable> action={callback} params={fields.fields}>
284
- {typeof children === 'function' ? (
285
- form => children({ ...form, ...fields })
286
- ) : (
287
- children
168
+ <FieldsProvider<Writable>
169
+ defaults={defaults || ({} as Partial<Writable>)}
170
+ >
171
+ {fields => (
172
+ <ActionProvider<Partial<Writable>, Readable> action={callback} params={fields.fields}>
173
+ {typeof children === 'function' ? (
174
+ form => children({ ...form, ...fields })
175
+ ) : (
176
+ children
177
+ )}
178
+ </ActionProvider>
288
179
  )}
289
- </ActionProvider>
290
- )}
291
- </FieldsProvider>
180
+ </FieldsProvider>
292
181
  )
293
- }
182
+ }
294
183
 
295
- function FilterForm<T extends TableKey>({
184
+ export function FilterForm<TSchema extends TableSchema>({
185
+ schema,
296
186
  table,
297
187
  defaults,
298
188
  onSuccess,
299
189
  children,
300
- }: {
301
- table: T
302
- defaults?: Partial<ListProps<z.infer<Database[T]['readable']>>>
303
- onSuccess?: (result: z.infer<Database[T]['readable']>[]) => void
190
+ }: {
191
+ schema: TSchema
192
+ table: string
193
+ defaults?: Partial<ListProps<z.infer<TSchema['readable']>>>
194
+ onSuccess?: (result: z.infer<TSchema['readable']>[]) => void
304
195
  children: React.ReactNode | (
305
- ( props: ReturnType<typeof useActionProvider<ListProps<z.infer<Database[T]['readable']>>, z.infer<Database[T]['readable']>[]>>
306
- & ReturnType<typeof useFields<ListProps<z.infer<Database[T]['readable']>>>>
307
- ) => React.ReactNode
196
+ (props: ReturnType<typeof useActionProvider<ListProps<z.infer<TSchema['readable']>>, z.infer<TSchema['readable']>[]>>
197
+ & ReturnType<typeof useFields<ListProps<z.infer<TSchema['readable']>>>>
198
+ ) => React.ReactNode
308
199
  )
309
- }) {
310
- type Readable = z.infer<Database[T]['readable']>
311
- type Writable = z.infer<Database[T]['writable']>
200
+ }) {
201
+ type Readable = z.infer<TSchema['readable']>
312
202
 
313
- const { list } = useTable(table)
203
+ const { list } = useDatabaseTable(table)
314
204
 
315
205
  const callback = useCallback(
316
- async (fields: Omit<ListProps<Readable>, 'table'>) => {
317
- const result = await list.trigger(fields)
318
- if (onSuccess) onSuccess(result)
319
- return result
320
- },
321
- [list, onSuccess]
206
+ async (fields: Omit<ListProps<Readable>, 'table'>) => {
207
+ const result = await list.trigger(fields)
208
+ if (onSuccess) onSuccess(result)
209
+ return result
210
+ },
211
+ [list, onSuccess]
322
212
  )
323
213
 
324
214
  return (
325
- <FieldsProvider<ListProps<Readable>>
326
- defaults={(defaults || { query: {} }) as ListProps<Readable>}
327
- >
328
- {fields => (
329
- <ActionProvider<ListProps<Readable>, Readable[]> action={callback} params={fields.fields}>
330
- {typeof children === 'function' ? (
331
- form => children({ ...form, ...fields })
332
- ) : (
333
- children
215
+ <FieldsProvider<ListProps<Readable>>
216
+ defaults={(defaults || { query: {} }) as ListProps<Readable>}
217
+ >
218
+ {fields => (
219
+ <ActionProvider<ListProps<Readable>, Readable[]> action={callback} params={fields.fields}>
220
+ {typeof children === 'function' ? (
221
+ form => children({ ...form, ...fields })
222
+ ) : (
223
+ children
224
+ )}
225
+ </ActionProvider>
334
226
  )}
335
- </ActionProvider>
336
- )}
337
- </FieldsProvider>
227
+ </FieldsProvider>
338
228
  )
339
- }
229
+ }
340
230
 
341
- const useCreateForm = <T extends TableKey>(table: T) => {
231
+ export function useCreateForm<TSchema extends TableSchema>(schema: TSchema) {
342
232
  return {
343
- ...useFields<z.infer<Database[T]['writable']>>(),
344
- ...useAction<
345
- z.infer<Database[T]['writable']>,
346
- z.infer<Database[T]['readable']>
347
- >(),
233
+ ...useFields<z.infer<TSchema['writable']>>(),
234
+ ...useAction<
235
+ z.infer<TSchema['writable']>,
236
+ z.infer<TSchema['readable']>
237
+ >()
348
238
  }
349
- }
350
- const useUpdateForm = <T extends TableKey>(table: T) => {
239
+ }
240
+
241
+ export function useUpdateForm<TSchema extends TableSchema>(schema: TSchema) {
351
242
  return {
352
- ...useFields<Partial<z.infer<Database[T]['writable']>>>(),
353
- ...useAction<
354
- Partial<z.infer<Database[T]['writable']>>,
355
- z.infer<Database[T]['readable']>
356
- >(),
243
+ ...useFields<Partial<z.infer<TSchema['writable']>>>(),
244
+ ...useAction<
245
+ Partial<z.infer<TSchema['writable']>>,
246
+ z.infer<TSchema['readable']>
247
+ >()
357
248
  }
358
- }
359
- const useFiltersForm = <T extends TableKey>(table: T) => {
249
+ }
250
+
251
+ export function useFiltersForm <TSchema extends TableSchema>(schema: TSchema) {
360
252
  return {
361
- ...useFields<z.infer<Database[T]['readable']>>(),
362
- ...useAction<z.infer<Database[T]['readable']>,
363
- z.infer<Database[T]['readable']>[]
364
- >(),
253
+ ...useFields<z.infer<TSchema['readable']>>(),
254
+ ...useAction<z.infer<TSchema['readable']>,
255
+ z.infer<TSchema['readable']>[]
256
+ >()
365
257
  }
366
- }
367
-
368
- return {
369
- DatabaseProvider,
370
- useTable,
371
- useTableProvider,
372
- TableProvider,
373
- SingleProvider,
374
- useSingle,
375
- CreateForm,
376
- UpdateForm,
377
- FilterForm,
378
- useCreateForm,
379
- useUpdateForm,
380
- useFiltersForm,
381
- }
382
258
  }
383
259
 
384
- export class ReactInterface<Database extends DatabaseInterface> {
385
- constructor(
386
- database: Database,
387
- tableInterface: TableInterface<
388
- z.infer<Database[keyof Database]['readable']>,
389
- z.infer<Database[keyof Database]['writable']>
390
- >
391
- ) {
392
- return reactInterface(database, tableInterface)
393
- }
260
+ export function useSingleProvider<T>({
261
+ id,
262
+ table,
263
+ }: {
264
+ id: string
265
+ table: string
266
+ }) {
267
+ const { index, find } = useDatabaseTable(table)
268
+ const [single, setSingle] = useState<T>(
269
+ // @ts-expect-error
270
+ () => index[id as keyof typeof index]
271
+ )
272
+ useEffect(() => {
273
+ // @ts-expect-error
274
+ if (!single) find.trigger({ id }).then(setSingle)
275
+ }, [])
276
+ useEffect(() => {
277
+ // @ts-expect-error
278
+ setSingle(index[id as keyof typeof index])
279
+ }, [index[id as keyof typeof index]])
280
+ return {
281
+ id,
282
+ single,
283
+ setSingle,
284
+ loading: find.loading,
285
+ }
286
+ }
287
+
288
+ export const SingleContext = createContext<
289
+ ReturnType<typeof useSingleProvider> | undefined
290
+ >(undefined)
291
+
292
+ export function SingleProvider<T>({
293
+ children,
294
+ ...props
295
+ }: {
296
+ id: string
297
+ table: string
298
+ children: React.ReactNode | ((props: ReturnType<typeof useSingleProvider>) => React.ReactNode)
299
+ }) {
300
+ const value = useSingleProvider(props)
301
+ if (!value.single) return null
302
+ return (
303
+ <SingleContext.Provider value={value}>
304
+ {typeof children === 'function' ? (
305
+ children(value)
306
+ ) : (
307
+ children
308
+ )}
309
+ </SingleContext.Provider>
310
+ )
311
+ }
312
+
313
+ export function useSingle<T>() {
314
+ return useContext(SingleContext) as ReturnType<typeof useSingleProvider<T>>
394
315
  }