turbine-orm 0.56.0 → 0.57.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.
@@ -31,6 +31,15 @@
31
31
  * atomic.
32
32
  * - **Result reshaping**: `_count` objects keyed back to Prisma relation names,
33
33
  * and to-one relations surfaced as `object | null`.
34
+ * - **Turbine-native query options** (`timeout`, `forceCustomPlan`,
35
+ * `warnOnUnlimited`, `skipGlobalFilters`, `stableRelationOrder`,
36
+ * `allowFullTableScan`, `includePii`, `optimisticLock`, `distinctOn`) reach
37
+ * core on every operation whose arg surface declares them. The set is not a
38
+ * hand-maintained list here: it comes from the compiler-checked tables in
39
+ * `query/option-surface.ts`, so a new core option cannot be silently stranded
40
+ * by this layer, and a key that is neither a Prisma arg nor a turbine option
41
+ * gets a dev-mode warning instead of vanishing (see
42
+ * {@link PRISMA_ARG_KEYS} and `warnUnknownQueryOptions`).
34
43
  *
35
44
  * ## What it deliberately does NOT do (documented divergences)
36
45
  *
@@ -63,6 +72,14 @@
63
72
  * exclusive-cursor + `offset` translation.
64
73
  * - **Negative `take`** (take-from-end) and **`skip` on a nested relation
65
74
  * include** throw, Turbine's `with` clause has no offset and no reverse-take.
75
+ * - **`limit` on `updateMany` / `deleteMany`** (Prisma 6.7+) throws. Turbine has
76
+ * no row-bounded mass mutation, and dropping a SAFETY BOUND with a warning
77
+ * would turn "change at most 10 rows" into "change every matching row".
78
+ * - **Write projections** (`select` / `include` / `omit` on
79
+ * create/update/delete/upsert), **`select` on `count`**, and
80
+ * **`orderBy` / `cursor` / `take` / `skip` on `aggregate`** are accepted and
81
+ * IGNORED (they are legitimate Prisma, so they never warn); the full row / a
82
+ * plain number comes back.
66
83
  *
67
84
  * ## Type dependencies (0.41.0)
68
85
  *
@@ -93,7 +110,7 @@
93
110
  * ```
94
111
  */
95
112
  import type { TurbineClient } from './client.js';
96
- import type { DeferredQuery } from './query/index.js';
113
+ import { type DeferredQuery } from './query/index.js';
97
114
  import type { PrismaCompatMap, SchemaMetadata } from './schema.js';
98
115
  /** A build-only query object with the `build*` methods the adapter drives. */
99
116
  export interface CompatQueryInterface {
@@ -237,6 +254,20 @@ export interface PrismaCompatOptions {
237
254
  */
238
255
  prismaErrorCodes?: boolean;
239
256
  }
257
+ /** The delegate operations this adapter exposes. */
258
+ export type CompatOperation = 'findMany' | 'findFirst' | 'findFirstOrThrow' | 'findUnique' | 'findUniqueOrThrow' | 'create' | 'createMany' | 'update' | 'updateMany' | 'delete' | 'deleteMany' | 'upsert' | 'count' | 'aggregate' | 'groupBy';
259
+ /**
260
+ * Every argument key Prisma itself accepts, per operation.
261
+ *
262
+ * Extracted from a generated `@prisma/client` 7.9.0 `index.d.ts` (the
263
+ * `<Model><Op>Args` blocks). It must stay the UNION across the Prisma majors
264
+ * this adapter supports, never one version's set: a key a newer major
265
+ * introduces should degrade to one noisy dev line, never to a throw, and a key
266
+ * an older major had must keep working. The drift test in
267
+ * `src/test/prisma-compat-option-surface.test.ts` re-extracts from a generated
268
+ * client when one is present and asserts this stays a superset.
269
+ */
270
+ export declare const PRISMA_ARG_KEYS: Record<CompatOperation, readonly string[]>;
240
271
  /** Symbol under which a lazy delegate call exposes its batchable plan. */
241
272
  export declare const COMPAT_DEFERRED: unique symbol;
242
273
  /**
@@ -32,6 +32,15 @@
32
32
  * atomic.
33
33
  * - **Result reshaping**: `_count` objects keyed back to Prisma relation names,
34
34
  * and to-one relations surfaced as `object | null`.
35
+ * - **Turbine-native query options** (`timeout`, `forceCustomPlan`,
36
+ * `warnOnUnlimited`, `skipGlobalFilters`, `stableRelationOrder`,
37
+ * `allowFullTableScan`, `includePii`, `optimisticLock`, `distinctOn`) reach
38
+ * core on every operation whose arg surface declares them. The set is not a
39
+ * hand-maintained list here: it comes from the compiler-checked tables in
40
+ * `query/option-surface.ts`, so a new core option cannot be silently stranded
41
+ * by this layer, and a key that is neither a Prisma arg nor a turbine option
42
+ * gets a dev-mode warning instead of vanishing (see
43
+ * {@link PRISMA_ARG_KEYS} and `warnUnknownQueryOptions`).
35
44
  *
36
45
  * ## What it deliberately does NOT do (documented divergences)
37
46
  *
@@ -64,6 +73,14 @@
64
73
  * exclusive-cursor + `offset` translation.
65
74
  * - **Negative `take`** (take-from-end) and **`skip` on a nested relation
66
75
  * include** throw, Turbine's `with` clause has no offset and no reverse-take.
76
+ * - **`limit` on `updateMany` / `deleteMany`** (Prisma 6.7+) throws. Turbine has
77
+ * no row-bounded mass mutation, and dropping a SAFETY BOUND with a warning
78
+ * would turn "change at most 10 rows" into "change every matching row".
79
+ * - **Write projections** (`select` / `include` / `omit` on
80
+ * create/update/delete/upsert), **`select` on `count`**, and
81
+ * **`orderBy` / `cursor` / `take` / `skip` on `aggregate`** are accepted and
82
+ * IGNORED (they are legitimate Prisma, so they never warn); the full row / a
83
+ * plain number comes back.
67
84
  *
68
85
  * ## Type dependencies (0.41.0)
69
86
  *
@@ -94,10 +111,12 @@
94
111
  * ```
