turbine-orm 0.35.0 → 0.36.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 +18 -16
- package/dist/cjs/cli/index.js +109 -16
- package/dist/cjs/cli/migrate.js +78 -3
- package/dist/cjs/cli/studio-ui.generated.js +1 -1
- package/dist/cjs/cli/studio.js +333 -22
- package/dist/cjs/cli/ui.js +7 -1
- package/dist/cjs/dialect.js +1 -1
- package/dist/cjs/generate.js +23 -2
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/mssql.js +22 -5
- package/dist/cjs/powdb.js +41 -1
- package/dist/cjs/powql.js +80 -25
- package/dist/cjs/query/aggregates.js +683 -0
- package/dist/cjs/query/batched-loader.js +2 -0
- package/dist/cjs/query/builder.js +297 -4504
- package/dist/cjs/query/filters.js +12 -0
- package/dist/cjs/query/relations.js +1698 -0
- package/dist/cjs/query/where-compile.js +180 -0
- package/dist/cjs/query/where.js +1491 -0
- package/dist/cjs/query/writes.js +680 -0
- package/dist/cjs/schema-builder.js +6 -0
- package/dist/cjs/schema-metadata.js +4 -0
- package/dist/cjs/schema-sql.js +265 -3
- package/dist/cjs/sqlite.js +1 -1
- package/dist/cli/index.d.ts +8 -2
- package/dist/cli/index.js +111 -18
- package/dist/cli/migrate.d.ts +24 -1
- package/dist/cli/migrate.js +77 -3
- package/dist/cli/studio-ui.generated.js +1 -1
- package/dist/cli/studio.d.ts +46 -13
- package/dist/cli/studio.js +331 -23
- package/dist/cli/ui.js +7 -1
- package/dist/dialect.d.ts +15 -6
- package/dist/dialect.js +1 -1
- package/dist/generate.js +23 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mssql.js +22 -5
- package/dist/powdb.d.ts +20 -0
- package/dist/powdb.js +40 -0
- package/dist/powql.d.ts +33 -1
- package/dist/powql.js +80 -25
- package/dist/query/aggregates.d.ts +74 -0
- package/dist/query/aggregates.js +641 -0
- package/dist/query/batched-loader.d.ts +6 -0
- package/dist/query/batched-loader.js +2 -0
- package/dist/query/builder.d.ts +62 -829
- package/dist/query/builder.js +302 -4509
- package/dist/query/deferred.d.ts +7 -0
- package/dist/query/filters.d.ts +7 -0
- package/dist/query/filters.js +11 -0
- package/dist/query/relations.d.ts +441 -0
- package/dist/query/relations.js +1627 -0
- package/dist/query/types.d.ts +15 -0
- package/dist/query/where-compile.d.ts +139 -0
- package/dist/query/where-compile.js +175 -0
- package/dist/query/where.d.ts +494 -0
- package/dist/query/where.js +1431 -0
- package/dist/query/writes.d.ts +131 -0
- package/dist/query/writes.js +626 -0
- package/dist/schema-builder.d.ts +18 -3
- package/dist/schema-builder.js +6 -0
- package/dist/schema-metadata.js +4 -0
- package/dist/schema-sql.d.ts +60 -3
- package/dist/schema-sql.js +261 -4
- package/dist/schema.d.ts +10 -0
- package/dist/sqlite.js +1 -1
- package/package.json +2 -2
package/dist/cjs/powdb.js
CHANGED
|
@@ -90,7 +90,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
90
90
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
91
91
|
};
|
|
92
92
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
93
|
-
exports.PowqlInterface = exports.introspectPowdbDatabase = exports.PowdbEmbeddedPool = exports.PowdbPool = exports.DEFAULT_TX_QUEUE_TIMEOUT_MS = exports.POWQL_KEYWORDS = exports.ALL_POWDB_CAPABILITIES = exports.MIN_POWDB_VERSION = exports.PowdbJsonParam = exports.PowdbFloatParam = exports.powdbDialect = void 0;
|
|
93
|
+
exports.PowqlInterface = exports.introspectPowdbDatabase = exports.PowdbEmbeddedPool = exports.POWQL_LEXER_TESTED_CEILING = exports.PowdbPool = exports.DEFAULT_TX_QUEUE_TIMEOUT_MS = exports.POWQL_KEYWORDS = exports.ALL_POWDB_CAPABILITIES = exports.MIN_POWDB_VERSION = exports.PowdbJsonParam = exports.PowdbFloatParam = exports.powdbDialect = void 0;
|
|
94
94
|
exports.parsePowdbUrl = parsePowdbUrl;
|
|
95
95
|
exports.assertSupportedPowdbVersion = assertSupportedPowdbVersion;
|
|
96
96
|
exports.capabilitiesFromVersion = capabilitiesFromVersion;
|
|
@@ -1430,6 +1430,26 @@ function encodePowqlLiteral(value) {
|
|
|
1430
1430
|
return encodePowqlString(value);
|
|
1431
1431
|
throw new errors_js_1.ValidationError(`[turbine] Value of type ${typeof value} cannot be encoded as a PowDB literal.`);
|
|
1432
1432
|
}
|
|
1433
|
+
/**
|
|
1434
|
+
* The newest PowDB engine LINE (major.minor) whose lexer escape handling
|
|
1435
|
+
* {@link encodePowqlString} is VERIFIED against by reading
|
|
1436
|
+
* `crates/query/src/lexer.rs`. The legacy materialize path
|
|
1437
|
+
* ({@link materializePowql}) inlines encoded string literals directly into query
|
|
1438
|
+
* text, so it is only injection-safe while the lexer recognizes exactly the
|
|
1439
|
+
* escape set the escaper emits (`\"`, `\\`, `\n`, `\t`, everything else raw). If
|
|
1440
|
+
* a future engine line teaches the lexer new escapes (e.g. `\u`, `\x`), a string
|
|
1441
|
+
* that the escaper leaves raw could be re-interpreted by the lexer and break out
|
|
1442
|
+
* of the literal, turning the fallback into an injection primitive.
|
|
1443
|
+
*
|
|
1444
|
+
* CONTRACT: bump this ceiling ONLY after re-verifying the escape handling in
|
|
1445
|
+
* `crates/query/src/lexer.rs` for the newer line AND confirming
|
|
1446
|
+
* {@link encodePowqlString} still escapes every breakout vector the lexer
|
|
1447
|
+
* recognizes. The legacy path guards on this value (see
|
|
1448
|
+
* {@link PowdbEmbeddedPool.exec}): an embedded addon whose engine line exceeds
|
|
1449
|
+
* the ceiling yet still routes through the string wire is refused rather than
|
|
1450
|
+
* materialized.
|
|
1451
|
+
*/
|
|
1452
|
+
exports.POWQL_LEXER_TESTED_CEILING = '0.15';
|
|
1433
1453
|
/** Escape a string into a PowQL `"…"` literal, matching the engine lexer's escape rules. */
|
|
1434
1454
|
function encodePowqlString(s) {
|
|
1435
1455
|
let out = '"';
|
|
@@ -1532,6 +1552,26 @@ class PowdbEmbeddedPool {
|
|
|
1532
1552
|
// Legacy string wire (addon < 0.14): the engine takes no params array, so
|
|
1533
1553
|
// materialize each `$N` into a PowQL literal. Byte-for-byte unchanged, kept
|
|
1534
1554
|
// live and tested as the pre-0.14 fallback.
|
|
1555
|
+
//
|
|
1556
|
+
// Safety assertion (see {@link POWQL_LEXER_TESTED_CEILING}): an addon whose
|
|
1557
|
+
// engine line EXCEEDS the escaper's verified lexer ceiling must never be
|
|
1558
|
+
// materialized: a newer lexer may recognize escapes the escaper leaves raw,
|
|
1559
|
+
// making the inline path an injection primitive. Reachability: addons >= 0.14
|
|
1560
|
+
// expose `queryWithParams` and take the native path above, so the ONLY way to
|
|
1561
|
+
// reach this branch with a newer-than-ceiling engine is the anomalous
|
|
1562
|
+
// newer-addon-without-native case (feature-detect failed). Refuse it rather
|
|
1563
|
+
// than inline-encode against an unverified lexer.
|
|
1564
|
+
const engineSem = parsePowdbSemver(this.capabilities.engineVersion);
|
|
1565
|
+
const ceiling = parsePowdbSemver(exports.POWQL_LEXER_TESTED_CEILING);
|
|
1566
|
+
if (engineSem &&
|
|
1567
|
+
ceiling &&
|
|
1568
|
+
(engineSem.major > ceiling.major || (engineSem.major === ceiling.major && engineSem.minor > ceiling.minor))) {
|
|
1569
|
+
throw new errors_js_1.ValidationError(`[turbine] Refusing the PowDB legacy string wire: this embedded addon reports engine ` +
|
|
1570
|
+
`${this.capabilities.engineVersion}, which is newer than the escaper's verified lexer range ` +
|
|
1571
|
+
`(<= ${exports.POWQL_LEXER_TESTED_CEILING}) AND such an addon exposes the parameterized native API, so ` +
|
|
1572
|
+
`reaching the legacy materialize path means the queryWithParams feature-detect failed. Upgrade ` +
|
|
1573
|
+
`turbine-orm so its PowQL escaper is verified against this engine line before running on it.`);
|
|
1574
|
+
}
|
|
1535
1575
|
const materialized = materializePowql(powql, params);
|
|
1536
1576
|
return adaptResult(normalizeEmbeddedResult(this.db.query(materialized)));
|
|
1537
1577
|
}
|
package/dist/cjs/powql.js
CHANGED
|
@@ -653,10 +653,17 @@ class PowqlInterface {
|
|
|
653
653
|
// -------------------------------------------------------------------------
|
|
654
654
|
// Projection / order
|
|
655
655
|
// -------------------------------------------------------------------------
|
|
656
|
-
/**
|
|
657
|
-
|
|
656
|
+
/**
|
|
657
|
+
* Resolve the set of columns to project, honouring `select` / `omit` and the
|
|
658
|
+
* query-level `includePii` opt-in. PII-tagged (`defineSchema` `pii: true`)
|
|
659
|
+
* columns are EXCLUDED from a default (or omit-only) projection unless
|
|
660
|
+
* `includePii` is true; an explicit `select` naming a PII column IS the opt-in
|
|
661
|
+
* and returns it regardless. Untagged tables project exactly as before.
|
|
662
|
+
*/
|
|
663
|
+
projectedColumns(select, omit, includePii) {
|
|
658
664
|
let cols = this.meta.columns.map((c) => c.name);
|
|
659
|
-
|
|
665
|
+
const hasSelect = select && Object.keys(select).length;
|
|
666
|
+
if (hasSelect) {
|
|
660
667
|
const picked = new Set(Object.entries(select)
|
|
661
668
|
.filter(([, v]) => v)
|
|
662
669
|
.map(([k]) => this.column(k).name));
|
|
@@ -665,6 +672,14 @@ class PowqlInterface {
|
|
|
665
672
|
picked.add(pk);
|
|
666
673
|
cols = cols.filter((c) => picked.has(c));
|
|
667
674
|
}
|
|
675
|
+
else if (!includePii) {
|
|
676
|
+
// Default / omit-only projection: drop PII columns (kept above only when a
|
|
677
|
+
// caller names them in `select`). PK is never PII in practice; if one is
|
|
678
|
+
// tagged it is still dropped here, so tag sensitive data, not keys.
|
|
679
|
+
const pii = this.piiColumnNames();
|
|
680
|
+
if (pii.size)
|
|
681
|
+
cols = cols.filter((c) => !pii.has(c));
|
|
682
|
+
}
|
|
668
683
|
if (omit && Object.keys(omit).length) {
|
|
669
684
|
const dropped = new Set(Object.entries(omit)
|
|
670
685
|
.filter(([, v]) => v)
|
|
@@ -673,6 +688,47 @@ class PowqlInterface {
|
|
|
673
688
|
}
|
|
674
689
|
return cols;
|
|
675
690
|
}
|
|
691
|
+
/**
|
|
692
|
+
* The snake_case names of this table's PII-tagged columns. Empty for a table
|
|
693
|
+
* with no `pii: true` column, so untagged tables keep their prior projection.
|
|
694
|
+
*/
|
|
695
|
+
piiColumnNames() {
|
|
696
|
+
const out = new Set();
|
|
697
|
+
for (const col of this.meta.columns) {
|
|
698
|
+
if (col.pii)
|
|
699
|
+
out.add(col.name);
|
|
700
|
+
}
|
|
701
|
+
return out;
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* The camelCase field names of this table's PII-tagged columns: the read
|
|
705
|
+
* policy applied to a write's returned row (create/update/upsert/delete accept
|
|
706
|
+
* no `includePii`/`select`, so their result always drops PII; you may still
|
|
707
|
+
* write PII fields freely).
|
|
708
|
+
*
|
|
709
|
+
* SPEC LIMITATION (PowQL): the driver contract
|
|
710
|
+
* (`docs/integrations/powql-for-drivers.md`) exposes `returning` only as a
|
|
711
|
+
* bare keyword that hands back every column; it accepts NO column list, so
|
|
712
|
+
* (unlike the SQL engines, which emit an explicit non-PII `RETURNING`/`OUTPUT`
|
|
713
|
+
* projection) the create/update/delete `returning` paths cannot exclude PII at
|
|
714
|
+
* the query-language level and must strip it here after the fact. This is the
|
|
715
|
+
* client-side strip of last resort, not defense-in-depth, for those paths; we
|
|
716
|
+
* do NOT reverse-engineer an undocumented projection form. The upsert path is
|
|
717
|
+
* different: it has no `returning` and reselects by PK through the read
|
|
718
|
+
* projection ({@link projectedColumns}), which already omits PII, so PII never
|
|
719
|
+
* crosses the wire there. If a future spec revision lets `returning` take a
|
|
720
|
+
* projection, switch the write paths to emit the non-PII list and this strip
|
|
721
|
+
* becomes a no-op like {@link parseWriteRow} on the SQL engines.
|
|
722
|
+
*/
|
|
723
|
+
stripWritePii(entity) {
|
|
724
|
+
if (!entity)
|
|
725
|
+
return entity;
|
|
726
|
+
for (const col of this.meta.columns) {
|
|
727
|
+
if (col.pii)
|
|
728
|
+
delete entity[col.field];
|
|
729
|
+
}
|
|
730
|
+
return entity;
|
|
731
|
+
}
|
|
676
732
|
/** `{ .c1, .c2, … }` projection clause. */
|
|
677
733
|
projection(cols) {
|
|
678
734
|
return `{ ${cols.map((c) => `.${c}`).join(', ')} }`;
|
|
@@ -877,10 +933,7 @@ class PowqlInterface {
|
|
|
877
933
|
const { rows, native, resolvedWhere } = await this.runFind(args, 'findMany');
|
|
878
934
|
const entities = this.shape(rows, native);
|
|
879
935
|
if (args.with) {
|
|
880
|
-
await this.loadRelations(entities, args.with, args.timeout, 0, {
|
|
881
|
-
args,
|
|
882
|
-
resolvedWhere,
|
|
883
|
-
});
|
|
936
|
+
await this.loadRelations(entities, args.with, args.timeout, 0, { args, resolvedWhere }, args.includePii === true);
|
|
884
937
|
}
|
|
885
938
|
return entities;
|
|
886
939
|
});
|
|
@@ -897,7 +950,7 @@ class PowqlInterface {
|
|
|
897
950
|
}
|
|
898
951
|
const resolvedWhere = await this.resolveRelationFilters(args.where, args.timeout);
|
|
899
952
|
const where = this.buildWhere(resolvedWhere, params);
|
|
900
|
-
const cols = this.projectedColumns(args.select, args.omit);
|
|
953
|
+
const cols = this.projectedColumns(args.select, args.omit, args.includePii === true);
|
|
901
954
|
const distinct = args.distinct?.length ? ' distinct' : '';
|
|
902
955
|
const filter = where ? ` filter ${where}` : '';
|
|
903
956
|
const order = this.buildOrder(args.orderBy, params);
|
|
@@ -949,7 +1002,7 @@ class PowqlInterface {
|
|
|
949
1002
|
return null;
|
|
950
1003
|
const entities = this.shape(rows, native);
|
|
951
1004
|
if (args.with)
|
|
952
|
-
await this.loadRelations(entities, args.with, args.timeout);
|
|
1005
|
+
await this.loadRelations(entities, args.with, args.timeout, 0, undefined, args.includePii === true);
|
|
953
1006
|
return entities[0];
|
|
954
1007
|
});
|
|
955
1008
|
}
|
|
@@ -960,7 +1013,7 @@ class PowqlInterface {
|
|
|
960
1013
|
return null;
|
|
961
1014
|
const entities = this.shape(rows, native);
|
|
962
1015
|
if (args.with)
|
|
963
|
-
await this.loadRelations(entities, args.with, args.timeout);
|
|
1016
|
+
await this.loadRelations(entities, args.with, args.timeout, 0, undefined, args.includePii === true);
|
|
964
1017
|
return entities[0];
|
|
965
1018
|
});
|
|
966
1019
|
}
|
|
@@ -990,7 +1043,7 @@ class PowqlInterface {
|
|
|
990
1043
|
* the default `'batched'` strategy) keeps the loaders. Output is byte-equal
|
|
991
1044
|
* either way (the join reuses the same stitch / shape helpers).
|
|
992
1045
|
*/
|
|
993
|
-
async loadRelations(parents, withClause, timeout, depth = 0, parent) {
|
|
1046
|
+
async loadRelations(parents, withClause, timeout, depth = 0, parent, includePii = false) {
|
|
994
1047
|
if (depth >= 10) {
|
|
995
1048
|
throw new errors_js_1.ValidationError(`[turbine] Nested 'with' on PowDB exceeded depth 10 (relation cycle?).`);
|
|
996
1049
|
}
|
|
@@ -1010,7 +1063,7 @@ class PowqlInterface {
|
|
|
1010
1063
|
throw new errors_js_1.ValidationError(`[turbine] Unknown relation "${relName}" on "${this.table}".`);
|
|
1011
1064
|
if (strategyIsJoin && parent && this.joinEligible(rel, opt, parent.args, parents.length)) {
|
|
1012
1065
|
if (this.capabilities.serverJoins) {
|
|
1013
|
-
await this.loadRelationViaJoin(parents, rel, relName, opt, parent, timeout);
|
|
1066
|
+
await this.loadRelationViaJoin(parents, rel, relName, opt, parent, timeout, includePii);
|
|
1014
1067
|
continue;
|
|
1015
1068
|
}
|
|
1016
1069
|
// An otherwise-eligible relation the engine cannot join: a PER-QUERY
|
|
@@ -1022,7 +1075,7 @@ class PowqlInterface {
|
|
|
1022
1075
|
}
|
|
1023
1076
|
}
|
|
1024
1077
|
if (rel.type === 'manyToMany') {
|
|
1025
|
-
await this.loadManyToMany(parents, rel, relName, opt, timeout);
|
|
1078
|
+
await this.loadManyToMany(parents, rel, relName, opt, timeout, includePii);
|
|
1026
1079
|
continue;
|
|
1027
1080
|
}
|
|
1028
1081
|
const fk = (0, schema_js_1.normalizeKeyColumns)(rel.foreignKey);
|
|
@@ -1079,6 +1132,7 @@ class PowqlInterface {
|
|
|
1079
1132
|
where: childWhere,
|
|
1080
1133
|
with: options.with,
|
|
1081
1134
|
timeout: options.timeout ?? timeout,
|
|
1135
|
+
includePii,
|
|
1082
1136
|
}));
|
|
1083
1137
|
for (const child of children) {
|
|
1084
1138
|
const k = this.joinKey(child[childKeyField]);
|
|
@@ -1115,7 +1169,7 @@ class PowqlInterface {
|
|
|
1115
1169
|
* single-key N+1 loaders; the junction's source/target columns must be single
|
|
1116
1170
|
* (composite junction keys would need PowQL tuple-`in`, which it lacks).
|
|
1117
1171
|
*/
|
|
1118
|
-
async loadManyToMany(parents, rel, relName, opt, timeout) {
|
|
1172
|
+
async loadManyToMany(parents, rel, relName, opt, timeout, includePii = false) {
|
|
1119
1173
|
const through = rel.through;
|
|
1120
1174
|
if (!through)
|
|
1121
1175
|
throw new errors_js_1.ValidationError(`[turbine] manyToMany relation "${relName}" is missing its junction (\`through\`).`);
|
|
@@ -1179,6 +1233,7 @@ class PowqlInterface {
|
|
|
1179
1233
|
where,
|
|
1180
1234
|
with: options.with,
|
|
1181
1235
|
timeout: options.timeout ?? timeout,
|
|
1236
|
+
includePii,
|
|
1182
1237
|
}));
|
|
1183
1238
|
for (const t of targets)
|
|
1184
1239
|
targetByPk.set(String(t[targetPkField]), t);
|
|
@@ -1296,9 +1351,9 @@ class PowqlInterface {
|
|
|
1296
1351
|
return tableMeta.indexes.some((idx) => idx.unique && !idx.docPath && idx.columns.length === 1 && idx.columns[0] === col);
|
|
1297
1352
|
}
|
|
1298
1353
|
/** Dispatch one eligible relation to the correct native-join loader. */
|
|
1299
|
-
async loadRelationViaJoin(parents, rel, relName, opt, parent, timeout) {
|
|
1354
|
+
async loadRelationViaJoin(parents, rel, relName, opt, parent, timeout, includePii = false) {
|
|
1300
1355
|
if (rel.type === 'manyToMany') {
|
|
1301
|
-
await this.loadManyToManyViaJoin(parents, rel, relName, opt, parent, timeout);
|
|
1356
|
+
await this.loadManyToManyViaJoin(parents, rel, relName, opt, parent, timeout, includePii);
|
|
1302
1357
|
return;
|
|
1303
1358
|
}
|
|
1304
1359
|
const options = (opt === true ? {} : opt);
|
|
@@ -1316,7 +1371,7 @@ class PowqlInterface {
|
|
|
1316
1371
|
const childKeyCol = rel.type === 'belongsTo' ? rk[0] : fk[0];
|
|
1317
1372
|
const parentKeyField = this.meta.reverseColumnMap[parentKeyCol] ?? parentKeyCol;
|
|
1318
1373
|
const params = [];
|
|
1319
|
-
const childCols = this.joinChildCols(targetQi, options);
|
|
1374
|
+
const childCols = this.joinChildCols(targetQi, options, includePii);
|
|
1320
1375
|
const filter = await this.joinFilter(targetQi, parent.resolvedWhere, options.where, 'c', params, options.timeout ?? timeout);
|
|
1321
1376
|
const order = targetQi.buildOrder(options.orderBy, params, 'c');
|
|
1322
1377
|
const limitClause = options.limit !== undefined ? ` limit ${this.param(options.limit, params)}` : '';
|
|
@@ -1340,7 +1395,7 @@ class PowqlInterface {
|
|
|
1340
1395
|
* → the already-fetched side (alias `p`), correlating `__tpk` from the
|
|
1341
1396
|
* junction's source key. Always a list, stitched exactly like the loader.
|
|
1342
1397
|
*/
|
|
1343
|
-
async loadManyToManyViaJoin(parents, rel, relName, opt, parent, timeout) {
|
|
1398
|
+
async loadManyToManyViaJoin(parents, rel, relName, opt, parent, timeout, includePii = false) {
|
|
1344
1399
|
const through = rel.through;
|
|
1345
1400
|
if (!through)
|
|
1346
1401
|
throw new errors_js_1.ValidationError(`[turbine] manyToMany relation "${relName}" is missing its junction (\`through\`).`);
|
|
@@ -1355,7 +1410,7 @@ class PowqlInterface {
|
|
|
1355
1410
|
const targetPkCol = targetMeta.primaryKey[0];
|
|
1356
1411
|
const parentRefField = this.meta.reverseColumnMap[sourceRefCol] ?? sourceRefCol;
|
|
1357
1412
|
const params = [];
|
|
1358
|
-
const childCols = this.joinChildCols(targetQi, options);
|
|
1413
|
+
const childCols = this.joinChildCols(targetQi, options, includePii);
|
|
1359
1414
|
const filter = await this.joinFilter(targetQi, parent.resolvedWhere, options.where, 't', params, options.timeout ?? timeout);
|
|
1360
1415
|
const proj = this.joinProjection(childCols, `j.${(0, powdb_js_1.quotePowqlIdent)(sourceJCol)}`, 't');
|
|
1361
1416
|
const powql = `${targetQi.qt} as t ` +
|
|
@@ -1374,8 +1429,8 @@ class PowqlInterface {
|
|
|
1374
1429
|
* with a loud guard: a real column named `__tpk` would collide with the
|
|
1375
1430
|
* reserved correlation alias, so refuse rather than silently mis-stitch.
|
|
1376
1431
|
*/
|
|
1377
|
-
joinChildCols(targetQi, options) {
|
|
1378
|
-
const cols = targetQi.projectedColumns(options.select, options.omit);
|
|
1432
|
+
joinChildCols(targetQi, options, includePii = false) {
|
|
1433
|
+
const cols = targetQi.projectedColumns(options.select, options.omit, includePii);
|
|
1379
1434
|
if (cols.includes('__tpk')) {
|
|
1380
1435
|
throw new errors_js_1.ValidationError(`[turbine] relation target "${targetQi.table}" has a column named "__tpk", which collides with the reserved ` +
|
|
1381
1436
|
`join correlation alias. Rename the column or load this relation with relationLoadStrategy: 'batched'.`);
|
|
@@ -1504,7 +1559,7 @@ class PowqlInterface {
|
|
|
1504
1559
|
.join(', ');
|
|
1505
1560
|
// `returning` surfaces the inserted row (all columns, schema order) in one round-trip.
|
|
1506
1561
|
const { rows, native } = await this.exec(`insert ${this.qt} { ${body} } returning`, params, args.timeout, 'create');
|
|
1507
|
-
const row = rows.length ? this.shape(rows, native)[0] : null;
|
|
1562
|
+
const row = rows.length ? this.stripWritePii(this.shape(rows, native)[0]) : null;
|
|
1508
1563
|
if (!row)
|
|
1509
1564
|
throw new errors_js_1.NotFoundError({ table: this.table, where: data });
|
|
1510
1565
|
return row;
|
|
@@ -1522,7 +1577,7 @@ class PowqlInterface {
|
|
|
1522
1577
|
});
|
|
1523
1578
|
// Multi-row insert with `returning` hands back every inserted row in one round-trip.
|
|
1524
1579
|
const { rows, native } = await this.exec(`insert ${this.qt} ${tuples.join(', ')} returning`, params, args.timeout, 'createMany');
|
|
1525
|
-
return this.shape(rows, native);
|
|
1580
|
+
return this.shape(rows, native).map((r) => this.stripWritePii(r));
|
|
1526
1581
|
});
|
|
1527
1582
|
}
|
|
1528
1583
|
async update(args) {
|
|
@@ -1537,7 +1592,7 @@ class PowqlInterface {
|
|
|
1537
1592
|
const setClause = this.buildUpdateAssignments(args.data, params);
|
|
1538
1593
|
// `returning` hands back the post-update row(s); take the first (single-row contract).
|
|
1539
1594
|
const { rows, native } = await this.exec(`${this.qt} filter ${where} update { ${setClause} } returning`, params, args.timeout, 'update');
|
|
1540
|
-
const row = rows.length ? this.shape(rows, native)[0] : null;
|
|
1595
|
+
const row = rows.length ? this.stripWritePii(this.shape(rows, native)[0]) : null;
|
|
1541
1596
|
if (!row)
|
|
1542
1597
|
throw new errors_js_1.NotFoundError({ table: this.table, where: args.where });
|
|
1543
1598
|
return row;
|
|
@@ -1683,7 +1738,7 @@ class PowqlInterface {
|
|
|
1683
1738
|
this.assertCompiledWhere(where, false, 'delete');
|
|
1684
1739
|
// `returning` hands back the deleted row(s) — no separate pre-image reselect needed.
|
|
1685
1740
|
const { rows, native } = await this.exec(`${this.qt} filter ${where} delete returning`, params, args.timeout, 'delete');
|
|
1686
|
-
const row = rows.length ? this.shape(rows, native)[0] : null;
|
|
1741
|
+
const row = rows.length ? this.stripWritePii(this.shape(rows, native)[0]) : null;
|
|
1687
1742
|
if (!row)
|
|
1688
1743
|
throw new errors_js_1.NotFoundError({ table: this.table, where: args.where });
|
|
1689
1744
|
return row;
|