@vibeorm/runtime 1.0.1 → 1.1.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 +19 -0
- package/package.json +1 -1
- package/src/adapter.ts +33 -1
- package/src/client.ts +88 -33
- package/src/errors.ts +427 -6
- package/src/index.ts +15 -1
- package/src/lateral-join-builder.ts +157 -81
- package/src/query-builder.ts +573 -194
- package/src/relation-loader.ts +54 -20
- package/src/types.ts +25 -0
- package/src/where-builder.ts +56 -21
package/README.md
CHANGED
|
@@ -36,6 +36,25 @@ const db = VibeClient({
|
|
|
36
36
|
|
|
37
37
|
Creates a VibeORM client instance. Called by generated code — takes model metadata, optional Zod schemas, and client options.
|
|
38
38
|
|
|
39
|
+
`countStrategy` can be set globally in client options and overridden per count call:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
await db.user.count({
|
|
43
|
+
where: { isActive: true },
|
|
44
|
+
countStrategy: "subquery",
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Per-operation `countStrategy` takes precedence over the client default.
|
|
49
|
+
|
|
50
|
+
### Mutation RETURNING behavior
|
|
51
|
+
|
|
52
|
+
`create`, `update`, `delete`, and `upsert` now narrow SQL `RETURNING` columns when `select` is provided, reducing row payload size.
|
|
53
|
+
|
|
54
|
+
- Default behavior: full scalar row is returned (same as before)
|
|
55
|
+
- With `select`: only selected scalar columns are returned (plus internal keys when needed)
|
|
56
|
+
- With `returning: true`: force full scalar `RETURNING` payload even when `select` is present
|
|
57
|
+
|
|
39
58
|
### `toSqlExecutor({ adapter })`
|
|
40
59
|
|
|
41
60
|
Bridges a `DatabaseAdapter` to a `SqlExecutor` for use with the migrate package.
|
package/package.json
CHANGED
package/src/adapter.ts
CHANGED
|
@@ -6,6 +6,35 @@
|
|
|
6
6
|
* and interacts with the database exclusively through this contract.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
// ─── Transaction Options ──────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Options for controlling transaction behavior.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* await db.$transaction(async (tx) => {
|
|
17
|
+
* await tx.account.update({ where: { id: 1 }, data: { balance: { decrement: 100 } } });
|
|
18
|
+
* await tx.account.update({ where: { id: 2 }, data: { balance: { increment: 100 } } });
|
|
19
|
+
* }, { isolationLevel: "Serializable", timeout: 5000 });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export type TransactionOptions = {
|
|
23
|
+
/**
|
|
24
|
+
* PostgreSQL isolation level for the transaction.
|
|
25
|
+
* - "ReadCommitted" (default): Standard PostgreSQL default.
|
|
26
|
+
* - "RepeatableRead": Prevents non-repeatable reads.
|
|
27
|
+
* - "Serializable": Full serializability — conflicts throw serialization_failure.
|
|
28
|
+
*/
|
|
29
|
+
isolationLevel?: "ReadCommitted" | "RepeatableRead" | "Serializable";
|
|
30
|
+
/**
|
|
31
|
+
* Maximum time in milliseconds the transaction may run before being cancelled.
|
|
32
|
+
* Implemented via `SET LOCAL statement_timeout = N` inside the transaction,
|
|
33
|
+
* so it is scoped to the transaction and does not affect other connections.
|
|
34
|
+
*/
|
|
35
|
+
timeout?: number;
|
|
36
|
+
};
|
|
37
|
+
|
|
9
38
|
// ─── Core Adapter Interface ───────────────────────────────────────
|
|
10
39
|
|
|
11
40
|
/**
|
|
@@ -38,8 +67,11 @@ export type DatabaseAdapter = {
|
|
|
38
67
|
* Run a function inside a database transaction.
|
|
39
68
|
* The callback receives a transactional adapter with the same interface.
|
|
40
69
|
* If the callback throws, the transaction is automatically rolled back.
|
|
70
|
+
*
|
|
71
|
+
* @param fn - The transactional callback.
|
|
72
|
+
* @param options - Optional isolation level and timeout.
|
|
41
73
|
*/
|
|
42
|
-
transaction<T>(fn: (txAdapter: DatabaseAdapter) => Promise<T
|
|
74
|
+
transaction<T>(fn: (txAdapter: DatabaseAdapter) => Promise<T>, options?: TransactionOptions): Promise<T>;
|
|
43
75
|
|
|
44
76
|
/**
|
|
45
77
|
* Eagerly warm up the connection pool.
|
package/src/client.ts
CHANGED
|
@@ -16,8 +16,8 @@ import type {
|
|
|
16
16
|
ProfilingContext,
|
|
17
17
|
} from "./types.ts";
|
|
18
18
|
import { getScalarFieldMap, getModelByNameMap, PgArray } from "./types.ts";
|
|
19
|
-
import type { DatabaseAdapter } from "./adapter.ts";
|
|
20
|
-
import { VibeValidationError } from "./errors.ts";
|
|
19
|
+
import type { DatabaseAdapter, TransactionOptions } from "./adapter.ts";
|
|
20
|
+
import { VibeValidationError, VibeRequestError, normalizeError } from "./errors.ts";
|
|
21
21
|
import {
|
|
22
22
|
buildSelectQuery,
|
|
23
23
|
buildInsertQuery,
|
|
@@ -30,11 +30,10 @@ import {
|
|
|
30
30
|
buildGroupByQuery,
|
|
31
31
|
buildUpsertQuery,
|
|
32
32
|
} from "./query-builder.ts";
|
|
33
|
-
import { loadRelations } from "./relation-loader.ts";
|
|
33
|
+
import { loadRelations, resolveRelationsToLoad } from "./relation-loader.ts";
|
|
34
34
|
import {
|
|
35
35
|
loadRelationsWithLateralJoin,
|
|
36
36
|
executeLateralJoinQuery,
|
|
37
|
-
resolveRelationsToLoad,
|
|
38
37
|
} from "./lateral-join-builder.ts";
|
|
39
38
|
import { generateDefault } from "./id-generators.ts";
|
|
40
39
|
|
|
@@ -51,6 +50,8 @@ export function createClient(params: {
|
|
|
51
50
|
const adapter = options.adapter;
|
|
52
51
|
const shouldLog = options?.log === true || options?.log === "query";
|
|
53
52
|
const shouldDebug = !!options?.debug;
|
|
53
|
+
const defaultOrderByPk = options?.defaultOrderByPk ?? false;
|
|
54
|
+
const distinctOrderByPk = options?.distinctOrderByPk ?? true;
|
|
54
55
|
|
|
55
56
|
/** Emit a query profile to the user's debug handler or console. */
|
|
56
57
|
function debugEmit(profile: QueryProfile): void {
|
|
@@ -158,6 +159,7 @@ export function createClient(params: {
|
|
|
158
159
|
// SQL executor function — delegates to the adapter.
|
|
159
160
|
// Array values are converted via adapter.formatArrayParam so that
|
|
160
161
|
// = ANY($1) works correctly.
|
|
162
|
+
// Database errors are normalized into VibeRequestError / VibeTransientError.
|
|
161
163
|
async function executeSql(params: { text: string; values: unknown[] }): Promise<Record<string, unknown>[]> {
|
|
162
164
|
const { text, values: rawValues } = params;
|
|
163
165
|
// Convert PgArray instances - let the adapter handle the format
|
|
@@ -170,7 +172,11 @@ export function createClient(params: {
|
|
|
170
172
|
}
|
|
171
173
|
}
|
|
172
174
|
|
|
173
|
-
|
|
175
|
+
try {
|
|
176
|
+
return await adapter.execute({ text, values });
|
|
177
|
+
} catch (err) {
|
|
178
|
+
throw normalizeError({ error: err });
|
|
179
|
+
}
|
|
174
180
|
}
|
|
175
181
|
|
|
176
182
|
// Create delegate for a model
|
|
@@ -252,6 +258,7 @@ export function createClient(params: {
|
|
|
252
258
|
args,
|
|
253
259
|
executor: executeSql,
|
|
254
260
|
profilingCtx,
|
|
261
|
+
defaultOrderByPk,
|
|
255
262
|
});
|
|
256
263
|
const t1 = performance.now();
|
|
257
264
|
const sizeBytes = estimateResultSize({ records: result });
|
|
@@ -278,6 +285,7 @@ export function createClient(params: {
|
|
|
278
285
|
allModelsMeta,
|
|
279
286
|
args,
|
|
280
287
|
executor,
|
|
288
|
+
defaultOrderByPk,
|
|
281
289
|
});
|
|
282
290
|
validateOutput({ records: result, operation: "findMany" });
|
|
283
291
|
return result;
|
|
@@ -291,6 +299,8 @@ export function createClient(params: {
|
|
|
291
299
|
modelMeta,
|
|
292
300
|
allModelsMeta,
|
|
293
301
|
args,
|
|
302
|
+
defaultOrderByPk,
|
|
303
|
+
distinctOrderByPk,
|
|
294
304
|
});
|
|
295
305
|
const t1 = performance.now();
|
|
296
306
|
let records = await profExec(query);
|
|
@@ -327,6 +337,8 @@ export function createClient(params: {
|
|
|
327
337
|
modelMeta,
|
|
328
338
|
allModelsMeta,
|
|
329
339
|
args,
|
|
340
|
+
defaultOrderByPk,
|
|
341
|
+
distinctOrderByPk,
|
|
330
342
|
});
|
|
331
343
|
let records = await executor(query);
|
|
332
344
|
|
|
@@ -352,6 +364,7 @@ export function createClient(params: {
|
|
|
352
364
|
allModelsMeta,
|
|
353
365
|
args: argsWithLimit,
|
|
354
366
|
executor,
|
|
367
|
+
defaultOrderByPk,
|
|
355
368
|
});
|
|
356
369
|
validateOutput({ records, operation: "findFirst" });
|
|
357
370
|
return records[0] ?? null;
|
|
@@ -361,7 +374,7 @@ export function createClient(params: {
|
|
|
361
374
|
const profilingCtx: ProfilingContext = { relationProfiles: [] };
|
|
362
375
|
const { executor: profExec } = createProfiledExecutor(profilingCtx);
|
|
363
376
|
const t0 = performance.now();
|
|
364
|
-
const query = buildSelectQuery({ modelMeta, allModelsMeta, args: argsWithLimit });
|
|
377
|
+
const query = buildSelectQuery({ modelMeta, allModelsMeta, args: argsWithLimit, defaultOrderByPk, distinctOrderByPk });
|
|
365
378
|
const t1 = performance.now();
|
|
366
379
|
let records = await profExec(query);
|
|
367
380
|
const t2 = performance.now();
|
|
@@ -385,6 +398,8 @@ export function createClient(params: {
|
|
|
385
398
|
modelMeta,
|
|
386
399
|
allModelsMeta,
|
|
387
400
|
args: argsWithLimit,
|
|
401
|
+
defaultOrderByPk,
|
|
402
|
+
distinctOrderByPk,
|
|
388
403
|
});
|
|
389
404
|
let records = await executor(query);
|
|
390
405
|
|
|
@@ -414,6 +429,7 @@ export function createClient(params: {
|
|
|
414
429
|
allModelsMeta,
|
|
415
430
|
args: argsWithLimit,
|
|
416
431
|
executor,
|
|
432
|
+
defaultOrderByPk,
|
|
417
433
|
});
|
|
418
434
|
validateOutput({ records, operation: "findUnique" });
|
|
419
435
|
return records[0] ?? null;
|
|
@@ -423,7 +439,7 @@ export function createClient(params: {
|
|
|
423
439
|
const profilingCtx: ProfilingContext = { relationProfiles: [] };
|
|
424
440
|
const { executor: profExec } = createProfiledExecutor(profilingCtx);
|
|
425
441
|
const t0 = performance.now();
|
|
426
|
-
const query = buildSelectQuery({ modelMeta, allModelsMeta, args: argsWithLimit });
|
|
442
|
+
const query = buildSelectQuery({ modelMeta, allModelsMeta, args: argsWithLimit, defaultOrderByPk, distinctOrderByPk });
|
|
427
443
|
const t1 = performance.now();
|
|
428
444
|
let records = await profExec(query);
|
|
429
445
|
const t2 = performance.now();
|
|
@@ -447,6 +463,8 @@ export function createClient(params: {
|
|
|
447
463
|
modelMeta,
|
|
448
464
|
allModelsMeta,
|
|
449
465
|
args: argsWithLimit,
|
|
466
|
+
defaultOrderByPk,
|
|
467
|
+
distinctOrderByPk,
|
|
450
468
|
});
|
|
451
469
|
let records = await executor(query);
|
|
452
470
|
|
|
@@ -466,9 +484,11 @@ export function createClient(params: {
|
|
|
466
484
|
async function findUniqueOrThrow(args: Record<string, unknown>) {
|
|
467
485
|
const result = await findUnique(args);
|
|
468
486
|
if (!result) {
|
|
469
|
-
throw new
|
|
470
|
-
|
|
471
|
-
|
|
487
|
+
throw new VibeRequestError({
|
|
488
|
+
code: "NOT_FOUND",
|
|
489
|
+
message: `No ${modelMeta.name} found for the given where clause`,
|
|
490
|
+
meta: { model: modelMeta.name, operation: "findUniqueOrThrow" },
|
|
491
|
+
});
|
|
472
492
|
}
|
|
473
493
|
return result;
|
|
474
494
|
}
|
|
@@ -476,9 +496,11 @@ export function createClient(params: {
|
|
|
476
496
|
async function findFirstOrThrow(args: Record<string, unknown> = {}) {
|
|
477
497
|
const result = await findFirst(args);
|
|
478
498
|
if (!result) {
|
|
479
|
-
throw new
|
|
480
|
-
|
|
481
|
-
|
|
499
|
+
throw new VibeRequestError({
|
|
500
|
+
code: "NOT_FOUND",
|
|
501
|
+
message: `No ${modelMeta.name} found for the given where clause`,
|
|
502
|
+
meta: { model: modelMeta.name, operation: "findFirstOrThrow" },
|
|
503
|
+
});
|
|
482
504
|
}
|
|
483
505
|
return result;
|
|
484
506
|
}
|
|
@@ -503,6 +525,7 @@ export function createClient(params: {
|
|
|
503
525
|
const query = buildInsertQuery({
|
|
504
526
|
modelMeta,
|
|
505
527
|
data: processedData,
|
|
528
|
+
args: deferredCreates.length === 0 ? args : undefined,
|
|
506
529
|
});
|
|
507
530
|
let records = await executor(query);
|
|
508
531
|
|
|
@@ -537,7 +560,7 @@ export function createClient(params: {
|
|
|
537
560
|
executor,
|
|
538
561
|
});
|
|
539
562
|
|
|
540
|
-
records = applySelectFiltering({ records, args, modelMeta });
|
|
563
|
+
records = applySelectFiltering({ records, args, modelMeta, allowReturningOverride: true });
|
|
541
564
|
|
|
542
565
|
validateOutput({ records, operation: "create" });
|
|
543
566
|
return records[0]!;
|
|
@@ -569,13 +592,16 @@ export function createClient(params: {
|
|
|
569
592
|
allModelsMeta,
|
|
570
593
|
where: whereInput,
|
|
571
594
|
data: scalarData,
|
|
595
|
+
args: nestedOps.length === 0 ? args : undefined,
|
|
572
596
|
});
|
|
573
597
|
let records = await executor(query);
|
|
574
598
|
|
|
575
599
|
if (records.length === 0) {
|
|
576
|
-
throw new
|
|
577
|
-
|
|
578
|
-
|
|
600
|
+
throw new VibeRequestError({
|
|
601
|
+
code: "NOT_FOUND",
|
|
602
|
+
message: `An operation failed because it depends on one or more records that were required but not found. No ${modelMeta.name} found for the given where clause.`,
|
|
603
|
+
meta: { model: modelMeta.name, operation: "update" },
|
|
604
|
+
});
|
|
579
605
|
}
|
|
580
606
|
|
|
581
607
|
const updatedRecord = records[0]!;
|
|
@@ -599,7 +625,7 @@ export function createClient(params: {
|
|
|
599
625
|
executor,
|
|
600
626
|
});
|
|
601
627
|
|
|
602
|
-
records = applySelectFiltering({ records, args, modelMeta });
|
|
628
|
+
records = applySelectFiltering({ records, args, modelMeta, allowReturningOverride: true });
|
|
603
629
|
|
|
604
630
|
validateOutput({ records, operation: "update" });
|
|
605
631
|
return records[0]!;
|
|
@@ -629,6 +655,7 @@ export function createClient(params: {
|
|
|
629
655
|
where: whereInput,
|
|
630
656
|
create: createData,
|
|
631
657
|
update: updateData,
|
|
658
|
+
args,
|
|
632
659
|
});
|
|
633
660
|
|
|
634
661
|
let records = await executor(query);
|
|
@@ -638,7 +665,11 @@ export function createClient(params: {
|
|
|
638
665
|
if (records.length === 0) {
|
|
639
666
|
const existing = await findUnique({ where, select: args.select, include: args.include });
|
|
640
667
|
if (existing) return existing;
|
|
641
|
-
throw new
|
|
668
|
+
throw new VibeRequestError({
|
|
669
|
+
code: "NOT_FOUND",
|
|
670
|
+
message: `Upsert failed: could not insert or find ${modelMeta.name}`,
|
|
671
|
+
meta: { model: modelMeta.name, operation: "upsert" },
|
|
672
|
+
});
|
|
642
673
|
}
|
|
643
674
|
|
|
644
675
|
records = await loadRelationsForStrategy({
|
|
@@ -649,7 +680,7 @@ export function createClient(params: {
|
|
|
649
680
|
executor,
|
|
650
681
|
});
|
|
651
682
|
|
|
652
|
-
records = applySelectFiltering({ records, args, modelMeta });
|
|
683
|
+
records = applySelectFiltering({ records, args, modelMeta, allowReturningOverride: true });
|
|
653
684
|
|
|
654
685
|
validateOutput({ records, operation: "upsert" });
|
|
655
686
|
return records[0]!;
|
|
@@ -666,17 +697,20 @@ export function createClient(params: {
|
|
|
666
697
|
modelMeta,
|
|
667
698
|
allModelsMeta,
|
|
668
699
|
where: whereInput,
|
|
700
|
+
args,
|
|
669
701
|
});
|
|
670
702
|
let records = await executor(query);
|
|
671
703
|
|
|
672
704
|
if (records.length === 0) {
|
|
673
|
-
throw new
|
|
674
|
-
|
|
675
|
-
|
|
705
|
+
throw new VibeRequestError({
|
|
706
|
+
code: "NOT_FOUND",
|
|
707
|
+
message: `An operation failed because it depends on one or more records that were required but not found. No ${modelMeta.name} found for the given where clause.`,
|
|
708
|
+
meta: { model: modelMeta.name, operation: "delete" },
|
|
709
|
+
});
|
|
676
710
|
}
|
|
677
711
|
|
|
678
712
|
coerceFieldTypes({ records, modelMeta });
|
|
679
|
-
records = applySelectFiltering({ records, args, modelMeta });
|
|
713
|
+
records = applySelectFiltering({ records, args, modelMeta, allowReturningOverride: true });
|
|
680
714
|
|
|
681
715
|
validateOutput({ records, operation: "delete" });
|
|
682
716
|
return records[0]!;
|
|
@@ -704,7 +738,11 @@ export function createClient(params: {
|
|
|
704
738
|
}
|
|
705
739
|
|
|
706
740
|
async function count(args: Record<string, unknown> = {}) {
|
|
707
|
-
const
|
|
741
|
+
const operationCountStrategy = args.countStrategy;
|
|
742
|
+
const countStrategy =
|
|
743
|
+
operationCountStrategy === "direct" || operationCountStrategy === "subquery"
|
|
744
|
+
? operationCountStrategy
|
|
745
|
+
: options?.countStrategy ?? "direct";
|
|
708
746
|
|
|
709
747
|
if (shouldDebug) {
|
|
710
748
|
const t0 = performance.now();
|
|
@@ -817,7 +855,7 @@ export function createClient(params: {
|
|
|
817
855
|
executor,
|
|
818
856
|
});
|
|
819
857
|
|
|
820
|
-
records = applySelectFiltering({ records, args, modelMeta });
|
|
858
|
+
records = applySelectFiltering({ records, args, modelMeta, allowReturningOverride: true });
|
|
821
859
|
|
|
822
860
|
validateOutput({ records, operation: "createManyAndReturn" });
|
|
823
861
|
return records;
|
|
@@ -940,6 +978,7 @@ export function createClient(params: {
|
|
|
940
978
|
args: params.args,
|
|
941
979
|
executor: params.executor,
|
|
942
980
|
profilingCtx: params.profilingCtx,
|
|
981
|
+
defaultOrderByPk,
|
|
943
982
|
});
|
|
944
983
|
} else {
|
|
945
984
|
records = await loadRelations({
|
|
@@ -949,6 +988,7 @@ export function createClient(params: {
|
|
|
949
988
|
args: params.args,
|
|
950
989
|
executor: params.executor,
|
|
951
990
|
profilingCtx: params.profilingCtx,
|
|
991
|
+
defaultOrderByPk,
|
|
952
992
|
});
|
|
953
993
|
}
|
|
954
994
|
|
|
@@ -979,21 +1019,28 @@ export function createClient(params: {
|
|
|
979
1019
|
});
|
|
980
1020
|
}
|
|
981
1021
|
|
|
982
|
-
// $transaction — supports both callback style and array-of-promises style
|
|
1022
|
+
// $transaction — supports both callback style and array-of-promises style.
|
|
1023
|
+
//
|
|
1024
|
+
// Array-of-promises style: wraps pre-created promises in a transaction.
|
|
1025
|
+
// Note: The promises must be created from THIS client's delegates.
|
|
1026
|
+
// They execute within the transaction's commit/rollback boundary, but
|
|
1027
|
+
// their SQL was dispatched on the non-transactional adapter. For full
|
|
1028
|
+
// transactional isolation, use the callback style instead.
|
|
983
1029
|
client.$transaction = async function <T>(
|
|
984
|
-
fnOrPromises: ((tx: Record<string, unknown>) => Promise<T>) | Promise<unknown>[]
|
|
1030
|
+
fnOrPromises: ((tx: Record<string, unknown>) => Promise<T>) | Promise<unknown>[],
|
|
1031
|
+
txOptions?: TransactionOptions
|
|
985
1032
|
): Promise<T | unknown[]> {
|
|
986
1033
|
// Array-of-promises style
|
|
987
1034
|
if (Array.isArray(fnOrPromises)) {
|
|
988
1035
|
return adapter.transaction(async () => {
|
|
989
1036
|
return Promise.all(fnOrPromises);
|
|
990
|
-
});
|
|
1037
|
+
}, txOptions);
|
|
991
1038
|
}
|
|
992
1039
|
|
|
993
1040
|
// Callback style
|
|
994
1041
|
const fn = fnOrPromises as (tx: Record<string, unknown>) => Promise<T>;
|
|
995
1042
|
return adapter.transaction(async (txAdapter) => {
|
|
996
|
-
// Create a transactional executor
|
|
1043
|
+
// Create a transactional executor — normalizes DB errors
|
|
997
1044
|
async function txExecutor(txParams: { text: string; values: unknown[] }): Promise<Record<string, unknown>[]> {
|
|
998
1045
|
const values = txParams.values.map((v) => (v instanceof PgArray ? txAdapter.formatArrayParam(v.values) : v));
|
|
999
1046
|
if (shouldLog) {
|
|
@@ -1002,7 +1049,11 @@ export function createClient(params: {
|
|
|
1002
1049
|
console.log(`[vibeorm:tx] params:`, values);
|
|
1003
1050
|
}
|
|
1004
1051
|
}
|
|
1005
|
-
|
|
1052
|
+
try {
|
|
1053
|
+
return await txAdapter.execute({ text: txParams.text, values });
|
|
1054
|
+
} catch (err) {
|
|
1055
|
+
throw normalizeError({ error: err });
|
|
1056
|
+
}
|
|
1006
1057
|
}
|
|
1007
1058
|
|
|
1008
1059
|
// Build transactional delegates
|
|
@@ -1044,7 +1095,7 @@ export function createClient(params: {
|
|
|
1044
1095
|
};
|
|
1045
1096
|
|
|
1046
1097
|
return fn(txClient);
|
|
1047
|
-
});
|
|
1098
|
+
}, txOptions);
|
|
1048
1099
|
};
|
|
1049
1100
|
|
|
1050
1101
|
// $queryRaw — tagged template literal for safe parameterized queries
|
|
@@ -1179,8 +1230,12 @@ function applySelectFiltering(params: {
|
|
|
1179
1230
|
records: Record<string, unknown>[];
|
|
1180
1231
|
args: Record<string, unknown>;
|
|
1181
1232
|
modelMeta: ModelMeta;
|
|
1233
|
+
allowReturningOverride?: boolean;
|
|
1182
1234
|
}): Record<string, unknown>[] {
|
|
1183
|
-
const { records, args, modelMeta } = params;
|
|
1235
|
+
const { records, args, modelMeta, allowReturningOverride = false } = params;
|
|
1236
|
+
if (allowReturningOverride && args.returning === true) {
|
|
1237
|
+
return records;
|
|
1238
|
+
}
|
|
1184
1239
|
const select = args.select as Record<string, boolean | object> | undefined;
|
|
1185
1240
|
if (!select) return records;
|
|
1186
1241
|
|