@zenstackhq/runtime 3.0.0-alpha.18 → 3.0.0-alpha.19
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/{contract-Cn4sSxg8.d.cts → contract-CxX20JtH.d.cts} +16 -10
- package/dist/{contract-Cn4sSxg8.d.ts → contract-CxX20JtH.d.ts} +16 -10
- package/dist/index.cjs +207 -140
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +207 -140
- package/dist/index.js.map +1 -1
- package/dist/plugins/policy/index.cjs +98 -42
- package/dist/plugins/policy/index.cjs.map +1 -1
- package/dist/plugins/policy/index.d.cts +1 -1
- package/dist/plugins/policy/index.d.ts +1 -1
- package/dist/plugins/policy/index.js +98 -42
- package/dist/plugins/policy/index.js.map +1 -1
- package/package.json +9 -9
|
@@ -151,6 +151,10 @@ var InternalError = class extends Error {
|
|
|
151
151
|
};
|
|
152
152
|
|
|
153
153
|
// src/client/query-utils.ts
|
|
154
|
+
function getModel(schema, model) {
|
|
155
|
+
return schema.models[model];
|
|
156
|
+
}
|
|
157
|
+
__name(getModel, "getModel");
|
|
154
158
|
function requireModel(schema, model) {
|
|
155
159
|
const matchedName = Object.keys(schema.models).find((k) => k.toLowerCase() === model.toLowerCase());
|
|
156
160
|
if (!matchedName) {
|
|
@@ -159,6 +163,11 @@ function requireModel(schema, model) {
|
|
|
159
163
|
return schema.models[matchedName];
|
|
160
164
|
}
|
|
161
165
|
__name(requireModel, "requireModel");
|
|
166
|
+
function getField(schema, model, field) {
|
|
167
|
+
const modelDef = getModel(schema, model);
|
|
168
|
+
return modelDef?.fields[field];
|
|
169
|
+
}
|
|
170
|
+
__name(getField, "getField");
|
|
162
171
|
function requireField(schema, model, field) {
|
|
163
172
|
const modelDef = requireModel(schema, model);
|
|
164
173
|
if (!modelDef.fields[field]) {
|
|
@@ -213,13 +222,13 @@ function getRelationForeignKeyFieldPairs(schema, model, relationField) {
|
|
|
213
222
|
}
|
|
214
223
|
__name(getRelationForeignKeyFieldPairs, "getRelationForeignKeyFieldPairs");
|
|
215
224
|
function isRelationField(schema, model, field) {
|
|
216
|
-
const fieldDef =
|
|
217
|
-
return !!fieldDef
|
|
225
|
+
const fieldDef = getField(schema, model, field);
|
|
226
|
+
return !!fieldDef?.relation;
|
|
218
227
|
}
|
|
219
228
|
__name(isRelationField, "isRelationField");
|
|
220
229
|
function isInheritedField(schema, model, field) {
|
|
221
|
-
const fieldDef =
|
|
222
|
-
return !!fieldDef
|
|
230
|
+
const fieldDef = getField(schema, model, field);
|
|
231
|
+
return !!fieldDef?.originModel;
|
|
223
232
|
}
|
|
224
233
|
__name(isInheritedField, "isInheritedField");
|
|
225
234
|
function getUniqueFields(schema, model) {
|
|
@@ -589,7 +598,7 @@ var BaseCrudDialect = class {
|
|
|
589
598
|
buildLiteralFilter(eb, lhs, type, rhs) {
|
|
590
599
|
return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type, false) : rhs);
|
|
591
600
|
}
|
|
592
|
-
buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0) {
|
|
601
|
+
buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0, excludeKeys = []) {
|
|
593
602
|
if (payload === null || !(0, import_common_helpers.isPlainObject)(payload)) {
|
|
594
603
|
return {
|
|
595
604
|
conditions: [
|
|
@@ -604,6 +613,9 @@ var BaseCrudDialect = class {
|
|
|
604
613
|
if (onlyForKeys && !onlyForKeys.includes(op)) {
|
|
605
614
|
continue;
|
|
606
615
|
}
|
|
616
|
+
if (excludeKeys.includes(op)) {
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
607
619
|
const rhs = Array.isArray(value) ? value.map(getRhs) : getRhs(value);
|
|
608
620
|
const condition = (0, import_ts_pattern.match)(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
|
|
609
621
|
(0, import_common_helpers.invariant)(Array.isArray(rhs), "right hand side must be an array");
|
|
@@ -637,21 +649,20 @@ var BaseCrudDialect = class {
|
|
|
637
649
|
};
|
|
638
650
|
}
|
|
639
651
|
buildStringFilter(eb, fieldRef, payload) {
|
|
640
|
-
let
|
|
641
|
-
if (payload && typeof payload === "object" && "mode" in payload
|
|
642
|
-
|
|
643
|
-
fieldRef = eb.fn("lower", [
|
|
644
|
-
fieldRef
|
|
645
|
-
]);
|
|
652
|
+
let mode;
|
|
653
|
+
if (payload && typeof payload === "object" && "mode" in payload) {
|
|
654
|
+
mode = payload.mode;
|
|
646
655
|
}
|
|
647
|
-
const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload,
|
|
656
|
+
const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, mode === "insensitive" ? eb.fn("lower", [
|
|
657
|
+
fieldRef
|
|
658
|
+
]) : fieldRef, (value) => this.prepStringCasing(eb, value, mode), (value) => this.buildStringFilter(eb, fieldRef, value));
|
|
648
659
|
if (payload && typeof payload === "object") {
|
|
649
660
|
for (const [key, value] of Object.entries(payload)) {
|
|
650
661
|
if (key === "mode" || consumedKeys.includes(key)) {
|
|
651
662
|
continue;
|
|
652
663
|
}
|
|
653
|
-
const condition = (0, import_ts_pattern.match)(key).with("contains", () => insensitive ? eb(fieldRef, "ilike", import_kysely.sql.
|
|
654
|
-
throw new
|
|
664
|
+
const condition = (0, import_ts_pattern.match)(key).with("contains", () => mode === "insensitive" ? eb(fieldRef, "ilike", import_kysely.sql.val(`%${value}%`)) : eb(fieldRef, "like", import_kysely.sql.val(`%${value}%`))).with("startsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", import_kysely.sql.val(`${value}%`)) : eb(fieldRef, "like", import_kysely.sql.val(`${value}%`))).with("endsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", import_kysely.sql.val(`%${value}`)) : eb(fieldRef, "like", import_kysely.sql.val(`%${value}`))).otherwise(() => {
|
|
665
|
+
throw new QueryError(`Invalid string filter key: ${key}`);
|
|
655
666
|
});
|
|
656
667
|
if (condition) {
|
|
657
668
|
conditions.push(condition);
|
|
@@ -660,15 +671,18 @@ var BaseCrudDialect = class {
|
|
|
660
671
|
}
|
|
661
672
|
return this.and(eb, ...conditions);
|
|
662
673
|
}
|
|
663
|
-
prepStringCasing(eb, value,
|
|
674
|
+
prepStringCasing(eb, value, mode) {
|
|
675
|
+
if (!mode || mode === "default") {
|
|
676
|
+
return value === null ? value : import_kysely.sql.val(value);
|
|
677
|
+
}
|
|
664
678
|
if (typeof value === "string") {
|
|
665
|
-
return
|
|
666
|
-
import_kysely.sql.
|
|
667
|
-
])
|
|
679
|
+
return eb.fn("lower", [
|
|
680
|
+
import_kysely.sql.val(value)
|
|
681
|
+
]);
|
|
668
682
|
} else if (Array.isArray(value)) {
|
|
669
|
-
return value.map((v) => this.prepStringCasing(eb, v,
|
|
683
|
+
return value.map((v) => this.prepStringCasing(eb, v, mode));
|
|
670
684
|
} else {
|
|
671
|
-
return value === null ? null : import_kysely.sql.
|
|
685
|
+
return value === null ? null : import_kysely.sql.val(value);
|
|
672
686
|
}
|
|
673
687
|
}
|
|
674
688
|
buildNumberFilter(eb, fieldRef, type, payload) {
|
|
@@ -830,6 +844,32 @@ var BaseCrudDialect = class {
|
|
|
830
844
|
});
|
|
831
845
|
return query;
|
|
832
846
|
}
|
|
847
|
+
buildCountJson(model, eb, parentAlias, payload) {
|
|
848
|
+
const modelDef = requireModel(this.schema, model);
|
|
849
|
+
const toManyRelations = Object.entries(modelDef.fields).filter(([, field]) => field.relation && field.array);
|
|
850
|
+
const selections = payload === true ? {
|
|
851
|
+
select: toManyRelations.reduce((acc, [field]) => {
|
|
852
|
+
acc[field] = true;
|
|
853
|
+
return acc;
|
|
854
|
+
}, {})
|
|
855
|
+
} : payload;
|
|
856
|
+
const jsonObject = {};
|
|
857
|
+
for (const [field, value] of Object.entries(selections.select)) {
|
|
858
|
+
const fieldDef = requireField(this.schema, model, field);
|
|
859
|
+
const fieldModel = fieldDef.type;
|
|
860
|
+
const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
|
|
861
|
+
let fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
|
|
862
|
+
for (const [left, right] of joinPairs) {
|
|
863
|
+
fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
|
|
864
|
+
}
|
|
865
|
+
if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
|
|
866
|
+
const filter = this.buildFilter(eb, fieldModel, fieldModel, value.where);
|
|
867
|
+
fieldCountQuery = fieldCountQuery.where(filter);
|
|
868
|
+
}
|
|
869
|
+
jsonObject[field] = fieldCountQuery;
|
|
870
|
+
}
|
|
871
|
+
return this.buildJsonObject(eb, jsonObject);
|
|
872
|
+
}
|
|
833
873
|
// #endregion
|
|
834
874
|
// #region utils
|
|
835
875
|
negateSort(sort, negated) {
|
|
@@ -958,7 +998,7 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
958
998
|
});
|
|
959
999
|
return qb;
|
|
960
1000
|
}
|
|
961
|
-
buildRelationObjectArgs(relationModel, relationField, eb, payload,
|
|
1001
|
+
buildRelationObjectArgs(relationModel, relationField, eb, payload, parentAlias) {
|
|
962
1002
|
const relationModelDef = requireModel(this.schema, relationModel);
|
|
963
1003
|
const objArgs = [];
|
|
964
1004
|
const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
|
|
@@ -974,20 +1014,28 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
|
|
|
974
1014
|
buildFieldRef(this.schema, relationModel, field, this.options, eb)
|
|
975
1015
|
]).flatMap((v) => v));
|
|
976
1016
|
} else if (payload.select) {
|
|
977
|
-
objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) => {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
1017
|
+
objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
|
|
1018
|
+
if (field === "_count") {
|
|
1019
|
+
const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
|
|
1020
|
+
return [
|
|
1021
|
+
import_kysely2.sql.lit(field),
|
|
1022
|
+
subJson
|
|
1023
|
+
];
|
|
1024
|
+
} else {
|
|
1025
|
+
const fieldDef = requireField(this.schema, relationModel, field);
|
|
1026
|
+
const fieldValue = fieldDef.relation ? eb.ref(`${parentAlias}$${relationField}$${field}.$j`) : buildFieldRef(this.schema, relationModel, field, this.options, eb);
|
|
1027
|
+
return [
|
|
1028
|
+
import_kysely2.sql.lit(field),
|
|
1029
|
+
fieldValue
|
|
1030
|
+
];
|
|
1031
|
+
}
|
|
984
1032
|
}).flatMap((v) => v));
|
|
985
1033
|
}
|
|
986
1034
|
if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
|
|
987
1035
|
objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
|
|
988
1036
|
import_kysely2.sql.lit(field),
|
|
989
1037
|
// reference the synthesized JSON field
|
|
990
|
-
eb.ref(`${
|
|
1038
|
+
eb.ref(`${parentAlias}$${relationField}$${field}.$j`)
|
|
991
1039
|
]).flatMap((v) => v));
|
|
992
1040
|
}
|
|
993
1041
|
return objArgs;
|
|
@@ -1073,11 +1121,11 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
1073
1121
|
buildRelationSelection(query, model, relationField, parentAlias, payload) {
|
|
1074
1122
|
return query.select((eb) => this.buildRelationJSON(model, eb, relationField, parentAlias, payload).as(relationField));
|
|
1075
1123
|
}
|
|
1076
|
-
buildRelationJSON(model, eb, relationField,
|
|
1124
|
+
buildRelationJSON(model, eb, relationField, parentAlias, payload) {
|
|
1077
1125
|
const relationFieldDef = requireField(this.schema, model, relationField);
|
|
1078
1126
|
const relationModel = relationFieldDef.type;
|
|
1079
1127
|
const relationModelDef = requireModel(this.schema, relationModel);
|
|
1080
|
-
const subQueryName = `${
|
|
1128
|
+
const subQueryName = `${parentAlias}$${relationField}`;
|
|
1081
1129
|
let tbl = eb.selectFrom(() => {
|
|
1082
1130
|
let subQuery = this.buildSelectModel(eb, relationModel);
|
|
1083
1131
|
subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0);
|
|
@@ -1101,14 +1149,14 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
1101
1149
|
const relationIds = getIdFields(this.schema, relationModel);
|
|
1102
1150
|
(0, import_common_helpers3.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
|
|
1103
1151
|
(0, import_common_helpers3.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
|
|
1104
|
-
subQuery = subQuery.where(eb(eb.ref(`${relationModel}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${
|
|
1152
|
+
subQuery = subQuery.where(eb(eb.ref(`${relationModel}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentAlias}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
|
|
1105
1153
|
} else {
|
|
1106
1154
|
const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
|
|
1107
1155
|
keyPairs.forEach(({ fk, pk }) => {
|
|
1108
1156
|
if (ownedByModel) {
|
|
1109
|
-
subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${
|
|
1157
|
+
subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${parentAlias}.${fk}`);
|
|
1110
1158
|
} else {
|
|
1111
|
-
subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${
|
|
1159
|
+
subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${parentAlias}.${pk}`);
|
|
1112
1160
|
}
|
|
1113
1161
|
});
|
|
1114
1162
|
}
|
|
@@ -1130,24 +1178,32 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
|
|
|
1130
1178
|
]).flatMap((v) => v));
|
|
1131
1179
|
} else if (payload.select) {
|
|
1132
1180
|
objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
|
|
1181
|
+
if (field === "_count") {
|
|
1182
|
+
const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
|
|
1136
1183
|
return [
|
|
1137
1184
|
import_kysely3.sql.lit(field),
|
|
1138
1185
|
subJson
|
|
1139
1186
|
];
|
|
1140
1187
|
} else {
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1188
|
+
const fieldDef = requireField(this.schema, relationModel, field);
|
|
1189
|
+
if (fieldDef.relation) {
|
|
1190
|
+
const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
|
|
1191
|
+
return [
|
|
1192
|
+
import_kysely3.sql.lit(field),
|
|
1193
|
+
subJson
|
|
1194
|
+
];
|
|
1195
|
+
} else {
|
|
1196
|
+
return [
|
|
1197
|
+
import_kysely3.sql.lit(field),
|
|
1198
|
+
buildFieldRef(this.schema, relationModel, field, this.options, eb)
|
|
1199
|
+
];
|
|
1200
|
+
}
|
|
1145
1201
|
}
|
|
1146
1202
|
}).flatMap((v) => v));
|
|
1147
1203
|
}
|
|
1148
1204
|
if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
|
|
1149
1205
|
objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field, value]) => {
|
|
1150
|
-
const subJson = this.buildRelationJSON(relationModel, eb, field, `${
|
|
1206
|
+
const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
|
|
1151
1207
|
return [
|
|
1152
1208
|
import_kysely3.sql.lit(field),
|
|
1153
1209
|
subJson
|