@zenstackhq/runtime 3.0.0-alpha.28 → 3.0.0-alpha.29

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.
@@ -287,7 +287,9 @@ function buildFieldRef(schema, model, field, options, eb, modelAlias, inlineComp
287
287
  if (!computer) {
288
288
  throw new QueryError(`Computed field "${field}" implementation not provided for model "${model}"`);
289
289
  }
290
- return computer(eb);
290
+ return computer(eb, {
291
+ currentModel: modelAlias
292
+ });
291
293
  }
292
294
  }
293
295
  __name(buildFieldRef, "buildFieldRef");
@@ -330,11 +332,33 @@ function getManyToManyRelation(schema, model, field) {
330
332
  model,
331
333
  fieldDef.type
332
334
  ].sort();
335
+ let orderedFK;
336
+ if (model !== fieldDef.type) {
337
+ orderedFK = sortedModelNames[0] === model ? [
338
+ "A",
339
+ "B"
340
+ ] : [
341
+ "B",
342
+ "A"
343
+ ];
344
+ } else {
345
+ const sortedFieldNames = [
346
+ field,
347
+ oppositeFieldDef.name
348
+ ].sort();
349
+ orderedFK = sortedFieldNames[0] === field ? [
350
+ "A",
351
+ "B"
352
+ ] : [
353
+ "B",
354
+ "A"
355
+ ];
356
+ }
333
357
  return {
334
- parentFkName: sortedModelNames[0] === model ? "A" : "B",
358
+ parentFkName: orderedFK[0],
335
359
  otherModel: fieldDef.type,
336
360
  otherField: fieldDef.relation.opposite,
337
- otherFkName: sortedModelNames[0] === fieldDef.type ? "A" : "B",
361
+ otherFkName: orderedFK[1],
338
362
  joinTable: fieldDef.relation.name ? `_${fieldDef.relation.name}` : `_${sortedModelNames[0]}To${sortedModelNames[1]}`
339
363
  };
