@zenstackhq/runtime 3.0.0-alpha.32 → 3.0.0-alpha.33

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-CToGslMD.cjs';
2
+ import { R as RuntimePlugin, V as OnKyselyQueryArgs } from '../../contract-CusA0mQO.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-CToGslMD.js';
2
+ import { R as RuntimePlugin, V as OnKyselyQueryArgs } from '../../contract-CusA0mQO.js';
3
3
  import { SchemaDef } from '@zenstackhq/sdk/schema';
4
4
  import 'decimal.js';
5
5
 
@@ -120,7 +120,10 @@ var ExpressionUtils = {
120
120
  isUnary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "unary"), "isUnary"),
121
121
  isBinary: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "binary"), "isBinary"),
122
122
  isField: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "field"), "isField"),
123
- isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember")
123
+ isMember: /* @__PURE__ */ __name((value) => ExpressionUtils.is(value, "member"), "isMember"),
124
+ getLiteralValue: /* @__PURE__ */ __name((expr2) => {
125
+ return ExpressionUtils.isLiteral(expr2) ? expr2.value : void 0;
126
+ }, "getLiteralValue")
124
127
  };
125
128
 
126
129
  // src/client/errors.ts
@@ -911,6 +914,16 @@ var BaseCrudDialect = class {
911
914
  }
912
915
  return result;
913
916
  }
917
+ buildModelSelect(eb, model, subQueryAlias, payload, selectAllFields) {
918
+ let subQuery = this.buildSelectModel(eb, model, subQueryAlias);
919
+ if (selectAllFields) {
920
+ subQuery = this.buildSelectAllFields(model, subQuery, typeof payload === "object" ? payload?.omit : void 0, subQueryAlias);
921
+ }
922
+ if (payload && typeof payload === "object") {
923
+ subQuery = this.buildFilterSortTake(model, payload, subQuery, subQueryAlias);
924
+ }
925
+ return subQuery;
926
+ }
914
927
  buildSelectField(query, model, modelAlias, field) {
915
928
  const fieldDef = requireField(this.schema, model, field);
916
929
  if (fieldDef.computed) {
@@ -1008,6 +1021,18 @@ var BaseCrudDialect = class {
1008
1021
  fieldRef(model, field, eb, modelAlias, inlineComputedField = true) {
1009
1022
  return buildFieldRef(this.schema, model, field, this.options, eb, modelAlias, inlineComputedField);
1010
1023
  }
1024
+ canJoinWithoutNestedSelect(modelDef, payload) {
1025
+ if (modelDef.computedFields) {
1026
+ return false;
1027
+ }
1028
+ if (modelDef.baseModel || modelDef.isDelegate) {
1029
+ return false;
1030
+ }
1031
+ if (typeof payload === "object" && (payload.orderBy || payload.skip !== void 0 || payload.take !== void 0 || payload.cursor || payload.distinct)) {
1032
+ return false;
1033
+ }
1034
+ return true;
1035
+ }
1011
1036
  };
1012
1037
 
1013
1038
  // src/client/crud/dialects/postgresql.ts
@@ -1033,52 +1058,58 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1033
1058
  }
1034
1059
  }
1035
1060
  buildRelationSelection(query, model, relationField, parentAlias, payload) {
1036
- const joinedQuery = this.buildRelationJSON(model, query, relationField, parentAlias, payload);
1037
- return joinedQuery.select(`${parentAlias}$${relationField}.$j as ${relationField}`);
1061
+ const relationResultName = `${parentAlias}$${relationField}`;
1062
+ const joinedQuery = this.buildRelationJSON(model, query, relationField, parentAlias, payload, relationResultName);
1063
+ return joinedQuery.select(`${relationResultName}.$data as ${relationField}`);
1038
1064
  }
