@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.
@@ -1,5 +1,5 @@
1
1
  import * as kysely from 'kysely';
2
- import { R as RuntimePlugin, V as OnKyselyQueryArgs } from '../../contract-C6xcEG6Q.cjs';
2
+ import { R as RuntimePlugin, V as OnKyselyQueryArgs } from '../../contract-CxX20JtH.cjs';
3
3
  import { SchemaDef } from '@zenstackhq/sdk/schema';
4
4
  import 'decimal.js';
5
5
 
@@ -1,5 +1,5 @@
1
1
  import * as kysely from 'kysely';
2
- import { R as RuntimePlugin, V as OnKyselyQueryArgs } from '../../contract-C6xcEG6Q.js';
2
+ import { R as RuntimePlugin, V as OnKyselyQueryArgs } from '../../contract-CxX20JtH.js';
3
3
  import { SchemaDef } from '@zenstackhq/sdk/schema';
4
4
  import 'decimal.js';
5
5
 
@@ -126,6 +126,10 @@ var InternalError = class extends Error {
126
126
  };
127
127
 
128
128
  // src/client/query-utils.ts
129
+ function getModel(schema, model) {
130
+ return schema.models[model];
131
+ }
132
+ __name(getModel, "getModel");
129
133
  function requireModel(schema, model) {
130
134
  const matchedName = Object.keys(schema.models).find((k) => k.toLowerCase() === model.toLowerCase());
131
135
  if (!matchedName) {
@@ -134,6 +138,11 @@ function requireModel(schema, model) {
134
138
  return schema.models[matchedName];
135
139
  }
136
140
  __name(requireModel, "requireModel");
141
+ function getField(schema, model, field) {
142
+ const modelDef = getModel(schema, model);
143
+ return modelDef?.fields[field];
144
+ }
145
+ __name(getField, "getField");
137
146
  function requireField(schema, model, field) {
138
147
  const modelDef = requireModel(schema, model);
139
148
  if (!modelDef.fields[field]) {
@@ -188,13 +197,13 @@ function getRelationForeignKeyFieldPairs(schema, model, relationField) {
188
197
  }
189
198
  __name(getRelationForeignKeyFieldPairs, "getRelationForeignKeyFieldPairs");
190
199
  function isRelationField(schema, model, field) {
191
- const fieldDef = requireField(schema, model, field);
192
- return !!fieldDef.relation;
200
+ const fieldDef = getField(schema, model, field);
201
+ return !!fieldDef?.relation;
193
202
  }
194
203
  __name(isRelationField, "isRelationField");
195
204
  function isInheritedField(schema, model, field) {
196
- const fieldDef = requireField(schema, model, field);
197
- return !!fieldDef.originModel;
205
+ const fieldDef = getField(schema, model, field);
206
+ return !!fieldDef?.originModel;
198
207
  }
199
208
  __name(isInheritedField, "isInheritedField");
200
209
  function getUniqueFields(schema, model) {
@@ -564,7 +573,7 @@ var BaseCrudDialect = class {
564
573
  buildLiteralFilter(eb, lhs, type, rhs) {
565
574
  return eb(lhs, "=", rhs !== null && rhs !== void 0 ? this.transformPrimitive(rhs, type, false) : rhs);
566
575
  }
567
- buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0) {
576
+ buildStandardFilter(eb, type, payload, lhs, getRhs, recurse, throwIfInvalid = false, onlyForKeys = void 0, excludeKeys = []) {
568
577
  if (payload === null || !isPlainObject(payload)) {
569
578
  return {
570
579
  conditions: [
@@ -579,6 +588,9 @@ var BaseCrudDialect = class {
579
588
  if (onlyForKeys && !onlyForKeys.includes(op)) {
580
589
  continue;
581
590
  }
591
+ if (excludeKeys.includes(op)) {
592
+ continue;
593
+ }
582
594
  const rhs = Array.isArray(value) ? value.map(getRhs) : getRhs(value);
583
595
  const condition = match(op).with("equals", () => rhs === null ? eb(lhs, "is", null) : eb(lhs, "=", rhs)).with("in", () => {
584
596
  invariant(Array.isArray(rhs), "right hand side must be an array");
@@ -612,21 +624,20 @@ var BaseCrudDialect = class {
612
624
  };
613
625
  }
614
626
  buildStringFilter(eb, fieldRef, payload) {
615
- let insensitive = false;
616
- if (payload && typeof payload === "object" && "mode" in payload && payload.mode === "insensitive") {
617
- insensitive = true;
618
- fieldRef = eb.fn("lower", [
619
- fieldRef
620
- ]);
627
+ let mode;
628
+ if (payload && typeof payload === "object" && "mode" in payload) {
629
+ mode = payload.mode;
621
630
  }
622
- const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, fieldRef, (value) => this.prepStringCasing(eb, value, insensitive), (value) => this.buildStringFilter(eb, fieldRef, value));
631
+ const { conditions, consumedKeys } = this.buildStandardFilter(eb, "String", payload, mode === "insensitive" ? eb.fn("lower", [
632
+ fieldRef
633
+ ]) : fieldRef, (value) => this.prepStringCasing(eb, value, mode), (value) => this.buildStringFilter(eb, fieldRef, value));
623
634
  if (payload && typeof payload === "object") {
624
635
  for (const [key, value] of Object.entries(payload)) {
625
636
  if (key === "mode" || consumedKeys.includes(key)) {
626
637
  continue;
627
638
  }
628
- const condition = match(key).with("contains", () => insensitive ? eb(fieldRef, "ilike", sql.lit(`%${value}%`)) : eb(fieldRef, "like", sql.lit(`%${value}%`))).with("startsWith", () => insensitive ? eb(fieldRef, "ilike", sql.lit(`${value}%`)) : eb(fieldRef, "like", sql.lit(`${value}%`))).with("endsWith", () => insensitive ? eb(fieldRef, "ilike", sql.lit(`%${value}`)) : eb(fieldRef, "like", sql.lit(`%${value}`))).otherwise(() => {
629
- throw new Error(`Invalid string filter key: ${key}`);
639
+ const condition = match(key).with("contains", () => mode === "insensitive" ? eb(fieldRef, "ilike", sql.val(`%${value}%`)) : eb(fieldRef, "like", sql.val(`%${value}%`))).with("startsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", sql.val(`${value}%`)) : eb(fieldRef, "like", sql.val(`${value}%`))).with("endsWith", () => mode === "insensitive" ? eb(fieldRef, "ilike", sql.val(`%${value}`)) : eb(fieldRef, "like", sql.val(`%${value}`))).otherwise(() => {
640
+ throw new QueryError(`Invalid string filter key: ${key}`);
630
641
  });
631
642
  if (condition) {
632
643
  conditions.push(condition);
@@ -635,15 +646,18 @@ var BaseCrudDialect = class {
635
646
  }
636
647
  return this.and(eb, ...conditions);
637
648
  }
638
- prepStringCasing(eb, value, toLower = true) {
649
+ prepStringCasing(eb, value, mode) {
650
+ if (!mode || mode === "default") {
651
+ return value === null ? value : sql.val(value);
652
+ }
639
653
  if (typeof value === "string") {
640
- return toLower ? eb.fn("lower", [
641
- sql.lit(value)
642
- ]) : sql.lit(value);
654
+ return eb.fn("lower", [
655
+ sql.val(value)
656
+ ]);
643
657
  } else if (Array.isArray(value)) {
644
- return value.map((v) => this.prepStringCasing(eb, v, toLower));
658
+ return value.map((v) => this.prepStringCasing(eb, v, mode));
645
659
  } else {
646
- return value === null ? null : sql.lit(value);
660
+ return value === null ? null : sql.val(value);
647
661
  }
648
662
  }
649
663
  buildNumberFilter(eb, fieldRef, type, payload) {
@@ -805,6 +819,32 @@ var BaseCrudDialect = class {
805
819
  });
806
820
  return query;
807
821
  }
822
+ buildCountJson(model, eb, parentAlias, payload) {
823
+ const modelDef = requireModel(this.schema, model);
824
+ const toManyRelations = Object.entries(modelDef.fields).filter(([, field]) => field.relation && field.array);
825
+ const selections = payload === true ? {
826
+ select: toManyRelations.reduce((acc, [field]) => {
827
+ acc[field] = true;
828
+ return acc;
829
+ }, {})
830
+ } : payload;
831
+ const jsonObject = {};
832
+ for (const [field, value] of Object.entries(selections.select)) {
833
+ const fieldDef = requireField(this.schema, model, field);
834
+ const fieldModel = fieldDef.type;
835
+ const joinPairs = buildJoinPairs(this.schema, model, parentAlias, field, fieldModel);
836
+ let fieldCountQuery = eb.selectFrom(fieldModel).select(eb.fn.countAll().as(`_count$${field}`));
837
+ for (const [left, right] of joinPairs) {
838
+ fieldCountQuery = fieldCountQuery.whereRef(left, "=", right);
839
+ }
840
+ if (value && typeof value === "object" && "where" in value && value.where && typeof value.where === "object") {
841
+ const filter = this.buildFilter(eb, fieldModel, fieldModel, value.where);
842
+ fieldCountQuery = fieldCountQuery.where(filter);
843
+ }
844
+ jsonObject[field] = fieldCountQuery;
845
+ }
846
+ return this.buildJsonObject(eb, jsonObject);
847
+ }
808
848
  // #endregion
809
849
  // #region utils
810
850
  negateSort(sort, negated) {
@@ -933,7 +973,7 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
933
973
  });
934
974
  return qb;
935
975
  }
936
- buildRelationObjectArgs(relationModel, relationField, eb, payload, parentName) {
976
+ buildRelationObjectArgs(relationModel, relationField, eb, payload, parentAlias) {
937
977
  const relationModelDef = requireModel(this.schema, relationModel);
938
978
  const objArgs = [];
939
979
  const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
@@ -949,20 +989,28 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
949
989
  buildFieldRef(this.schema, relationModel, field, this.options, eb)
950
990
  ]).flatMap((v) => v));
951
991
  } else if (payload.select) {
952
- objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field]) => {
953
- const fieldDef = requireField(this.schema, relationModel, field);
954
- const fieldValue = fieldDef.relation ? eb.ref(`${parentName}$${relationField}$${field}.$j`) : buildFieldRef(this.schema, relationModel, field, this.options, eb);
955
- return [
956
- sql2.lit(field),
957
- fieldValue
958
- ];
992
+ objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
993
+ if (field === "_count") {
994
+ const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
995
+ return [
996
+ sql2.lit(field),
997
+ subJson
998
+ ];
999
+ } else {
1000
+ const fieldDef = requireField(this.schema, relationModel, field);
1001
+ const fieldValue = fieldDef.relation ? eb.ref(`${parentAlias}$${relationField}$${field}.$j`) : buildFieldRef(this.schema, relationModel, field, this.options, eb);
1002
+ return [
1003
+ sql2.lit(field),
1004
+ fieldValue
1005
+ ];
1006
+ }
959
1007
  }).flatMap((v) => v));
960
1008
  }
961
1009
  if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
962
1010
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
963
1011
  sql2.lit(field),
964
1012
  // reference the synthesized JSON field
965
- eb.ref(`${parentName}$${relationField}$${field}.$j`)
1013
+ eb.ref(`${parentAlias}$${relationField}$${field}.$j`)
966
1014
  ]).flatMap((v) => v));
967
1015
  }
968
1016
  return objArgs;
@@ -1015,6 +1063,9 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1015
1063
  return `ARRAY[${values.map((v) => typeof v === "string" ? `'${v}'` : v)}]`;
1016
1064
  }
1017
1065
  }
1066
+ get supportInsertWithDefault() {
1067
+ return true;
1068
+ }
1018
1069
  };
1019
1070
 
1020
1071
  // src/client/crud/dialects/sqlite.ts
@@ -1045,11 +1096,11 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1045
1096
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
1046
1097
  return query.select((eb) => this.buildRelationJSON(model, eb, relationField, parentAlias, payload).as(relationField));
1047
1098
  }