340
364
  } else {
@@ -424,20 +448,20 @@ var BaseCrudDialect = class {
424
448
  return value;
425
449
  }
426
450
  // #region common query builders
427
- buildSelectModel(eb, model) {
451
+ buildSelectModel(eb, model, modelAlias) {
428
452
  const modelDef = requireModel(this.schema, model);
429
- let result = eb.selectFrom(model);
453
+ let result = eb.selectFrom(model === modelAlias ? model : `${model} as ${modelAlias}`);
430
454
  let joinBase = modelDef.baseModel;
431
455
  while (joinBase) {
432
- result = this.buildDelegateJoin(model, joinBase, result);
456
+ result = this.buildDelegateJoin(model, modelAlias, joinBase, result);
433
457
  joinBase = requireModel(this.schema, joinBase).baseModel;
434
458
  }
435
459
  return result;
436
460
  }
437
- buildFilterSortTake(model, args, query) {
461
+ buildFilterSortTake(model, args, query, modelAlias) {
438
462
  let result = query;
439
463
  if (args.where) {
440
- result = result.where((eb) => this.buildFilter(eb, model, model, args?.where));
464
+ result = result.where((eb) => this.buildFilter(eb, model, modelAlias, args?.where));
441
465
  }
442
466
  let negateOrderBy = false;
443
467
  const skip = args.skip;
@@ -447,17 +471,17 @@ var BaseCrudDialect = class {
447
471
  take = -take;
448
472
  }
449
473
  result = this.buildSkipTake(result, skip, take);
450
- result = this.buildOrderBy(result, model, model, args.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
474
+ result = this.buildOrderBy(result, model, modelAlias, args.orderBy, skip !== void 0 || take !== void 0, negateOrderBy);
451
475
  if ("distinct" in args && args.distinct) {
452
476
  const distinct = ensureArray(args.distinct);
453
477
  if (this.supportsDistinctOn) {
454
- result = result.distinctOn(distinct.map((f) => import_kysely.sql.ref(`${model}.${f}`)));
478
+ result = result.distinctOn(distinct.map((f) => import_kysely.sql.ref(`${modelAlias}.${f}`)));
455
479
  } else {
456
480
  throw new QueryError(`"distinct" is not supported by "${this.schema.provider.type}" provider`);
457
481
  }
458
482
  }
459
483
  if (args.cursor) {
460
- result = this.buildCursorFilter(model, result, args.cursor, args.orderBy, negateOrderBy);
484
+ result = this.buildCursorFilter(model, result, args.cursor, args.orderBy, negateOrderBy, modelAlias);
461
485
  }
462
486
  return result;
463
487
  }
@@ -498,11 +522,12 @@ var BaseCrudDialect = class {
498
522
  }
499
523
  return result;
500
524
  }
501
- buildCursorFilter(model, query, cursor, orderBy, negateOrderBy) {
525
+ buildCursorFilter(model, query, cursor, orderBy, negateOrderBy, modelAlias) {
502
526
  const _orderBy = orderBy ?? makeDefaultOrderBy(this.schema, model);
503
527
  const orderByItems = ensureArray(_orderBy).flatMap((obj) => Object.entries(obj));
504
528
  const eb = (0, import_kysely.expressionBuilder)();
505
- const cursorFilter = this.buildFilter(eb, model, model, cursor);
529
+ const subQueryAlias = `${model}$cursor$sub`;
530
+ const cursorFilter = this.buildFilter(eb, model, subQueryAlias, cursor);
506
531
  let result = query;
507
532
  const filters = [];
508
533
  for (let i = orderByItems.length - 1; i >= 0; i--) {
@@ -511,7 +536,7 @@ var BaseCrudDialect = class {
511
536
  const [field, order] = orderByItems[j];
512
537
  const _order = negateOrderBy ? order === "asc" ? "desc" : "asc" : order;
513
538
  const op = j === i ? _order === "asc" ? ">=" : "<=" : "=";
514
- andFilters.push(eb(eb.ref(`${model}.${field}`), op, eb.selectFrom(model).select(`${model}.${field}`).where(cursorFilter)));
539
+ andFilters.push(eb(eb.ref(`${modelAlias}.${field}`), op, this.buildSelectModel(eb, model, subQueryAlias).select(`${subQueryAlias}.${field}`).where(cursorFilter)));
515
540
  }
516
541
  filters.push(eb.and(andFilters));
517
542
  }
@@ -580,25 +605,26 @@ var BaseCrudDialect = class {
580
605
  }
581
606
  return this.and(eb, ...conditions);
582
607
  }
583
- buildToManyRelationFilter(eb, model, table, field, fieldDef, payload) {
608
+ buildToManyRelationFilter(eb, model, modelAlias, field, fieldDef, payload) {
584
609
  if (payload === null) {
585
- return eb(import_kysely.sql.ref(`${table}.${field}`), "is", null);
610
+ return eb(import_kysely.sql.ref(`${modelAlias}.${field}`), "is", null);
586
611
  }
587
612
  const relationModel = fieldDef.type;
613
+ const relationFilterSelectAlias = `${modelAlias}$${field}$filter`;
588
614
  const buildPkFkWhereRefs = /* @__PURE__ */ __name((eb2) => {
589
615
  const m2m = getManyToManyRelation(this.schema, model, field);
590
616
  if (m2m) {
591
617
  const modelIdField = getIdFields(this.schema, model)[0];
592
618
  const relationIdField = getIdFields(this.schema, relationModel)[0];
593
- return eb2(import_kysely.sql.ref(`${relationModel}.${relationIdField}`), "in", eb2.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(import_kysely.sql.ref(`${m2m.joinTable}.${m2m.parentFkName}`), "=", import_kysely.sql.ref(`${table}.${modelIdField}`)));
619
+ return eb2(import_kysely.sql.ref(`${relationFilterSelectAlias}.${relationIdField}`), "in", eb2.selectFrom(m2m.joinTable).select(`${m2m.joinTable}.${m2m.otherFkName}`).whereRef(import_kysely.sql.ref(`${m2m.joinTable}.${m2m.parentFkName}`), "=", import_kysely.sql.ref(`${modelAlias}.${modelIdField}`)));
594
620
  } else {
595
621
  const relationKeyPairs = getRelationForeignKeyFieldPairs(this.schema, model, field);
596
622
  let result2 = this.true(eb2);
597
623
  for (const { fk, pk } of relationKeyPairs.keyPairs) {
598
624
  if (relationKeyPairs.ownedByModel) {
599
- result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${table}.${fk}`), "=", import_kysely.sql.ref(`${relationModel}.${pk}`)));
625
+ result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${modelAlias}.${fk}`), "=", import_kysely.sql.ref(`${relationFilterSelectAlias}.${pk}`)));
600
626
  } else {
601
- result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${table}.${pk}`), "=", import_kysely.sql.ref(`${relationModel}.${fk}`)));
627
+ result2 = this.and(eb2, result2, eb2(import_kysely.sql.ref(`${modelAlias}.${pk}`), "=", import_kysely.sql.ref(`${relationFilterSelectAlias}.${fk}`)));
602
628
  }
603
629
  }
604
630
  return result2;
@@ -611,15 +637,15 @@ var BaseCrudDialect = class {
611
637
  }
612
638
  switch (key) {
613
639
  case "some": {
614
- result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => this.buildFilter(eb1, relationModel, relationModel, subPayload)), ">", 0));
640
+ result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel, relationFilterSelectAlias).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => this.buildFilter(eb1, relationModel, relationFilterSelectAlias, subPayload)), ">", 0));
615
641
  break;
616
642
  }
617
643
  case "every": {
618
- result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => eb1.not(this.buildFilter(eb1, relationModel, relationModel, subPayload))), "=", 0));
644
+ result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel, relationFilterSelectAlias).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => eb1.not(this.buildFilter(eb1, relationModel, relationFilterSelectAlias, subPayload))), "=", 0));
619
645
  break;
620
646
  }
621
647
  case "none": {
622
- result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => this.buildFilter(eb1, relationModel, relationModel, subPayload)), "=", 0));
648
+ result = this.and(eb, result, eb(this.buildSelectModel(eb, relationModel, relationFilterSelectAlias).select((eb1) => eb1.fn.count(eb1.lit(1)).as("$count")).where(buildPkFkWhereRefs(eb)).where((eb1) => this.buildFilter(eb1, relationModel, relationFilterSelectAlias, subPayload)), "=", 0));
623
649
  break;
624
650
  }
625
651
  }
@@ -862,8 +888,9 @@ var BaseCrudDialect = class {
862
888
  (0, import_common_helpers.invariant)(value._count === "asc" || value._count === "desc", 'invalid orderBy value for field "_count"');
863
889
  const sort = this.negateSort(value._count, negated);
864
890
  result = result.orderBy((eb) => {
865
- let subQuery = this.buildSelectModel(eb, relationModel);
866
- const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, relationModel);
891
+ const subQueryAlias = `${modelAlias}$orderBy$${field}$count`;
892
+ let subQuery = this.buildSelectModel(eb, relationModel, subQueryAlias);
893
+ const joinPairs = buildJoinPairs(this.schema, model, modelAlias, field, subQueryAlias);
867
894
  subQuery = subQuery.where(() => this.and(eb, ...joinPairs.map(([left, right]) => eb(import_kysely.sql.ref(left), "=", import_kysely.sql.ref(right)))));
868
895
  subQuery = subQuery.select(() => eb.fn.count(eb.lit(1)).as("_count"));
869
896
  return subQuery;
@@ -881,7 +908,7 @@ var BaseCrudDialect = class {
881
908
  });
882
909
  return result;
883
910
  }
884
- buildSelectAllFields(model, query, omit) {
911
+ buildSelectAllFields(model, query, omit, modelAlias) {
885
912
  const modelDef = requireModel(this.schema, model);
886
913
  let result = query;
887
914
  for (const field of Object.keys(modelDef.fields)) {
@@ -891,11 +918,11 @@ var BaseCrudDialect = class {
891
918
  if (omit?.[field] === true) {
892
919
  continue;
893
920
  }
894
- result = this.buildSelectField(result, model, model, field);
921
+ result = this.buildSelectField(result, model, modelAlias, field);
895
922
  }
896
923
  const descendants = getDelegateDescendantModels(this.schema, model);
897
924
  for (const subModel of descendants) {
898
- result = this.buildDelegateJoin(model, subModel.name, result);
925
+ result = this.buildDelegateJoin(model, modelAlias, subModel.name, result);
899
926
  result = result.select((eb) => {
900
927
  const jsonObject = {};
901
928
  for (const field of Object.keys(subModel.fields)) {
@@ -919,11 +946,11 @@ var BaseCrudDialect = class {
919
946
  return this.buildSelectField(query, fieldDef.originModel, fieldDef.originModel, field);
920
947
  }
921
948
  }
922
- buildDelegateJoin(thisModel, otherModel, query) {
949
+ buildDelegateJoin(thisModel, thisModelAlias, otherModelAlias, query) {
923
950
  const idFields = getIdFields(this.schema, thisModel);
924
- query = query.leftJoin(otherModel, (qb) => {
951
+ query = query.leftJoin(otherModelAlias, (qb) => {
925
952
  for (const idField of idFields) {
926
- qb = qb.onRef(`${thisModel}.${idField}`, "=", `${otherModel}.${idField}`);
953
+ qb = qb.onRef(`${thisModelAlias}.${idField}`, "=", `${otherModelAlias}.${idField}`);
927
954
  }
928
955
  return qb;
929
956
  });
@@ -1040,11 +1067,12 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1040
1067
  return qb.leftJoinLateral((eb) => {
1041
1068
  const joinTableName = `${parentName}$${relationField}`;
1042
1069
  let result = eb.selectFrom(`${relationModel} as ${joinTableName}`);
1070
+ const subQueryAlias = `${relationModel}$${relationField}$sub`;
1043
1071
  result = eb.selectFrom(() => {
1044
- let subQuery = this.buildSelectModel(eb, relationModel);
1045
- subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0);
1072
+ let subQuery = this.buildSelectModel(eb, relationModel, subQueryAlias);
1073
+ subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0, subQueryAlias);
1046
1074
  if (payload && typeof payload === "object") {
1047
- subQuery = this.buildFilterSortTake(relationModel, payload, subQuery);
1075
+ subQuery = this.buildFilterSortTake(relationModel, payload, subQuery, subQueryAlias);
1048
1076
  }
1049
1077
  const m2m = getManyToManyRelation(this.schema, model, relationField);
1050
1078
  if (m2m) {
@@ -1052,21 +1080,21 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1052
1080
  const relationIds = getIdFields(this.schema, relationModel);
1053
1081
  (0, import_common_helpers2.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1054
1082
  (0, import_common_helpers2.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1055
- 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}`)));
1083
+ 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}`)));
1056
1084
  } else {
1057
- const joinPairs = buildJoinPairs(this.schema, model, parentName, relationField, relationModel);
1085
+ const joinPairs = buildJoinPairs(this.schema, model, parentName, relationField, subQueryAlias);
1058
1086
  subQuery = subQuery.where((eb2) => this.and(eb2, ...joinPairs.map(([left, right]) => eb2(import_kysely2.sql.ref(left), "=", import_kysely2.sql.ref(right)))));
1059
1087
  }
1060
1088
  return subQuery.as(joinTableName);
1061
1089
  });
1062
- result = this.buildRelationObjectSelect(relationModel, relationField, relationFieldDef, result, payload, parentName);
1090
+ result = this.buildRelationObjectSelect(relationModel, joinTableName, relationField, relationFieldDef, result, payload, parentName);
1063
1091
  result = this.buildRelationJoins(relationModel, relationField, result, payload, parentName);
1064
1092
  return result.as(joinTableName);
1065
1093
  }, (join) => join.onTrue());
1066
1094
  }
1067
- buildRelationObjectSelect(relationModel, relationField, relationFieldDef, qb, payload, parentName) {
1095
+ buildRelationObjectSelect(relationModel, relationModelAlias, relationField, relationFieldDef, qb, payload, parentName) {
1068
1096
  qb = qb.select((eb) => {
1069
- const objArgs = this.buildRelationObjectArgs(relationModel, relationField, eb, payload, parentName);
1097
+ const objArgs = this.buildRelationObjectArgs(relationModel, relationModelAlias, relationField, eb, payload, parentName);
1070
1098
  if (relationFieldDef.array) {
1071
1099
  return eb.fn.coalesce(import_kysely2.sql`jsonb_agg(jsonb_build_object(${import_kysely2.sql.join(objArgs)}))`, import_kysely2.sql`'[]'::jsonb`).as("$j");
1072
1100
  } else {
@@ -1075,7 +1103,7 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1075
1103
  });
1076
1104
  return qb;
1077
1105
  }
1078
- buildRelationObjectArgs(relationModel, relationField, eb, payload, parentAlias) {
1106
+ buildRelationObjectArgs(relationModel, relationModelAlias, relationField, eb, payload, parentAlias) {
1079
1107
  const relationModelDef = requireModel(this.schema, relationModel);
1080
1108
  const objArgs = [];
1081
1109
  const descendantModels = getDelegateDescendantModels(this.schema, relationModel);
@@ -1088,7 +1116,7 @@ var PostgresCrudDialect = class extends BaseCrudDialect {
1088
1116
  if (payload === true || !payload.select) {
1089
1117
  objArgs.push(...Object.entries(relationModelDef.fields).filter(([, value]) => !value.relation).filter(([name]) => !(typeof payload === "object" && payload.omit?.[name] === true)).map(([field]) => [
1090
1118
  import_kysely2.sql.lit(field),
1091
- this.fieldRef(relationModel, field, eb, void 0, false)
1119
+ this.fieldRef(relationModel, field, eb, relationModelAlias, false)
1092
1120
  ]).flatMap((v) => v));
1093
1121
  } else if (payload.select) {
1094
1122
  objArgs.push(...Object.entries(payload.select).filter(([, value]) => value).map(([field, value]) => {
@@ -1204,10 +1232,11 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1204
1232
  const relationModelDef = requireModel(this.schema, relationModel);
1205
1233
  const subQueryName = `${parentAlias}$${relationField}`;
1206
1234
  let tbl = eb.selectFrom(() => {
1207
- let subQuery = this.buildSelectModel(eb, relationModel);
1208
- subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0);
1235
+ const subQueryAlias = `${parentAlias}$${relationField}$sub`;
1236
+ let subQuery = this.buildSelectModel(eb, relationModel, subQueryAlias);
1237
+ subQuery = this.buildSelectAllFields(relationModel, subQuery, typeof payload === "object" ? payload?.omit : void 0, subQueryAlias);
1209
1238
  if (payload && typeof payload === "object") {
1210
- subQuery = this.buildFilterSortTake(relationModel, payload, subQuery);
1239
+ subQuery = this.buildFilterSortTake(relationModel, payload, subQuery, subQueryAlias);
1211
1240
  }
1212
1241
  const m2m = getManyToManyRelation(this.schema, model, relationField);
1213
1242
  if (m2m) {
@@ -1215,14 +1244,14 @@ var SqliteCrudDialect = class extends BaseCrudDialect {
1215
1244
  const relationIds = getIdFields(this.schema, relationModel);
1216
1245
  (0, import_common_helpers3.invariant)(parentIds.length === 1, "many-to-many relation must have exactly one id field");
1217
1246
  (0, import_common_helpers3.invariant)(relationIds.length === 1, "many-to-many relation must have exactly one id field");
1218
- 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}`)));
1247
+ 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}`)));
1219
1248
  } else {
1220
1249
  const { keyPairs, ownedByModel } = getRelationForeignKeyFieldPairs(this.schema, model, relationField);
1221
1250
  keyPairs.forEach(({ fk, pk }) => {
1222
1251
  if (ownedByModel) {
1223
- subQuery = subQuery.whereRef(`${relationModel}.${pk}`, "=", `${parentAlias}.${fk}`);
1252
+ subQuery = subQuery.whereRef(`${subQueryAlias}.${pk}`, "=", `${parentAlias}.${fk}`);
1224
1253
  } else {
1225
- subQuery = subQuery.whereRef(`${relationModel}.${fk}`, "=", `${parentAlias}.${pk}`);
1254
+ subQuery = subQuery.whereRef(`${subQueryAlias}.${fk}`, "=", `${parentAlias}.${pk}`);
1226
1255
  }
1227
1256
  });
1228
1257
  }