turbine-orm 0.61.0 → 0.62.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 +65 -21
- package/dist/cjs/cli/config.d.ts +40 -0
- package/dist/cjs/cli/config.js +74 -2
- package/dist/cjs/cli/index.d.ts +85 -1
- package/dist/cjs/cli/index.js +323 -24
- package/dist/cjs/cli/mcp.d.ts +8 -0
- package/dist/cjs/cli/mcp.js +448 -29
- package/dist/cjs/cli/pii-tags.d.ts +64 -9
- package/dist/cjs/cli/pii-tags.js +218 -39
- package/dist/cjs/cli/studio-ui.generated.js +1 -1
- package/dist/cjs/cli/studio.d.ts +23 -0
- package/dist/cjs/cli/studio.js +126 -53
- package/dist/cjs/cli/ui.d.ts +15 -1
- package/dist/cjs/cli/ui.js +19 -5
- package/dist/cjs/client.js +186 -3
- package/dist/cjs/errors.d.ts +38 -1
- package/dist/cjs/errors.js +235 -24
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +7 -2
- package/dist/cjs/pipeline.js +15 -2
- package/dist/cjs/powql.d.ts +12 -0
- package/dist/cjs/powql.js +46 -21
- package/dist/cjs/prisma-compat.d.ts +15 -5
- package/dist/cjs/prisma-compat.js +273 -78
- package/dist/cjs/query/aggregates.d.ts +1 -1
- package/dist/cjs/query/aggregates.js +24 -10
- package/dist/cjs/query/batched-loader.d.ts +9 -4
- package/dist/cjs/query/batched-loader.js +4 -1
- package/dist/cjs/query/builder.d.ts +47 -0
- package/dist/cjs/query/builder.js +125 -21
- package/dist/cjs/query/index.d.ts +3 -1
- package/dist/cjs/query/index.js +7 -1
- package/dist/cjs/query/option-surface.d.ts +11 -0
- package/dist/cjs/query/option-surface.js +13 -0
- package/dist/cjs/query/relations.d.ts +8 -0
- package/dist/cjs/query/relations.js +21 -1
- package/dist/cjs/query/types.d.ts +152 -18
- package/dist/cjs/query/types.js +212 -1
- package/dist/cjs/query/where.d.ts +3 -3
- package/dist/cjs/query/where.js +8 -2
- package/dist/cjs/query/writes.js +10 -9
- package/dist/cli/config.d.ts +40 -0
- package/dist/cli/config.js +73 -2
- package/dist/cli/index.d.ts +85 -1
- package/dist/cli/index.js +321 -26
- package/dist/cli/mcp.d.ts +8 -0
- package/dist/cli/mcp.js +448 -29
- package/dist/cli/pii-tags.d.ts +64 -9
- package/dist/cli/pii-tags.js +217 -39
- package/dist/cli/studio-ui.generated.js +1 -1
- package/dist/cli/studio.d.ts +23 -0
- package/dist/cli/studio.js +125 -53
- package/dist/cli/ui.d.ts +15 -1
- package/dist/cli/ui.js +18 -4
- package/dist/client.js +187 -4
- package/dist/errors.d.ts +38 -1
- package/dist/errors.js +234 -23
- package/dist/index.d.ts +2 -2
- package/dist/index.js +5 -2
- package/dist/pipeline.js +15 -2
- package/dist/powql.d.ts +12 -0
- package/dist/powql.js +46 -21
- package/dist/prisma-compat.d.ts +15 -5
- package/dist/prisma-compat.js +274 -79
- package/dist/query/aggregates.d.ts +1 -1
- package/dist/query/aggregates.js +24 -10
- package/dist/query/batched-loader.d.ts +9 -4
- package/dist/query/batched-loader.js +4 -1
- package/dist/query/builder.d.ts +47 -0
- package/dist/query/builder.js +124 -21
- package/dist/query/index.d.ts +3 -1
- package/dist/query/index.js +2 -0
- package/dist/query/option-surface.d.ts +11 -0
- package/dist/query/option-surface.js +13 -0
- package/dist/query/relations.d.ts +8 -0
- package/dist/query/relations.js +21 -1
- package/dist/query/types.d.ts +152 -18
- package/dist/query/types.js +207 -2
- package/dist/query/where.d.ts +3 -3
- package/dist/query/where.js +8 -2
- package/dist/query/writes.js +10 -9
- package/package.json +13 -3
package/dist/cjs/powql.js
CHANGED
|
@@ -77,6 +77,10 @@ const powdb_js_1 = require("./powdb.js");
|
|
|
77
77
|
const aggregates_js_1 = require("./query/aggregates.js");
|
|
78
78
|
const compound_unique_js_1 = require("./query/compound-unique.js");
|
|
79
79
|
const filters_js_1 = require("./query/filters.js");
|
|
80
|
+
// The privilege sentinel and its resolver: `includePii` / `allowFullTableScan`
|
|
81
|
+
// are unlocked ONLY by the UNSAFE symbol, on this engine exactly as on the SQL
|
|
82
|
+
// engines, so a spread request body cannot turn either on here either.
|
|
83
|
+
const types_js_1 = require("./query/types.js");
|
|
80
84
|
const utils_js_1 = require("./query/utils.js");
|
|
81
85
|
const where_js_1 = require("./query/where.js");
|
|
82
86
|
const schema_js_1 = require("./schema.js");
|
|
@@ -990,6 +994,21 @@ class PowqlInterface {
|
|
|
990
994
|
* contract): for identical cross-engine results pass `nulls: 'last'`
|
|
991
995
|
* explicitly on Postgres, which defaults nulls-first for `desc`.
|
|
992
996
|
*/
|
|
997
|
+
/**
|
|
998
|
+
* Validate one orderBy direction token and return the PowQL keyword.
|
|
999
|
+
*
|
|
1000
|
+
* Every direction site on this engine used to be spelled
|
|
1001
|
+
* `x === 'desc' ? 'desc' : 'asc'`, so `'DESC'`, a token the CORE explicitly
|
|
1002
|
+
* accepts and honours, compiled to `asc` here: identical application code
|
|
1003
|
+
* sorted one way on Postgres and silently the opposite way on PowDB. The rule
|
|
1004
|
+
* is core's {@link assertDirectionToken}, reused rather than re-derived, so
|
|
1005
|
+
* the two engines cannot drift again. `undefined` stays "not specified"
|
|
1006
|
+
* (defaults asc); `null` is a VALUE and is refused like any other bad token.
|
|
1007
|
+
*/
|
|
1008
|
+
dirKeyword(value, context) {
|
|
1009
|
+
(0, types_js_1.assertDirectionToken)(value, context);
|
|
1010
|
+
return typeof value === 'string' && value.toLowerCase() === 'desc' ? 'desc' : 'asc';
|
|
1011
|
+
}
|
|
993
1012
|
buildOrder(orderBy, params, alias) {
|
|
994
1013
|
if (!orderBy)
|
|
995
1014
|
return '';
|
|
@@ -1010,7 +1029,7 @@ class PowqlInterface {
|
|
|
1010
1029
|
if (spec.nulls === 'first') {
|
|
1011
1030
|
throw new errors_js_1.UnsupportedFeatureError('NULLS FIRST placement', 'PowDB', `field "${field}": PowDB orders NULLs / missing keys LAST in both directions`);
|
|
1012
1031
|
}
|
|
1013
|
-
return `${this.ref(field, alias)} ${spec.sort
|
|
1032
|
+
return `${this.ref(field, alias)} ${this.dirKeyword(spec.sort, `orderBy on "${field}"`)}`;
|
|
1014
1033
|
}
|
|
1015
1034
|
// Name the actual feature in the refusal, a pick-row ordering
|
|
1016
1035
|
// reported as "vector / distance ordering" sends users hunting for
|
|
@@ -1026,7 +1045,7 @@ class PowqlInterface {
|
|
|
1026
1045
|
: 'object-valued ordering';
|
|
1027
1046
|
throw new errors_js_1.UnsupportedFeatureError(feature, 'PowDB', `field "${field}"`);
|
|
1028
1047
|
}
|
|
1029
|
-
return `${this.ref(field, alias)} ${dir
|
|
1048
|
+
return `${this.ref(field, alias)} ${this.dirKeyword(dir, `orderBy on "${field}"`)}`;
|
|
1030
1049
|
});
|
|
1031
1050
|
return ` order ${parts.join(', ')}`;
|
|
1032
1051
|
}
|
|
@@ -1044,7 +1063,7 @@ class PowqlInterface {
|
|
|
1044
1063
|
// `type: 'numeric'` casts a JSON STRING number for numeric ordering; native
|
|
1045
1064
|
// JSON numbers already order numerically without a cast.
|
|
1046
1065
|
const expr = spec.type === 'numeric' ? `cast(${pathExpr}, "float")` : pathExpr;
|
|
1047
|
-
return `${expr} ${spec.direction
|
|
1066
|
+
return `${expr} ${this.dirKeyword(spec.direction, `JSON-path orderBy on "${field}"`)}`;
|
|
1048
1067
|
}
|
|
1049
1068
|
// -------------------------------------------------------------------------
|
|
1050
1069
|
// Execution plumbing
|
|
@@ -1189,7 +1208,7 @@ class PowqlInterface {
|
|
|
1189
1208
|
if (linkPlans.length)
|
|
1190
1209
|
this.attachLinkRows(entities, linkPlans, native);
|
|
1191
1210
|
if (residualWith) {
|
|
1192
|
-
await this.loadRelations(entities, residualWith, args.timeout, 0, { args, resolvedWhere }, args.includePii
|
|
1211
|
+
await this.loadRelations(entities, residualWith, args.timeout, 0, { args, resolvedWhere }, (0, types_js_1.resolveUnsafeFlag)(args.includePii, 'includePii'));
|
|
1193
1212
|
}
|
|
1194
1213
|
return entities;
|
|
1195
1214
|
});
|
|
@@ -1212,7 +1231,7 @@ class PowqlInterface {
|
|
|
1212
1231
|
throw new errors_js_1.UnsupportedFeatureError('cursor pagination', 'PowDB', 'use limit/offset instead');
|
|
1213
1232
|
}
|
|
1214
1233
|
const resolvedWhere = await this.resolveRelationFilters(args.where, args.timeout);
|
|
1215
|
-
const cols = this.projectedColumns(args.select, args.omit, args.includePii
|
|
1234
|
+
const cols = this.projectedColumns(args.select, args.omit, (0, types_js_1.resolveUnsafeFlag)(args.includePii, 'includePii'));
|
|
1216
1235
|
// Partition the `with` clause: nested-projection blocks vs loader residue.
|
|
1217
1236
|
// A parent `distinct` never nests (distinct over a row containing a JSON
|
|
1218
1237
|
// array is not a defined comparison), and a relation whose field name
|
|
@@ -1228,7 +1247,9 @@ class PowqlInterface {
|
|
|
1228
1247
|
if (!opt)
|
|
1229
1248
|
continue;
|
|
1230
1249
|
const rel = this.meta.relations[relName];
|
|
1231
|
-
const plan = rel && !cols.includes(relName)
|
|
1250
|
+
const plan = rel && !cols.includes(relName)
|
|
1251
|
+
? this.planNestedRelation(relName, rel, opt, (0, types_js_1.resolveUnsafeFlag)(args.includePii, 'includePii'))
|
|
1252
|
+
: null;
|
|
1232
1253
|
if (plan) {
|
|
1233
1254
|
nestedPlans.push(plan);
|
|
1234
1255
|
continue;
|
|
@@ -1238,7 +1259,7 @@ class PowqlInterface {
|
|
|
1238
1259
|
// inside, only when a genuine candidate reaches it), else it stays on the
|
|
1239
1260
|
// loaders.
|
|
1240
1261
|
const linkPlan = rel && !cols.includes(relName)
|
|
1241
|
-
? await this.planLinkPathRelation(relName, rel, opt, args.includePii
|
|
1262
|
+
? await this.planLinkPathRelation(relName, rel, opt, (0, types_js_1.resolveUnsafeFlag)(args.includePii, 'includePii'), cols, linkPlans.length + 1)
|
|
1242
1263
|
: null;
|
|
1243
1264
|
if (linkPlan)
|
|
1244
1265
|
linkPlans.push(linkPlan);
|
|
@@ -1331,7 +1352,7 @@ class PowqlInterface {
|
|
|
1331
1352
|
if (linkPlans.length)
|
|
1332
1353
|
this.attachLinkRows(entities, linkPlans, native);
|
|
1333
1354
|
if (residualWith)
|
|
1334
|
-
await this.loadRelations(entities, residualWith, args.timeout, 0, undefined, args.includePii
|
|
1355
|
+
await this.loadRelations(entities, residualWith, args.timeout, 0, undefined, (0, types_js_1.resolveUnsafeFlag)(args.includePii, 'includePii'));
|
|
1335
1356
|
return entities[0];
|
|
1336
1357
|
});
|
|
1337
1358
|
}
|
|
@@ -1347,7 +1368,7 @@ class PowqlInterface {
|
|
|
1347
1368
|
if (linkPlans.length)
|
|
1348
1369
|
this.attachLinkRows(entities, linkPlans, native);
|
|
1349
1370
|
if (residualWith)
|
|
1350
|
-
await this.loadRelations(entities, residualWith, args.timeout, 0, undefined, args.includePii
|
|
1371
|
+
await this.loadRelations(entities, residualWith, args.timeout, 0, undefined, (0, types_js_1.resolveUnsafeFlag)(args.includePii, 'includePii'));
|
|
1351
1372
|
return entities[0];
|
|
1352
1373
|
});
|
|
1353
1374
|
}
|
|
@@ -1467,7 +1488,9 @@ class PowqlInterface {
|
|
|
1467
1488
|
where: childWhere,
|
|
1468
1489
|
with: options.with,
|
|
1469
1490
|
timeout: options.timeout ?? timeout,
|
|
1470
|
-
|
|
1491
|
+
// Re-entering the public findMany, so the opt-in has to be spelled
|
|
1492
|
+
// in its PUBLIC form (the sentinel); a plain `true` is refused there.
|
|
1493
|
+
includePii: includePii ? types_js_1.UNSAFE : undefined,
|
|
1471
1494
|
}));
|
|
1472
1495
|
for (const child of children) {
|
|
1473
1496
|
const k = this.joinKey(child[childKeyField]);
|
|
@@ -1572,7 +1595,8 @@ class PowqlInterface {
|
|
|
1572
1595
|
where,
|
|
1573
1596
|
with: options.with,
|
|
1574
1597
|
timeout: options.timeout ?? timeout,
|
|
1575
|
-
|
|
1598
|
+
// Public findMany, so the sentinel form. See loadRelation above.
|
|
1599
|
+
includePii: includePii ? types_js_1.UNSAFE : undefined,
|
|
1576
1600
|
}));
|
|
1577
1601
|
for (const t of targets)
|
|
1578
1602
|
targetByPk.set(String(t[targetPkField]), t);
|
|
@@ -2329,7 +2353,7 @@ class PowqlInterface {
|
|
|
2329
2353
|
const params = [];
|
|
2330
2354
|
const resolvedWhere = await this.resolveRelationFilters(args.where, args.timeout);
|
|
2331
2355
|
const where = this.buildWhere(resolvedWhere, params);
|
|
2332
|
-
this.assertCompiledWhere(where, args.allowFullTableScan, 'updateMany');
|
|
2356
|
+
this.assertCompiledWhere(where, (0, types_js_1.resolveUnsafeFlag)(args.allowFullTableScan, 'allowFullTableScan'), 'updateMany');
|
|
2333
2357
|
const setClause = this.buildUpdateAssignments(args.data, params);
|
|
2334
2358
|
const filter = where ? ` filter ${where}` : '';
|
|
2335
2359
|
const { rowCount } = await this.exec(`${this.qt}${filter} update { ${setClause} }`, params, args.timeout, 'updateMany');
|
|
@@ -2479,7 +2503,7 @@ class PowqlInterface {
|
|
|
2479
2503
|
const params = [];
|
|
2480
2504
|
const resolvedWhere = await this.resolveRelationFilters(args.where, args.timeout);
|
|
2481
2505
|
const where = this.buildWhere(resolvedWhere, params);
|
|
2482
|
-
this.assertCompiledWhere(where, args.allowFullTableScan, 'deleteMany');
|
|
2506
|
+
this.assertCompiledWhere(where, (0, types_js_1.resolveUnsafeFlag)(args.allowFullTableScan, 'allowFullTableScan'), 'deleteMany');
|
|
2483
2507
|
const filter = where ? ` filter ${where}` : '';
|
|
2484
2508
|
const { rowCount } = await this.exec(`${this.qt}${filter} delete`, params, args.timeout, 'deleteMany');
|
|
2485
2509
|
return { count: rowCount };
|
|
@@ -2618,7 +2642,7 @@ class PowqlInterface {
|
|
|
2618
2642
|
const powfn = fn.slice(1); // sum/avg/min/max
|
|
2619
2643
|
// Same PII contract as the SQL engines: _min/_max return a stored cell.
|
|
2620
2644
|
if (fn === '_min' || fn === '_max') {
|
|
2621
|
-
(0, aggregates_js_1.assertAggregatePiiOptIn)(this.table, this.meta, field, this.column(field).name, `aggregate ${fn}`, args.includePii);
|
|
2645
|
+
(0, aggregates_js_1.assertAggregatePiiOptIn)(this.table, this.meta, field, this.column(field).name, `aggregate ${fn}`, (0, types_js_1.resolveUnsafeFlag)(args.includePii, 'includePii'));
|
|
2622
2646
|
}
|
|
2623
2647
|
acc[field] = await scalar(`${powfn}(${this.qt}${filter} { ${this.ref(field)} })`);
|
|
2624
2648
|
}
|
|
@@ -2672,7 +2696,7 @@ class PowqlInterface {
|
|
|
2672
2696
|
for (const entry of args.by) {
|
|
2673
2697
|
if (typeof entry === 'string') {
|
|
2674
2698
|
const col = this.column(entry);
|
|
2675
|
-
(0, aggregates_js_1.assertAggregatePiiOptIn)(this.table, this.meta, entry, col.name, 'groupBy `by` key', args.includePii);
|
|
2699
|
+
(0, aggregates_js_1.assertAggregatePiiOptIn)(this.table, this.meta, entry, col.name, 'groupBy `by` key', (0, types_js_1.resolveUnsafeFlag)(args.includePii, 'includePii'));
|
|
2676
2700
|
claim(entry, `column "${col.name}"`);
|
|
2677
2701
|
if (col.name !== entry)
|
|
2678
2702
|
claim(col.name, `column "${col.name}"`);
|
|
@@ -2686,7 +2710,7 @@ class PowqlInterface {
|
|
|
2686
2710
|
if (!(0, powdb_js_1.isJsonColumn)(col)) {
|
|
2687
2711
|
throw new errors_js_1.ValidationError(`[turbine] groupBy JSON group key on "${entry.field}" (table "${this.table}") requires a json column.`);
|
|
2688
2712
|
}
|
|
2689
|
-
(0, aggregates_js_1.assertAggregatePiiOptIn)(this.table, this.meta, entry.field, col.name, 'groupBy JSON `by` key', args.includePii);
|
|
2713
|
+
(0, aggregates_js_1.assertAggregatePiiOptIn)(this.table, this.meta, entry.field, col.name, 'groupBy JSON `by` key', (0, types_js_1.resolveUnsafeFlag)(args.includePii, 'includePii'));
|
|
2690
2714
|
this.assertJsonPath('group key', entry.field, entry.path);
|
|
2691
2715
|
const pathExpr = this.jsonPathExpr(col, entry.path, params);
|
|
2692
2716
|
const alias = entry.alias ?? String(entry.path[entry.path.length - 1]);
|
|
@@ -2737,7 +2761,7 @@ class PowqlInterface {
|
|
|
2737
2761
|
if (target === true) {
|
|
2738
2762
|
const col = this.column(key);
|
|
2739
2763
|
if (fn === '_min' || fn === '_max') {
|
|
2740
|
-
(0, aggregates_js_1.assertAggregatePiiOptIn)(this.table, this.meta, key, col.name, `groupBy ${fn}`, args.includePii);
|
|
2764
|
+
(0, aggregates_js_1.assertAggregatePiiOptIn)(this.table, this.meta, key, col.name, `groupBy ${fn}`, (0, types_js_1.resolveUnsafeFlag)(args.includePii, 'includePii'));
|
|
2741
2765
|
}
|
|
2742
2766
|
claim(`${fn}_${col.name}`, `${fn} of column "${col.name}"`);
|
|
2743
2767
|
const inner = `.${col.name}`;
|
|
@@ -2752,7 +2776,7 @@ class PowqlInterface {
|
|
|
2752
2776
|
throw new errors_js_1.ValidationError(`[turbine] groupBy ${fn} target "${key}" on "${target.field}" (table "${this.table}") requires a json column.`);
|
|
2753
2777
|
}
|
|
2754
2778
|
if (fn === '_min' || fn === '_max') {
|
|
2755
|
-
(0, aggregates_js_1.assertAggregatePiiOptIn)(this.table, this.meta, target.field, col.name, `groupBy ${fn} JSON target`, args.includePii);
|
|
2779
|
+
(0, aggregates_js_1.assertAggregatePiiOptIn)(this.table, this.meta, target.field, col.name, `groupBy ${fn} JSON target`, (0, types_js_1.resolveUnsafeFlag)(args.includePii, 'includePii'));
|
|
2756
2780
|
}
|
|
2757
2781
|
this.assertJsonPath(`${fn} target "${key}"`, target.field, target.path);
|
|
2758
2782
|
const alwaysNumeric = fn === '_sum' || fn === '_avg';
|
|
@@ -2952,9 +2976,9 @@ class PowqlInterface {
|
|
|
2952
2976
|
if (spec.nulls === 'first') {
|
|
2953
2977
|
throw new errors_js_1.UnsupportedFeatureError('NULLS FIRST placement', 'PowDB', `groupBy orderBy "${keyForMsg}": PowDB orders NULLs / missing keys LAST in both directions`);
|
|
2954
2978
|
}
|
|
2955
|
-
return spec.sort
|
|
2979
|
+
return this.dirKeyword(spec.sort, `groupBy orderBy "${keyForMsg}"`);
|
|
2956
2980
|
}
|
|
2957
|
-
return value
|
|
2981
|
+
return this.dirKeyword(value, `groupBy orderBy "${keyForMsg}"`);
|
|
2958
2982
|
}
|
|
2959
2983
|
// -------------------------------------------------------------------------
|
|
2960
2984
|
// Streaming / unsupported
|
|
@@ -2991,7 +3015,8 @@ class PowqlInterface {
|
|
|
2991
3015
|
if (compiledWhere.length > 0)
|
|
2992
3016
|
return;
|
|
2993
3017
|
throw new errors_js_1.ValidationError(`[turbine] ${action} on "${this.table}" refused: the \`where\` clause is empty. ` +
|
|
2994
|
-
|
|
3018
|
+
"Pass `allowFullTableScan: UNSAFE` to opt in (import { UNSAFE } from 'turbine-orm'), " +
|
|
3019
|
+
'or check that your filter values are defined.');
|
|
2995
3020
|
}
|
|
2996
3021
|
}
|
|
2997
3022
|
exports.PowqlInterface = PowqlInterface;
|
|
@@ -40,6 +40,11 @@
|
|
|
40
40
|
* by this layer, and a key that is neither a Prisma arg nor a turbine option
|
|
41
41
|
* gets a dev-mode warning instead of vanishing (see
|
|
42
42
|
* {@link PRISMA_ARG_KEYS} and `warnUnknownQueryOptions`).
|
|
43
|
+
* The three PRIVILEGE options among them (`skipGlobalFilters`, `includePii`,
|
|
44
|
+
* `allowFullTableScan`) are forwarded VERBATIM, which is what makes them safe
|
|
45
|
+
* here: core accepts only the `UNSAFE` sentinel, so a Prisma-shaped args
|
|
46
|
+
* object carrying `includePii: true` reaches core and is refused there, and
|
|
47
|
+
* this layer never needs its own copy of that rule.
|
|
43
48
|
*
|
|
44
49
|
* ## What it deliberately does NOT do (documented divergences)
|
|
45
50
|
*
|
|
@@ -75,11 +80,16 @@
|
|
|
75
80
|
* - **`limit` on `updateMany` / `deleteMany`** (Prisma 6.7+) throws. Turbine has
|
|
76
81
|
* no row-bounded mass mutation, and dropping a SAFETY BOUND with a warning
|
|
77
82
|
* would turn "change at most 10 rows" into "change every matching row".
|
|
78
|
-
* - **Write projections
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
+
* - **Write projections**: `select` / `omit` on create/update/delete/upsert
|
|
84
|
+
* narrow the RETURNED OBJECT (see {@link resolveWriteProjection}); they do
|
|
85
|
+
* NOT narrow the statement's `RETURNING` list, so the column still crosses
|
|
86
|
+
* the wire, and `pii: true` remains the SQL-level control. A relation key in
|
|
87
|
+
* either (or any `include` on a write) THROWS, since a write returns its own
|
|
88
|
+
* row only. `omit` on READS is translated to core's own `omit`, see
|
|
89
|
+
* {@link translateOmit}.
|
|
90
|
+
* - **`select` on `count`** and **`orderBy` / `cursor` / `take` / `skip` on
|
|
91
|
+
* `aggregate`** are accepted and IGNORED (they are legitimate Prisma, so they
|
|
92
|
+
* never warn); a plain number / the aggregate comes back.
|
|
83
93
|
*
|
|
84
94
|
* ## Type dependencies (0.41.0)
|
|
85
95
|
*
|