@firtoz/drizzle-utils 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/CHANGELOG.md +12 -0
- package/package.json +5 -3
- package/src/collection-utils.ts +434 -2
- package/src/index.ts +11 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @firtoz/drizzle-utils
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`58d2cba`](https://github.com/firtoz/fullstack-toolkit/commit/58d2cbac8ea4e540b5460b7088b6b62e50357558) Thanks [@firtoz](https://github.com/firtoz)! - Add sync mode functionality for IndexedDB and SQLite collections
|
|
8
|
+
|
|
9
|
+
- Introduced support for both eager and on-demand sync modes in Drizzle providers
|
|
10
|
+
- Implemented operation tracking via interceptors to monitor database operations during queries
|
|
11
|
+
- Enhanced DrizzleIndexedDBProvider and DrizzleSqliteProvider to accept interceptors for debugging and testing purposes
|
|
12
|
+
- Added createInsertSchemaWithDefaults and createInsertSchemaWithIdDefault utilities for better schema management
|
|
13
|
+
- Refactored collection utilities to improve data handling and consistency across collections
|
|
14
|
+
|
|
3
15
|
## 0.1.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@firtoz/drizzle-utils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Shared utilities and types for Drizzle-based packages",
|
|
5
5
|
"main": "./src/index.ts",
|
|
6
6
|
"module": "./src/index.ts",
|
|
@@ -57,11 +57,13 @@
|
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"@tanstack/db": "^0.5.0",
|
|
59
59
|
"drizzle-orm": "^0.44.7",
|
|
60
|
-
"drizzle-valibot": "^0.4.2"
|
|
60
|
+
"drizzle-valibot": "^0.4.2",
|
|
61
|
+
"valibot": "^1.0.0"
|
|
61
62
|
},
|
|
62
63
|
"devDependencies": {
|
|
63
64
|
"@tanstack/db": "^0.5.0",
|
|
64
65
|
"drizzle-orm": "^0.44.7",
|
|
65
|
-
"drizzle-valibot": "^0.4.2"
|
|
66
|
+
"drizzle-valibot": "^0.4.2",
|
|
67
|
+
"valibot": "^1.0.0"
|
|
66
68
|
}
|
|
67
69
|
}
|
package/src/collection-utils.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Table, SQL, getTableColumns } from "drizzle-orm";
|
|
2
2
|
import type { BuildSchema } from "drizzle-valibot";
|
|
3
|
-
import
|
|
3
|
+
import { createInsertSchema } from "drizzle-valibot";
|
|
4
|
+
import * as v from "valibot";
|
|
5
|
+
import type {
|
|
6
|
+
Collection,
|
|
7
|
+
UtilsRecord,
|
|
8
|
+
CollectionConfig,
|
|
9
|
+
InferSchemaOutput,
|
|
10
|
+
SyncConfig,
|
|
11
|
+
SyncConfigRes,
|
|
12
|
+
SyncMode,
|
|
13
|
+
LoadSubsetOptions,
|
|
14
|
+
} from "@tanstack/db";
|
|
15
|
+
import { DeduplicatedLoadSubset } from "@tanstack/db";
|
|
4
16
|
|
|
5
17
|
/**
|
|
6
18
|
* Utility type for branded IDs
|
|
@@ -74,3 +86,423 @@ export type InferCollectionFromTable<TTable extends Table> = Collection<
|
|
|
74
86
|
id?: IdOf<TTable>;
|
|
75
87
|
}
|
|
76
88
|
>;
|
|
89
|
+
|
|
90
|
+
// WORKAROUND: DeduplicatedLoadSubset has a bug where toggling queries (e.g., isNull/isNotNull)
|
|
91
|
+
// creates invalid expressions like not(or(isNull(...), not(isNull(...))))
|
|
92
|
+
// See: https://github.com/TanStack/db/issues/828
|
|
93
|
+
// TODO: Re-enable once the bug is fixed
|
|
94
|
+
export const USE_DEDUPE = false as boolean;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Base configuration for sync lifecycle management
|
|
98
|
+
*/
|
|
99
|
+
export interface BaseSyncConfig<TTable extends Table> {
|
|
100
|
+
/**
|
|
101
|
+
* The Drizzle table definition
|
|
102
|
+
*/
|
|
103
|
+
table: TTable;
|
|
104
|
+
/**
|
|
105
|
+
* Promise that resolves when the database is ready
|
|
106
|
+
*/
|
|
107
|
+
readyPromise: Promise<void>;
|
|
108
|
+
/**
|
|
109
|
+
* Sync mode: 'eager' (immediate) or 'lazy' (on-demand)
|
|
110
|
+
*/
|
|
111
|
+
syncMode?: SyncMode;
|
|
112
|
+
/**
|
|
113
|
+
* Enable debug logging
|
|
114
|
+
*/
|
|
115
|
+
debug?: boolean;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Backend-specific implementations required for sync
|
|
120
|
+
*/
|
|
121
|
+
export interface SyncBackend<TTable extends Table> {
|
|
122
|
+
/**
|
|
123
|
+
* Initial data load - should call write() for each item
|
|
124
|
+
*/
|
|
125
|
+
initialLoad: (
|
|
126
|
+
write: (value: InferSchemaOutput<SelectSchema<TTable>>) => void,
|
|
127
|
+
) => Promise<void>;
|
|
128
|
+
/**
|
|
129
|
+
* Load a subset of data based on query options
|
|
130
|
+
*/
|
|
131
|
+
loadSubset: (
|
|
132
|
+
options: LoadSubsetOptions,
|
|
133
|
+
write: (value: InferSchemaOutput<SelectSchema<TTable>>) => void,
|
|
134
|
+
) => Promise<void>;
|
|
135
|
+
/**
|
|
136
|
+
* Handle insert mutations
|
|
137
|
+
*/
|
|
138
|
+
handleInsert: (
|
|
139
|
+
mutations: Array<{
|
|
140
|
+
modified: InferSchemaOutput<SelectSchema<TTable>>;
|
|
141
|
+
}>,
|
|
142
|
+
) => Promise<Array<InferSchemaOutput<SelectSchema<TTable>>>>;
|
|
143
|
+
/**
|
|
144
|
+
* Handle update mutations
|
|
145
|
+
*/
|
|
146
|
+
handleUpdate: (
|
|
147
|
+
mutations: Array<{
|
|
148
|
+
key: string;
|
|
149
|
+
changes: Partial<InferSchemaOutput<SelectSchema<TTable>>>;
|
|
150
|
+
original: InferSchemaOutput<SelectSchema<TTable>>;
|
|
151
|
+
}>,
|
|
152
|
+
) => Promise<Array<InferSchemaOutput<SelectSchema<TTable>>>>;
|
|
153
|
+
/**
|
|
154
|
+
* Handle delete mutations
|
|
155
|
+
*/
|
|
156
|
+
handleDelete: (
|
|
157
|
+
mutations: Array<{
|
|
158
|
+
key: string;
|
|
159
|
+
modified: InferSchemaOutput<SelectSchema<TTable>>;
|
|
160
|
+
original: InferSchemaOutput<SelectSchema<TTable>>;
|
|
161
|
+
}>,
|
|
162
|
+
) => Promise<void>;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Return type for createSyncFunction that includes both sync config and listeners
|
|
167
|
+
*/
|
|
168
|
+
export type SyncFunctionResult<TTable extends Table> = {
|
|
169
|
+
sync: SyncConfig<InferSchemaOutput<SelectSchema<TTable>>, string>["sync"];
|
|
170
|
+
onInsert: CollectionConfig<
|
|
171
|
+
InferSchemaOutput<SelectSchema<TTable>>,
|
|
172
|
+
string,
|
|
173
|
+
// biome-ignore lint/suspicious/noExplicitAny: Schema type parameter needs to be flexible
|
|
174
|
+
any
|
|
175
|
+
>["onInsert"];
|
|
176
|
+
onUpdate: CollectionConfig<
|
|
177
|
+
InferSchemaOutput<SelectSchema<TTable>>,
|
|
178
|
+
string,
|
|
179
|
+
// biome-ignore lint/suspicious/noExplicitAny: Schema type parameter needs to be flexible
|
|
180
|
+
any
|
|
181
|
+
>["onUpdate"];
|
|
182
|
+
onDelete: CollectionConfig<
|
|
183
|
+
InferSchemaOutput<SelectSchema<TTable>>,
|
|
184
|
+
string,
|
|
185
|
+
// biome-ignore lint/suspicious/noExplicitAny: Schema type parameter needs to be flexible
|
|
186
|
+
any
|
|
187
|
+
>["onDelete"];
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Creates the sync function with common lifecycle management
|
|
192
|
+
*/
|
|
193
|
+
export function createSyncFunction<TTable extends Table>(
|
|
194
|
+
config: BaseSyncConfig<TTable>,
|
|
195
|
+
backend: SyncBackend<TTable>,
|
|
196
|
+
): SyncFunctionResult<TTable> {
|
|
197
|
+
type CollectionType = CollectionConfig<
|
|
198
|
+
InferSchemaOutput<SelectSchema<TTable>>,
|
|
199
|
+
string,
|
|
200
|
+
// biome-ignore lint/suspicious/noExplicitAny: Schema type parameter needs to be flexible
|
|
201
|
+
any
|
|
202
|
+
>;
|
|
203
|
+
|
|
204
|
+
let insertListener: CollectionType["onInsert"];
|
|
205
|
+
let updateListener: CollectionType["onUpdate"];
|
|
206
|
+
let deleteListener: CollectionType["onDelete"];
|
|
207
|
+
|
|
208
|
+
const syncFn: SyncConfig<
|
|
209
|
+
InferSchemaOutput<SelectSchema<TTable>>,
|
|
210
|
+
string
|
|
211
|
+
>["sync"] = (params) => {
|
|
212
|
+
const { begin, write, commit, markReady } = params;
|
|
213
|
+
|
|
214
|
+
const initialSync = async () => {
|
|
215
|
+
await config.readyPromise;
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
begin();
|
|
219
|
+
await backend.initialLoad((item) => {
|
|
220
|
+
write({
|
|
221
|
+
type: "insert",
|
|
222
|
+
value: item,
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
commit();
|
|
226
|
+
} finally {
|
|
227
|
+
markReady();
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
if (config.syncMode === "eager" || !config.syncMode) {
|
|
232
|
+
initialSync();
|
|
233
|
+
} else {
|
|
234
|
+
markReady();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
insertListener = async (params) => {
|
|
238
|
+
const results = await backend.handleInsert(
|
|
239
|
+
params.transaction.mutations.map((m) => ({
|
|
240
|
+
modified: m.modified,
|
|
241
|
+
})),
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
begin();
|
|
245
|
+
for (const result of results) {
|
|
246
|
+
write({
|
|
247
|
+
type: "insert",
|
|
248
|
+
value: result,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
commit();
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
updateListener = async (params) => {
|
|
255
|
+
const results = await backend.handleUpdate(params.transaction.mutations);
|
|
256
|
+
|
|
257
|
+
begin();
|
|
258
|
+
for (const result of results) {
|
|
259
|
+
write({
|
|
260
|
+
type: "update",
|
|
261
|
+
value: result,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
commit();
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
deleteListener = async (params) => {
|
|
268
|
+
await backend.handleDelete(params.transaction.mutations);
|
|
269
|
+
|
|
270
|
+
begin();
|
|
271
|
+
for (const item of params.transaction.mutations) {
|
|
272
|
+
write({
|
|
273
|
+
type: "delete",
|
|
274
|
+
value: item.modified,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
commit();
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const loadSubset = async (options: LoadSubsetOptions) => {
|
|
281
|
+
await config.readyPromise;
|
|
282
|
+
|
|
283
|
+
begin();
|
|
284
|
+
|
|
285
|
+
try {
|
|
286
|
+
await backend.loadSubset(options, (item) => {
|
|
287
|
+
write({
|
|
288
|
+
type: "insert",
|
|
289
|
+
value: item,
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
commit();
|
|
293
|
+
} catch (error) {
|
|
294
|
+
commit();
|
|
295
|
+
throw error;
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
// Create deduplicated loadSubset wrapper to avoid redundant queries
|
|
300
|
+
let loadSubsetDedupe: DeduplicatedLoadSubset | null = null;
|
|
301
|
+
if (USE_DEDUPE) {
|
|
302
|
+
loadSubsetDedupe = new DeduplicatedLoadSubset({
|
|
303
|
+
loadSubset,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return {
|
|
308
|
+
cleanup: () => {
|
|
309
|
+
insertListener = undefined;
|
|
310
|
+
updateListener = undefined;
|
|
311
|
+
deleteListener = undefined;
|
|
312
|
+
loadSubsetDedupe?.reset();
|
|
313
|
+
},
|
|
314
|
+
loadSubset: loadSubsetDedupe?.loadSubset ?? loadSubset,
|
|
315
|
+
} satisfies SyncConfigRes;
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
sync: syncFn,
|
|
320
|
+
onInsert: async (params) => {
|
|
321
|
+
if (!insertListener) {
|
|
322
|
+
throw new Error(
|
|
323
|
+
"insertListener not initialized - sync function may not have been called yet",
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
return insertListener(params);
|
|
327
|
+
},
|
|
328
|
+
onUpdate: async (params) => {
|
|
329
|
+
if (!updateListener) {
|
|
330
|
+
throw new Error(
|
|
331
|
+
"updateListener not initialized - sync function may not have been called yet",
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
return updateListener(params);
|
|
335
|
+
},
|
|
336
|
+
onDelete: async (params) => {
|
|
337
|
+
if (!deleteListener) {
|
|
338
|
+
throw new Error(
|
|
339
|
+
"deleteListener not initialized - sync function may not have been called yet",
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
return deleteListener(params);
|
|
343
|
+
},
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Creates an insert schema with default value handling
|
|
349
|
+
* Validates that SQL expressions are not used for defaults (IndexedDB compatibility)
|
|
350
|
+
*/
|
|
351
|
+
export function createInsertSchemaWithDefaults<TTable extends Table>(
|
|
352
|
+
table: TTable,
|
|
353
|
+
): v.GenericSchema<unknown> {
|
|
354
|
+
const insertSchema = createInsertSchema(table);
|
|
355
|
+
const columns = getTableColumns(table);
|
|
356
|
+
|
|
357
|
+
// Validate that no SQL expressions are used as defaults
|
|
358
|
+
for (const columnName in columns) {
|
|
359
|
+
const column = columns[columnName];
|
|
360
|
+
|
|
361
|
+
let defaultValue: unknown | undefined;
|
|
362
|
+
if (column.defaultFn) {
|
|
363
|
+
defaultValue = column.defaultFn();
|
|
364
|
+
} else if (column.default !== undefined) {
|
|
365
|
+
defaultValue = column.default;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (defaultValue instanceof SQL) {
|
|
369
|
+
throw new Error(
|
|
370
|
+
`Default value for column ${columnName} is a SQL expression, which is not supported for IndexedDB`,
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// Transform the schema to apply defaults
|
|
376
|
+
return v.pipe(
|
|
377
|
+
insertSchema,
|
|
378
|
+
v.transform((input) => {
|
|
379
|
+
const result = { ...input } as Record<string, unknown>;
|
|
380
|
+
|
|
381
|
+
for (const columnName in columns) {
|
|
382
|
+
const column = columns[columnName];
|
|
383
|
+
if (result[columnName] !== undefined) continue;
|
|
384
|
+
|
|
385
|
+
let defaultValue: unknown | undefined;
|
|
386
|
+
if (column.defaultFn) {
|
|
387
|
+
defaultValue = column.defaultFn();
|
|
388
|
+
} else if (column.default !== undefined) {
|
|
389
|
+
defaultValue = column.default;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
if (defaultValue instanceof SQL) {
|
|
393
|
+
throw new Error(
|
|
394
|
+
`Default value for column ${columnName} is a SQL expression, which is not supported for IndexedDB`,
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (defaultValue !== undefined) {
|
|
399
|
+
result[columnName] = defaultValue;
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (column.notNull) {
|
|
404
|
+
throw new Error(`Column ${columnName} is not nullable`);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
result[columnName] = null;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
return result;
|
|
411
|
+
}),
|
|
412
|
+
) as v.GenericSchema<unknown>;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Creates a minimal insert schema that only applies ID defaults
|
|
417
|
+
* Other defaults (like timestamps) are handled by the database
|
|
418
|
+
*/
|
|
419
|
+
export function createInsertSchemaWithIdDefault<TTable extends Table>(
|
|
420
|
+
table: TTable,
|
|
421
|
+
): v.GenericSchema<unknown> {
|
|
422
|
+
const insertSchema = createInsertSchema(table);
|
|
423
|
+
const columns = getTableColumns(table);
|
|
424
|
+
const idColumn = columns.id;
|
|
425
|
+
|
|
426
|
+
return v.pipe(
|
|
427
|
+
insertSchema,
|
|
428
|
+
v.transform((input) => {
|
|
429
|
+
const result = { ...input } as Record<string, unknown>;
|
|
430
|
+
|
|
431
|
+
// Apply ID default if missing
|
|
432
|
+
if (result.id === undefined && idColumn?.defaultFn) {
|
|
433
|
+
result.id = idColumn.defaultFn();
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
return result;
|
|
437
|
+
}),
|
|
438
|
+
) as v.GenericSchema<unknown>;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Standard getKey function for collections
|
|
443
|
+
*/
|
|
444
|
+
export function createGetKeyFunction<TTable extends Table>() {
|
|
445
|
+
return (item: InferSchemaOutput<SelectSchema<TTable>>) => {
|
|
446
|
+
const id = (item as { id: string }).id;
|
|
447
|
+
return id;
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* Base collection config factory
|
|
453
|
+
* Combines schema, sync, and event handlers into a collection config
|
|
454
|
+
*/
|
|
455
|
+
export function createCollectionConfig<
|
|
456
|
+
TTable extends Table,
|
|
457
|
+
TSchema extends v.GenericSchema<unknown>,
|
|
458
|
+
>(config: {
|
|
459
|
+
schema: TSchema;
|
|
460
|
+
getKey: (item: InferSchemaOutput<SelectSchema<TTable>>) => string;
|
|
461
|
+
syncResult: SyncFunctionResult<TTable>;
|
|
462
|
+
onInsert?: CollectionConfig<
|
|
463
|
+
InferSchemaOutput<SelectSchema<TTable>>,
|
|
464
|
+
string,
|
|
465
|
+
// biome-ignore lint/suspicious/noExplicitAny: Schema type parameter needs to be flexible
|
|
466
|
+
any
|
|
467
|
+
>["onInsert"];
|
|
468
|
+
onUpdate?: CollectionConfig<
|
|
469
|
+
InferSchemaOutput<SelectSchema<TTable>>,
|
|
470
|
+
string,
|
|
471
|
+
// biome-ignore lint/suspicious/noExplicitAny: Schema type parameter needs to be flexible
|
|
472
|
+
any
|
|
473
|
+
>["onUpdate"];
|
|
474
|
+
onDelete?: CollectionConfig<
|
|
475
|
+
InferSchemaOutput<SelectSchema<TTable>>,
|
|
476
|
+
string,
|
|
477
|
+
// biome-ignore lint/suspicious/noExplicitAny: Schema type parameter needs to be flexible
|
|
478
|
+
any
|
|
479
|
+
>["onDelete"];
|
|
480
|
+
syncMode?: SyncMode;
|
|
481
|
+
}): CollectionConfig<
|
|
482
|
+
InferSchemaOutput<SelectSchema<TTable>>,
|
|
483
|
+
string,
|
|
484
|
+
// biome-ignore lint/suspicious/noExplicitAny: Schema type parameter needs to be flexible
|
|
485
|
+
any
|
|
486
|
+
> & {
|
|
487
|
+
schema: TSchema;
|
|
488
|
+
} {
|
|
489
|
+
return {
|
|
490
|
+
schema: config.schema,
|
|
491
|
+
getKey: config.getKey,
|
|
492
|
+
sync: {
|
|
493
|
+
sync: config.syncResult.sync,
|
|
494
|
+
},
|
|
495
|
+
// Merge provided handlers with sync result handlers (provided handlers take precedence)
|
|
496
|
+
onInsert: config.onInsert ?? config.syncResult.onInsert,
|
|
497
|
+
onUpdate: config.onUpdate ?? config.syncResult.onUpdate,
|
|
498
|
+
onDelete: config.onDelete ?? config.syncResult.onDelete,
|
|
499
|
+
syncMode: config.syncMode,
|
|
500
|
+
} as CollectionConfig<
|
|
501
|
+
InferSchemaOutput<SelectSchema<TTable>>,
|
|
502
|
+
string,
|
|
503
|
+
// biome-ignore lint/suspicious/noExplicitAny: Schema type parameter needs to be flexible
|
|
504
|
+
any
|
|
505
|
+
> & {
|
|
506
|
+
schema: TSchema;
|
|
507
|
+
};
|
|
508
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -24,9 +24,19 @@ export type {
|
|
|
24
24
|
InsertSchema,
|
|
25
25
|
GetTableFromSchema,
|
|
26
26
|
InferCollectionFromTable,
|
|
27
|
+
BaseSyncConfig,
|
|
28
|
+
SyncBackend,
|
|
27
29
|
} from "./collection-utils";
|
|
28
30
|
|
|
29
|
-
export {
|
|
31
|
+
export {
|
|
32
|
+
makeId,
|
|
33
|
+
USE_DEDUPE,
|
|
34
|
+
createSyncFunction,
|
|
35
|
+
createInsertSchemaWithDefaults,
|
|
36
|
+
createInsertSchemaWithIdDefault,
|
|
37
|
+
createGetKeyFunction,
|
|
38
|
+
createCollectionConfig,
|
|
39
|
+
} from "./collection-utils";
|
|
30
40
|
|
|
31
41
|
export {
|
|
32
42
|
createdAtColumn,
|