@lunora/server 1.0.0-alpha.18 → 1.0.0-alpha.19
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/dist/data-model.d.mts +55 -17
- package/dist/data-model.d.ts +55 -17
- package/dist/index.d.mts +92 -18
- package/dist/index.d.ts +92 -18
- package/dist/index.mjs +4 -4
- package/dist/packem_shared/{bindOrm-CNXKgfUa.mjs → bindOrm-Bfgl7f-Q.mjs} +34 -18
- package/dist/packem_shared/{buildRlsReadRegistry-DFBFLydB.mjs → buildRlsReadRegistry-D54vUQe4.mjs} +1 -1
- package/dist/packem_shared/{mask-Dc8G5Gl7.mjs → mask-BT1YgRbF.mjs} +1 -1
- package/dist/packem_shared/{rls-3sCJIH6F.mjs → rls-B_ZWgslr.mjs} +24 -1
- package/dist/rls/testing.mjs +1 -1
- package/dist/types.d.mts +52 -3
- package/dist/types.d.ts +52 -3
- package/package.json +1 -1
package/dist/data-model.d.mts
CHANGED
|
@@ -345,12 +345,24 @@ interface TableWriterFacade<DM, IM extends Record<keyof DM, object>, REL extends
|
|
|
345
345
|
* {@link TableWriterFacade.hardDelete} to force physical removal.
|
|
346
346
|
*/
|
|
347
347
|
delete: (id: Id<string & T>) => Promise<void>;
|
|
348
|
-
/**
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
348
|
+
/**
|
|
349
|
+
* Delete many rows in this table. Pass an array of ids (requested count is
|
|
350
|
+
* returned; unknown ids are no-ops) or `{ where }` to delete matching rows
|
|
351
|
+
* (actual removed count is returned). Atomic within a mutation.
|
|
352
|
+
*/
|
|
353
|
+
deleteMany: {
|
|
354
|
+
(ids: ReadonlyArray<Id<string & T>>, options?: {
|
|
355
|
+
limit?: number;
|
|
356
|
+
}): Promise<{
|
|
357
|
+
deleted: number;
|
|
358
|
+
}>;
|
|
359
|
+
(args: {
|
|
360
|
+
limit?: number;
|
|
361
|
+
where: Partial<DM[T]>;
|
|
362
|
+
}): Promise<{
|
|
363
|
+
deleted: number;
|
|
364
|
+
}>;
|
|
365
|
+
};
|
|
354
366
|
/** Physically remove a row (and physically cascade `onDelete`), bypassing `.softDelete()`. Same as `delete()` on a non-soft table. */
|
|
355
367
|
hardDelete: (id: Id<string & T>) => Promise<void>;
|
|
356
368
|
/**
|
|
@@ -366,18 +378,44 @@ interface TableWriterFacade<DM, IM extends Record<keyof DM, object>, REL extends
|
|
|
366
378
|
skipDuplicates?: boolean;
|
|
367
379
|
}): Promise<Id<string & T>>;
|
|
368
380
|
};
|
|
369
|
-
/**
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
381
|
+
/**
|
|
382
|
+
* Insert many documents into this table in one call, returning the minted ids
|
|
383
|
+
* in input order. With `{ skipDuplicates: true }`, UNIQUE breaches resolve to
|
|
384
|
+
* `null` for that row instead of failing the batch. Atomic within a mutation.
|
|
385
|
+
*/
|
|
386
|
+
insertMany: {
|
|
387
|
+
(values: ReadonlyArray<IM[T]>, options: {
|
|
388
|
+
limit?: number;
|
|
389
|
+
skipDuplicates: true;
|
|
390
|
+
}): Promise<(Id<string & T> | null)[]>;
|
|
391
|
+
(values: ReadonlyArray<IM[T]>, options?: {
|
|
392
|
+
limit?: number;
|
|
393
|
+
skipDuplicates?: boolean;
|
|
394
|
+
}): Promise<Id<string & T>[]>;
|
|
395
|
+
};
|
|
373
396
|
patch: (id: Id<string & T>, values: Partial<IM[T]>) => Promise<void>;
|
|
374
|
-
/**
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
397
|
+
/**
|
|
398
|
+
* Patch many rows in this table. Pass an array of `{ id, values }` or
|
|
399
|
+
* `{ where, values }` to patch matching rows with the same values. Returns
|
|
400
|
+
* the actual patched count. Atomic within a mutation.
|
|
401
|
+
*/
|
|
402
|
+
patchMany: {
|
|
403
|
+
(patches: ReadonlyArray<{
|
|
404
|
+
id: Id<string & T>;
|
|
405
|
+
values: Partial<IM[T]>;
|
|
406
|
+
}>, options?: {
|
|
407
|
+
limit?: number;
|
|
408
|
+
}): Promise<{
|
|
409
|
+
patched: number;
|
|
410
|
+
}>;
|
|
411
|
+
(args: {
|
|
412
|
+
limit?: number;
|
|
413
|
+
values: Partial<IM[T]>;
|
|
414
|
+
where: Partial<DM[T]>;
|
|
415
|
+
}): Promise<{
|
|
416
|
+
patched: number;
|
|
417
|
+
}>;
|
|
418
|
+
};
|
|
381
419
|
replace: (id: Id<string & T>, values: IM[T]) => Promise<void>;
|
|
382
420
|
/** Un-soft-delete a row by id: clears the `.softDelete()` marker so list reads see it again. Throws on a non-soft table. */
|
|
383
421
|
restore: (id: Id<string & T>) => Promise<void>;
|
package/dist/data-model.d.ts
CHANGED
|
@@ -345,12 +345,24 @@ interface TableWriterFacade<DM, IM extends Record<keyof DM, object>, REL extends
|
|
|
345
345
|
* {@link TableWriterFacade.hardDelete} to force physical removal.
|
|
346
346
|
*/
|
|
347
347
|
delete: (id: Id<string & T>) => Promise<void>;
|
|
348
|
-
/**
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
348
|
+
/**
|
|
349
|
+
* Delete many rows in this table. Pass an array of ids (requested count is
|
|
350
|
+
* returned; unknown ids are no-ops) or `{ where }` to delete matching rows
|
|
351
|
+
* (actual removed count is returned). Atomic within a mutation.
|
|
352
|
+
*/
|
|
353
|
+
deleteMany: {
|
|
354
|
+
(ids: ReadonlyArray<Id<string & T>>, options?: {
|
|
355
|
+
limit?: number;
|
|
356
|
+
}): Promise<{
|
|
357
|
+
deleted: number;
|
|
358
|
+
}>;
|
|
359
|
+
(args: {
|
|
360
|
+
limit?: number;
|
|
361
|
+
where: Partial<DM[T]>;
|
|
362
|
+
}): Promise<{
|
|
363
|
+
deleted: number;
|
|
364
|
+
}>;
|
|
365
|
+
};
|
|
354
366
|
/** Physically remove a row (and physically cascade `onDelete`), bypassing `.softDelete()`. Same as `delete()` on a non-soft table. */
|
|
355
367
|
hardDelete: (id: Id<string & T>) => Promise<void>;
|
|
356
368
|
/**
|
|
@@ -366,18 +378,44 @@ interface TableWriterFacade<DM, IM extends Record<keyof DM, object>, REL extends
|
|
|
366
378
|
skipDuplicates?: boolean;
|
|
367
379
|
}): Promise<Id<string & T>>;
|
|
368
380
|
};
|
|
369
|
-
/**
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
381
|
+
/**
|
|
382
|
+
* Insert many documents into this table in one call, returning the minted ids
|
|
383
|
+
* in input order. With `{ skipDuplicates: true }`, UNIQUE breaches resolve to
|
|
384
|
+
* `null` for that row instead of failing the batch. Atomic within a mutation.
|
|
385
|
+
*/
|
|
386
|
+
insertMany: {
|
|
387
|
+
(values: ReadonlyArray<IM[T]>, options: {
|
|
388
|
+
limit?: number;
|
|
389
|
+
skipDuplicates: true;
|
|
390
|
+
}): Promise<(Id<string & T> | null)[]>;
|
|
391
|
+
(values: ReadonlyArray<IM[T]>, options?: {
|
|
392
|
+
limit?: number;
|
|
393
|
+
skipDuplicates?: boolean;
|
|
394
|
+
}): Promise<Id<string & T>[]>;
|
|
395
|
+
};
|
|
373
396
|
patch: (id: Id<string & T>, values: Partial<IM[T]>) => Promise<void>;
|
|
374
|
-
/**
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
397
|
+
/**
|
|
398
|
+
* Patch many rows in this table. Pass an array of `{ id, values }` or
|
|
399
|
+
* `{ where, values }` to patch matching rows with the same values. Returns
|
|
400
|
+
* the actual patched count. Atomic within a mutation.
|
|
401
|
+
*/
|
|
402
|
+
patchMany: {
|
|
403
|
+
(patches: ReadonlyArray<{
|
|
404
|
+
id: Id<string & T>;
|
|
405
|
+
values: Partial<IM[T]>;
|
|
406
|
+
}>, options?: {
|
|
407
|
+
limit?: number;
|
|
408
|
+
}): Promise<{
|
|
409
|
+
patched: number;
|
|
410
|
+
}>;
|
|
411
|
+
(args: {
|
|
412
|
+
limit?: number;
|
|
413
|
+
values: Partial<IM[T]>;
|
|
414
|
+
where: Partial<DM[T]>;
|
|
415
|
+
}): Promise<{
|
|
416
|
+
patched: number;
|
|
417
|
+
}>;
|
|
418
|
+
};
|
|
381
419
|
replace: (id: Id<string & T>, values: IM[T]) => Promise<void>;
|
|
382
420
|
/** Un-soft-delete a row by id: clears the `.softDelete()` marker so list reads see it again. Throws on a non-soft table. */
|
|
383
421
|
restore: (id: Id<string & T>) => Promise<void>;
|
package/dist/index.d.mts
CHANGED
|
@@ -299,6 +299,11 @@ interface FacadeWriterLike {
|
|
|
299
299
|
}, expectedTable?: string): Promise<{
|
|
300
300
|
deleted: number;
|
|
301
301
|
}>;
|
|
302
|
+
deleteWhere?(tableName: string, where: Record<string, unknown>, options?: {
|
|
303
|
+
limit?: number;
|
|
304
|
+
}): Promise<{
|
|
305
|
+
deleted: number;
|
|
306
|
+
}>;
|
|
302
307
|
findFirst(tableName: string, args?: unknown): Promise<unknown>;
|
|
303
308
|
findFirstOrThrow(tableName: string, args?: unknown): Promise<unknown>;
|
|
304
309
|
findMany(tableName: string, args?: unknown): Promise<unknown>;
|
|
@@ -307,14 +312,25 @@ interface FacadeWriterLike {
|
|
|
307
312
|
insert(tableName: string, document: Record<string, unknown>): Promise<string>;
|
|
308
313
|
insertMany?(tableName: string, documents: ReadonlyArray<Record<string, unknown>>, options?: {
|
|
309
314
|
limit?: number;
|
|
310
|
-
|
|
315
|
+
skipDuplicates?: boolean;
|
|
316
|
+
}): Promise<(string | null)[]>;
|
|
311
317
|
patch(id: string, patch: Record<string, unknown>, expectedTable?: string): Promise<void>;
|
|
312
318
|
patchMany?(patches: ReadonlyArray<{
|
|
313
319
|
id: string;
|
|
314
320
|
patch: Record<string, unknown>;
|
|
315
321
|
}>, options?: {
|
|
316
322
|
limit?: number;
|
|
317
|
-
}, expectedTable?: string): Promise<
|
|
323
|
+
}, expectedTable?: string): Promise<{
|
|
324
|
+
patched: number;
|
|
325
|
+
}>;
|
|
326
|
+
patchWhere?(tableName: string, args: {
|
|
327
|
+
patch: Record<string, unknown>;
|
|
328
|
+
where: Record<string, unknown>;
|
|
329
|
+
}, options?: {
|
|
330
|
+
limit?: number;
|
|
331
|
+
}): Promise<{
|
|
332
|
+
patched: number;
|
|
333
|
+
}>;
|
|
318
334
|
query(tableName: string): {
|
|
319
335
|
withSearchIndex(indexName: string, search: (q: unknown) => unknown): unknown;
|
|
320
336
|
};
|
|
@@ -328,11 +344,19 @@ interface FacadeEntry {
|
|
|
328
344
|
aggregate: (options: unknown) => Promise<unknown>;
|
|
329
345
|
count: (where?: unknown) => Promise<number>;
|
|
330
346
|
delete: (id: string) => Promise<void>;
|
|
331
|
-
deleteMany:
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
347
|
+
deleteMany: {
|
|
348
|
+
(ids: ReadonlyArray<string>, options?: {
|
|
349
|
+
limit?: number;
|
|
350
|
+
}): Promise<{
|
|
351
|
+
deleted: number;
|
|
352
|
+
}>;
|
|
353
|
+
(args: {
|
|
354
|
+
limit?: number;
|
|
355
|
+
where: Record<string, unknown>;
|
|
356
|
+
}): Promise<{
|
|
357
|
+
deleted: number;
|
|
358
|
+
}>;
|
|
359
|
+
};
|
|
336
360
|
/** `true` when at least one row matches `where` (or any row exists when omitted). Honors RLS like `findFirst`. */
|
|
337
361
|
exists: (where?: unknown) => Promise<boolean>;
|
|
338
362
|
findFirst: (args?: unknown) => Promise<unknown>;
|
|
@@ -343,16 +367,34 @@ interface FacadeEntry {
|
|
|
343
367
|
/** Physically remove a row (and physically cascade), bypassing `.softDelete()`. */
|
|
344
368
|
hardDelete: (id: string) => Promise<void>;
|
|
345
369
|
insert: (document: Record<string, unknown>, options?: FacadeInsertOptions) => Promise<null | string>;
|
|
370
|
+
/**
|
|
371
|
+
* Insert many documents into this table in one call. With
|
|
372
|
+
* `{ skipDuplicates: true }`, UNIQUE breaches resolve to `null` for that row
|
|
373
|
+
* instead of failing the batch. The typed facade narrows the return to
|
|
374
|
+
* `Id<T>[]` when skipDuplicates is not requested.
|
|
375
|
+
*/
|
|
346
376
|
insertMany: (documents: ReadonlyArray<Record<string, unknown>>, options?: {
|
|
347
377
|
limit?: number;
|
|
348
|
-
|
|
378
|
+
skipDuplicates?: boolean;
|
|
379
|
+
}) => Promise<(string | null)[]>;
|
|
349
380
|
patch: (id: string, patch: Record<string, unknown>) => Promise<void>;
|
|
350
|
-
patchMany:
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
381
|
+
patchMany: {
|
|
382
|
+
(patches: ReadonlyArray<{
|
|
383
|
+
id: string;
|
|
384
|
+
values: Record<string, unknown>;
|
|
385
|
+
}>, options?: {
|
|
386
|
+
limit?: number;
|
|
387
|
+
}): Promise<{
|
|
388
|
+
patched: number;
|
|
389
|
+
}>;
|
|
390
|
+
(args: {
|
|
391
|
+
limit?: number;
|
|
392
|
+
values: Record<string, unknown>;
|
|
393
|
+
where: Record<string, unknown>;
|
|
394
|
+
}): Promise<{
|
|
395
|
+
patched: number;
|
|
396
|
+
}>;
|
|
397
|
+
};
|
|
356
398
|
rank: (indexName: string, options: unknown) => Promise<unknown>;
|
|
357
399
|
rankPage: (indexName: string, options?: unknown) => Promise<unknown>;
|
|
358
400
|
replace: (id: string, document: Record<string, unknown>) => Promise<void>;
|
|
@@ -843,6 +885,11 @@ interface MaskDatabase {
|
|
|
843
885
|
}) => Promise<{
|
|
844
886
|
deleted: number;
|
|
845
887
|
}>;
|
|
888
|
+
deleteWhere?: (tableName: string, where: Record<string, unknown>, options?: {
|
|
889
|
+
limit?: number;
|
|
890
|
+
}) => Promise<{
|
|
891
|
+
deleted: number;
|
|
892
|
+
}>;
|
|
846
893
|
findFirst: (tableName: string, args?: QueryArgs$1) => Promise<Record<string, unknown> | null>;
|
|
847
894
|
findFirstOrThrow: (tableName: string, args?: QueryArgs$1) => Promise<Record<string, unknown>>;
|
|
848
895
|
findMany: (tableName: string, args?: QueryArgs$1) => Promise<QueryPage$1>;
|
|
@@ -854,7 +901,8 @@ interface MaskDatabase {
|
|
|
854
901
|
insert: (tableName: string, document: Record<string, unknown>) => Promise<string>;
|
|
855
902
|
insertMany: (tableName: string, documents: ReadonlyArray<Record<string, unknown>>, options?: {
|
|
856
903
|
limit?: number;
|
|
857
|
-
|
|
904
|
+
skipDuplicates?: boolean;
|
|
905
|
+
}) => Promise<(string | null)[]>;
|
|
858
906
|
lookupById?: (id: string, expectedTable?: string) => Promise<null | {
|
|
859
907
|
row: Record<string, unknown>;
|
|
860
908
|
tableName: string;
|
|
@@ -865,7 +913,17 @@ interface MaskDatabase {
|
|
|
865
913
|
patch: Record<string, unknown>;
|
|
866
914
|
}>, options?: {
|
|
867
915
|
limit?: number;
|
|
868
|
-
}) => Promise<
|
|
916
|
+
}) => Promise<{
|
|
917
|
+
patched: number;
|
|
918
|
+
}>;
|
|
919
|
+
patchWhere?: (tableName: string, args: {
|
|
920
|
+
patch: Record<string, unknown>;
|
|
921
|
+
where: Record<string, unknown>;
|
|
922
|
+
}, options?: {
|
|
923
|
+
limit?: number;
|
|
924
|
+
}) => Promise<{
|
|
925
|
+
patched: number;
|
|
926
|
+
}>;
|
|
869
927
|
query: (tableName: string) => TableReaderLike$1;
|
|
870
928
|
rank: (tableName: string, indexName: string, options: unknown) => Promise<null | {
|
|
871
929
|
position: number;
|
|
@@ -1737,6 +1795,11 @@ interface DatabaseWriterLike {
|
|
|
1737
1795
|
}, expectedTable?: string) => Promise<{
|
|
1738
1796
|
deleted: number;
|
|
1739
1797
|
}>;
|
|
1798
|
+
deleteWhere?: (tableName: string, where: WhereInput, options?: {
|
|
1799
|
+
limit?: number;
|
|
1800
|
+
}) => Promise<{
|
|
1801
|
+
deleted: number;
|
|
1802
|
+
}>;
|
|
1740
1803
|
findFirst: (tableName: string, args?: QueryArgs) => Promise<Record<string, unknown> | null>;
|
|
1741
1804
|
findFirstOrThrow: (tableName: string, args?: QueryArgs) => Promise<Record<string, unknown>>;
|
|
1742
1805
|
findMany: (tableName: string, args?: QueryArgs) => Promise<QueryPage>;
|
|
@@ -1753,7 +1816,8 @@ interface DatabaseWriterLike {
|
|
|
1753
1816
|
insert: (tableName: string, document: Record<string, unknown>) => Promise<string>;
|
|
1754
1817
|
insertMany: (tableName: string, documents: ReadonlyArray<Record<string, unknown>>, options?: {
|
|
1755
1818
|
limit?: number;
|
|
1756
|
-
|
|
1819
|
+
skipDuplicates?: boolean;
|
|
1820
|
+
}) => Promise<(string | null)[]>;
|
|
1757
1821
|
insertManyUnsafe: (tableName: string, documents: ReadonlyArray<Record<string, unknown>>, options?: {
|
|
1758
1822
|
allowExplicitId?: boolean;
|
|
1759
1823
|
limit?: number;
|
|
@@ -1776,7 +1840,17 @@ interface DatabaseWriterLike {
|
|
|
1776
1840
|
patch: Record<string, unknown>;
|
|
1777
1841
|
}>, options?: {
|
|
1778
1842
|
limit?: number;
|
|
1779
|
-
}, expectedTable?: string) => Promise<
|
|
1843
|
+
}, expectedTable?: string) => Promise<{
|
|
1844
|
+
patched: number;
|
|
1845
|
+
}>;
|
|
1846
|
+
patchWhere?: (tableName: string, args: {
|
|
1847
|
+
patch: Record<string, unknown>;
|
|
1848
|
+
where: WhereInput;
|
|
1849
|
+
}, options?: {
|
|
1850
|
+
limit?: number;
|
|
1851
|
+
}) => Promise<{
|
|
1852
|
+
patched: number;
|
|
1853
|
+
}>;
|
|
1780
1854
|
query: (tableName: string) => TableReaderLike;
|
|
1781
1855
|
/**
|
|
1782
1856
|
* Rank a row within its partition. A position is a count-of-rows-before, so
|
package/dist/index.d.ts
CHANGED
|
@@ -299,6 +299,11 @@ interface FacadeWriterLike {
|
|
|
299
299
|
}, expectedTable?: string): Promise<{
|
|
300
300
|
deleted: number;
|
|
301
301
|
}>;
|
|
302
|
+
deleteWhere?(tableName: string, where: Record<string, unknown>, options?: {
|
|
303
|
+
limit?: number;
|
|
304
|
+
}): Promise<{
|
|
305
|
+
deleted: number;
|
|
306
|
+
}>;
|
|
302
307
|
findFirst(tableName: string, args?: unknown): Promise<unknown>;
|
|
303
308
|
findFirstOrThrow(tableName: string, args?: unknown): Promise<unknown>;
|
|
304
309
|
findMany(tableName: string, args?: unknown): Promise<unknown>;
|
|
@@ -307,14 +312,25 @@ interface FacadeWriterLike {
|
|
|
307
312
|
insert(tableName: string, document: Record<string, unknown>): Promise<string>;
|
|
308
313
|
insertMany?(tableName: string, documents: ReadonlyArray<Record<string, unknown>>, options?: {
|
|
309
314
|
limit?: number;
|
|
310
|
-
|
|
315
|
+
skipDuplicates?: boolean;
|
|
316
|
+
}): Promise<(string | null)[]>;
|
|
311
317
|
patch(id: string, patch: Record<string, unknown>, expectedTable?: string): Promise<void>;
|
|
312
318
|
patchMany?(patches: ReadonlyArray<{
|
|
313
319
|
id: string;
|
|
314
320
|
patch: Record<string, unknown>;
|
|
315
321
|
}>, options?: {
|
|
316
322
|
limit?: number;
|
|
317
|
-
}, expectedTable?: string): Promise<
|
|
323
|
+
}, expectedTable?: string): Promise<{
|
|
324
|
+
patched: number;
|
|
325
|
+
}>;
|
|
326
|
+
patchWhere?(tableName: string, args: {
|
|
327
|
+
patch: Record<string, unknown>;
|
|
328
|
+
where: Record<string, unknown>;
|
|
329
|
+
}, options?: {
|
|
330
|
+
limit?: number;
|
|
331
|
+
}): Promise<{
|
|
332
|
+
patched: number;
|
|
333
|
+
}>;
|
|
318
334
|
query(tableName: string): {
|
|
319
335
|
withSearchIndex(indexName: string, search: (q: unknown) => unknown): unknown;
|
|
320
336
|
};
|
|
@@ -328,11 +344,19 @@ interface FacadeEntry {
|
|
|
328
344
|
aggregate: (options: unknown) => Promise<unknown>;
|
|
329
345
|
count: (where?: unknown) => Promise<number>;
|
|
330
346
|
delete: (id: string) => Promise<void>;
|
|
331
|
-
deleteMany:
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
347
|
+
deleteMany: {
|
|
348
|
+
(ids: ReadonlyArray<string>, options?: {
|
|
349
|
+
limit?: number;
|
|
350
|
+
}): Promise<{
|
|
351
|
+
deleted: number;
|
|
352
|
+
}>;
|
|
353
|
+
(args: {
|
|
354
|
+
limit?: number;
|
|
355
|
+
where: Record<string, unknown>;
|
|
356
|
+
}): Promise<{
|
|
357
|
+
deleted: number;
|
|
358
|
+
}>;
|
|
359
|
+
};
|
|
336
360
|
/** `true` when at least one row matches `where` (or any row exists when omitted). Honors RLS like `findFirst`. */
|
|
337
361
|
exists: (where?: unknown) => Promise<boolean>;
|
|
338
362
|
findFirst: (args?: unknown) => Promise<unknown>;
|
|
@@ -343,16 +367,34 @@ interface FacadeEntry {
|
|
|
343
367
|
/** Physically remove a row (and physically cascade), bypassing `.softDelete()`. */
|
|
344
368
|
hardDelete: (id: string) => Promise<void>;
|
|
345
369
|
insert: (document: Record<string, unknown>, options?: FacadeInsertOptions) => Promise<null | string>;
|
|
370
|
+
/**
|
|
371
|
+
* Insert many documents into this table in one call. With
|
|
372
|
+
* `{ skipDuplicates: true }`, UNIQUE breaches resolve to `null` for that row
|
|
373
|
+
* instead of failing the batch. The typed facade narrows the return to
|
|
374
|
+
* `Id<T>[]` when skipDuplicates is not requested.
|
|
375
|
+
*/
|
|
346
376
|
insertMany: (documents: ReadonlyArray<Record<string, unknown>>, options?: {
|
|
347
377
|
limit?: number;
|
|
348
|
-
|
|
378
|
+
skipDuplicates?: boolean;
|
|
379
|
+
}) => Promise<(string | null)[]>;
|
|
349
380
|
patch: (id: string, patch: Record<string, unknown>) => Promise<void>;
|
|
350
|
-
patchMany:
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
381
|
+
patchMany: {
|
|
382
|
+
(patches: ReadonlyArray<{
|
|
383
|
+
id: string;
|
|
384
|
+
values: Record<string, unknown>;
|
|
385
|
+
}>, options?: {
|
|
386
|
+
limit?: number;
|
|
387
|
+
}): Promise<{
|
|
388
|
+
patched: number;
|
|
389
|
+
}>;
|
|
390
|
+
(args: {
|
|
391
|
+
limit?: number;
|
|
392
|
+
values: Record<string, unknown>;
|
|
393
|
+
where: Record<string, unknown>;
|
|
394
|
+
}): Promise<{
|
|
395
|
+
patched: number;
|
|
396
|
+
}>;
|
|
397
|
+
};
|
|
356
398
|
rank: (indexName: string, options: unknown) => Promise<unknown>;
|
|
357
399
|
rankPage: (indexName: string, options?: unknown) => Promise<unknown>;
|
|
358
400
|
replace: (id: string, document: Record<string, unknown>) => Promise<void>;
|
|
@@ -843,6 +885,11 @@ interface MaskDatabase {
|
|
|
843
885
|
}) => Promise<{
|
|
844
886
|
deleted: number;
|
|
845
887
|
}>;
|
|
888
|
+
deleteWhere?: (tableName: string, where: Record<string, unknown>, options?: {
|
|
889
|
+
limit?: number;
|
|
890
|
+
}) => Promise<{
|
|
891
|
+
deleted: number;
|
|
892
|
+
}>;
|
|
846
893
|
findFirst: (tableName: string, args?: QueryArgs$1) => Promise<Record<string, unknown> | null>;
|
|
847
894
|
findFirstOrThrow: (tableName: string, args?: QueryArgs$1) => Promise<Record<string, unknown>>;
|
|
848
895
|
findMany: (tableName: string, args?: QueryArgs$1) => Promise<QueryPage$1>;
|
|
@@ -854,7 +901,8 @@ interface MaskDatabase {
|
|
|
854
901
|
insert: (tableName: string, document: Record<string, unknown>) => Promise<string>;
|
|
855
902
|
insertMany: (tableName: string, documents: ReadonlyArray<Record<string, unknown>>, options?: {
|
|
856
903
|
limit?: number;
|
|
857
|
-
|
|
904
|
+
skipDuplicates?: boolean;
|
|
905
|
+
}) => Promise<(string | null)[]>;
|
|
858
906
|
lookupById?: (id: string, expectedTable?: string) => Promise<null | {
|
|
859
907
|
row: Record<string, unknown>;
|
|
860
908
|
tableName: string;
|
|
@@ -865,7 +913,17 @@ interface MaskDatabase {
|
|
|
865
913
|
patch: Record<string, unknown>;
|
|
866
914
|
}>, options?: {
|
|
867
915
|
limit?: number;
|
|
868
|
-
}) => Promise<
|
|
916
|
+
}) => Promise<{
|
|
917
|
+
patched: number;
|
|
918
|
+
}>;
|
|
919
|
+
patchWhere?: (tableName: string, args: {
|
|
920
|
+
patch: Record<string, unknown>;
|
|
921
|
+
where: Record<string, unknown>;
|
|
922
|
+
}, options?: {
|
|
923
|
+
limit?: number;
|
|
924
|
+
}) => Promise<{
|
|
925
|
+
patched: number;
|
|
926
|
+
}>;
|
|
869
927
|
query: (tableName: string) => TableReaderLike$1;
|
|
870
928
|
rank: (tableName: string, indexName: string, options: unknown) => Promise<null | {
|
|
871
929
|
position: number;
|
|
@@ -1737,6 +1795,11 @@ interface DatabaseWriterLike {
|
|
|
1737
1795
|
}, expectedTable?: string) => Promise<{
|
|
1738
1796
|
deleted: number;
|
|
1739
1797
|
}>;
|
|
1798
|
+
deleteWhere?: (tableName: string, where: WhereInput, options?: {
|
|
1799
|
+
limit?: number;
|
|
1800
|
+
}) => Promise<{
|
|
1801
|
+
deleted: number;
|
|
1802
|
+
}>;
|
|
1740
1803
|
findFirst: (tableName: string, args?: QueryArgs) => Promise<Record<string, unknown> | null>;
|
|
1741
1804
|
findFirstOrThrow: (tableName: string, args?: QueryArgs) => Promise<Record<string, unknown>>;
|
|
1742
1805
|
findMany: (tableName: string, args?: QueryArgs) => Promise<QueryPage>;
|
|
@@ -1753,7 +1816,8 @@ interface DatabaseWriterLike {
|
|
|
1753
1816
|
insert: (tableName: string, document: Record<string, unknown>) => Promise<string>;
|
|
1754
1817
|
insertMany: (tableName: string, documents: ReadonlyArray<Record<string, unknown>>, options?: {
|
|
1755
1818
|
limit?: number;
|
|
1756
|
-
|
|
1819
|
+
skipDuplicates?: boolean;
|
|
1820
|
+
}) => Promise<(string | null)[]>;
|
|
1757
1821
|
insertManyUnsafe: (tableName: string, documents: ReadonlyArray<Record<string, unknown>>, options?: {
|
|
1758
1822
|
allowExplicitId?: boolean;
|
|
1759
1823
|
limit?: number;
|
|
@@ -1776,7 +1840,17 @@ interface DatabaseWriterLike {
|
|
|
1776
1840
|
patch: Record<string, unknown>;
|
|
1777
1841
|
}>, options?: {
|
|
1778
1842
|
limit?: number;
|
|
1779
|
-
}, expectedTable?: string) => Promise<
|
|
1843
|
+
}, expectedTable?: string) => Promise<{
|
|
1844
|
+
patched: number;
|
|
1845
|
+
}>;
|
|
1846
|
+
patchWhere?: (tableName: string, args: {
|
|
1847
|
+
patch: Record<string, unknown>;
|
|
1848
|
+
where: WhereInput;
|
|
1849
|
+
}, options?: {
|
|
1850
|
+
limit?: number;
|
|
1851
|
+
}) => Promise<{
|
|
1852
|
+
patched: number;
|
|
1853
|
+
}>;
|
|
1780
1854
|
query: (tableName: string) => TableReaderLike;
|
|
1781
1855
|
/**
|
|
1782
1856
|
* Rank a row within its partition. A position is a count-of-rows-before, so
|
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ export { initLunora } from './packem_shared/initLunora-sQUqaejx.mjs';
|
|
|
3
3
|
export { createSecrets } from './packem_shared/createSecrets-DwaR2rNG.mjs';
|
|
4
4
|
export { LunoraEnvError, defineEnv, redactSecrets } from './packem_shared/LunoraEnvError-BGmd1Qs0.mjs';
|
|
5
5
|
export { LunoraError } from './packem_shared/LunoraError-WbxmrpxR.mjs';
|
|
6
|
-
export { bindOrm, bindTableFacade } from './packem_shared/bindOrm-
|
|
6
|
+
export { bindOrm, bindTableFacade } from './packem_shared/bindOrm-Bfgl7f-Q.mjs';
|
|
7
7
|
export { httpAction, httpRoute, httpRouter, isSafeHeaderValue, serveStorageObject } from './packem_shared/httpAction-DCXoYPIk.mjs';
|
|
8
8
|
export { defineIdentity } from './packem_shared/defineIdentity-DiX4zM9x.mjs';
|
|
9
9
|
export { onConnect, onDisconnect } from './packem_shared/onConnect-CIPXKPyw.mjs';
|
|
@@ -17,11 +17,11 @@ export { defineShape } from './packem_shared/defineShape-C5scNOrf.mjs';
|
|
|
17
17
|
export { anyApi } from './types.mjs';
|
|
18
18
|
export { cronJobs } from '@lunora/scheduler';
|
|
19
19
|
export { ValidationError, v } from '@lunora/values';
|
|
20
|
-
export { buildRlsReadRegistry, composeShapeReadWhere } from './packem_shared/buildRlsReadRegistry-
|
|
20
|
+
export { buildRlsReadRegistry, composeShapeReadWhere } from './packem_shared/buildRlsReadRegistry-D54vUQe4.mjs';
|
|
21
21
|
export { createPolicyDsl, definePermission, definePolicies, definePolicy, defineRole } from './packem_shared/createPolicyDsl-By3QB4he.mjs';
|
|
22
22
|
export { defineStorageRule, defineStorageRules } from './packem_shared/defineStorageRule-B5nL4Z1P.mjs';
|
|
23
|
-
export { mask } from './packem_shared/mask-
|
|
24
|
-
export { rls } from './packem_shared/rls-
|
|
23
|
+
export { mask } from './packem_shared/mask-BT1YgRbF.mjs';
|
|
24
|
+
export { rls } from './packem_shared/rls-B_ZWgslr.mjs';
|
|
25
25
|
export { storageRules } from './packem_shared/storageRules-6QxzDOcx.mjs';
|
|
26
26
|
|
|
27
27
|
const VERSION = "0.0.0";
|
|
@@ -44,15 +44,24 @@ const bindTableFacade = (writer, tableName) => {
|
|
|
44
44
|
count: (where) => writer.count(tableName, where),
|
|
45
45
|
delete: (id) => writer.delete(id, tableName),
|
|
46
46
|
// `deleteMany`/`patchMany` forward the bound `tableName` as `expectedTable`
|
|
47
|
-
// (threaded through the writer + the RLS middleware's
|
|
48
|
-
// batched id is scoped to this table — the same IDOR
|
|
49
|
-
// `delete`/`patch` apply.
|
|
50
|
-
// the writer's `{
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
// for id-based calls (threaded through the writer + the RLS middleware's
|
|
48
|
+
// per-id gate) so every batched id is scoped to this table — the same IDOR
|
|
49
|
+
// guard the single-row `delete`/`patch` apply. The where-based form routes
|
|
50
|
+
// through the structural writer's `deleteMany(tableName, { where })`.
|
|
51
|
+
// `patchMany` maps the facade's `values` payload to the writer's
|
|
52
|
+
// `{ id, patch }` shape.
|
|
53
|
+
deleteMany: (first, options) => {
|
|
54
|
+
if (Array.isArray(first)) {
|
|
55
|
+
if (writer.deleteMany === void 0) {
|
|
56
|
+
throw new LunoraError$1("INTERNAL", `ctx.db.${tableName}.deleteMany is unavailable: this writer has no batch delete`);
|
|
57
|
+
}
|
|
58
|
+
return writer.deleteMany(first, options, tableName);
|
|
54
59
|
}
|
|
55
|
-
|
|
60
|
+
if (writer.deleteWhere === void 0) {
|
|
61
|
+
throw new LunoraError$1("INTERNAL", `ctx.db.${tableName}.deleteMany({ where }) is unavailable: this writer has no where-based delete`);
|
|
62
|
+
}
|
|
63
|
+
const whereArgs = first;
|
|
64
|
+
return writer.deleteWhere(tableName, whereArgs.where, { limit: whereArgs.limit });
|
|
56
65
|
},
|
|
57
66
|
// `exists` reuses `findFirst` (RLS-filtered, indexed when a `.withIndex`-able
|
|
58
67
|
// `where` is supplied) and only asks whether a row came back — no count scan.
|
|
@@ -72,17 +81,24 @@ const bindTableFacade = (writer, tableName) => {
|
|
|
72
81
|
return writer.insertMany(tableName, documents, options);
|
|
73
82
|
},
|
|
74
83
|
patch: (id, patch) => writer.patch(id, patch, tableName),
|
|
75
|
-
patchMany: (
|
|
76
|
-
if (
|
|
77
|
-
|
|
84
|
+
patchMany: (first, options) => {
|
|
85
|
+
if (Array.isArray(first)) {
|
|
86
|
+
if (writer.patchMany === void 0) {
|
|
87
|
+
throw new LunoraError$1("INTERNAL", `ctx.db.${tableName}.patchMany is unavailable: this writer has no batch patch`);
|
|
88
|
+
}
|
|
89
|
+
return writer.patchMany(
|
|
90
|
+
first.map((entry) => {
|
|
91
|
+
return { id: entry.id, patch: entry.values };
|
|
92
|
+
}),
|
|
93
|
+
options,
|
|
94
|
+
tableName
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
if (writer.patchWhere === void 0) {
|
|
98
|
+
throw new LunoraError$1("INTERNAL", `ctx.db.${tableName}.patchMany({ where, values }) is unavailable: this writer has no where-based patch`);
|
|
78
99
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return { id: entry.id, patch: entry.values };
|
|
82
|
-
}),
|
|
83
|
-
options,
|
|
84
|
-
tableName
|
|
85
|
-
);
|
|
100
|
+
const whereArgs = first;
|
|
101
|
+
return writer.patchWhere(tableName, { patch: whereArgs.values, where: whereArgs.where }, { limit: whereArgs.limit });
|
|
86
102
|
},
|
|
87
103
|
rank: (indexName, options) => writer.rank(tableName, indexName, options),
|
|
88
104
|
rankPage: (indexName, options) => writer.rankPage(tableName, indexName, options),
|
package/dist/packem_shared/{buildRlsReadRegistry-DFBFLydB.mjs → buildRlsReadRegistry-D54vUQe4.mjs}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { indexRolePermissions, computeReadBaseWhere, permissionName } from './rls-
|
|
1
|
+
import { indexRolePermissions, computeReadBaseWhere, permissionName } from './rls-B_ZWgslr.mjs';
|
|
2
2
|
import { r as readRlsTag } from './policy-tag-DvpVH2tv.mjs';
|
|
3
3
|
|
|
4
4
|
const FALSE_PREDICATE = { OR: [] };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LunoraError } from './LunoraError-WbxmrpxR.mjs';
|
|
2
|
-
import { bindTableFacade, bindOrm } from './bindOrm-
|
|
2
|
+
import { bindTableFacade, bindOrm } from './bindOrm-Bfgl7f-Q.mjs';
|
|
3
3
|
|
|
4
4
|
const permissionName = (permission) => typeof permission === "string" ? permission : permission.name;
|
|
5
5
|
const indexRolePermissions = (roles) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LunoraError } from './LunoraError-WbxmrpxR.mjs';
|
|
2
|
-
import { bindTableFacade, bindOrm } from './bindOrm-
|
|
2
|
+
import { bindTableFacade, bindOrm } from './bindOrm-Bfgl7f-Q.mjs';
|
|
3
3
|
import { t as tagRlsMiddleware } from './policy-tag-DvpVH2tv.mjs';
|
|
4
4
|
|
|
5
5
|
const DEFAULT_BATCH_LIMIT = 500;
|
|
@@ -333,6 +333,16 @@ const wrapDatabase = (base, raw, perTable, context) => {
|
|
|
333
333
|
}
|
|
334
334
|
return { deleted: ids.length };
|
|
335
335
|
},
|
|
336
|
+
async deleteWhere(tableName, where, options) {
|
|
337
|
+
const { baseWhere } = readBase(tableName);
|
|
338
|
+
const resolved = await route(tableName).findMany(tableName, {
|
|
339
|
+
baseWhere: mergeBaseWhere(where, baseWhere),
|
|
340
|
+
relationBaseWhere: relationReadFilter
|
|
341
|
+
});
|
|
342
|
+
const ids = resolved.page.map((row) => String(row["_id"]));
|
|
343
|
+
assertBatchLimit(ids.length, options?.limit, "deleteWhere");
|
|
344
|
+
return wrapped.deleteMany(ids, options);
|
|
345
|
+
},
|
|
336
346
|
async findFirst(tableName, args) {
|
|
337
347
|
const { baseWhere } = readBase(tableName);
|
|
338
348
|
return route(tableName).findFirst(tableName, {
|
|
@@ -436,6 +446,19 @@ const wrapDatabase = (base, raw, perTable, context) => {
|
|
|
436
446
|
expectedTable
|
|
437
447
|
);
|
|
438
448
|
}
|
|
449
|
+
return { patched: patches.length };
|
|
450
|
+
},
|
|
451
|
+
async patchWhere(tableName, args, options) {
|
|
452
|
+
const { baseWhere } = readBase(tableName);
|
|
453
|
+
const resolved = await route(tableName).findMany(tableName, {
|
|
454
|
+
baseWhere: mergeBaseWhere(args.where, baseWhere),
|
|
455
|
+
relationBaseWhere: relationReadFilter
|
|
456
|
+
});
|
|
457
|
+
const patches = resolved.page.map((row) => {
|
|
458
|
+
return { id: String(row["_id"]), patch: args.patch };
|
|
459
|
+
});
|
|
460
|
+
assertBatchLimit(patches.length, options?.limit, "patchWhere");
|
|
461
|
+
return wrapped.patchMany(patches, options);
|
|
439
462
|
},
|
|
440
463
|
query(tableName) {
|
|
441
464
|
const { baseWhere } = readBase(tableName);
|
package/dist/rls/testing.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { indexRolePermissions, computeReadBaseWhere, matchesWhere, evaluateWrite, permissionName } from '../packem_shared/rls-
|
|
1
|
+
import { indexRolePermissions, computeReadBaseWhere, matchesWhere, evaluateWrite, permissionName } from '../packem_shared/rls-B_ZWgslr.mjs';
|
|
2
2
|
|
|
3
3
|
const expectPolicy = (policies, options = {}) => {
|
|
4
4
|
const rolePermissions = indexRolePermissions(options.roles);
|
package/dist/types.d.mts
CHANGED
|
@@ -518,6 +518,16 @@ interface BatchWriteOptions {
|
|
|
518
518
|
/** Reject the call when the batch size exceeds this value (default 500). */
|
|
519
519
|
limit?: number;
|
|
520
520
|
}
|
|
521
|
+
/** Options accepted by {@link DatabaseWriter.insertMany} and the per-table facade. */
|
|
522
|
+
interface InsertManyOptions extends BatchWriteOptions {
|
|
523
|
+
/**
|
|
524
|
+
* When `true`, a UNIQUE-constraint breach for a row resolves to `null`
|
|
525
|
+
* instead of throwing — the rest of the batch is still inserted. Skipped rows
|
|
526
|
+
* keep their input-order slot with `null` in the returned array. Mirrors
|
|
527
|
+
* better-drizzle's `createMany({ skipDuplicates: true })`.
|
|
528
|
+
*/
|
|
529
|
+
skipDuplicates?: boolean;
|
|
530
|
+
}
|
|
521
531
|
interface DatabaseWriter extends DatabaseReader {
|
|
522
532
|
delete: <T extends string>(id: Id<T>) => Promise<void>;
|
|
523
533
|
/**
|
|
@@ -535,6 +545,18 @@ interface DatabaseWriter extends DatabaseReader {
|
|
|
535
545
|
deleted: number;
|
|
536
546
|
}>;
|
|
537
547
|
/**
|
|
548
|
+
* Delete every row matching `where` in one call. Matching rows are resolved
|
|
549
|
+
* first, then each row is deleted through the single-row delete pipeline
|
|
550
|
+
* (triggers, companion sync, CDC, broadcast) so reactive subscriptions and
|
|
551
|
+
* search/aggregate companions stay correct.
|
|
552
|
+
*
|
|
553
|
+
* **Atomic within a mutation:** the DO wraps a mutation's dispatch in a
|
|
554
|
+
* BEGIN/COMMIT span, so a mid-batch failure rolls back the whole mutation.
|
|
555
|
+
*/
|
|
556
|
+
deleteWhere: (tableName: string, where: Record<string, unknown>, options?: BatchWriteOptions) => Promise<{
|
|
557
|
+
deleted: number;
|
|
558
|
+
}>;
|
|
559
|
+
/**
|
|
538
560
|
* Insert a document, returning its server id.
|
|
539
561
|
*
|
|
540
562
|
* Pass `options.clientId` (a UUID) to key the row yourself — for an
|
|
@@ -551,12 +573,21 @@ interface DatabaseWriter extends DatabaseReader {
|
|
|
551
573
|
* row gets defaults, validators, triggers, and a per-row RLS check — but the
|
|
552
574
|
* caller pays one round-trip instead of N.
|
|
553
575
|
*
|
|
576
|
+
* Pass `{ skipDuplicates: true }` to turn UNIQUE-constraint breaches into
|
|
577
|
+
* `null` results for that row instead of failing the whole batch; the rest of
|
|
578
|
+
* the batch is still inserted and order is preserved.
|
|
579
|
+
*
|
|
554
580
|
* **Atomic within a mutation:** the DO wraps a mutation's dispatch in a
|
|
555
581
|
* BEGIN/COMMIT span, so a mid-batch failure (an invalid or RLS-denied row)
|
|
556
582
|
* rolls back the whole mutation. (In an action there is no transaction span,
|
|
557
583
|
* so the prior inserts persist; the in-memory test harness mirrors the span.)
|
|
558
584
|
*/
|
|
559
|
-
insertMany:
|
|
585
|
+
insertMany: {
|
|
586
|
+
<T extends string>(tableName: T, documents: ReadonlyArray<Record<string, unknown>>, options: BatchWriteOptions & {
|
|
587
|
+
skipDuplicates: true;
|
|
588
|
+
}): Promise<(Id<T> | null)[]>;
|
|
589
|
+
<T extends string>(tableName: T, documents: ReadonlyArray<Record<string, unknown>>, options?: InsertManyOptions): Promise<Id<T>[]>;
|
|
590
|
+
};
|
|
560
591
|
/**
|
|
561
592
|
* **Trusted** bulk insert: one multi-row `INSERT` that **skips per-row
|
|
562
593
|
* `.check()` validators and before/after triggers** for throughput on data you
|
|
@@ -576,7 +607,8 @@ interface DatabaseWriter extends DatabaseReader {
|
|
|
576
607
|
patch: <T extends string>(id: Id<T>, patch: Record<string, unknown>) => Promise<void>;
|
|
577
608
|
/**
|
|
578
609
|
* Patch many rows by id in one call. Each `{ id, patch }` is applied like a
|
|
579
|
-
* single `patch()` (per-row triggers + RLS).
|
|
610
|
+
* single `patch()` (per-row triggers + RLS). Returns the number of rows
|
|
611
|
+
* actually patched.
|
|
580
612
|
*
|
|
581
613
|
* **Atomic within a mutation:** the DO wraps a mutation's dispatch in a
|
|
582
614
|
* BEGIN/COMMIT span, so a mid-batch failure rolls back the whole mutation.
|
|
@@ -586,7 +618,24 @@ interface DatabaseWriter extends DatabaseReader {
|
|
|
586
618
|
patchMany: <T extends string>(patches: ReadonlyArray<{
|
|
587
619
|
id: Id<T>;
|
|
588
620
|
patch: Record<string, unknown>;
|
|
589
|
-
}>, options?: BatchWriteOptions) => Promise<
|
|
621
|
+
}>, options?: BatchWriteOptions) => Promise<{
|
|
622
|
+
patched: number;
|
|
623
|
+
}>;
|
|
624
|
+
/**
|
|
625
|
+
* Patch every row matching `where` with the same `patch` in one call. The
|
|
626
|
+
* matching rows are resolved first, then each row is updated through the
|
|
627
|
+
* single-row patch pipeline (OCC, triggers, companion sync, CDC, broadcast)
|
|
628
|
+
* so reactive subscriptions and search/aggregate companions stay correct.
|
|
629
|
+
*
|
|
630
|
+
* **Atomic within a mutation:** the DO wraps a mutation's dispatch in a
|
|
631
|
+
* BEGIN/COMMIT span, so a mid-batch failure rolls back the whole mutation.
|
|
632
|
+
*/
|
|
633
|
+
patchWhere: (tableName: string, args: {
|
|
634
|
+
patch: Record<string, unknown>;
|
|
635
|
+
where: Record<string, unknown>;
|
|
636
|
+
}, options?: BatchWriteOptions) => Promise<{
|
|
637
|
+
patched: number;
|
|
638
|
+
}>;
|
|
590
639
|
replace: <T extends string>(id: Id<T>, document: Record<string, unknown>) => Promise<void>;
|
|
591
640
|
}
|
|
592
641
|
/** Authenticated identity surfaced into every context. */
|
package/dist/types.d.ts
CHANGED
|
@@ -518,6 +518,16 @@ interface BatchWriteOptions {
|
|
|
518
518
|
/** Reject the call when the batch size exceeds this value (default 500). */
|
|
519
519
|
limit?: number;
|
|
520
520
|
}
|
|
521
|
+
/** Options accepted by {@link DatabaseWriter.insertMany} and the per-table facade. */
|
|
522
|
+
interface InsertManyOptions extends BatchWriteOptions {
|
|
523
|
+
/**
|
|
524
|
+
* When `true`, a UNIQUE-constraint breach for a row resolves to `null`
|
|
525
|
+
* instead of throwing — the rest of the batch is still inserted. Skipped rows
|
|
526
|
+
* keep their input-order slot with `null` in the returned array. Mirrors
|
|
527
|
+
* better-drizzle's `createMany({ skipDuplicates: true })`.
|
|
528
|
+
*/
|
|
529
|
+
skipDuplicates?: boolean;
|
|
530
|
+
}
|
|
521
531
|
interface DatabaseWriter extends DatabaseReader {
|
|
522
532
|
delete: <T extends string>(id: Id<T>) => Promise<void>;
|
|
523
533
|
/**
|
|
@@ -535,6 +545,18 @@ interface DatabaseWriter extends DatabaseReader {
|
|
|
535
545
|
deleted: number;
|
|
536
546
|
}>;
|
|
537
547
|
/**
|
|
548
|
+
* Delete every row matching `where` in one call. Matching rows are resolved
|
|
549
|
+
* first, then each row is deleted through the single-row delete pipeline
|
|
550
|
+
* (triggers, companion sync, CDC, broadcast) so reactive subscriptions and
|
|
551
|
+
* search/aggregate companions stay correct.
|
|
552
|
+
*
|
|
553
|
+
* **Atomic within a mutation:** the DO wraps a mutation's dispatch in a
|
|
554
|
+
* BEGIN/COMMIT span, so a mid-batch failure rolls back the whole mutation.
|
|
555
|
+
*/
|
|
556
|
+
deleteWhere: (tableName: string, where: Record<string, unknown>, options?: BatchWriteOptions) => Promise<{
|
|
557
|
+
deleted: number;
|
|
558
|
+
}>;
|
|
559
|
+
/**
|
|
538
560
|
* Insert a document, returning its server id.
|
|
539
561
|
*
|
|
540
562
|
* Pass `options.clientId` (a UUID) to key the row yourself — for an
|
|
@@ -551,12 +573,21 @@ interface DatabaseWriter extends DatabaseReader {
|
|
|
551
573
|
* row gets defaults, validators, triggers, and a per-row RLS check — but the
|
|
552
574
|
* caller pays one round-trip instead of N.
|
|
553
575
|
*
|
|
576
|
+
* Pass `{ skipDuplicates: true }` to turn UNIQUE-constraint breaches into
|
|
577
|
+
* `null` results for that row instead of failing the whole batch; the rest of
|
|
578
|
+
* the batch is still inserted and order is preserved.
|
|
579
|
+
*
|
|
554
580
|
* **Atomic within a mutation:** the DO wraps a mutation's dispatch in a
|
|
555
581
|
* BEGIN/COMMIT span, so a mid-batch failure (an invalid or RLS-denied row)
|
|
556
582
|
* rolls back the whole mutation. (In an action there is no transaction span,
|
|
557
583
|
* so the prior inserts persist; the in-memory test harness mirrors the span.)
|
|
558
584
|
*/
|
|
559
|
-
insertMany:
|
|
585
|
+
insertMany: {
|
|
586
|
+
<T extends string>(tableName: T, documents: ReadonlyArray<Record<string, unknown>>, options: BatchWriteOptions & {
|
|
587
|
+
skipDuplicates: true;
|
|
588
|
+
}): Promise<(Id<T> | null)[]>;
|
|
589
|
+
<T extends string>(tableName: T, documents: ReadonlyArray<Record<string, unknown>>, options?: InsertManyOptions): Promise<Id<T>[]>;
|
|
590
|
+
};
|
|
560
591
|
/**
|
|
561
592
|
* **Trusted** bulk insert: one multi-row `INSERT` that **skips per-row
|
|
562
593
|
* `.check()` validators and before/after triggers** for throughput on data you
|
|
@@ -576,7 +607,8 @@ interface DatabaseWriter extends DatabaseReader {
|
|
|
576
607
|
patch: <T extends string>(id: Id<T>, patch: Record<string, unknown>) => Promise<void>;
|
|
577
608
|
/**
|
|
578
609
|
* Patch many rows by id in one call. Each `{ id, patch }` is applied like a
|
|
579
|
-
* single `patch()` (per-row triggers + RLS).
|
|
610
|
+
* single `patch()` (per-row triggers + RLS). Returns the number of rows
|
|
611
|
+
* actually patched.
|
|
580
612
|
*
|
|
581
613
|
* **Atomic within a mutation:** the DO wraps a mutation's dispatch in a
|
|
582
614
|
* BEGIN/COMMIT span, so a mid-batch failure rolls back the whole mutation.
|
|
@@ -586,7 +618,24 @@ interface DatabaseWriter extends DatabaseReader {
|
|
|
586
618
|
patchMany: <T extends string>(patches: ReadonlyArray<{
|
|
587
619
|
id: Id<T>;
|
|
588
620
|
patch: Record<string, unknown>;
|
|
589
|
-
}>, options?: BatchWriteOptions) => Promise<
|
|
621
|
+
}>, options?: BatchWriteOptions) => Promise<{
|
|
622
|
+
patched: number;
|
|
623
|
+
}>;
|
|
624
|
+
/**
|
|
625
|
+
* Patch every row matching `where` with the same `patch` in one call. The
|
|
626
|
+
* matching rows are resolved first, then each row is updated through the
|
|
627
|
+
* single-row patch pipeline (OCC, triggers, companion sync, CDC, broadcast)
|
|
628
|
+
* so reactive subscriptions and search/aggregate companions stay correct.
|
|
629
|
+
*
|
|
630
|
+
* **Atomic within a mutation:** the DO wraps a mutation's dispatch in a
|
|
631
|
+
* BEGIN/COMMIT span, so a mid-batch failure rolls back the whole mutation.
|
|
632
|
+
*/
|
|
633
|
+
patchWhere: (tableName: string, args: {
|
|
634
|
+
patch: Record<string, unknown>;
|
|
635
|
+
where: Record<string, unknown>;
|
|
636
|
+
}, options?: BatchWriteOptions) => Promise<{
|
|
637
|
+
patched: number;
|
|
638
|
+
}>;
|
|
590
639
|
replace: <T extends string>(id: Id<T>, document: Record<string, unknown>) => Promise<void>;
|
|
591
640
|
}
|
|
592
641
|
/** Authenticated identity surfaced into every context. */
|