@zenstackhq/runtime 3.0.0-alpha.17 → 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.
@@ -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 = requireField(schema, model, field);
217
- return !!fieldDef.relation;
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 = requireField(schema, model, field);
222
- return !!fieldDef.originModel;
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 insensitive = false;
641
- if (payload && typeof payload === "object" && "mode" in payload && payload.mode === "insensitive") {
642
- insensitive = true;
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, fieldRef, (value) => this.prepStringCasing(eb, value, insensitive), (value) => this.buildStringFilter(eb, fieldRef, value));
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.lit(`%${value}%`)) : eb(fieldRef, "like", import_kysely.sql.lit(`%${value}%`))).with("startsWith", () => insensitive ? eb(fieldRef, "ilike", import_kysely.sql.lit(`${value}%`)) : eb(fieldRef, "like", import_kysely.sql.lit(`${value}%`))).with("endsWith", () => insensitive ? eb(fieldRef, "ilike", import_kysely.sql.lit(`%${value}`)) : eb(fieldRef, "like", import_kysely.sql.lit(`%${value}`))).otherwise(() => {
654
- throw new Error(`Invalid string filter key: ${key}`);
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, toLower = true) {
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 toLower ? eb.fn("lower", [
666
- import_kysely.sql.lit(value)
667
- ]) : import_kysely.sql.lit(value);
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, toLower));
683
+ return value.map((v) => this.prepStringCasing(eb, v, mode));
670
684
  } else {
671
- return value === null ? null : import_kysely.sql.lit(value);
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, parentName) {
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
- const fieldDef = requireField(this.schema, relationModel, field);
979
- const fieldValue = fieldDef.relation ? eb.ref(`${parentName}$${relationField}$${field}.$j`) : buildFieldRef(this.schema, relationModel, field, this.options, eb);
980
- return [
981
- import_kysely2.sql.lit(field),
982
- fieldValue
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(`${parentName}$${relationField}$${field}.$j`)
1038
+ eb.ref(`${parentAlias}$${relationField}$${field}.$j`)
991
1039
  ]).flatMap((v) => v));
992
1040
  }
993
1041
  return objArgs;
@@ -1040,6 +1088,9 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1040
1088
  return `ARRAY[${values.map((v) => typeof v === "string" ? `'${v}'` : v)}]`;
1041
1089
  }
1042
1090
  }
1091
+ get supportInsertWithDefault() {
1092
+ return true;
1093
+ }
1043
1094
  };
1044
1095
 
1045
1096
  // src/client/crud/dialects/sqlite.ts
@@ -1070,11 +1121,11 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1070
1121
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
1071
1122
  return query.select((eb) => this.buildRelationJSON(model, eb, relationField, parentAlias, payload).as(relationField));
1072
1123
  }
1073
- buildRelationJSON(model, eb, relationField, parentName, payload) {
1124
+ buildRelationJSON(model, eb, relationField, parentAlias, payload) {
1074
1125
  const relationFieldDef = requireField(this.schema, model, relationField);
1075
1126
  const relationModel = relationFieldDef.type;
1076
1127
  const relationModelDef = requireModel(this.schema, relationModel);
1077
- const subQueryName = `${parentName}$${relationField}`;
1128
+ const subQueryName = `${parentAlias}$${relationField}`;
1078
1129
  let tbl = eb.selectFrom(() => {
1079
1130
  let subQuery = this.buildSelectModel(eb, relationModel);
1080
1131
  subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0);
@@ -1098,14 +1149,14 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1098
1149
  const relationIds = getIdFields(this.schema, relationModel);
1099
1150
  (0, import_common_helpers3.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1100
1151
  (0, import_common_helpers3.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1101
- subQuery = subQuery.where(eb(eb.ref(`${relationModel}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentName}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
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}`)));
1102
1153
  } else {
1103
1154
  const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
1104
1155
  keyPairs.forEach(({ fk, pk }) => {
1105
1156
  if (ownedByModel) {
1106
- subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${parentName}.${fk}`);
1157
+ subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${parentAlias}.${fk}`);
1107
1158
  } else {
1108
- subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${parentName}.${pk}`);
1159
+ subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${parentAlias}.${pk}`);
1109
1160
  }
1110
1161
  });
1111
1162
  }
@@ -1127,24 +1178,32 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1127
1178
  ]).flatMap((v) => v));
1128
1179
  } else if (payload.select) {
1129
1180
  objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
1130
- const fieldDef = requireField(this.schema, relationModel, field);
1131
- if (fieldDef.relation) {
1132
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
1181
+ if (field === "_count") {
1182
+ const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
1133
1183
  return [
1134
1184
  import_kysely3.sql.lit(field),
1135
1185
  subJson
1136
1186
  ];
1137
1187
  } else {
1138
- return [
1139
- import_kysely3.sql.lit(field),
1140
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
1141
- ];
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
+ }
1142
1201
  }
1143
1202
  }).flatMap((v) => v));
1144
1203
  }
1145
1204
  if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
1146
1205
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field, value]) => {
1147
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
1206
+ const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
1148
1207
  return [
1149
1208
  import_kysely3.sql.lit(field),
1150
1209
  subJson
@@ -1194,6 +1253,9 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1194
1253
  buildArrayLiteralSQL(_values) {
1195
1254
  throw new Error("SQLite does not support array literals");
1196
1255
  }
1256
+ get supportInsertWithDefault() {
1257
+ return false;
1258
+ }
1197
1259
  };
1198
1260
 
1199
1261
  // src/client/crud/dialects/index.ts