1039
- buildRelationJSON(model, qb, relationField, parentName, payload) {
1065
+ buildRelationJSON(model, qb, relationField, parentAlias, payload, resultName) {
1040
1066
  const relationFieldDef = requireField(this.schema, model, relationField);
1041
1067
  const relationModel = relationFieldDef.type;
1042
1068
  return qb.leftJoinLateral((eb) => {
1043
- const joinTableName = `${parentName}$${relationField}`;
1044
- let result = eb.selectFrom(`${relationModel} as ${joinTableName}`);
1045
- const subQueryAlias = `${relationModel}$${relationField}$sub`;
1046
- result = eb.selectFrom(() => {
1047
- let subQuery = this.buildSelectModel(eb, relationModel, subQueryAlias);
1048
- subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0, subQueryAlias);
1049
- if (payload && typeof payload === "object") {
1050
- subQuery = this.buildFilterSortTake(relationModel, payload, subQuery, subQueryAlias);
1051
- }
1052
- const m2m = getManyToManyRelation(this.schema, model, relationField);
1053
- if (m2m) {
1054
- const parentIds = getIdFields(this.schema, model);
1055
- const relationIds = getIdFields(this.schema, relationModel);
1056
- invariant2(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1057
- invariant2(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1058
- subQuery = subQuery.where(eb(eb.ref(`${subQueryAlias}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentName}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
1059
- } else {
1060
- const joinPairs = buildJoinPairs(this.schema, model, parentName, relationField, subQueryAlias);
1061
- subQuery = subQuery.where((eb2) => this.and(eb2, ...joinPairs.map(([left, right]) => eb2(sql2.ref(left), "=", sql2.ref(right)))));
1062
- }
1063
- return subQuery.as(joinTableName);
1064
- });
1065
- result = this.buildRelationObjectSelect(relationModel, joinTableName, relationField, relationFieldDef, result, payload, parentName);
1066
- result = this.buildRelationJoins(relationModel, relationField, result, payload, parentName);
1067
- return result.as(joinTableName);
1069
+ const relationSelectName = `${resultName}$sub`;
1070
+ const relationModelDef = requireModel(this.schema, relationModel);
1071
+ let tbl;
1072
+ if (this.canJoinWithoutNestedSelect(relationModelDef, payload)) {
1073
+ tbl = this.buildModelSelect(eb, relationModel, relationSelectName, payload, false);
1074
+ tbl = this.buildRelationJoinFilter(tbl, model, relationField, relationModel, relationSelectName, parentAlias);
1075
+ } else {
1076
+ tbl = eb.selectFrom(() => {
1077
+ let subQuery = this.buildModelSelect(eb, relationModel, `${relationSelectName}$t`, payload, true);
1078
+ subQuery = this.buildRelationJoinFilter(subQuery, model, relationField, relationModel, `${relationSelectName}$t`, parentAlias);
1079
+ return subQuery.as(relationSelectName);
1080
+ });
1081
+ }
1082
+ tbl = this.buildRelationObjectSelect(relationModel, relationSelectName, relationFieldDef, tbl, payload, resultName);
1083
+ tbl = this.buildRelationJoins(tbl, relationModel, relationSelectName, payload, resultName);
1084
+ return tbl.as(resultName);
1068
1085
  }, (join) => join.onTrue());
1069
1086
  }
1070
- buildRelationObjectSelect(relationModel, relationModelAlias, relationField, relationFieldDef, qb, payload, parentName) {
1087
+ buildRelationJoinFilter(query, model, relationField, relationModel, relationModelAlias, parentAlias) {
1088
+ const m2m = getManyToManyRelation(this.schema, model, relationField);
1089
+ if (m2m) {
1090
+ const parentIds = getIdFields(this.schema, model);
1091
+ const relationIds = getIdFields(this.schema, relationModel);
1092
+ invariant2(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1093
+ invariant2(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1094
+ query = query.where((eb) => eb(eb.ref(`${relationModelAlias}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentAlias}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
1095
+ } else {
1096
+ const joinPairs = buildJoinPairs(this.schema, model, parentAlias, relationField, relationModelAlias);
1097
+ query = query.where((eb) => this.and(eb, ...joinPairs.map(([left, right]) => eb(sql2.ref(left), "=", sql2.ref(right)))));
1098
+ }
1099
+ return query;
1100
+ }
1101
+ buildRelationObjectSelect(relationModel, relationModelAlias, relationFieldDef, qb, payload, parentResultName) {
1071
1102
  qb = qb.select((eb) => {
1072
- const objArgs = this.buildRelationObjectArgs(relationModel, relationModelAlias, relationField, eb, payload, parentName);
1103
+ const objArgs = this.buildRelationObjectArgs(relationModel, relationModelAlias, eb, payload, parentResultName);
1073
1104
  if (relationFieldDef.array) {
1074
- return eb.fn.coalesce(sql2`jsonb_agg(jsonb_build_object(${sql2.join(objArgs)}))`, sql2`'[]'::jsonb`).as("$j");
1105
+ return eb.fn.coalesce(sql2`jsonb_agg(jsonb_build_object(${sql2.join(objArgs)}))`, sql2`'[]'::jsonb`).as("$data");
1075
1106
  } else {
1076
- return sql2`jsonb_build_object(${sql2.join(objArgs)})`.as("$j");
1107
+ return sql2`jsonb_build_object(${sql2.join(objArgs)})`.as("$data");
1077
1108
  }
1078
1109
  });
1079
1110
  return qb;
1080
1111
  }
1081
- buildRelationObjectArgs(relationModel, relationModelAlias, relationField, eb, payload, parentAlias) {
1112
+ buildRelationObjectArgs(relationModel, relationModelAlias, eb, payload, parentResultName) {
1082
1113
  const relationModelDef = requireModel(this.schema, relationModel);
1083
1114
  const objArgs = [];
1084
1115
  const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
@@ -1096,14 +1127,14 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1096
1127
  } else if (payload.select) {
1097
1128
  objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
1098
1129
  if (field === "_count") {
1099
- const subJson = this.buildCountJson(relationModel, eb, `${parentAlias}$${relationField}`, value);
1130
+ const subJson = this.buildCountJson(relationModel, eb, relationModelAlias, value);
1100
1131
  return [
1101
1132
  sql2.lit(field),
1102
1133
  subJson
1103
1134
  ];
1104
1135
  } else {
1105
1136
  const fieldDef = requireField(this.schema, relationModel, field);
1106
- const fieldValue = fieldDef.relation ? eb.ref(`${parentAlias}$${relationField}$${field}.$j`) : this.fieldRef(relationModel, field, eb, void 0, false);
1137
+ const fieldValue = fieldDef.relation ? eb.ref(`${parentResultName}$${field}.$data`) : this.fieldRef(relationModel, field, eb, relationModelAlias, false);
1107
1138
  return [
1108
1139
  sql2.lit(field),
1109
1140
  fieldValue
@@ -1115,18 +1146,18 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1115
1146
  objArgs.push(...Object.entries(payload.include).filter(([, value]) => value).map(([field]) => [
1116
1147
  sql2.lit(field),
1117
1148
  // reference the synthesized JSON field
1118
- eb.ref(`${parentAlias}$${relationField}$${field}.$j`)
1149
+ eb.ref(`${parentResultName}$${field}.$data`)
1119
1150
  ]).flatMap((v) => v));
1120
1151
  }
1121
1152
  return objArgs;
1122
1153
  }
1123
- buildRelationJoins(relationModel, relationField, qb, payload, parentName) {
1124
- let result = qb;
1154
+ buildRelationJoins(query, relationModel, relationModelAlias, payload, parentResultName) {
1155
+ let result = query;
1125
1156
  if (typeof payload === "object") {
1126
1157
  const selectInclude = payload.include ?? payload.select;
1127
1158
  if (selectInclude && typeof selectInclude === "object") {
1128
1159
  Object.entries(selectInclude).filter(([, value]) => value).filter(([field]) => isRelationField(this.schema, relationModel, field)).forEach(([field, value]) => {
1129
- result = this.buildRelationJSON(relationModel, result, field, `${parentName}$${relationField}`, value);
1160
+ result = this.buildRelationJSON(relationModel, result, field, relationModelAlias, value, `${parentResultName}$${field}`);
1130
1161
  });
1131
1162
  }
1132
1163
  }
@@ -1206,32 +1237,18 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1206
1237
  const relationModel = relationFieldDef.type;
1207
1238
  const relationModelDef = requireModel(this.schema, relationModel);
1208
1239
  const subQueryName = `${parentAlias}$${relationField}`;
1209
- let tbl = eb.selectFrom(() => {
1210
- const subQueryAlias = `${parentAlias}$${relationField}$sub`;
1211
- let subQuery = this.buildSelectModel(eb, relationModel, subQueryAlias);
1212
- subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0, subQueryAlias);
1213
- if (payload && typeof payload === "object") {
1214
- subQuery = this.buildFilterSortTake(relationModel, payload, subQuery, subQueryAlias);
1215
- }
1216
- const m2m = getManyToManyRelation(this.schema, model, relationField);
1217
- if (m2m) {
1218
- const parentIds = getIdFields(this.schema, model);
1219
- const relationIds = getIdFields(this.schema, relationModel);
1220
- invariant3(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1221
- invariant3(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1222
- subQuery = subQuery.where(eb(eb.ref(`${subQueryAlias}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentAlias}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
1223
- } else {
1224
- const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
1225
- keyPairs.forEach(({ fk, pk }) => {
1226
- if (ownedByModel) {
1227
- subQuery = subQuery.whereRef(`${subQueryAlias}.${pk}`, "=", `${parentAlias}.${fk}`);
1228
- } else {
1229
- subQuery = subQuery.whereRef(`${subQueryAlias}.${fk}`, "=", `${parentAlias}.${pk}`);
1230
- }
1231
- });
1232
- }
1233
- return subQuery.as(subQueryName);
1234
- });
1240
+ let tbl;
1241
+ if (this.canJoinWithoutNestedSelect(relationModelDef, payload)) {
1242
+ tbl = this.buildModelSelect(eb, relationModel, subQueryName, payload, false);
1243
+ tbl = this.buildRelationJoinFilter(tbl, model, relationField, subQueryName, parentAlias);
1244
+ } else {
1245
+ tbl = eb.selectFrom(() => {
1246
+ const selectModelAlias = `${parentAlias}$${relationField}$sub`;
1247
+ let selectModelQuery = this.buildModelSelect(eb, relationModel, selectModelAlias, payload, true);
1248
+ selectModelQuery = this.buildRelationJoinFilter(selectModelQuery, model, relationField, selectModelAlias, parentAlias);
1249
+ return selectModelQuery.as(subQueryName);
1250
+ });
1251
+ }
1235
1252
  tbl = tbl.select(() => {
1236
1253
  const objArgs = [];
1237
1254
  const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
@@ -1244,7 +1261,7 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1244
1261
  if (payload === true || !payload.select) {
1245
1262
  objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
1246
1263
  sql3.lit(field),
1247
- this.fieldRef(relationModel, field, eb, void 0, false)
1264
+ this.fieldRef(relationModel, field, eb, subQueryName, false)
1248
1265
  ]).flatMap((v) => v));
1249
1266
  } else if (payload.select) {
1250
1267
  objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
@@ -1265,7 +1282,7 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1265
1282
  } else {
1266
1283
  return [
1267
1284
  sql3.lit(field),
1268
- this.fieldRef(relationModel, field, eb, void 0, false)
1285
+ this.fieldRef(relationModel, field, eb, subQueryName, false)
1269
1286
  ];
1270
1287
  }
1271
1288
  }
@@ -1281,13 +1298,35 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1281
1298
  }).flatMap((v) => v));
1282
1299
  }
1283
1300
  if (relationFieldDef.array) {
1284
- return eb.fn.coalesce(sql3`json_group_array(json_object(${sql3.join(objArgs)}))`, sql3`json_array()`).as("$j");
1301
+ return eb.fn.coalesce(sql3`json_group_array(json_object(${sql3.join(objArgs)}))`, sql3`json_array()`).as("$data");
1285
1302
  } else {
1286
- return sql3`json_object(${sql3.join(objArgs)})`.as("data");
1303
+ return sql3`json_object(${sql3.join(objArgs)})`.as("$data");
1287
1304
  }
1288
1305
  });
1289
1306
  return tbl;
1290
1307
  }
1308
+ buildRelationJoinFilter(selectModelQuery, model, relationField, relationModelAlias, parentAlias) {
1309
+ const fieldDef = requireField(this.schema, model, relationField);
1310
+ const relationModel = fieldDef.type;
1311
+ const m2m = getManyToManyRelation(this.schema, model, relationField);
1312
+ if (m2m) {
1313
+ const parentIds = getIdFields(this.schema, model);
1314
+ const relationIds = getIdFields(this.schema, relationModel);
1315
+ invariant3(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1316
+ invariant3(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1317
+ selectModelQuery = selectModelQuery.where((eb) => eb(eb.ref(`${relationModelAlias}.${relationIds[0]}`), "in", eb.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(`${parentAlias}.${parentIds[0]}`, "=", `${m2m.joinTable}.${m2m.parentFkName}`)));
1318
+ } else {
1319
+ const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
1320
+ keyPairs.forEach(({ fk, pk }) => {
1321
+ if (ownedByModel) {
1322
+ selectModelQuery = selectModelQuery.whereRef(`${relationModelAlias}.${pk}`, "=", `${parentAlias}.${fk}`);
1323
+ } else {
1324
+ selectModelQuery = selectModelQuery.whereRef(`${relationModelAlias}.${fk}`, "=", `${parentAlias}.${pk}`);
1325
+ }
1326
+ });
1327
+ }
1328
+ return selectModelQuery;
1329
+ }
1291
1330
  buildSkipTake(query, skip, take) {
1292
1331
  if (take !== void 0) {
1293
1332
  query = query.limit(take);