@prisma/orm-family-sql 8.0.0-rc.14-dev.43 → 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 +196 -20
- package/dist/orm-client.d.mts.map +1 -1
- package/dist/orm-client.mjs +441 -35
- 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,12 +4354,28 @@ 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
|
}
|
|
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
|
+
}
|
|
3984
4379
|
variant(value) {
|
|
3985
4380
|
const polyInfo = resolvePolymorphismInfo(this.contract, this.namespaceId, this.modelName);
|
|
3986
4381
|
const selectedVariantName = this.state.variantName;
|
|
@@ -4549,6 +4944,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4549
4944
|
assertReturningCapability(this.contract, "update()");
|
|
4550
4945
|
const annotationsMap = this.#collectAnnotationsFromMeta(configure, "write", "update");
|
|
4551
4946
|
if (hasNestedMutationCallbacks(this.contract, this.namespaceId, this.modelName, blindCast(data))) {
|
|
4947
|
+
assertRelationUpdateIgnoresNothing(this.state, this.modelName);
|
|
4552
4948
|
const updatedRow = await executeNestedUpdateMutation({
|
|
4553
4949
|
context: this.ctx.context,
|
|
4554
4950
|
runtime: this.ctx.runtime,
|
|
@@ -4569,6 +4965,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4569
4965
|
});
|
|
4570
4966
|
}
|
|
4571
4967
|
updateAll(data, configure) {
|
|
4968
|
+
assertBulkWriteIgnoresNothing(this.state, this.modelName, "updateAll");
|
|
4572
4969
|
return this.#updateAllWithAnnotations(data, this.#collectAnnotationsFromMeta(configure, "write", "updateAll"));
|
|
4573
4970
|
}
|
|
4574
4971
|
#updateAllWithAnnotations(data, annotationsMap) {
|
|
@@ -4596,6 +4993,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4596
4993
|
});
|
|
4597
4994
|
}
|
|
4598
4995
|
async updateAndCount(data, configure) {
|
|
4996
|
+
assertBulkWriteIgnoresNothing(this.state, this.modelName, "updateAndCount");
|
|
4599
4997
|
const mappedData = mapModelDataToStorageRow(this.contract, this.namespaceId, this.modelName, data);
|
|
4600
4998
|
if (Object.keys(mappedData).length === 0) return 0;
|
|
4601
4999
|
applyUpdateDefaults(this.ctx, this.namespaceId, this.tableName, mappedData);
|
|
@@ -4610,10 +5008,15 @@ var CollectionBase = class CollectionBase {
|
|
|
4610
5008
|
const scoped = this.#withRuntime(scope);
|
|
4611
5009
|
const identityWhere = await scoped.#findFirstMatchingRowIdentityWhere();
|
|
4612
5010
|
if (!identityWhere) return null;
|
|
4613
|
-
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;
|
|
4614
5016
|
});
|
|
4615
5017
|
}
|
|
4616
5018
|
deleteAll(configure) {
|
|
5019
|
+
assertBulkWriteIgnoresNothing(this.state, this.modelName, "deleteAll");
|
|
4617
5020
|
return this.#deleteAllWithAnnotations(this.#collectAnnotationsFromMeta(configure, "write", "deleteAll"));
|
|
4618
5021
|
}
|
|
4619
5022
|
#deleteAllWithAnnotations(annotationsMap) {
|
|
@@ -4672,6 +5075,7 @@ var CollectionBase = class CollectionBase {
|
|
|
4672
5075
|
return new AsyncIterableResult(generator());
|
|
4673
5076
|
}
|
|
4674
5077
|
async deleteAndCount(configure) {
|
|
5078
|
+
assertBulkWriteIgnoresNothing(this.state, this.modelName, "deleteAndCount");
|
|
4675
5079
|
const annotationsMap = this.#collectAnnotationsFromMeta(configure, "write", "deleteAndCount");
|
|
4676
5080
|
const compiled = mergeAnnotations(compileDeleteCount(this.contract, this.namespaceId, this.tableName, this.state.filters, this.state.variantName, this.modelName), annotationsMap);
|
|
4677
5081
|
return (await this.ctx.runtime.execute(compiled)).affectedRows;
|
|
@@ -4723,6 +5127,8 @@ var CollectionBase = class CollectionBase {
|
|
|
4723
5127
|
model: this.modelName,
|
|
4724
5128
|
table: this.tableName
|
|
4725
5129
|
} });
|
|
5130
|
+
checkLimitOffset("limit", this.state.limit);
|
|
5131
|
+
if (this.state.limit === 0) return null;
|
|
4726
5132
|
const firstRow = await this.#clone({
|
|
4727
5133
|
selectedFields: [...identityColumns],
|
|
4728
5134
|
includes: []
|
|
@@ -4936,8 +5342,8 @@ function orm(options) {
|
|
|
4936
5342
|
}
|
|
4937
5343
|
return new Proxy({}, { get(_target, prop) {
|
|
4938
5344
|
if (typeof prop !== "string") return;
|
|
4939
|
-
if (
|
|
4940
|
-
return
|
|
5345
|
+
if (Object.hasOwn(contract.domain.namespaces, prop)) return namespaceFacet(prop);
|
|
5346
|
+
return prop === "scope" ? defineFieldScope : void 0;
|
|
4941
5347
|
} });
|
|
4942
5348
|
}
|
|
4943
5349
|
function createCollectionRegistry(contract, collections) {
|
|
@@ -4984,6 +5390,6 @@ function createPreparedRowQuery(description, statement) {
|
|
|
4984
5390
|
} });
|
|
4985
5391
|
}
|
|
4986
5392
|
//#endregion
|
|
4987
|
-
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 };
|
|
4988
5394
|
|
|
4989
5395
|
//# sourceMappingURL=orm-client.mjs.map
|