1048
- buildRelationJSON(model, eb, relationField, parentName, payload) {
1099
+ buildRelationJSON(model, eb, relationField, parentAlias, payload) {
1049
1100
  const relationFieldDef = requireField(this.schema, model, relationField);
1050
1101
  const relationModel = relationFieldDef.type;
1051
1102
  const relationModelDef = requireModel(this.schema, relationModel);
1052
- const subQueryName = `${parentName}$${relationField}`;
1103
+ const subQueryName = `${parentAlias}$${relationField}`;
1053
1104
  let tbl = eb.selectFrom(() => {
1054
1105
  let subQuery = this.buildSelectModel(eb, relationModel);
1055
1106
  subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0);
@@ -1073,14 +1124,14 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1073
1124
  const relationIds = getIdFields(this.schema, relationModel);
1074
1125
  invariant3(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1075
1126
  invariant3(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1076
- 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}`)));
1127
+ 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}`)));
1077
1128
  } else {
1078
1129
  const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
1079
1130
  keyPairs.forEach(({ fk, pk }) => {
1080
1131
  if (ownedByModel) {
1081
- subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${parentName}.${fk}`);
1132
+ subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${parentAlias}.${fk}`);
1082
1133
  } else {
1083
- subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${parentName}.${pk}`);
1134
+ subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${parentAlias}.${pk}`);
1084
1135
  }
1085
1136
  });
