@prisma/orm-family-sql 8.0.0-rc.14-dev.42 → 8.0.0-rc.14-dev.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{aggregate-descriptor-registry-B88lvGQB.mjs → aggregate-descriptor-registry-DrJ1vHEo.mjs} +2 -2
- package/dist/{aggregate-descriptor-registry-B88lvGQB.mjs.map → aggregate-descriptor-registry-DrJ1vHEo.mjs.map} +1 -1
- package/dist/{ast-DOubq2En.mjs → ast-DFvrXEbF.mjs} +2 -2
- package/dist/ast-DFvrXEbF.mjs.map +1 -0
- package/dist/{ast-DWgP3Fnu.d.mts → ast-fsQdXFSV.d.mts} +3 -3
- package/dist/{ast-DWgP3Fnu.d.mts.map → ast-fsQdXFSV.d.mts.map} +1 -1
- package/dist/{authoring-entity-types-CZ-vdwYS-BDKo-VHB.d.mts → authoring-entity-types-CZ-vdwYS-Bq3LXsCn.d.mts} +2 -2
- package/dist/{authoring-entity-types-CZ-vdwYS-BDKo-VHB.d.mts.map → authoring-entity-types-CZ-vdwYS-Bq3LXsCn.d.mts.map} +1 -1
- package/dist/{authoring-type-constructors-dihiQslc-BcIPoPEn.mjs → authoring-type-constructors-dihiQslc-DqtjQyqj.mjs} +2 -2
- package/dist/{authoring-type-constructors-dihiQslc-BcIPoPEn.mjs.map → authoring-type-constructors-dihiQslc-DqtjQyqj.mjs.map} +1 -1
- package/dist/builder.d.mts +2 -2
- package/dist/builder__runtime.d.mts +6 -6
- package/dist/builder__runtime.mjs +2 -2
- package/dist/builder__types.d.mts +2 -2
- package/dist/{config-types-BvoqAKkw.mjs → config-types-CPTtyHK8.mjs} +2 -2
- package/dist/{config-types-BvoqAKkw.mjs.map → config-types-CPTtyHK8.mjs.map} +1 -1
- package/dist/{config-types-LClcQOkt.d.mts → config-types-Cag6qJnA.d.mts} +2 -2
- package/dist/{config-types-LClcQOkt.d.mts.map → config-types-Cag6qJnA.d.mts.map} +1 -1
- package/dist/{contract-builder-DoT-AH8l.d.mts → contract-builder-BaJMQFAc.d.mts} +17 -5
- package/dist/contract-builder-BaJMQFAc.d.mts.map +1 -0
- package/dist/{contract-builder-BRrG-DWN.mjs → contract-builder-Dy172HD2.mjs} +3 -3
- package/dist/{contract-builder-BRrG-DWN.mjs.map → contract-builder-Dy172HD2.mjs.map} +1 -1
- package/dist/contract-prisma7__provider.mjs +3 -3
- package/dist/contract-psl.d.mts +1 -1
- package/dist/contract-psl.mjs +1 -1
- package/dist/contract-psl__attribute-specs.d.mts +2 -2
- package/dist/contract-psl__attribute-specs.mjs +1 -1
- package/dist/contract-psl__provider.mjs +2 -2
- package/dist/contract-ts.d.mts +4 -4
- package/dist/contract-ts.mjs +4 -4
- package/dist/contract-ts__config-types.d.mts +1 -1
- package/dist/contract-ts__config-types.mjs +1 -1
- package/dist/contract-ts__contract-builder.d.mts +3 -3
- package/dist/contract-ts__contract-builder.mjs +3 -3
- package/dist/{control-C4PkND9K.mjs → control-CMe5ABYI.mjs} +3 -3
- package/dist/{control-C4PkND9K.mjs.map → control-CMe5ABYI.mjs.map} +1 -1
- package/dist/{control-BThycYAG.d.mts → control-D18L8cFa.d.mts} +7 -7
- package/dist/{control-BThycYAG.d.mts.map → control-D18L8cFa.d.mts.map} +1 -1
- package/dist/control-adapter-Ciule8Fh.d.mts +1 -0
- package/dist/{control-adapter-CkFfBVei-D8yZvwK7.d.mts → control-adapter-CkFfBVei-gLS9b87G.d.mts} +4 -4
- package/dist/{control-adapter-CkFfBVei-D8yZvwK7.d.mts.map → control-adapter-CkFfBVei-gLS9b87G.d.mts.map} +1 -1
- package/dist/{db-CJxU3aL_-CMuiIKs5.d.mts → db-CJxU3aL_-CM2IReAK.d.mts} +6 -6
- package/dist/{db-CJxU3aL_-CMuiIKs5.d.mts.map → db-CJxU3aL_-CM2IReAK.d.mts.map} +1 -1
- package/dist/{ddl-types-BT_bz9ck-BjAW4tq0.d.mts → ddl-types-DtKZjNtN-6TxFf4bH.d.mts} +3 -3
- package/dist/{ddl-types-BT_bz9ck-BjAW4tq0.d.mts.map → ddl-types-DtKZjNtN-6TxFf4bH.d.mts.map} +1 -1
- package/dist/{derived-checks-CsB3zLJ--C7ymzzbW.mjs → derived-checks-DAbro9yn-DtEowq-J.mjs} +6 -6
- package/dist/{derived-checks-CsB3zLJ--C7ymzzbW.mjs.map → derived-checks-DAbro9yn-DtEowq-J.mjs.map} +1 -1
- package/dist/{derived-checks-DPdD01O0-CABDLeK0.d.mts → derived-checks-DpPkO6Dt-BituyKFg.d.mts} +2 -2
- package/dist/derived-checks-DpPkO6Dt-BituyKFg.d.mts.map +1 -0
- package/dist/{diff-CN8CxYDc.d.mts → diff-Bg9o9CgK.d.mts} +3 -3
- package/dist/{diff-CN8CxYDc.d.mts.map → diff-Bg9o9CgK.d.mts.map} +1 -1
- package/dist/{expression-B-9RZQN9.d.mts → expression-B-QXMOmY.d.mts} +3 -3
- package/dist/{expression-B-9RZQN9.d.mts.map → expression-B-QXMOmY.d.mts.map} +1 -1
- package/dist/{expression-gmLQa4Ie.mjs → expression-JOe6lo4g.mjs} +2 -2
- package/dist/{expression-gmLQa4Ie.mjs.map → expression-JOe6lo4g.mjs.map} +1 -1
- package/dist/family.d.mts +7 -7
- package/dist/family.mjs +1 -1
- package/dist/family__control-adapter.d.mts +2 -2
- package/dist/family__control.d.mts +2 -2
- package/dist/family__control.mjs +1 -1
- package/dist/family__diff.d.mts +2 -2
- package/dist/family__migration.d.mts +1 -1
- package/dist/family__pack.d.mts +1 -1
- package/dist/family__pack.mjs +2 -2
- package/dist/{index-NVxwovsn.d.mts → index-Z2FIIMxv.d.mts} +9 -9
- package/dist/{index-NVxwovsn.d.mts.map → index-Z2FIIMxv.d.mts.map} +1 -1
- package/dist/{interpreter-D50jf6Dd-DQMtcGPt.mjs → interpreter-D50jf6Dd-BW-Bj8Qr.mjs} +3 -3
- package/dist/{interpreter-D50jf6Dd-DQMtcGPt.mjs.map → interpreter-D50jf6Dd-BW-Bj8Qr.mjs.map} +1 -1
- package/dist/middleware-BFoORv3y.d.mts +1 -0
- package/dist/{middleware-DAmCZlPN-B8QEPIUy.d.mts → middleware-mLwvcOLS-6Y52seRP.d.mts} +3 -3
- package/dist/{middleware-DAmCZlPN-B8QEPIUy.d.mts.map → middleware-mLwvcOLS-6Y52seRP.d.mts.map} +1 -1
- package/dist/{migration-K_EPNCmR.d.mts → migration-o-g1rSb-.d.mts} +2 -2
- package/dist/{migration-K_EPNCmR.d.mts.map → migration-o-g1rSb-.d.mts.map} +1 -1
- package/dist/orm-client.d.mts +223 -31
- package/dist/orm-client.d.mts.map +1 -1
- package/dist/orm-client.mjs +469 -47
- package/dist/orm-client.mjs.map +1 -1
- package/dist/{pack-B-_m58dV.d.mts → pack-l0vLQrO8.d.mts} +2 -2
- package/dist/{pack-B-_m58dV.d.mts.map → pack-l0vLQrO8.d.mts.map} +1 -1
- package/dist/plan-CmfWjqtI.d.mts +2 -0
- package/dist/{plan-1wnpBALU-CkFF8oIz.d.mts → plan-cGEaSXHv-2F5y-Dpy.d.mts} +3 -3
- package/dist/plan-cGEaSXHv-2F5y-Dpy.d.mts.map +1 -0
- package/dist/{prepared-statement-YtgdlN7e-BJzjum7z.d.mts → prepared-statement-YtgdlN7e-BU4UQxB5.d.mts} +13 -13
- package/dist/{prepared-statement-YtgdlN7e-BJzjum7z.d.mts.map → prepared-statement-YtgdlN7e-BU4UQxB5.d.mts.map} +1 -1
- package/dist/{psl-column-resolution-BegCa1-t-o2A6uWWC.d.mts → psl-column-resolution-BegCa1-t-1XiYCC7t.d.mts} +2 -2
- package/dist/{psl-column-resolution-BegCa1-t-o2A6uWWC.d.mts.map → psl-column-resolution-BegCa1-t-1XiYCC7t.d.mts.map} +1 -1
- package/dist/{psl-field-resolution-Bi-CSeoQ-BjACY_53.mjs → psl-field-resolution-Bi-CSeoQ-Do_5hZ8Z.mjs} +2 -2
- package/dist/{psl-field-resolution-Bi-CSeoQ-BjACY_53.mjs.map → psl-field-resolution-Bi-CSeoQ-Do_5hZ8Z.mjs.map} +1 -1
- package/dist/{query-lane-context-Ft8I-pge-nABTUotc.d.mts → query-lane-context-CJoNBspB-Ylhia3fC.d.mts} +3 -3
- package/dist/{query-lane-context-Ft8I-pge-nABTUotc.d.mts.map → query-lane-context-CJoNBspB-Ylhia3fC.d.mts.map} +1 -1
- package/dist/query-lane-context-qK5s2okl.d.mts +1 -0
- package/dist/relational-core.d.mts +12 -12
- package/dist/relational-core.mjs +4 -4
- package/dist/relational-core__aggregate-descriptor-registry.d.mts +1 -1
- package/dist/relational-core__aggregate-descriptor-registry.mjs +1 -1
- package/dist/relational-core__ast.d.mts +4 -4
- package/dist/relational-core__ast.mjs +3 -3
- package/dist/relational-core__codec-descriptor-registry.d.mts +2 -2
- package/dist/relational-core__contract-free.d.mts +2 -2
- package/dist/relational-core__contract-free.mjs +1 -1
- package/dist/relational-core__contract-free.mjs.map +1 -1
- package/dist/relational-core__expression.d.mts +1 -1
- package/dist/relational-core__expression.mjs +1 -1
- package/dist/relational-core__middleware.d.mts +2 -2
- package/dist/relational-core__plan.d.mts +3 -3
- package/dist/relational-core__query-lane-context.d.mts +2 -2
- package/dist/relational-core__types.d.mts +2 -2
- package/dist/runtime.d.mts +4 -4
- package/dist/runtime.mjs +2 -2
- package/dist/runtime__internal__prepared-query.d.mts +1 -1
- package/dist/{sql-execution-plan-CdlkkwtB-NuamyL5f.d.mts → sql-execution-plan-C7XauPPu-BMi8hJlv.d.mts} +3 -3
- package/dist/sql-execution-plan-C7XauPPu-BMi8hJlv.d.mts.map +1 -0
- package/dist/types-14L6c26e.d.mts +1 -0
- package/dist/{types-0xZ8asKQ-tfwe3lxh.d.mts → types-BJQcLx-8-DSnaugR4.d.mts} +6 -6
- package/dist/{types-0xZ8asKQ-tfwe3lxh.d.mts.map → types-BJQcLx-8-DSnaugR4.d.mts.map} +1 -1
- package/dist/{types-CvuS68sy-Cj3SvUKo.d.mts → types-CvuS68sy-Dip2oI3M.d.mts} +2 -2
- package/dist/{types-CvuS68sy-Cj3SvUKo.d.mts.map → types-CvuS68sy-Dip2oI3M.d.mts.map} +1 -1
- package/dist/{types-C9UR53Lv-BF-_alNk.mjs → types-NTQsD2MS-DAP2yVDn.mjs} +3 -3
- package/dist/{types-C9UR53Lv-BF-_alNk.mjs.map → types-NTQsD2MS-DAP2yVDn.mjs.map} +1 -1
- package/dist/{types-CqwI8eGx-AYan1yI4.d.mts → types-Sh5HuaZE-C8I29pGQ.d.mts} +4 -3
- package/dist/{types-CqwI8eGx-AYan1yI4.d.mts.map → types-Sh5HuaZE-C8I29pGQ.d.mts.map} +1 -1
- package/package.json +18 -18
- package/dist/ast-DOubq2En.mjs.map +0 -1
- package/dist/contract-builder-DoT-AH8l.d.mts.map +0 -1
- package/dist/control-adapter-BUyIei4U.d.mts +0 -1
- package/dist/derived-checks-DPdD01O0-CABDLeK0.d.mts.map +0 -1
- package/dist/middleware-BAA8rimP.d.mts +0 -1
- package/dist/plan-1wnpBALU-CkFF8oIz.d.mts.map +0 -1
- package/dist/plan-BCQYGXrJ.d.mts +0 -2
- package/dist/query-lane-context-CEYIBLlG.d.mts +0 -1
- package/dist/sql-execution-plan-CdlkkwtB-NuamyL5f.d.mts.map +0 -1
- package/dist/types-DkRYdSXK.d.mts +0 -1
package/dist/orm-client.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { t as resolveStorageTable } from "./resolve-storage-table-DZsfnzeW.mjs";
|
|
2
2
|
import { i as isUniqueConstraintViolation } from "./dist-x6jvtkKM.mjs";
|
|
3
|
-
import { A as ParamRef, C as LiteralExpr, E as NullCheckExpr, F as SelectAst,
|
|
3
|
+
import { A as ParamRef, C as LiteralExpr, E as NullCheckExpr, F as SelectAst, G as isOrderByNulls, I as SubqueryExpr, L as TableSource, M as ProjectionItem, O as OrExpr, R as UpdateAst, S as ListExpression, T as NotExpr, U as isAggregateFn, V as checkLimitOffset, W as isOrderByDirection, _ as InsertAst, b as JsonArrayAggExpr, c as DeleteAst, f as EqColJoinOn, k as OrderByItem, l as DerivedTableSource, n as AndExpr, o as ColumnRef, p as ExistsExpr, q as isWhereExpr, r as BinaryExpr, s as DefaultValueExpr, t as AggregateExpr, v as InsertOnConflict, x as JsonObjectExpr, y as JoinAst, z as WindowFuncExpr } from "./types-NTQsD2MS-DAP2yVDn.mjs";
|
|
4
4
|
import { t as collectOrderedParamRefs } from "./util-BBgcP3gI-XJBkxo1K.mjs";
|
|
5
|
-
import { n as JsonDocumentProjection, r as NativeJsonValueProjection, t as CodecJsonValueProjection } from "./ast-
|
|
6
|
-
import { i as isExpression, o as toExpr } from "./expression-
|
|
5
|
+
import { n as JsonDocumentProjection, r as NativeJsonValueProjection, t as CodecJsonValueProjection } from "./ast-DFvrXEbF.mjs";
|
|
6
|
+
import { i as isExpression, o as toExpr } from "./expression-JOe6lo4g.mjs";
|
|
7
7
|
import { n as codecRefForStorageColumn } from "./codec-descriptor-registry-DoGFktu5.mjs";
|
|
8
8
|
import { structuredError } from "@prisma/orm-framework/utils/structured-error";
|
|
9
9
|
import { blindCast, castAs } from "@prisma/orm-framework/utils/casts";
|
|
@@ -589,6 +589,15 @@ function mapResultRows(result, mapper) {
|
|
|
589
589
|
};
|
|
590
590
|
return new AsyncIterableResult(generator());
|
|
591
591
|
}
|
|
592
|
+
function resolveColumn(contract, namespaceId, tableName, columnName) {
|
|
593
|
+
return resolveTableForContract(contract, namespaceId, tableName)?.table.columns[columnName];
|
|
594
|
+
}
|
|
595
|
+
function codecTraits(context, codecId) {
|
|
596
|
+
return context.codecDescriptors.descriptorFor(codecId)?.traits ?? [];
|
|
597
|
+
}
|
|
598
|
+
function hasTrait(context, codecId, trait) {
|
|
599
|
+
return codecTraits(context, codecId).includes(trait);
|
|
600
|
+
}
|
|
592
601
|
/**
|
|
593
602
|
* A keyset needs a cursor value for every order axis, so each active order must be a plain column without null placement.
|
|
594
603
|
*/
|
|
@@ -2440,7 +2449,7 @@ function resolveIncludedColumnBinding(contract, context, include, key) {
|
|
|
2440
2449
|
};
|
|
2441
2450
|
}
|
|
2442
2451
|
function resolveIncludedColumnRef(contract, include, key) {
|
|
2443
|
-
const baseColumn =
|
|
2452
|
+
const baseColumn = resolveColumn(contract, include.relatedNamespaceId, include.relatedTableName, key);
|
|
2444
2453
|
if (baseColumn) return {
|
|
2445
2454
|
table: include.relatedTableName,
|
|
2446
2455
|
column: key,
|
|
@@ -2452,7 +2461,7 @@ function resolveIncludedColumnRef(contract, include, key) {
|
|
|
2452
2461
|
const prefix = `${variant.table}__`;
|
|
2453
2462
|
if (!key.startsWith(prefix)) continue;
|
|
2454
2463
|
const column = key.slice(prefix.length);
|
|
2455
|
-
const variantColumn =
|
|
2464
|
+
const variantColumn = resolveColumn(contract, include.relatedNamespaceId, variant.table, column);
|
|
2456
2465
|
if (variantColumn) return {
|
|
2457
2466
|
table: variant.table,
|
|
2458
2467
|
column,
|
|
@@ -2460,9 +2469,6 @@ function resolveIncludedColumnRef(contract, include, key) {
|
|
|
2460
2469
|
};
|
|
2461
2470
|
}
|
|
2462
2471
|
}
|
|
2463
|
-
function resolveStorageColumn(contract, namespaceId, tableName, columnName) {
|
|
2464
|
-
return contract.storage.namespaces[namespaceId]?.entries.table?.[tableName]?.columns[columnName];
|
|
2465
|
-
}
|
|
2466
2472
|
function decodeIncludedColumnValue(ref, codecId, codec, value) {
|
|
2467
2473
|
if (ref.storageColumn.many !== false) {
|
|
2468
2474
|
if (!Array.isArray(value)) wrapIncludedDecodeFailure(/* @__PURE__ */ new TypeError(`expected an array from the driver for many-typed column, got ${typeof value}`), ref, codecId);
|
|
@@ -2737,7 +2743,7 @@ function shorthandToWhereExpr(context, namespaceId, modelName, filters) {
|
|
|
2737
2743
|
function assertFieldHasEqualityTrait(context, namespaceId, modelName, fieldName) {
|
|
2738
2744
|
const fieldType = modelOf(context.contract, namespaceId, modelName)?.fields?.[fieldName]?.type;
|
|
2739
2745
|
const codecId = fieldType?.kind === "scalar" ? fieldType.codecId : void 0;
|
|
2740
|
-
if (
|
|
2746
|
+
if (codecId === void 0 || !hasTrait(context, codecId, "equality")) throw ormError("ORM.FILTER_UNSUPPORTED", `Shorthand filter on "${modelName}.${fieldName}": field does not support equality comparisons`, { meta: {
|
|
2741
2747
|
model: modelName,
|
|
2742
2748
|
field: fieldName,
|
|
2743
2749
|
trait: "equality"
|
|
@@ -2874,26 +2880,12 @@ function createModelAccessorInScope(context, namespaceId, modelName, variantName
|
|
|
2874
2880
|
const columnName = variantField?.column ?? fieldToColumn[prop] ?? prop;
|
|
2875
2881
|
const column = resolveColumn(contract, namespaceId, resolvedTable, columnName);
|
|
2876
2882
|
if (!column) return;
|
|
2877
|
-
const traits = context
|
|
2883
|
+
const traits = codecTraits(context, column.codecId);
|
|
2878
2884
|
const operations = opsByCodecId.get(column.codecId) ?? [];
|
|
2879
2885
|
const codec = codecRefForStorageColumn(contract.storage, namespaceId, resolvedTable, columnName);
|
|
2880
2886
|
return createScalarFieldAccessor(fieldBinding, columnName, column.codecId, column.nullable, codec, traits, operations, context);
|
|
2881
2887
|
} }));
|
|
2882
2888
|
}
|
|
2883
|
-
function resolveColumn(contract, namespaceId, tableName, columnName) {
|
|
2884
|
-
let table;
|
|
2885
|
-
try {
|
|
2886
|
-
table = storageTableForContract(contract, namespaceId, tableName);
|
|
2887
|
-
} catch {
|
|
2888
|
-
return;
|
|
2889
|
-
}
|
|
2890
|
-
const column = table.columns[columnName];
|
|
2891
|
-
if (!column) return void 0;
|
|
2892
|
-
return {
|
|
2893
|
-
codecId: column.codecId,
|
|
2894
|
-
nullable: column.nullable
|
|
2895
|
-
};
|
|
2896
|
-
}
|
|
2897
2889
|
function createScalarFieldAccessor(tableBinding, columnName, codecId, nullable, codec, traits, operations, context) {
|
|
2898
2890
|
const column = tableBinding.column(columnName);
|
|
2899
2891
|
const comparisonEntries = [];
|
|
@@ -2917,7 +2909,7 @@ function createExtensionMethodFactory(selfExpr, entry, context) {
|
|
|
2917
2909
|
return (...args) => {
|
|
2918
2910
|
const result = blindCast(entry.impl)(selfExpr, ...args);
|
|
2919
2911
|
const returnCodecId = result.returnType.codecId;
|
|
2920
|
-
const returnTraits = context
|
|
2912
|
+
const returnTraits = codecTraits(context, returnCodecId);
|
|
2921
2913
|
if (returnTraits.includes("boolean")) return result.buildAst();
|
|
2922
2914
|
const resultAst = result.buildAst();
|
|
2923
2915
|
const returnCodec = { codecId: returnCodecId };
|
|
@@ -2972,9 +2964,6 @@ function relatedOrderableField(context, relation, relatedTableName, correlate, f
|
|
|
2972
2964
|
return SubqueryExpr.of(rows.source.withProjection([ProjectionItem.of(columnName, rows.childScope.current.column(columnName))]).withWhere(rows.correlation));
|
|
2973
2965
|
});
|
|
2974
2966
|
}
|
|
2975
|
-
function hasTrait(context, codecId, trait) {
|
|
2976
|
-
return (context.codecDescriptors.descriptorFor(codecId)?.traits ?? []).includes(trait);
|
|
2977
|
-
}
|
|
2978
2967
|
function buildRelationCountExpr(context, relation, rows, predicate) {
|
|
2979
2968
|
const childWhere = toRelationWhereExpr(context, relation.toNamespace, relation.to, predicate, rows.childScope);
|
|
2980
2969
|
return SubqueryExpr.of(rows.source.withProjection([ProjectionItem.of("count", plainAggregateExpr("count", void 0))]).withWhere(childWhere ? and(rows.correlation, childWhere) : rows.correlation));
|
|
@@ -3847,6 +3836,303 @@ function getRelationDefinitions(contract, namespaceId, modelName) {
|
|
|
3847
3836
|
function toFieldName(contract, namespaceId, modelName, columnName) {
|
|
3848
3837
|
return getColumnToFieldMap(contract, namespaceId, modelName)[columnName] ?? columnName;
|
|
3849
3838
|
}
|
|
3839
|
+
function nullability(nullable) {
|
|
3840
|
+
return nullable ? "may be null" : "is never null";
|
|
3841
|
+
}
|
|
3842
|
+
function isFieldBuilder(value) {
|
|
3843
|
+
return "build" in value && typeof value.build === "function";
|
|
3844
|
+
}
|
|
3845
|
+
function isListMultiplicity(value) {
|
|
3846
|
+
return typeof value === "object" && value !== null && "elementNullable" in value && typeof value.elementNullable === "boolean";
|
|
3847
|
+
}
|
|
3848
|
+
function isMultiplicity(value) {
|
|
3849
|
+
return value === void 0 || value === false || isListMultiplicity(value);
|
|
3850
|
+
}
|
|
3851
|
+
function isFieldSpec(value) {
|
|
3852
|
+
return "codecId" in value && typeof value.codecId === "string" && "nullable" in value && typeof value.nullable === "boolean" && (!("many" in value) || isMultiplicity(value.many));
|
|
3853
|
+
}
|
|
3854
|
+
function multiplicity(many) {
|
|
3855
|
+
return isListMultiplicity(many) ? { elementNullable: many.elementNullable } : false;
|
|
3856
|
+
}
|
|
3857
|
+
const FIELD_DECLARATION_FIX = "Declare each field with a field builder, such as field.temporal.timestamptz().optional(), or with { codecId, nullable }. Declare a list with .many() or many: { elementNullable: false }, or, when its elements may be null, with .many({ elementsNullable: true }) or many: { elementNullable: true }.";
|
|
3858
|
+
function declaredFieldSpec(name, declaration) {
|
|
3859
|
+
if (typeof declaration === "object" && declaration !== null && isFieldBuilder(declaration)) {
|
|
3860
|
+
const built = declaration.build();
|
|
3861
|
+
const descriptor = typeof built === "object" && built !== null && "descriptor" in built ? built.descriptor : void 0;
|
|
3862
|
+
const nullable = typeof built === "object" && built !== null && "nullable" in built ? built.nullable : void 0;
|
|
3863
|
+
if (typeof descriptor !== "object" || descriptor === null || !("codecId" in descriptor) || typeof descriptor.codecId !== "string" || typeof nullable !== "boolean") throw ormError("ORM.ARGUMENT_INVALID", `Cannot define the scope: the field builder for ${name} names no column type`, {
|
|
3864
|
+
why: "A scope for any model matches each declared field by its codec and nullability, and this builder refers to a named type instead of a column type.",
|
|
3865
|
+
fix: "Declare the field with a builder that has a column type, such as field.text() or field.column(textColumn), or with { codecId, nullable }.",
|
|
3866
|
+
meta: { field: name }
|
|
3867
|
+
});
|
|
3868
|
+
const many = typeof built === "object" && built !== null && "many" in built && built.many;
|
|
3869
|
+
if (!isMultiplicity(many)) throw ormError("ORM.ARGUMENT_INVALID", `Cannot define the scope: the field builder for ${name} builds a many that is not false or { elementNullable }`, {
|
|
3870
|
+
why: `A field builder's build() returns many as false or undefined for one value, or as { elementNullable } with a boolean elementNullable for a list; received ${describeReceived(many)} for ${name}.`,
|
|
3871
|
+
fix: FIELD_DECLARATION_FIX,
|
|
3872
|
+
meta: { field: name }
|
|
3873
|
+
});
|
|
3874
|
+
return {
|
|
3875
|
+
codecId: descriptor.codecId,
|
|
3876
|
+
nullable,
|
|
3877
|
+
many: multiplicity(many)
|
|
3878
|
+
};
|
|
3879
|
+
}
|
|
3880
|
+
if (typeof declaration === "object" && declaration !== null && isFieldSpec(declaration)) return {
|
|
3881
|
+
codecId: declaration.codecId,
|
|
3882
|
+
nullable: declaration.nullable,
|
|
3883
|
+
many: multiplicity(declaration.many)
|
|
3884
|
+
};
|
|
3885
|
+
throw ormError("ORM.ARGUMENT_INVALID", `Cannot define the scope: the declaration of field ${name} is not a field builder or { codecId, nullable }`, {
|
|
3886
|
+
why: `Each field of a scope is declared with a field builder or with an object that has a string codecId, a boolean nullable and, for a list, many: { elementNullable } with a boolean elementNullable; received ${describeReceived(declaration)} for ${name}.`,
|
|
3887
|
+
fix: FIELD_DECLARATION_FIX,
|
|
3888
|
+
meta: { field: name }
|
|
3889
|
+
});
|
|
3890
|
+
}
|
|
3891
|
+
function declaredFieldSpecs(declarations) {
|
|
3892
|
+
if (typeof declarations !== "object" || declarations === null || Array.isArray(declarations)) throw ormError("ORM.ARGUMENT_INVALID", "Cannot define the scope: the fields are not an object", {
|
|
3893
|
+
why: `The first argument of scope maps the name of each field the scope needs to its declaration; received ${describeReceived(declarations)}.`,
|
|
3894
|
+
fix: FIELD_DECLARATION_FIX,
|
|
3895
|
+
meta: { argument: "fields" }
|
|
3896
|
+
});
|
|
3897
|
+
return Object.entries(declarations).map(([name, declaration]) => [name, declaredFieldSpec(name, declaration)]);
|
|
3898
|
+
}
|
|
3899
|
+
/** Throws `ORM.ARGUMENT_INVALID` unless `body`, the body of a scope, is a function. */
|
|
3900
|
+
function assertScopeBody(body) {
|
|
3901
|
+
if (typeof body !== "function") throw ormError("ORM.ARGUMENT_INVALID", "Cannot define the scope: the body is not a function", {
|
|
3902
|
+
why: `The body of a scope is a function that receives a collection and returns one; received ${describeReceived(body)}.`,
|
|
3903
|
+
fix: "Pass a function, such as (rows) => rows.where(...).",
|
|
3904
|
+
meta: { argument: "body" }
|
|
3905
|
+
});
|
|
3906
|
+
}
|
|
3907
|
+
function hasContract(ctx) {
|
|
3908
|
+
return "context" in ctx && typeof ctx.context === "object" && ctx.context !== null && "contract" in ctx.context && typeof ctx.context.contract === "object" && ctx.context.contract !== null;
|
|
3909
|
+
}
|
|
3910
|
+
function isModelCollection(value) {
|
|
3911
|
+
return typeof value === "object" && value !== null && "ctx" in value && typeof value.ctx === "object" && value.ctx !== null && hasContract(value.ctx) && "modelName" in value && typeof value.modelName === "string" && "namespaceId" in value && typeof value.namespaceId === "string";
|
|
3912
|
+
}
|
|
3913
|
+
/** Throws `ORM.ARGUMENT_INVALID` unless `value`, what a scope is applied to, is a collection. */
|
|
3914
|
+
function assertScopeReceiver(value) {
|
|
3915
|
+
if (!isModelCollection(value)) throw ormError("ORM.ARGUMENT_INVALID", "Cannot apply the scope: it was not given a collection", {
|
|
3916
|
+
why: `A scope is applied to a collection, such as db.orm.public.Post; received ${describeReceived(value)}.`,
|
|
3917
|
+
fix: "Run the scope with apply on a collection: collection.apply(scope).",
|
|
3918
|
+
meta: { argument: "collection" }
|
|
3919
|
+
});
|
|
3920
|
+
}
|
|
3921
|
+
/** Throws `ORM.ARGUMENT_INVALID` unless `value` is a collection of the model and namespace a scope for one model was made from. */
|
|
3922
|
+
function assertModelScopeReceiver(source, value) {
|
|
3923
|
+
assertScopeReceiver(value);
|
|
3924
|
+
if (value.modelName !== source.modelName || value.namespaceId !== source.namespaceId) {
|
|
3925
|
+
const made = `${source.namespaceId}.${source.modelName}`;
|
|
3926
|
+
const given = `${value.namespaceId}.${value.modelName}`;
|
|
3927
|
+
throw ormError("ORM.ARGUMENT_INVALID", `Cannot apply a scope for ${made} to a collection of ${given}`, {
|
|
3928
|
+
why: `The scope was made with ${made}.scope(...), and its body was written for that model.`,
|
|
3929
|
+
fix: `Apply the scope to a collection of ${made}, or make a scope from ${given}.`,
|
|
3930
|
+
meta: {
|
|
3931
|
+
model: source.modelName,
|
|
3932
|
+
namespace: source.namespaceId,
|
|
3933
|
+
receivedModel: value.modelName,
|
|
3934
|
+
receivedNamespace: value.namespaceId
|
|
3935
|
+
}
|
|
3936
|
+
});
|
|
3937
|
+
}
|
|
3938
|
+
}
|
|
3939
|
+
/** The model as error messages name it: with its namespace when the contract has more than one. */
|
|
3940
|
+
function modelLabel(collection) {
|
|
3941
|
+
return Object.keys(collection.ctx.context.contract.domain.namespaces).length > 1 ? `${collection.namespaceId}.${collection.modelName}` : collection.modelName;
|
|
3942
|
+
}
|
|
3943
|
+
/** Throws `ORM.ARGUMENT_INVALID` unless `result`, what a scope's body returned, is a collection of the receiver's model, namespace and class. */
|
|
3944
|
+
function assertScopeResult(receiver, result) {
|
|
3945
|
+
if (!(isModelCollection(result) && result.modelName === receiver.modelName && result.namespaceId === receiver.namespaceId && result instanceof receiver.constructor)) {
|
|
3946
|
+
const label = modelLabel(receiver);
|
|
3947
|
+
throw ormError("ORM.ARGUMENT_INVALID", `Cannot apply the scope to ${label}: its body did not return a collection of ${label}`, {
|
|
3948
|
+
why: `The body of a scope for any model returns the collection it received, after where, orderBy, limit or offset; it returned ${isModelCollection(result) ? `a collection of ${modelLabel(result)}` : describeReceived(result)}.`,
|
|
3949
|
+
fix: "Return the collection the body receives, or one made from it by calling its methods.",
|
|
3950
|
+
meta: {
|
|
3951
|
+
model: receiver.modelName,
|
|
3952
|
+
namespace: receiver.namespaceId,
|
|
3953
|
+
returned: isModelCollection(result) ? result.modelName : describeReceived(result)
|
|
3954
|
+
}
|
|
3955
|
+
});
|
|
3956
|
+
}
|
|
3957
|
+
}
|
|
3958
|
+
function elementNullability(elementNullable) {
|
|
3959
|
+
return elementNullable ? "may be null" : "are never null";
|
|
3960
|
+
}
|
|
3961
|
+
function sameMultiplicity(a, b) {
|
|
3962
|
+
return a === false || b === false ? a === b : a.elementNullable === b.elementNullable;
|
|
3963
|
+
}
|
|
3964
|
+
function fieldShape(many) {
|
|
3965
|
+
return many === false ? "holds one value" : `is a list whose elements ${elementNullability(many.elementNullable)}`;
|
|
3966
|
+
}
|
|
3967
|
+
function declarationFor(many) {
|
|
3968
|
+
if (many === false) return "as one value, without .many() or many";
|
|
3969
|
+
return many.elementNullable ? "as a list whose elements may be null, with .many({ elementsNullable: true }) or many: { elementNullable: true }" : "as a list whose elements are never null, with .many() or many: { elementNullable: false }";
|
|
3970
|
+
}
|
|
3971
|
+
function describeField(field) {
|
|
3972
|
+
const value = `with codec ${field.codecId} that ${nullability(field.nullable)}`;
|
|
3973
|
+
return field.many === false ? value : `${value} and whose elements ${elementNullability(field.many.elementNullable)}`;
|
|
3974
|
+
}
|
|
3975
|
+
function assertScopeFields(collection, fields) {
|
|
3976
|
+
const { contract } = collection.ctx.context;
|
|
3977
|
+
const { modelName, namespaceId } = collection;
|
|
3978
|
+
const label = modelLabel(collection);
|
|
3979
|
+
const model = modelOf(contract, namespaceId, modelName);
|
|
3980
|
+
for (const [name, spec] of fields) {
|
|
3981
|
+
const declared = `The scope was declared for models that have a ${spec.many === false ? "field" : "list field"} ${name} ${describeField(spec)}.`;
|
|
3982
|
+
const meta = {
|
|
3983
|
+
model: modelName,
|
|
3984
|
+
namespace: namespaceId,
|
|
3985
|
+
field: name,
|
|
3986
|
+
codecId: spec.codecId,
|
|
3987
|
+
nullable: spec.nullable,
|
|
3988
|
+
many: spec.many
|
|
3989
|
+
};
|
|
3990
|
+
const modelFields = model?.fields ?? {};
|
|
3991
|
+
if (!Object.hasOwn(modelFields, name)) throw ormError("ORM.FIELD_UNKNOWN", `Cannot apply a scope to ${label}: it has no field ${name}`, {
|
|
3992
|
+
why: declared,
|
|
3993
|
+
fix: `Apply the scope to a model that has a field ${name}, or remove ${name} from the declaration in the scope.`,
|
|
3994
|
+
meta
|
|
3995
|
+
});
|
|
3996
|
+
const fieldMany = multiplicity(modelFields[name]?.many);
|
|
3997
|
+
const column = resolveColumn(contract, namespaceId, collection.tableName, resolveFieldToColumn(contract, namespaceId, modelName, name));
|
|
3998
|
+
const actual = column === void 0 ? `${label}.${name} has no column.` : fieldMany === false ? `${label}.${name} has codec ${column.codecId} and ${nullability(column.nullable)}.` : `${label}.${name} is a list ${describeField({
|
|
3999
|
+
codecId: column.codecId,
|
|
4000
|
+
nullable: column.nullable,
|
|
4001
|
+
many: fieldMany
|
|
4002
|
+
})}.`;
|
|
4003
|
+
const sameCodecAndNullability = column?.codecId === spec.codecId && column.nullable === spec.nullable;
|
|
4004
|
+
if (!sameCodecAndNullability || !sameMultiplicity(fieldMany, spec.many)) throw ormError("ORM.FIELD_UNKNOWN", `Cannot apply a scope to ${label}: its field ${name} does not match the declaration`, {
|
|
4005
|
+
why: `${declared} ${actual}`,
|
|
4006
|
+
fix: sameCodecAndNullability ? `Apply the scope to a model whose ${name} field ${fieldShape(spec.many)}, or declare ${name} ${declarationFor(fieldMany)}.` : `Apply the scope to a model whose ${name} field has that codec and nullability, or change the declaration in the scope.`,
|
|
4007
|
+
meta
|
|
4008
|
+
});
|
|
4009
|
+
}
|
|
4010
|
+
}
|
|
4011
|
+
/**
|
|
4012
|
+
* Define a scope for any model that has the declared fields. Reached as the `scope` method of the client `orm()` returns.
|
|
4013
|
+
*/
|
|
4014
|
+
function defineFieldScope(declarations, body) {
|
|
4015
|
+
const fields = declaredFieldSpecs(declarations);
|
|
4016
|
+
assertScopeBody(body);
|
|
4017
|
+
return blindCast((collection) => {
|
|
4018
|
+
const receiver = collection;
|
|
4019
|
+
assertScopeReceiver(receiver);
|
|
4020
|
+
assertScopeFields(receiver, fields);
|
|
4021
|
+
const result = body(blindCast(collection));
|
|
4022
|
+
assertScopeResult(receiver, result);
|
|
4023
|
+
return result;
|
|
4024
|
+
});
|
|
4025
|
+
}
|
|
4026
|
+
const SHOWN_LENGTH = 64;
|
|
4027
|
+
function shown(value) {
|
|
4028
|
+
const characters = Array.from(value);
|
|
4029
|
+
const cut = characters.length > SHOWN_LENGTH;
|
|
4030
|
+
return {
|
|
4031
|
+
text: JSON.stringify(cut ? `${characters.slice(0, SHOWN_LENGTH).join("")}…` : value),
|
|
4032
|
+
cut
|
|
4033
|
+
};
|
|
4034
|
+
}
|
|
4035
|
+
function describeReceived(value) {
|
|
4036
|
+
if (value === void 0 || value === null) return String(value);
|
|
4037
|
+
if (Array.isArray(value)) return "an array";
|
|
4038
|
+
const kind = typeof value;
|
|
4039
|
+
return kind === "object" ? "an object" : `a ${kind}`;
|
|
4040
|
+
}
|
|
4041
|
+
function cutNote(subject, value) {
|
|
4042
|
+
return value.cut ? ` The ${subject} above is cut to its first ${SHOWN_LENGTH} characters.` : "";
|
|
4043
|
+
}
|
|
4044
|
+
function fieldCodecId(collection, field) {
|
|
4045
|
+
const { contract } = collection.ctx.context;
|
|
4046
|
+
const column = resolveFieldToColumn(contract, collection.namespaceId, collection.modelName, field);
|
|
4047
|
+
return resolveColumn(contract, collection.namespaceId, collection.tableName, column)?.codecId;
|
|
4048
|
+
}
|
|
4049
|
+
function canOrder(collection, field) {
|
|
4050
|
+
const codecId = fieldCodecId(collection, field);
|
|
4051
|
+
return codecId !== void 0 && hasTrait(collection.ctx.context, codecId, "order");
|
|
4052
|
+
}
|
|
4053
|
+
function orderableFieldNames(collection) {
|
|
4054
|
+
const model = modelOf(collection.ctx.context.contract, collection.namespaceId, collection.modelName);
|
|
4055
|
+
return Object.keys(model?.fields ?? {}).filter((field) => canOrder(collection, field));
|
|
4056
|
+
}
|
|
4057
|
+
function whyNotOrderable(collection, name) {
|
|
4058
|
+
const { modelName } = collection;
|
|
4059
|
+
const model = modelOf(collection.ctx.context.contract, collection.namespaceId, modelName);
|
|
4060
|
+
const quoted = shown(name).text;
|
|
4061
|
+
if (Object.hasOwn(model?.relations ?? {}, name)) return `${quoted} is a relation of ${modelName}, not a field.`;
|
|
4062
|
+
if (!Object.hasOwn(model?.fields ?? {}, name)) return `${modelName} has no field ${quoted}.`;
|
|
4063
|
+
return canOrder(collection, name) ? `${quoted} is not one of the fields allowed for ordering.` : `The codec ${fieldCodecId(collection, name)} of ${modelName}.${name} cannot be ordered.`;
|
|
4064
|
+
}
|
|
4065
|
+
/**
|
|
4066
|
+
* An `orderBy` selector for a field named by a string, such as an order parameter of a request. `allowed` lists the fields a request may order by. A name that is not in `allowed` or not an orderable field of the collection's model, and a direction other than `asc` or `desc`, throw `ORM.ARGUMENT_INVALID`. An undefined direction is `asc`.
|
|
4067
|
+
*
|
|
4068
|
+
* ```ts
|
|
4069
|
+
* db.Post.orderBy(orderByField(db.Post, input.orderBy, input.direction, ['title', 'createdAt']));
|
|
4070
|
+
* ```
|
|
4071
|
+
*/
|
|
4072
|
+
function orderByField(collection, name, direction, allowed) {
|
|
4073
|
+
const receiver = collection;
|
|
4074
|
+
if (!isModelCollection(receiver)) throw ormError("ORM.ARGUMENT_INVALID", "Cannot order: orderByField was not given a collection", {
|
|
4075
|
+
why: `orderByField takes the collection it orders, such as db.orm.public.Post; received ${describeReceived(receiver)}.`,
|
|
4076
|
+
fix: "Pass the collection the selector is for as the first argument.",
|
|
4077
|
+
meta: { argument: "collection" }
|
|
4078
|
+
});
|
|
4079
|
+
const { modelName } = collection;
|
|
4080
|
+
const requestedName = name;
|
|
4081
|
+
const requestedDirection = direction === void 0 ? "asc" : direction;
|
|
4082
|
+
const allowedList = allowed;
|
|
4083
|
+
if (!Array.isArray(allowedList) || allowedList.some((field) => typeof field !== "string")) throw ormError("ORM.ARGUMENT_INVALID", `Cannot order ${modelName}: the allowed fields are not a list of names`, {
|
|
4084
|
+
why: `orderByField takes the list of fields a request may order by; received ${describeReceived(allowedList)}.`,
|
|
4085
|
+
fix: `Pass an array of field names of ${modelName}, such as ['title', 'createdAt'].`,
|
|
4086
|
+
meta: {
|
|
4087
|
+
model: modelName,
|
|
4088
|
+
argument: "allowed"
|
|
4089
|
+
}
|
|
4090
|
+
});
|
|
4091
|
+
if (typeof requestedDirection !== "string") throw ormError("ORM.ARGUMENT_INVALID", `Cannot order ${modelName}: the direction is not a string`, {
|
|
4092
|
+
why: `An order direction is "asc" or "desc"; received ${describeReceived(requestedDirection)}.`,
|
|
4093
|
+
fix: "Pass \"asc\" or \"desc\".",
|
|
4094
|
+
meta: {
|
|
4095
|
+
model: modelName,
|
|
4096
|
+
direction: requestedDirection
|
|
4097
|
+
}
|
|
4098
|
+
});
|
|
4099
|
+
if (!isOrderByDirection(requestedDirection)) {
|
|
4100
|
+
const shownDirection = shown(requestedDirection);
|
|
4101
|
+
throw ormError("ORM.ARGUMENT_INVALID", `Cannot order ${modelName} in direction ${shownDirection.text}`, {
|
|
4102
|
+
why: "An order direction is \"asc\" or \"desc\".",
|
|
4103
|
+
fix: `Pass "asc" or "desc".${cutNote("direction", shownDirection)}`,
|
|
4104
|
+
meta: {
|
|
4105
|
+
model: modelName,
|
|
4106
|
+
direction: requestedDirection
|
|
4107
|
+
}
|
|
4108
|
+
});
|
|
4109
|
+
}
|
|
4110
|
+
const orderable = orderableFieldNames(collection);
|
|
4111
|
+
const names = allowedList.filter((field) => orderable.includes(field));
|
|
4112
|
+
const orderByOneOf = names.length === 0 ? `Pass an allowed list that names at least one field of ${modelName} that can be ordered.` : `Order by one of: ${names.join(", ")}.`;
|
|
4113
|
+
if (typeof requestedName !== "string") throw ormError("ORM.ARGUMENT_INVALID", `Cannot order ${modelName}: the field name is not a string`, {
|
|
4114
|
+
why: `An order field name is a string; received ${describeReceived(requestedName)}.`,
|
|
4115
|
+
fix: orderByOneOf,
|
|
4116
|
+
meta: {
|
|
4117
|
+
model: modelName,
|
|
4118
|
+
field: requestedName
|
|
4119
|
+
}
|
|
4120
|
+
});
|
|
4121
|
+
if (!names.includes(requestedName)) {
|
|
4122
|
+
const shownName = shown(requestedName);
|
|
4123
|
+
throw ormError("ORM.ARGUMENT_INVALID", `Cannot order ${modelName} by ${shownName.text}`, {
|
|
4124
|
+
why: whyNotOrderable(collection, requestedName),
|
|
4125
|
+
fix: `${orderByOneOf}${cutNote("name", shownName)}`,
|
|
4126
|
+
meta: {
|
|
4127
|
+
model: modelName,
|
|
4128
|
+
field: requestedName
|
|
4129
|
+
}
|
|
4130
|
+
});
|
|
4131
|
+
}
|
|
4132
|
+
const field = blindCast(requestedName);
|
|
4133
|
+
const order = requestedDirection;
|
|
4134
|
+
return (row) => row[field][order]();
|
|
4135
|
+
}
|
|
3850
4136
|
function normalizeWhereArg(arg, options) {
|
|
3851
4137
|
if (arg === void 0) return;
|
|
3852
4138
|
if (arg === null) throw ormError("ORM.ARGUMENT_INVALID", "WhereArg cannot be null. Pass undefined or a valid WhereExpr/ToWhereExpr payload.", { meta: { argument: "where" } });
|
|
@@ -3857,6 +4143,99 @@ function normalizeWhereArg(arg, options) {
|
|
|
3857
4143
|
function isToWhereExpr(arg) {
|
|
3858
4144
|
return typeof arg === "object" && arg !== null && "toWhereExpr" in arg && !isWhereExpr(arg);
|
|
3859
4145
|
}
|
|
4146
|
+
const CHAIN_PARTS = {
|
|
4147
|
+
orderBy: {
|
|
4148
|
+
noun: "an order",
|
|
4149
|
+
call: "orderBy()"
|
|
4150
|
+
},
|
|
4151
|
+
limit: {
|
|
4152
|
+
noun: "a limit",
|
|
4153
|
+
call: "limit()"
|
|
4154
|
+
},
|
|
4155
|
+
offset: {
|
|
4156
|
+
noun: "an offset",
|
|
4157
|
+
call: "offset()"
|
|
4158
|
+
},
|
|
4159
|
+
cursor: {
|
|
4160
|
+
noun: "a cursor",
|
|
4161
|
+
call: "cursor()"
|
|
4162
|
+
},
|
|
4163
|
+
distinct: {
|
|
4164
|
+
noun: "a distinct selection",
|
|
4165
|
+
call: "distinct()"
|
|
4166
|
+
},
|
|
4167
|
+
distinctOn: {
|
|
4168
|
+
noun: "a distinctOn selection",
|
|
4169
|
+
call: "distinctOn()"
|
|
4170
|
+
}
|
|
4171
|
+
};
|
|
4172
|
+
function presentParts(state, names) {
|
|
4173
|
+
const present = names.filter((name) => {
|
|
4174
|
+
const value = state[name];
|
|
4175
|
+
return Array.isArray(value) ? value.length > 0 : value !== void 0;
|
|
4176
|
+
});
|
|
4177
|
+
return {
|
|
4178
|
+
nouns: present.map((name) => CHAIN_PARTS[name].noun),
|
|
4179
|
+
calls: present.map((name) => CHAIN_PARTS[name].call)
|
|
4180
|
+
};
|
|
4181
|
+
}
|
|
4182
|
+
function listed(items, conjunction) {
|
|
4183
|
+
const last = items.at(-1) ?? "";
|
|
4184
|
+
return items.length > 1 ? `${items.slice(0, -1).join(", ")} ${conjunction} ${last}` : last;
|
|
4185
|
+
}
|
|
4186
|
+
const HIDDEN_BY_A_SCOPE = "A scope applied with apply can add one without showing it at the call site.";
|
|
4187
|
+
/** Throws `ORM.ARGUMENT_INVALID` when the collection has a limit, an offset, a cursor or a distinct selection, which `method`, a write of every matching row, would ignore. */
|
|
4188
|
+
function assertBulkWriteIgnoresNothing(state, modelName, method) {
|
|
4189
|
+
const { nouns, calls } = presentParts(state, [
|
|
4190
|
+
"limit",
|
|
4191
|
+
"offset",
|
|
4192
|
+
"cursor",
|
|
4193
|
+
"distinct",
|
|
4194
|
+
"distinctOn"
|
|
4195
|
+
]);
|
|
4196
|
+
if (nouns.length === 0) return;
|
|
4197
|
+
const { limit, offset, cursor, distinct, distinctOn } = state;
|
|
4198
|
+
throw ormError("ORM.ARGUMENT_INVALID", `Cannot ${method} ${modelName}: the collection has ${listed(nouns, "and")}`, {
|
|
4199
|
+
why: `${method} changes every row that matches the filter. The statement it runs cannot apply ${listed(nouns, "or")}, so it would change more rows than the chain asks for. ${HIDDEN_BY_A_SCOPE}`,
|
|
4200
|
+
fix: `Remove ${listed(calls, "and")} before ${method}, or read the rows first and change them by their ids.`,
|
|
4201
|
+
meta: {
|
|
4202
|
+
model: modelName,
|
|
4203
|
+
method,
|
|
4204
|
+
limit,
|
|
4205
|
+
offset,
|
|
4206
|
+
cursor,
|
|
4207
|
+
distinct,
|
|
4208
|
+
distinctOn
|
|
4209
|
+
}
|
|
4210
|
+
});
|
|
4211
|
+
}
|
|
4212
|
+
/** Throws `ORM.ARGUMENT_INVALID` when the collection has an order, a limit, an offset, a cursor or a distinct selection, which an update with a relation callback would ignore. */
|
|
4213
|
+
function assertRelationUpdateIgnoresNothing(state, modelName) {
|
|
4214
|
+
const { nouns, calls } = presentParts(state, [
|
|
4215
|
+
"orderBy",
|
|
4216
|
+
"limit",
|
|
4217
|
+
"offset",
|
|
4218
|
+
"cursor",
|
|
4219
|
+
"distinct",
|
|
4220
|
+
"distinctOn"
|
|
4221
|
+
]);
|
|
4222
|
+
if (nouns.length === 0) return;
|
|
4223
|
+
const { orderBy, limit, offset, cursor, distinct, distinctOn } = state;
|
|
4224
|
+
throw ormError("ORM.ARGUMENT_INVALID", `Cannot update ${modelName} with a relation mutation: the collection has ${listed(nouns, "and")}`, {
|
|
4225
|
+
why: `An update that changes a relation finds its row by the filter alone. It would ignore ${listed(nouns, "and")}, and could change another row than first() returns. ${HIDDEN_BY_A_SCOPE}`,
|
|
4226
|
+
fix: `Remove ${listed(calls, "and")} before update, or filter to the one row, such as by its id.`,
|
|
4227
|
+
meta: {
|
|
4228
|
+
model: modelName,
|
|
4229
|
+
method: "update",
|
|
4230
|
+
ordered: orderBy !== void 0 && orderBy.length > 0,
|
|
4231
|
+
limit,
|
|
4232
|
+
offset,
|
|
4233
|
+
cursor,
|
|
4234
|
+
distinct,
|
|
4235
|
+
distinctOn
|
|
4236
|
+
}
|
|
4237
|
+
});
|
|
4238
|
+
}
|
|
3860
4239
|
function applyCreateDefaults(ctx, namespaceId, tableName, rows, defaultValueCache = /* @__PURE__ */ new Map()) {
|
|
3861
4240
|
for (const row of rows) {
|
|
3862
4241
|
const applied = ctx.context.applyMutationDefaults({
|
|
@@ -3975,25 +4354,57 @@ var CollectionBase = class CollectionBase {
|
|
|
3975
4354
|
if (!filter) return blindCast(this);
|
|
3976
4355
|
return this.#cloneSelf({ filters: [...this.state.filters, filter] });
|
|
3977
4356
|
}
|
|
3978
|
-
/**
|
|
3979
|
-
* Call `fn` with this collection and return its result.
|
|
3980
|
-
*/
|
|
3981
4357
|
apply(fn) {
|
|
3982
4358
|
return fn(this);
|
|
3983
4359
|
}
|
|
3984
|
-
|
|
3985
|
-
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
4360
|
+
/**
|
|
4361
|
+
* Define a scope for this collection's model, such as a shared `select` and `include`. The body is typed once, against the model's plain collection. The scope accepts any collection of the model that `select` and `variant` have not narrowed.
|
|
4362
|
+
*
|
|
4363
|
+
* ```ts
|
|
4364
|
+
* const summary = db.Post.scope((posts) => posts.select('id', 'title').include('user'));
|
|
4365
|
+
* db.User.include('posts', (posts) => posts.apply(summary));
|
|
4366
|
+
* ```
|
|
4367
|
+
*/
|
|
4368
|
+
scope(body) {
|
|
4369
|
+
assertScopeBody(body);
|
|
4370
|
+
const source = {
|
|
4371
|
+
modelName: this.modelName,
|
|
4372
|
+
namespaceId: this.namespaceId
|
|
4373
|
+
};
|
|
4374
|
+
return (collection) => {
|
|
4375
|
+
assertModelScopeReceiver(source, collection);
|
|
4376
|
+
return body(blindCast(collection));
|
|
4377
|
+
};
|
|
4378
|
+
}
|
|
4379
|
+
variant(value) {
|
|
4380
|
+
const polyInfo = resolvePolymorphismInfo(this.contract, this.namespaceId, this.modelName);
|
|
4381
|
+
const selectedVariantName = this.state.variantName;
|
|
4382
|
+
if (selectedVariantName !== void 0) {
|
|
4383
|
+
const selectedValue = polyInfo?.variants.get(selectedVariantName)?.value;
|
|
4384
|
+
throw ormError("ORM.OPERATION_UNSUPPORTED", `variant("${value}") cannot be called on model "${this.modelName}" because variant("${selectedValue}") is already selected; call variant() on the base collection instead`, { meta: {
|
|
4385
|
+
method: "variant",
|
|
4386
|
+
model: this.modelName,
|
|
4387
|
+
variant: selectedVariantName,
|
|
4388
|
+
selectedValue,
|
|
4389
|
+
reason: "variant-already-selected"
|
|
4390
|
+
} });
|
|
4391
|
+
}
|
|
4392
|
+
const variantInfo = polyInfo?.variantsByValue.get(value);
|
|
4393
|
+
if (!polyInfo || !variantInfo) {
|
|
4394
|
+
const declaredValues = [...polyInfo?.variantsByValue.keys() ?? []];
|
|
4395
|
+
throw ormError("ORM.ARGUMENT_INVALID", declaredValues.length === 0 ? `variant("${value}") cannot narrow model "${this.modelName}": it declares no discriminator values` : `variant("${value}") cannot narrow model "${this.modelName}": the declared discriminator values are ${declaredValues.map((declared) => `"${declared}"`).join(", ")}`, { meta: {
|
|
4396
|
+
method: "variant",
|
|
4397
|
+
argument: "value",
|
|
4398
|
+
model: this.modelName,
|
|
4399
|
+
value,
|
|
4400
|
+
declaredValues
|
|
4401
|
+
} });
|
|
4402
|
+
}
|
|
4403
|
+
const columnName = polyInfo.discriminatorColumn;
|
|
4404
|
+
const filter = BinaryExpr.eq(ColumnRef.of(this.tableName, columnName), LiteralExpr.of(variantInfo.value));
|
|
3994
4405
|
return this.#cloneWithRow({
|
|
3995
|
-
filters: [...
|
|
3996
|
-
variantName
|
|
4406
|
+
filters: [...this.state.filters, filter],
|
|
4407
|
+
variantName: variantInfo.modelName
|
|
3997
4408
|
});
|
|
3998
4409
|
}
|
|
3999
4410
|
include(relationName, refineFn) {
|
|
@@ -4533,6 +4944,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4533
4944
|
assertReturningCapability(this.contract, "update()");
|
|
4534
4945
|
const annotationsMap = this.#collectAnnotationsFromMeta(configure, "write", "update");
|
|
4535
4946
|
if (hasNestedMutationCallbacks(this.contract, this.namespaceId, this.modelName, blindCast(data))) {
|
|
4947
|
+
assertRelationUpdateIgnoresNothing(this.state, this.modelName);
|
|
4536
4948
|
const updatedRow = await executeNestedUpdateMutation({
|
|
4537
4949
|
context: this.ctx.context,
|
|
4538
4950
|
runtime: this.ctx.runtime,
|
|
@@ -4553,6 +4965,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4553
4965
|
});
|
|
4554
4966
|
}
|
|
4555
4967
|
updateAll(data, configure) {
|
|
4968
|
+
assertBulkWriteIgnoresNothing(this.state, this.modelName, "updateAll");
|
|
4556
4969
|
return this.#updateAllWithAnnotations(data, this.#collectAnnotationsFromMeta(configure, "write", "updateAll"));
|
|
4557
4970
|
}
|
|
4558
4971
|
#updateAllWithAnnotations(data, annotationsMap) {
|
|
@@ -4580,6 +4993,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4580
4993
|
});
|
|
4581
4994
|
}
|
|
4582
4995
|
async updateAndCount(data, configure) {
|
|
4996
|
+
assertBulkWriteIgnoresNothing(this.state, this.modelName, "updateAndCount");
|
|
4583
4997
|
const mappedData = mapModelDataToStorageRow(this.contract, this.namespaceId, this.modelName, data);
|
|
4584
4998
|
if (Object.keys(mappedData).length === 0) return 0;
|
|
4585
4999
|
applyUpdateDefaults(this.ctx, this.namespaceId, this.tableName, mappedData);
|
|
@@ -4594,10 +5008,15 @@ var CollectionBase = class CollectionBase {
|
|
|
4594
5008
|
const scoped = this.#withRuntime(scope);
|
|
4595
5009
|
const identityWhere = await scoped.#findFirstMatchingRowIdentityWhere();
|
|
4596
5010
|
if (!identityWhere) return null;
|
|
4597
|
-
return (await scoped.#clone({
|
|
5011
|
+
return (await scoped.#clone({
|
|
5012
|
+
filters: [identityWhere],
|
|
5013
|
+
limit: void 0,
|
|
5014
|
+
offset: void 0
|
|
5015
|
+
}).#executeDeleteReturning(annotationsMap).toArray())[0] ?? null;
|
|
4598
5016
|
});
|
|
4599
5017
|
}
|
|
4600
5018
|
deleteAll(configure) {
|
|
5019
|
+
assertBulkWriteIgnoresNothing(this.state, this.modelName, "deleteAll");
|
|
4601
5020
|
return this.#deleteAllWithAnnotations(this.#collectAnnotationsFromMeta(configure, "write", "deleteAll"));
|
|
4602
5021
|
}
|
|
4603
5022
|
#deleteAllWithAnnotations(annotationsMap) {
|
|
@@ -4656,6 +5075,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4656
5075
|
return new AsyncIterableResult(generator());
|
|
4657
5076
|
}
|
|
4658
5077
|
async deleteAndCount(configure) {
|
|
5078
|
+
assertBulkWriteIgnoresNothing(this.state, this.modelName, "deleteAndCount");
|
|
4659
5079
|
const annotationsMap = this.#collectAnnotationsFromMeta(configure, "write", "deleteAndCount");
|
|
4660
5080
|
const compiled = mergeAnnotations(compileDeleteCount(this.contract, this.namespaceId, this.tableName, this.state.filters, this.state.variantName, this.modelName), annotationsMap);
|
|
4661
5081
|
return (await this.ctx.runtime.execute(compiled)).affectedRows;
|
|
@@ -4707,6 +5127,8 @@ var CollectionBase = class CollectionBase {
|
|
|
4707
5127
|
model: this.modelName,
|
|
4708
5128
|
table: this.tableName
|
|
4709
5129
|
} });
|
|
5130
|
+
checkLimitOffset("limit", this.state.limit);
|
|
5131
|
+
if (this.state.limit === 0) return null;
|
|
4710
5132
|
const firstRow = await this.#clone({
|
|
4711
5133
|
selectedFields: [...identityColumns],
|
|
4712
5134
|
includes: []
|
|
@@ -4920,8 +5342,8 @@ function orm(options) {
|
|
|
4920
5342
|
}
|
|
4921
5343
|
return new Proxy({}, { get(_target, prop) {
|
|
4922
5344
|
if (typeof prop !== "string") return;
|
|
4923
|
-
if (
|
|
4924
|
-
return
|
|
5345
|
+
if (Object.hasOwn(contract.domain.namespaces, prop)) return namespaceFacet(prop);
|
|
5346
|
+
return prop === "scope" ? defineFieldScope : void 0;
|
|
4925
5347
|
} });
|
|
4926
5348
|
}
|
|
4927
5349
|
function createCollectionRegistry(contract, collections) {
|
|
@@ -4968,6 +5390,6 @@ function createPreparedRowQuery(description, statement) {
|
|
|
4968
5390
|
} });
|
|
4969
5391
|
}
|
|
4970
5392
|
//#endregion
|
|
4971
|
-
export { Collection, GroupedCollection, all, and, createModelAccessor, createPreparedRowQuery, emptyState, not, or, orm, prepareQuery };
|
|
5393
|
+
export { Collection, GroupedCollection, all, and, createModelAccessor, createPreparedRowQuery, emptyState, not, or, orderByField, orm, prepareQuery };
|
|
4972
5394
|
|
|
4973
5395
|
//# sourceMappingURL=orm-client.mjs.map
|