95
112
  */
96
113
  Object.defineProperty(exports, "__esModule", { value: true });
97
- exports.CLIENT_RESERVED_KEYS = exports.COMPAT_DEFERRED = exports.Prisma = void 0;
114
+ exports.CLIENT_RESERVED_KEYS = exports.COMPAT_DEFERRED = exports.PRISMA_ARG_KEYS = exports.Prisma = void 0;
98
115
  exports.createPrismaCompatClient = createPrismaCompatClient;
99
116
  const errors_js_1 = require("./errors.js");
100
117
  const nested_write_js_1 = require("./nested-write.js");
118
+ const index_js_1 = require("./query/index.js");
119
+ const utils_js_1 = require("./query/utils.js");
101
120
  const warn_registry_js_1 = require("./query/warn-registry.js");
102
121
  // ---------------------------------------------------------------------------
103
122
  // Prisma.sql-style raw fragments (local, minimal, never imports @prisma/client)
@@ -256,6 +275,199 @@ function isPlainObject(v) {
256
275
  function renameField(mm, prismaField) {
257
276
  return mm.fields[prismaField] ?? prismaField;
258
277
  }
278
+ /** The turbine arg surface each operation compiles into. */
279
+ const OPERATION_TABLES = {
280
+ findMany: index_js_1.FIND_MANY_OPTIONS,
281
+ findFirst: index_js_1.FIND_MANY_OPTIONS,
282
+ findFirstOrThrow: index_js_1.FIND_MANY_OPTIONS,
283
+ findUnique: index_js_1.FIND_UNIQUE_OPTIONS,
284
+ findUniqueOrThrow: index_js_1.FIND_UNIQUE_OPTIONS,
285
+ create: index_js_1.CREATE_OPTIONS,
286
+ createMany: index_js_1.CREATE_MANY_OPTIONS,
287
+ update: index_js_1.UPDATE_OPTIONS,
288
+ updateMany: index_js_1.UPDATE_MANY_OPTIONS,
289
+ delete: index_js_1.DELETE_OPTIONS,
290
+ deleteMany: index_js_1.DELETE_MANY_OPTIONS,
291
+ upsert: index_js_1.UPSERT_OPTIONS,
292
+ count: index_js_1.COUNT_OPTIONS,
293
+ aggregate: index_js_1.AGGREGATE_OPTIONS,
294
+ groupBy: index_js_1.GROUP_BY_OPTIONS,
295
+ };
296
+ /**
297
+ * Every argument key Prisma itself accepts, per operation.
298
+ *
299
+ * Extracted from a generated `@prisma/client` 7.9.0 `index.d.ts` (the
300
+ * `<Model><Op>Args` blocks). It must stay the UNION across the Prisma majors
301
+ * this adapter supports, never one version's set: a key a newer major
302
+ * introduces should degrade to one noisy dev line, never to a throw, and a key
303
+ * an older major had must keep working. The drift test in
304
+ * `src/test/prisma-compat-option-surface.test.ts` re-extracts from a generated
305
+ * client when one is present and asserts this stays a superset.
306
+ */
307
+ exports.PRISMA_ARG_KEYS = {
308
+ findMany: [
309
+ 'select',
310
+ 'omit',
311
+ 'include',
312
+ 'where',
313
+ 'orderBy',
314
+ 'cursor',
315
+ 'take',
316
+ 'skip',
317
+ 'distinct',
318
+ 'relationLoadStrategy',
319
+ ],
320
+ findFirst: [
321
+ 'select',
322
+ 'omit',
323
+ 'include',
324
+ 'where',
325
+ 'orderBy',
326
+ 'cursor',
327
+ 'take',
328
+ 'skip',
329
+ 'distinct',
330
+ 'relationLoadStrategy',
331
+ ],
332
+ findFirstOrThrow: [
333
+ 'select',
334
+ 'omit',
335
+ 'include',
336
+ 'where',
337
+ 'orderBy',
338
+ 'cursor',
339
+ 'take',
340
+ 'skip',
341
+ 'distinct',
342
+ 'relationLoadStrategy',
343
+ ],
344
+ findUnique: ['select', 'omit', 'include', 'where', 'relationLoadStrategy'],
345
+ findUniqueOrThrow: ['select', 'omit', 'include', 'where', 'relationLoadStrategy'],
346
+ create: ['select', 'omit', 'include', 'data', 'relationLoadStrategy'],
347
+ createMany: ['data', 'skipDuplicates'],
348
+ update: ['select', 'omit', 'include', 'data', 'where', 'relationLoadStrategy'],
349
+ updateMany: ['data', 'where', 'limit'],
350
+ delete: ['select', 'omit', 'include', 'where', 'relationLoadStrategy'],
351
+ deleteMany: ['where', 'limit'],
352
+ upsert: ['select', 'omit', 'include', 'where', 'create', 'update', 'relationLoadStrategy'],
353
+ count: ['where', 'orderBy', 'cursor', 'take', 'skip', 'select'],
354
+ aggregate: ['where', 'orderBy', 'cursor', 'take', 'skip', '_count', '_avg', '_sum', '_min', '_max'],
355
+ groupBy: ['where', 'orderBy', 'by', 'having', 'take', 'skip', '_count', '_avg', '_sum', '_min', '_max'],
356
+ };
357
+ /**
358
+ * Turbine spellings whose Prisma equivalent is spelled differently. A caller
359
+ * who reaches for one of these is not confused about the NAME, they are
360
+ * confused about which surface they are on, so they get a specific message
361
+ * rather than a fuzzy did-you-mean.
362
+ */
363
+ const ALIAS_HINT = {
364
+ limit: 'take',
365
+ offset: 'skip',
366
+ with: 'include',
367
+ };
368
+ /**
369
+ * Known(op) = Prisma's own keys for that operation, plus every key the
370
+ * operation's turbine arg surface declares except the `'internal'` ones.
371
+ *
372
+ * The second half is NOT just the `'native'` keys. Two turbine-only options are
373
+ * classified `'prisma'` because their values carry field names and so must be
374
+ * hand-translated (`optimisticLock`, `distinctOn`); they are fully honoured, and
375
+ * warning about a key the adapter just acted on would be the worst possible
376
+ * diagnostic. `'nativeAlias'` members are in the set on purpose too: `limit` on
377
+ * `findMany` IS recognized, it simply gets the alias message rather than the
378
+ * generic one. Only `'internal'` is excluded, because nothing on this surface
379
+ * can reach it.
380
+ *
381
+ * A `Set` rather than an `in` test on a record, so an inherited
382
+ * `Object.prototype` name (`toString`, `constructor`) is treated as the unknown
383
+ * key it is.
384
+ */
385
+ const KNOWN_KEYS = (() => {
386
+ const out = {};
387
+ for (const op of Object.keys(OPERATION_TABLES)) {
388
+ out[op] = new Set([
389
+ ...exports.PRISMA_ARG_KEYS[op],
390
+ ...(0, index_js_1.optionKeysOfKind)(OPERATION_TABLES[op], 'prisma', 'native', 'nativeAlias'),
391
+ ]);
392
+ }
393
+ return out;
394
+ })();
395
+ /**
396
+ * Dev-mode notice for a key on a delegate's args object that this operation has
397
+ * no meaning for.
398
+ *
399
+ * An unrecognized key is silently ignored (JavaScript objects have no schema),
400
+ * which makes a typo, a turbine spelling, and a genuinely missing feature all
401
+ * look identical: nothing happens. The client-config warner
402
+ * (`warnUnknownConfigKeys` in client.ts) exists for the same reason and this is
403
+ * its query-level twin, down to the ranking of the suggestion.
404
+ *
405
+ * Deliberately a WARNING, never an error. Throwing would turn a working app
406
+ * into a failing one on upgrade over one stray key, and a key from a Prisma
407
+ * major newer than {@link PRISMA_ARG_KEYS} would be exactly that key. The whole
408
+ * body is wrapped so a hostile or exotic args object (a Proxy whose `ownKeys`
409
+ * throws) can never be the reason a query fails. Dev-only and once per
410
+ * `model.operation.key` per process, like every other advisory here.
411
+ */
412
+ function warnUnknownQueryOptions(model, op, args) {
413
+ if (process.env.NODE_ENV === 'production')
414
+ return;
415
+ if (!isPlainObject(args))
416
+ return;
417
+ try {
418
+ const known = KNOWN_KEYS[op];
419
+ const table = OPERATION_TABLES[op];
420
+ for (const key of Object.keys(args)) {
421
+ // `{ ...maybeOptions }` routinely materializes keys with no value.
422
+ // Nothing is being dropped when the value is undefined.
423
+ if (args[key] === undefined)
424
+ continue;
425
+ const alias = table[key] === 'nativeAlias' ? ALIAS_HINT[key] : undefined;
426
+ if (!alias && known.has(key))
427
+ continue;
428
+ if (!(0, warn_registry_js_1.shouldWarnOnce)(warn_registry_js_1.WARN_NS.unknownQueryOption, `${model}.${op}.${key}`))
429
+ continue;
430
+ if (alias) {
431
+ console.warn(`[turbine] prisma-compat: "${key}" is Turbine's spelling and is ignored here;` +
432
+ ` prisma-compat takes Prisma's "${alias}". (${model}.${op})`);
433
+ continue;
434
+ }
435
+ const suggestion = (0, utils_js_1.suggestKey)(key, known);
436
+ console.warn(`[turbine] prisma-compat: unknown option "${key}" in ${model}.${op}(), it is ignored.` +
437
+ (suggestion ? ` Did you mean "${suggestion}"?` : ''));
438
+ }
439
+ }
440
+ catch {
441
+ // Key enumeration is the only thing that can fail here, and a diagnostic
442
+ // must never be the reason a query fails.
443
+ }
444
+ }
445
+ /**
446
+ * Prisma 6.7+ accepts `limit` on `updateMany` / `deleteMany` to BOUND how many
447
+ * rows a mass mutation touches. Turbine has no row-bounded mass mutation, so
448
+ * this one is refused rather than warned about: everywhere else in this design
449
+ * a dropped option costs the caller a feature, but silently dropping a safety
450
+ * bound turns "change at most 10 rows" into "change every row".
451
+ */
452
+ function refuseRowLimit(model, op, args) {
453
+ if (!isPlainObject(args) || args.limit === undefined)
454
+ return;
455
+ throw new errors_js_1.UnsupportedFeatureError(`\`limit\` on ${op} (row-bounded mass mutation)`, 'prisma-compat', `Turbine has no row-bounded ${op}; select the rows you mean with \`where\`` +
456
+ ` (on ${model}.${op}), or page them and mutate by primary key.`);
457
+ }
458
+ /**
459
+ * Prisma's `relationLoadStrategy` and Turbine's share a name and NOT a value
460
+ * domain: Prisma has `'query' | 'join'`, Turbine has
461
+ * `'join' | 'batched' | 'auto' | 'flatten'`. Core's strategy resolution has no
462
+ * branch for `'query'` and returns the value unchanged, so forwarding it
463
+ * verbatim gave a caller who asked for the per-relation query plan the JOIN
464
+ * plan, the exact opposite of the request. Prisma's `'query'` IS Turbine's
465
+ * `'batched'` (one follow-up statement per relation); the turbine-only values
466
+ * pass through so a compat caller can still reach them.
467
+ */
468
+ function mapRelationLoadStrategy(value) {
469
+ return value === 'query' ? 'batched' : value;
470
+ }
259
471
  /**
260
472
  * Translate a Prisma `where` (or nested relation where) into a Turbine `where`.
261
473
  * Renames scalar field keys and relation keys through the map, recurses into
@@ -450,6 +662,13 @@ function modelName(ctx, mm) {
450
662
  */
451
663
  function translateReadArgs(ctx, mm, prismaArgs, kind) {
452
664
  const t = {};
665
+ // FIRST, so a per-call `stableRelationOrder` overrides it: the client-level
666
+ // option is a default, the arg is an instruction.
667
+ if (ctx.options.stablePkOrder)
668
+ t.stableRelationOrder = true;
669
+ // Every turbine-native option the arg surface declares, in one line that
670
+ // cannot fall behind the interface (see the option-surface tables).
671
+ (0, index_js_1.applyNativeOptions)(kind === 'unique' ? index_js_1.FIND_UNIQUE_OPTIONS : index_js_1.FIND_MANY_OPTIONS, prismaArgs, t);
453
672
  if (prismaArgs.where !== undefined)
454
673
  t.where = translateWhere(ctx, mm, prismaArgs.where);
455
674
  if (prismaArgs.orderBy !== undefined)
@@ -462,17 +681,9 @@ function translateReadArgs(ctx, mm, prismaArgs, kind) {
462
681
  if (Array.isArray(prismaArgs.distinct)) {
463
682
  t.distinct = prismaArgs.distinct.map((f) => renameField(mm, f));
464
683
  }
465
- if (prismaArgs.relationLoadStrategy !== undefined)
466
- t.relationLoadStrategy = prismaArgs.relationLoadStrategy;
467
- if (typeof prismaArgs.timeout === 'number')
468
- t.timeout = prismaArgs.timeout;
469
- // Turbine-only passthrough. Prisma has no PII concept, so a compat caller
470
- // whose schema tags columns needs SOME way to opt in; without this the
471
- // adapter is a one-way door into redacted reads and refused aggregates.
472
- if (prismaArgs.includePii !== undefined)
473
- t.includePii = prismaArgs.includePii;
474
- if (ctx.options.stablePkOrder)
475
- t.stableRelationOrder = true;
684
+ if (prismaArgs.relationLoadStrategy !== undefined) {
685
+ t.relationLoadStrategy = mapRelationLoadStrategy(prismaArgs.relationLoadStrategy);
686
+ }
476
687
  // ORDER IS LOAD-BEARING: translateCursor MUST run BEFORE applyImplicitPkOrder.
477
688
  // The cursor translation reads `t.orderBy` to decide the seek direction and to
478
689
  // validate that a bare inclusive cursor names the sort key; it must see the
@@ -771,6 +982,7 @@ function translateUpsertNested(ctx, target, p) {
771
982
  const AGG_FIELD_BLOCKS = ['_sum', '_avg', '_min', '_max'];
772
983
  function translateAggregateArgs(ctx, mm, args, isGroupBy) {
773
984
  const t = {};
985
+ (0, index_js_1.applyNativeOptions)(isGroupBy ? index_js_1.GROUP_BY_OPTIONS : index_js_1.AGGREGATE_OPTIONS, args, t);
774
986
  if (args.where !== undefined)
775
987
  t.where = translateWhere(ctx, mm, args.where);
776
988
  if (args._count !== undefined)
@@ -779,12 +991,6 @@ function translateAggregateArgs(ctx, mm, args, isGroupBy) {
779
991
  if (args[block] !== undefined)
780
992
  t[block] = renameAggBlock(mm, args[block], false);
781
993
  }
782
- if (typeof args.timeout === 'number')
783
- t.timeout = args.timeout;
784
- // Turbine-only passthrough: the PII gate on groupBy keys and _min/_max needs
785
- // an opt-in that Prisma's arg shape has no equivalent for.
786
- if (args.includePii !== undefined)
787
- t.includePii = args.includePii;
788
994
  if (isGroupBy) {
789
995
  if (Array.isArray(args.by))
790
996
  t.by = args.by.map((f) => renameField(mm, f));
@@ -792,6 +998,8 @@ function translateAggregateArgs(ctx, mm, args, isGroupBy) {
792
998
  t.orderBy = translateOrderBy(ctx, mm, args.orderBy);
793
999
  if (args.having !== undefined)
794
1000
  t.having = renameHaving(mm, args.having);
1001
+ if (args.distinctOn !== undefined)
1002
+ t.distinctOn = translateDistinctOn(ctx, mm, args.distinctOn);
795
1003
  if (typeof args.take === 'number')
796
1004
  t.limit = mapTake(args.take);
797
1005
  if (typeof args.skip === 'number')
@@ -799,6 +1007,23 @@ function translateAggregateArgs(ctx, mm, args, isGroupBy) {
799
1007
  }
800
1008
  return t;
801
1009
  }
1010
+ /**
1011
+ * Translate a turbine-native groupBy `distinctOn`. Both halves of its value
1012
+ * (`columns`, `orderBy`) are FIELD NAMES, so this is the concrete reason the
1013
+ * option surface refuses to copy unknown keys through by default: a blind
1014
+ * passthrough is correct on a model whose Prisma and turbine names coincide and
1015
+ * silently wrong on one with a `@map`.
1016
+ */
1017
+ function translateDistinctOn(ctx, mm, val) {
1018
+ if (!isPlainObject(val))
1019
+ return val;
1020
+ const out = { ...val };
1021
+ if (Array.isArray(val.columns))
1022
+ out.columns = val.columns.map((f) => renameField(mm, f));
1023
+ if (val.orderBy !== undefined)
1024
+ out.orderBy = translateOrderBy(ctx, mm, val.orderBy);
1025
+ return out;
1026
+ }
802
1027
  /** Rename field keys inside an aggregate block; `_count`'s `_all` passes through. */
803
1028
  function renameAggBlock(mm, block, isCount) {
804
1029
  if (block === true || !isPlainObject(block))
@@ -1143,6 +1368,8 @@ async function createManyByRun(qi, t, runs) {
1143
1368
  const args = { data: run };
1144
1369
  if (t.skipDuplicates)
1145
1370
  args.skipDuplicates = true;
1371
+ if (t.timeout !== undefined)
1372
+ args.timeout = t.timeout;
1146
1373
  count += (await qi.createMany(args)).length;
1147
1374
  }
1148
1375
  return { count };
@@ -1158,7 +1385,14 @@ function makeDelegate(ctx, mm, getQI, runInTx) {
1158
1385
  // async run wrapper also converts any synchronous throw from the underlying
1159
1386
  // `qi.*` build into a rejection; the array `$transaction([...])` batch path
1160
1387
  // catches the same throw from `batch.build`.
1161
- const defer = (translate, run, batch) => {
1388
+ const defer = (op, rawArgs, translateRaw, run, batch) => {
1389
+ // The unknown-key check rides the SAME deferred boundary as the translation
1390
+ // itself, for the same reason (see the comment above): a compat promise that
1391
+ // is built and never awaited must produce no output at all.
1392
+ const translate = () => {
1393
+ warnUnknownQueryOptions(modelName(ctx, mm), op, rawArgs);
1394
+ return translateRaw();
1395
+ };
1162
1396
  const batchable = batch
1163
1397
  ? {
1164
1398
  build: () => batch.build(getQI(), translate()),
@@ -1198,27 +1432,27 @@ function makeDelegate(ctx, mm, getQI, runInTx) {
1198
1432
  return args;
1199
1433
  };
1200
1434
  return {
1201
- findMany: (args = {}) => defer(() => translateReadArgs(ctx, mm, args, 'many'), (qi, t) => qi.findMany(t).then((r) => reshapeRows(ctx, mm, r)), { build: (qi, t) => qi.buildFindMany(t), reshape: (raw) => reshapeRows(ctx, mm, raw) }),
1202
- findFirst: (args = {}) => defer(() => translateReadArgs(ctx, mm, args, 'first'), (qi, t) => qi.findFirst(t).then((r) => reshapeRowOrNull(ctx, mm, r)), { build: (qi, t) => qi.buildFindFirst(t), reshape: (raw) => reshapeRowOrNull(ctx, mm, raw) }),
1203
- findUnique: (args) => defer(() => translateReadArgs(ctx, mm, requireWhere(args, 'findUnique'), 'unique'), (qi, t) => qi.findUnique(t).then((r) => reshapeRowOrNull(ctx, mm, r)), { build: (qi, t) => qi.buildFindUnique(t), reshape: (raw) => reshapeRowOrNull(ctx, mm, raw) }),
1204
- findFirstOrThrow: (args = {}) => defer(() => translateReadArgs(ctx, mm, args, 'first'), (qi, t) => qi.findFirstOrThrow(t).then((r) => reshapeRow(ctx, mm, r)), { build: (qi, t) => qi.buildFindFirstOrThrow(t), reshape: (raw) => reshapeRow(ctx, mm, raw) }),
1205
- findUniqueOrThrow: (args) => defer(() => translateReadArgs(ctx, mm, requireWhere(args, 'findUniqueOrThrow'), 'unique'), (qi, t) => qi.findUniqueOrThrow(t).then((r) => reshapeRow(ctx, mm, r)), { build: (qi, t) => qi.buildFindUniqueOrThrow(t), reshape: (raw) => reshapeRow(ctx, mm, raw) }),
1206
- create: (args) => defer(() => {
1435
+ findMany: (args = {}) => defer('findMany', args, () => translateReadArgs(ctx, mm, args, 'many'), (qi, t) => qi.findMany(t).then((r) => reshapeRows(ctx, mm, r)), { build: (qi, t) => qi.buildFindMany(t), reshape: (raw) => reshapeRows(ctx, mm, raw) }),
1436
+ findFirst: (args = {}) => defer('findFirst', args, () => translateReadArgs(ctx, mm, args, 'first'), (qi, t) => qi.findFirst(t).then((r) => reshapeRowOrNull(ctx, mm, r)), { build: (qi, t) => qi.buildFindFirst(t), reshape: (raw) => reshapeRowOrNull(ctx, mm, raw) }),
1437
+ findUnique: (args) => defer('findUnique', args, () => translateReadArgs(ctx, mm, requireWhere(args, 'findUnique'), 'unique'), (qi, t) => qi.findUnique(t).then((r) => reshapeRowOrNull(ctx, mm, r)), { build: (qi, t) => qi.buildFindUnique(t), reshape: (raw) => reshapeRowOrNull(ctx, mm, raw) }),
1438
+ findFirstOrThrow: (args = {}) => defer('findFirstOrThrow', args, () => translateReadArgs(ctx, mm, args, 'first'), (qi, t) => qi.findFirstOrThrow(t).then((r) => reshapeRow(ctx, mm, r)), { build: (qi, t) => qi.buildFindFirstOrThrow(t), reshape: (raw) => reshapeRow(ctx, mm, raw) }),
1439
+ findUniqueOrThrow: (args) => defer('findUniqueOrThrow', args, () => translateReadArgs(ctx, mm, requireWhere(args, 'findUniqueOrThrow'), 'unique'), (qi, t) => qi.findUniqueOrThrow(t).then((r) => reshapeRow(ctx, mm, r)), { build: (qi, t) => qi.buildFindUniqueOrThrow(t), reshape: (raw) => reshapeRow(ctx, mm, raw) }),
1440
+ create: (args) => defer('create', args, () => {
1207
1441
  const t = { data: translateWriteData(ctx, mm, applyCreateDefaults(mm, args.data)) };
1208
- if (typeof args.timeout === 'number')
1209
- t.timeout = args.timeout;
1442
+ (0, index_js_1.applyNativeOptions)(index_js_1.CREATE_OPTIONS, args, t);
1210
1443
  return t;
1211
1444
  }, (qi, t) => qi.create(t).then((r) => reshapeRow(ctx, mm, r)), {
1212
1445
  build: (qi, t) => qi.buildCreate(t),
1213
1446
  reshape: (raw) => reshapeRow(ctx, mm, raw),
1214
1447
  nested: (t) => hasNestedKeys(ctx, mm, t.data),
1215
1448
  }),
1216
- createMany: (args) => defer(() => {
1449
+ createMany: (args) => defer('createMany', args, () => {
1217
1450
  const data = args.data;
1218
1451
  const rows = Array.isArray(data)
1219
1452
  ? data.map((d) => translateWriteData(ctx, mm, applyCreateDefaults(mm, d)))
1220
1453
  : [];
1221
1454
  const t = { data: rows };
1455
+ (0, index_js_1.applyNativeOptions)(index_js_1.CREATE_MANY_OPTIONS, args, t);
1222
1456
  if (args.skipDuplicates)
1223
1457
  t.skipDuplicates = true;
1224
1458
  return t;
@@ -1239,45 +1473,68 @@ function makeDelegate(ctx, mm, getQI, runInTx) {
1239
1473
  nested: (t) => createManyRunsOf(t).length > 1,
1240
1474
  execInTx: (table, t) => createManyByRun(table(mm.table), t, createManyRunsOf(t)),
1241
1475
  }),
1242
- update: (args) => defer(() => {
1476
+ update: (args) => defer('update', args, () => {
1243
1477
  const a = requireWhere(args, 'update');
1244
- return {
1478
+ const t = {
1245
1479
  where: translateWhere(ctx, mm, a.where),
1246
1480
  data: translateWriteData(ctx, mm, applyUpdateTouch(mm, a.data)),
1247
1481
  };
1482
+ (0, index_js_1.applyNativeOptions)(index_js_1.UPDATE_OPTIONS, a, t);
1483
+ // `optimisticLock.field` is a FIELD NAME, so it is renamed rather than
1484
+ // copied: a blind passthrough would send the Prisma spelling into core
1485
+ // and break on any model whose column is `@map`ped.
1486
+ if (isPlainObject(a.optimisticLock)) {
1487
+ t.optimisticLock = {
1488
+ ...a.optimisticLock,
1489
+ field: renameField(mm, String(a.optimisticLock.field)),
1490
+ };
1491
+ }
1492
+ return t;
1248
1493
  }, (qi, t) => qi.update(t).then((r) => reshapeRow(ctx, mm, r)), {
1249
1494
  build: (qi, t) => qi.buildUpdate(t),
1250
1495
  reshape: (raw) => reshapeRow(ctx, mm, raw),
1251
1496
  nested: (t) => hasNestedKeys(ctx, mm, t.data),
1252
1497
  }),
1253
- updateMany: (args) => defer(() => {
1498
+ updateMany: (args) => defer('updateMany', args, () => {
1254
1499
  const a = args;
1500
+ refuseRowLimit(modelName(ctx, mm), 'updateMany', a);
1255
1501
  const t = {
1256
1502
  where: translateWhere(ctx, mm, a.where ?? {}),
1257
1503
  data: translateWriteData(ctx, mm, applyUpdateTouch(mm, a.data)),
1258
1504
  };
1505
+ (0, index_js_1.applyNativeOptions)(index_js_1.UPDATE_MANY_OPTIONS, a, t);
1506
+ // LAST, so it wins: a Prisma updateMany with no `where` affects every
1507
+ // row, and an explicit `allowFullTableScan: false` must not be able to
1508
+ // turn that parity into a thrown empty-where guard.
1259
1509
  if (a.where === undefined)
1260
1510
  t.allowFullTableScan = true;
1261
1511
  return t;
1262
1512
  }, (qi, t) => qi.updateMany(t), { build: (qi, t) => qi.buildUpdateMany(t), reshape: (raw) => raw }),
1263
- delete: (args) => defer(() => {
1513
+ delete: (args) => defer('delete', args, () => {
1264
1514
  const a = requireWhere(args, 'delete');
1265
- return { where: translateWhere(ctx, mm, a.where) };
1515
+ const t = { where: translateWhere(ctx, mm, a.where) };
1516
+ (0, index_js_1.applyNativeOptions)(index_js_1.DELETE_OPTIONS, a, t);
1517
+ return t;
1266
1518
  }, (qi, t) => qi.delete(t).then((r) => reshapeRow(ctx, mm, r)), { build: (qi, t) => qi.buildDelete(t), reshape: (raw) => reshapeRow(ctx, mm, raw) }),
1267
- deleteMany: (args = {}) => defer(() => {
1519
+ deleteMany: (args = {}) => defer('deleteMany', args, () => {
1268
1520
  const a = args;
1521
+ refuseRowLimit(modelName(ctx, mm), 'deleteMany', a);
1269
1522
  const t = { where: translateWhere(ctx, mm, a.where ?? {}) };
1523
+ (0, index_js_1.applyNativeOptions)(index_js_1.DELETE_MANY_OPTIONS, a, t);
1524
+ // LAST, so it wins. See the same note on updateMany.
1270
1525
  if (a.where === undefined)
1271
1526
  t.allowFullTableScan = true;
1272
1527
  return t;
1273
1528
  }, (qi, t) => qi.deleteMany(t), { build: (qi, t) => qi.buildDeleteMany(t), reshape: (raw) => raw }),
1274
- upsert: (args) => defer(() => {
1529
+ upsert: (args) => defer('upsert', args, () => {
1275
1530
  const a = requireWhere(args, 'upsert');
1276
- return {
1531
+ const t = {
1277
1532
  where: translateWhere(ctx, mm, a.where),
1278
1533
  create: translateWriteData(ctx, mm, applyCreateDefaults(mm, a.create)),
1279
1534
  update: translateWriteData(ctx, mm, applyUpdateTouch(mm, a.update)),
1280
1535
  };
1536
+ (0, index_js_1.applyNativeOptions)(index_js_1.UPSERT_OPTIONS, a, t);
1537
+ return t;
1281
1538
  }, (qi, t) => {
1282
1539
  // Native ON CONFLICT upsert is only Prisma-equivalent when the where
1283
1540
  // key values equal the create values AND no nested write data is
@@ -1300,16 +1557,15 @@ function makeDelegate(ctx, mm, getQI, runInTx) {
1300
1557
  return reshapeRow(ctx, mm, await upsertLookupFirst(table(mm.table), t));
1301
1558
  },
1302
1559
  }),
1303
- count: (args = {}) => defer(() => {
1560
+ count: (args = {}) => defer('count', args, () => {
1304
1561
  const t = {};
1562
+ (0, index_js_1.applyNativeOptions)(index_js_1.COUNT_OPTIONS, args, t);
1305
1563
  if (args.where !== undefined)
1306
1564
  t.where = translateWhere(ctx, mm, args.where);
1307
- if (typeof args.timeout === 'number')
1308
- t.timeout = args.timeout;
1309
1565
  return t;
1310
1566
  }, (qi, t) => qi.count(t), { build: (qi, t) => qi.buildCount(t), reshape: (raw) => raw }),
1311
- aggregate: (args) => defer(() => translateAggregateArgs(ctx, mm, args, false), (qi, t) => qi.aggregate(t).then((r) => reshapeAggregate(ctx, mm, r)), { build: (qi, t) => qi.buildAggregate(t), reshape: (raw) => reshapeAggregate(ctx, mm, raw) }),
1312
- groupBy: (args) => defer(() => translateAggregateArgs(ctx, mm, args, true), (qi, t) => qi.groupBy(t).then((rows) => rows.map((r) => reshapeGroupRow(ctx, mm, r))), {
1567
+ aggregate: (args) => defer('aggregate', args, () => translateAggregateArgs(ctx, mm, args, false), (qi, t) => qi.aggregate(t).then((r) => reshapeAggregate(ctx, mm, r)), { build: (qi, t) => qi.buildAggregate(t), reshape: (raw) => reshapeAggregate(ctx, mm, raw) }),
1568
+ groupBy: (args) => defer('groupBy', args, () => translateAggregateArgs(ctx, mm, args, true), (qi, t) => qi.groupBy(t).then((rows) => rows.map((r) => reshapeGroupRow(ctx, mm, r))), {
1313
1569
  build: (qi, t) => qi.buildGroupBy(t),
1314
1570
  reshape: (raw) => raw.map((r) => reshapeGroupRow(ctx, mm, r)),
1315
1571
  }),
@@ -8,6 +8,8 @@
8
8
  export type { AggregateArgs, AggregateResult, ArrayFilter, ColumnRef, ConnectOrCreateOp, CountArgs, CreateArgs, CreateDataInput, CreateManyArgs, DeleteArgs, DeleteManyArgs, FieldResult, FindManyArgs, FindManyStreamArgs, FindUniqueArgs, GlobalFilters, GroupByAggregateSpec, GroupByArgs, GroupByDistinctOn, GroupByResult, HavingClause, JsonFilter, JsonPathAggregateTarget, JsonPathGroupKey, JsonPathOrderBy, NestedCreateOp, NestedUpdateOp, NestedUpdateOpItem, NestedUpsertOpItem, OmitResult, OrderByClause, OrderByObject, OrderDirection, QueryResult, RelationDescriptor, RelationFilter, RelationLoadStrategy, RelationPickBy, RelationPickOrderBy, SelectResult, SkipGlobalFilters, TextSearchFilter, TypedWithClause, UpdateArgs, UpdateDataInput, UpdateInput, UpdateManyArgs, UpdateOperatorInput, UpsertArgs, VectorDistanceFilter, VectorFilter, VectorMetric, VectorOrderBy, VectorOrderByDistance, WhereClause, WhereOperator, WhereValue, WithClause, WithOptions, WithOrderByObject, WithResult, } from './types.js';
9
9
  export type { BuiltStatement, BulkInsertStatementInput, ColumnDefinitionInput, ColumnTypeInput, CreateIndexStatementInput, CreateTableStatementInput, Dialect, InsertStatementInput, UpsertStatementInput, } from '../dialect.js';
10
10
  export { postgresDialect } from '../dialect.js';
11
+ export type { OptionKind, OptionTable } from './option-surface.js';
12
+ export { AGGREGATE_OPTIONS, ALL_OPTION_TABLES, applyNativeOptions, COUNT_OPTIONS, CREATE_MANY_OPTIONS, CREATE_OPTIONS, DELETE_MANY_OPTIONS, DELETE_OPTIONS, FIND_MANY_OPTIONS, FIND_MANY_STREAM_OPTIONS, FIND_UNIQUE_OPTIONS, GROUP_BY_OPTIONS, optionKeysOfKind, UPDATE_MANY_OPTIONS, UPDATE_OPTIONS, UPSERT_OPTIONS, } from './option-surface.js';
11
13
  export type { SqlCacheEntry } from './utils.js';
12
14
  export { buildCorrelation, escapeLike, escSingleQuote, fnv1a64Hex, LRUCache, OPERATOR_KEYS, quoteIdent, sqlToPreparedName, } from './utils.js';
13
15
  export type { DeferredQuery, MiddlewareFn, QueryEvent, QueryEventListener, QueryInterfaceOptions, ReselectExecutor, TemporalInfinityReading, } from './builder.js';
@@ -7,9 +7,26 @@
7
7
  * former monolithic `import { … } from './query.js'`.
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.QueryInterface = exports.AUTO_TO_ONE_JOIN_ROWS_MIN = exports.AUTO_TO_ONE_JOIN_ROWS_MAX = exports.AUTO_TO_ONE_JOIN_MAX_ROWS = exports.AUTO_JOIN_PENALTY_MS_PER_ROW = exports.AUTO_COUNT_BATCH_MIN_PARENT_ROWS = exports.AUTO_ASSUMED_ROUND_TRIP_MS = exports.sqlToPreparedName = exports.quoteIdent = exports.OPERATOR_KEYS = exports.LRUCache = exports.fnv1a64Hex = exports.escSingleQuote = exports.escapeLike = exports.buildCorrelation = exports.postgresDialect = void 0;
10
+ exports.QueryInterface = exports.AUTO_TO_ONE_JOIN_ROWS_MIN = exports.AUTO_TO_ONE_JOIN_ROWS_MAX = exports.AUTO_TO_ONE_JOIN_MAX_ROWS = exports.AUTO_JOIN_PENALTY_MS_PER_ROW = exports.AUTO_COUNT_BATCH_MIN_PARENT_ROWS = exports.AUTO_ASSUMED_ROUND_TRIP_MS = exports.sqlToPreparedName = exports.quoteIdent = exports.OPERATOR_KEYS = exports.LRUCache = exports.fnv1a64Hex = exports.escSingleQuote = exports.escapeLike = exports.buildCorrelation = exports.UPSERT_OPTIONS = exports.UPDATE_OPTIONS = exports.UPDATE_MANY_OPTIONS = exports.optionKeysOfKind = exports.GROUP_BY_OPTIONS = exports.FIND_UNIQUE_OPTIONS = exports.FIND_MANY_STREAM_OPTIONS = exports.FIND_MANY_OPTIONS = exports.DELETE_OPTIONS = exports.DELETE_MANY_OPTIONS = exports.CREATE_OPTIONS = exports.CREATE_MANY_OPTIONS = exports.COUNT_OPTIONS = exports.applyNativeOptions = exports.ALL_OPTION_TABLES = exports.AGGREGATE_OPTIONS = exports.postgresDialect = void 0;
11
11
  var dialect_js_1 = require("../dialect.js");
12
12
  Object.defineProperty(exports, "postgresDialect", { enumerable: true, get: function () { return dialect_js_1.postgresDialect; } });
13
+ var option_surface_js_1 = require("./option-surface.js");
14
+ Object.defineProperty(exports, "AGGREGATE_OPTIONS", { enumerable: true, get: function () { return option_surface_js_1.AGGREGATE_OPTIONS; } });
15
+ Object.defineProperty(exports, "ALL_OPTION_TABLES", { enumerable: true, get: function () { return option_surface_js_1.ALL_OPTION_TABLES; } });
16
+ Object.defineProperty(exports, "applyNativeOptions", { enumerable: true, get: function () { return option_surface_js_1.applyNativeOptions; } });
17
+ Object.defineProperty(exports, "COUNT_OPTIONS", { enumerable: true, get: function () { return option_surface_js_1.COUNT_OPTIONS; } });
18
+ Object.defineProperty(exports, "CREATE_MANY_OPTIONS", { enumerable: true, get: function () { return option_surface_js_1.CREATE_MANY_OPTIONS; } });
19
+ Object.defineProperty(exports, "CREATE_OPTIONS", { enumerable: true, get: function () { return option_surface_js_1.CREATE_OPTIONS; } });
20
+ Object.defineProperty(exports, "DELETE_MANY_OPTIONS", { enumerable: true, get: function () { return option_surface_js_1.DELETE_MANY_OPTIONS; } });
21
+ Object.defineProperty(exports, "DELETE_OPTIONS", { enumerable: true, get: function () { return option_surface_js_1.DELETE_OPTIONS; } });
22
+ Object.defineProperty(exports, "FIND_MANY_OPTIONS", { enumerable: true, get: function () { return option_surface_js_1.FIND_MANY_OPTIONS; } });
23
+ Object.defineProperty(exports, "FIND_MANY_STREAM_OPTIONS", { enumerable: true, get: function () { return option_surface_js_1.FIND_MANY_STREAM_OPTIONS; } });
24
+ Object.defineProperty(exports, "FIND_UNIQUE_OPTIONS", { enumerable: true, get: function () { return option_surface_js_1.FIND_UNIQUE_OPTIONS; } });
25
+ Object.defineProperty(exports, "GROUP_BY_OPTIONS", { enumerable: true, get: function () { return option_surface_js_1.GROUP_BY_OPTIONS; } });
26
+ Object.defineProperty(exports, "optionKeysOfKind", { enumerable: true, get: function () { return option_surface_js_1.optionKeysOfKind; } });
27
+ Object.defineProperty(exports, "UPDATE_MANY_OPTIONS", { enumerable: true, get: function () { return option_surface_js_1.UPDATE_MANY_OPTIONS; } });
28
+ Object.defineProperty(exports, "UPDATE_OPTIONS", { enumerable: true, get: function () { return option_surface_js_1.UPDATE_OPTIONS; } });
29
+ Object.defineProperty(exports, "UPSERT_OPTIONS", { enumerable: true, get: function () { return option_surface_js_1.UPSERT_OPTIONS; } });
13
30
  var utils_js_1 = require("./utils.js");
14
31
  Object.defineProperty(exports, "buildCorrelation", { enumerable: true, get: function () { return utils_js_1.buildCorrelation; } });
15
32
  Object.defineProperty(exports, "escapeLike", { enumerable: true, get: function () { return utils_js_1.escapeLike; } });