1086
1137
  }
@@ -1102,24 +1153,32 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1102
1153
  ]).flatMap((v) => v));
1103
1154
  } else if (payload.select) {
1104
1155
  objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
1105
- const fieldDef = requireField(this.schema, relationModel, field);
1106
- if (fieldDef.relation) {
1107
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
1156
+ if (field === "_count") {
1157
+ const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
1108
1158
  return [
1109
1159
  sql3.lit(field),
1110
1160
  subJson
1111
1161
  ];
1112
1162
  } else {
1113
- return [
1114
- sql3.lit(field),
1115
- buildFieldRef(this.schema, relationModel, field, this.options, eb)
1116
- ];
1163
+ const fieldDef = requireField(this.schema, relationModel, field);
1164
+ if (fieldDef.relation) {
1165
+ const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
1166
+ return [
1167
+ sql3.lit(field),
1168
+ subJson
1169
+ ];
1170
+ } else {
1171
+ return [
1172
+ sql3.lit(field),
1173
+ buildFieldRef(this.schema, relationModel, field, this.options, eb)
1174
+ ];
1175
+ }
1117
1176
  }
1118
1177
  }).flatMap((v) => v));
1119
1178
  }
1120
1179
  if (typeof payload === "object" && payload.include && typeof payload.include === "object") {
1121
1180
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field, value]) => {
1122
- const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentName}$${relationField}`, value);
1181
+ const subJson = this.buildRelationJSON(relationModel, eb, field, `${parentAlias}$${relationField}`, value);
1123
1182
  return [
1124
1183
  sql3.lit(field),
1125
1184
  subJson
@@ -1169,6 +1228,9 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1169
1228
  buildArrayLiteralSQL(_values) {
1170
1229
  throw new Error("SQLite does not support array literals");
1171
1230
  }
1231
+ get supportInsertWithDefault() {
1232
+ return false;
1233
+ }
1172
1234
  };
1173
1235
 
1174
1236
  // src/client/crud/dialects/index.ts