@zenstackhq/runtime 3.0.0-beta.11 → 3.0.0-beta.12

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/index.cjs CHANGED
@@ -1937,7 +1937,7 @@ var BaseOperationHandler = class {
1937
1937
  buildCountSelection(query, model, parentAlias, payload) {
1938
1938
  return query.select((eb) => this.dialect.buildCountJson(model, eb, parentAlias, payload).as("_count"));
1939
1939
  }
1940
- async create(kysely, model, data, fromRelation, creatingForDelegate = false) {
1940
+ async create(kysely, model, data, fromRelation, creatingForDelegate = false, returnFields) {
1941
1941
  const modelDef = this.requireModel(model);
1942
1942
  if (modelDef.isDelegate && !creatingForDelegate) {
1943
1943
  throw new QueryError(`Model "${this.model}" is a delegate and cannot be created directly.`);
@@ -1990,8 +1990,8 @@ var BaseOperationHandler = class {
1990
1990
  createFields = baseCreateResult.remainingFields;
1991
1991
  }
1992
1992
  const updatedData = this.fillGeneratedAndDefaultValues(modelDef, createFields);
1993
- const idFields = requireIdFields(this.schema, model);
1994
- const query = kysely.insertInto(model).$if(Object.keys(updatedData).length === 0, (qb) => qb.defaultValues()).$if(Object.keys(updatedData).length > 0, (qb) => qb.values(updatedData)).returning(idFields).modifyEnd(this.makeContextComment({
1993
+ returnFields = returnFields ?? requireIdFields(this.schema, model);
1994
+ const query = kysely.insertInto(model).$if(Object.keys(updatedData).length === 0, (qb) => qb.defaultValues()).$if(Object.keys(updatedData).length > 0, (qb) => qb.values(updatedData)).returning(returnFields).modifyEnd(this.makeContextComment({
1995
1995
  model,
1996
1996
  operation: "create"
1997
1997
  }));
@@ -2196,7 +2196,7 @@ var BaseOperationHandler = class {
2196
2196
  }
2197
2197
  }
2198
2198
  }
2199
- async createMany(kysely, model, input, returnData, fromRelation) {
2199
+ async createMany(kysely, model, input, returnData, fromRelation, fieldsToReturn) {
2200
2200
  if (!input.data || Array.isArray(input.data) && input.data.length === 0) {
2201
2201
  return returnData ? [] : {
2202
2202
  count: 0
@@ -2265,8 +2265,8 @@ var BaseOperationHandler = class {
2265
2265
  count: Number(result.numAffectedRows)
2266
2266
  };
2267
2267
  } else {
2268
- const idFields = requireIdFields(this.schema, model);
2269
- const result = await query.returning(idFields).execute();
2268
+ fieldsToReturn = fieldsToReturn ?? requireIdFields(this.schema, model);
2269
+ const result = await query.returning(fieldsToReturn).execute();
2270
2270
  return result;
2271
2271
  }
2272
2272
  }
@@ -2346,7 +2346,7 @@ var BaseOperationHandler = class {
2346
2346
  return void 0;
2347
2347
  }
2348
2348
  }
2349
- async update(kysely, model, where, data, fromRelation, allowRelationUpdate = true, throwIfNotFound = true) {
2349
+ async update(kysely, model, where, data, fromRelation, allowRelationUpdate = true, throwIfNotFound = true, fieldsToReturn) {
2350
2350
  if (!data || typeof data !== "object") {
2351
2351
  throw new InternalError("data must be an object");
2352
2352
  }
@@ -2452,8 +2452,8 @@ var BaseOperationHandler = class {
2452
2452
  if (!hasFieldUpdate) {
2453
2453
  return combinedWhere;
2454
2454
  } else {
2455
- const idFields = requireIdFields(this.schema, model);
2456
- const query = kysely.updateTable(model).where(() => this.dialect.buildFilter(model, model, combinedWhere)).set(updateFields).returning(idFields).modifyEnd(this.makeContextComment({
2455
+ fieldsToReturn = fieldsToReturn ?? requireIdFields(this.schema, model);
2456
+ const query = kysely.updateTable(model).where(() => this.dialect.buildFilter(model, model, combinedWhere)).set(updateFields).returning(fieldsToReturn).modifyEnd(this.makeContextComment({
2457
2457
  model,
2458
2458
  operation: "update"
2459
2459
  }));
@@ -2545,7 +2545,7 @@ var BaseOperationHandler = class {
2545
2545
  makeContextComment(_context) {
2546
2546
  return import_kysely5.sql``;
2547
2547
  }
2548
- async updateMany(kysely, model, where, data, limit, returnData, filterModel) {
2548
+ async updateMany(kysely, model, where, data, limit, returnData, filterModel, fieldsToReturn) {
2549
2549
  if (typeof data !== "object") {
2550
2550
  throw new InternalError("data must be an object");
2551
2551
  }
@@ -2602,8 +2602,8 @@ var BaseOperationHandler = class {
2602
2602
  count: Number(result.numAffectedRows)
2603
2603
  };
2604
2604
  } else {
2605
- const idFields = requireIdFields(this.schema, model);
2606
- const finalQuery = query.returning(idFields);
2605
+ fieldsToReturn = fieldsToReturn ?? requireIdFields(this.schema, model);
2606
+ const finalQuery = query.returning(fieldsToReturn);
2607
2607
  const result = await this.executeQuery(kysely, finalQuery, "update");
2608
2608
  return result.rows;
2609
2609
  }
@@ -3007,7 +3007,7 @@ var BaseOperationHandler = class {
3007
3007
  });
3008
3008
  }
3009
3009
  }
3010
- if (throwForNotFound && expectedDeleteCount > deleteResult.count) {
3010
+ if (throwForNotFound && expectedDeleteCount > deleteResult.rows.length) {
3011
3011
  throw new NotFoundError(deleteFromModel);
3012
3012
  }
3013
3013
  }
@@ -3015,7 +3015,7 @@ var BaseOperationHandler = class {
3015
3015
  return enumerate(data).map((item) => flattenCompoundUniqueFilters(this.schema, model, item));
3016
3016
  }
3017
3017
  // #endregion
3018
- async delete(kysely, model, where, limit, filterModel) {
3018
+ async delete(kysely, model, where, limit, filterModel, fieldsToReturn) {
3019
3019
  filterModel ??= model;
3020
3020
  const modelDef = this.requireModel(model);
3021
3021
  if (modelDef.baseModel) {
@@ -3024,7 +3024,8 @@ var BaseOperationHandler = class {
3024
3024
  }
3025
3025
  return this.processBaseModelDelete(kysely, modelDef.baseModel, where, limit, filterModel);
3026
3026
  }
3027
- let query = kysely.deleteFrom(model);
3027
+ fieldsToReturn = fieldsToReturn ?? requireIdFields(this.schema, model);
3028
+ let query = kysely.deleteFrom(model).returning(fieldsToReturn);
3028
3029
  let needIdFilter = false;
3029
3030
  if (limit !== void 0 && !this.dialect.supportsDeleteWithLimit) {
3030
3031
  needIdFilter = true;
@@ -3044,10 +3045,7 @@ var BaseOperationHandler = class {
3044
3045
  model,
3045
3046
  operation: "delete"
3046
3047
  }));
3047
- const result = await this.executeQuery(kysely, query, "delete");
3048
- return {
3049
- count: Number(result.numAffectedRows)
3050
- };
3048
+ return this.executeQuery(kysely, query, "delete");
3051
3049
  }
3052
3050
  async processDelegateRelationDelete(kysely, modelDef, where, limit) {
3053
3051
  for (const fieldDef of Object.values(modelDef.fields)) {
@@ -3101,7 +3099,7 @@ var BaseOperationHandler = class {
3101
3099
  return callback(this.kysely);
3102
3100
  } else {
3103
3101
  let txBuilder = this.kysely.transaction();
3104
- txBuilder = txBuilder.setIsolationLevel(isolationLevel ?? TransactionIsolationLevel.RepeatableRead);
3102
+ txBuilder = txBuilder.setIsolationLevel(isolationLevel ?? TransactionIsolationLevel.ReadCommitted);
3105
3103
  return txBuilder.execute(callback);
3106
3104
  }
3107
3105
  }
@@ -3153,6 +3151,48 @@ var BaseOperationHandler = class {
3153
3151
  }
3154
3152
  return result.rows[0];
3155
3153
  }
3154
+ mutationNeedsReadBack(model, args) {
3155
+ if (this.hasPolicyEnabled) {
3156
+ return {
3157
+ needReadBack: true,
3158
+ selectedFields: void 0
3159
+ };
3160
+ }
3161
+ if (args.include && typeof args.include === "object" && Object.keys(args.include).length > 0) {
3162
+ return {
3163
+ needReadBack: true,
3164
+ selectedFields: void 0
3165
+ };
3166
+ }
3167
+ const modelDef = this.requireModel(model);
3168
+ if (modelDef.baseModel || modelDef.isDelegate) {
3169
+ return {
3170
+ needReadBack: true,
3171
+ selectedFields: void 0
3172
+ };
3173
+ }
3174
+ const allFields = Object.keys(modelDef.fields);
3175
+ const relationFields = Object.values(modelDef.fields).filter((f) => f.relation).map((f) => f.name);
3176
+ const computedFields = Object.values(modelDef.fields).filter((f) => f.computed).map((f) => f.name);
3177
+ const omit = Object.entries(args.omit ?? {}).filter(([, v]) => v).map(([k]) => k);
3178
+ const allFieldsSelected = [];
3179
+ if (!args.select || typeof args.select !== "object") {
3180
+ allFieldsSelected.push(...allFields.filter((f) => !relationFields.includes(f) && !omit.includes(f)));
3181
+ } else {
3182
+ allFieldsSelected.push(...Object.entries(args.select).filter(([k, v]) => v && !omit.includes(k)).map(([k]) => k));
3183
+ }
3184
+ if (allFieldsSelected.some((f) => relationFields.includes(f) || computedFields.includes(f))) {
3185
+ return {
3186
+ needReadBack: true,
3187
+ selectedFields: void 0
3188
+ };
3189
+ } else {
3190
+ return {
3191
+ needReadBack: false,
3192
+ selectedFields: allFieldsSelected
3193
+ };
3194
+ }
3195
+ }
3156
3196
  };
3157
3197
 
3158
3198
  // src/client/crud/operations/aggregate.ts
@@ -3313,14 +3353,19 @@ var CreateOperationHandler = class extends BaseOperationHandler {
3313
3353
  }).exhaustive();
3314
3354
  }
3315
3355
  async runCreate(args) {
3356
+ const { needReadBack, selectedFields } = this.mutationNeedsReadBack(this.model, args);
3316
3357
  const result = await this.safeTransaction(async (tx) => {
3317
- const createResult = await this.create(tx, this.model, args.data);
3318
- return this.readUnique(tx, this.model, {
3319
- select: args.select,
3320
- include: args.include,
3321
- omit: args.omit,
3322
- where: getIdValues(this.schema, this.model, createResult)
3323
- });
3358
+ const createResult = await this.create(tx, this.model, args.data, void 0, false, selectedFields);
3359
+ if (needReadBack) {
3360
+ return this.readUnique(tx, this.model, {
3361
+ select: args.select,
3362
+ include: args.include,
3363
+ omit: args.omit,
3364
+ where: getIdValues(this.schema, this.model, createResult)
3365
+ });
3366
+ } else {
3367
+ return createResult;
3368
+ }
3324
3369
  });
3325
3370
  if (!result && this.hasPolicyEnabled) {
3326
3371
  throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, `result is not allowed to be read back`);
@@ -3339,15 +3384,20 @@ var CreateOperationHandler = class extends BaseOperationHandler {
3339
3384
  if (args === void 0) {
3340
3385
  return [];
3341
3386
  }
3387
+ const { needReadBack, selectedFields } = this.mutationNeedsReadBack(this.model, args);
3342
3388
  return this.safeTransaction(async (tx) => {
3343
- const createResult = await this.createMany(tx, this.model, args, true);
3344
- return this.read(tx, this.model, {
3345
- select: args.select,
3346
- omit: args.omit,
3347
- where: {
3348
- OR: createResult.map((item) => getIdValues(this.schema, this.model, item))
3349
- }
3350
- });
3389
+ const createResult = await this.createMany(tx, this.model, args, true, void 0, selectedFields);
3390
+ if (needReadBack) {
3391
+ return this.read(tx, this.model, {
3392
+ select: args.select,
3393
+ omit: args.omit,
3394
+ where: {
3395
+ OR: createResult.map((item) => getIdValues(this.schema, this.model, item))
3396
+ }
3397
+ });
3398
+ } else {
3399
+ return createResult;
3400
+ }
3351
3401
  });
3352
3402
  }
3353
3403
  };
@@ -3363,27 +3413,34 @@ var DeleteOperationHandler = class extends BaseOperationHandler {
3363
3413
  return (0, import_ts_pattern9.match)(operation).with("delete", () => this.runDelete(this.inputValidator.validateDeleteArgs(this.model, normalizedArgs))).with("deleteMany", () => this.runDeleteMany(this.inputValidator.validateDeleteManyArgs(this.model, normalizedArgs))).exhaustive();
3364
3414
  }
3365
3415
  async runDelete(args) {
3366
- const existing = await this.readUnique(this.kysely, this.model, {
3367
- select: args.select,
3368
- include: args.include,
3369
- omit: args.omit,
3370
- where: args.where
3371
- });
3372
- await this.safeTransaction(async (tx) => {
3373
- const result = await this.delete(tx, this.model, args.where);
3374
- if (result.count === 0) {
3416
+ const { needReadBack, selectedFields } = this.mutationNeedsReadBack(this.model, args);
3417
+ const result = await this.safeTransaction(async (tx) => {
3418
+ let preDeleteRead = void 0;
3419
+ if (needReadBack) {
3420
+ preDeleteRead = await this.readUnique(tx, this.model, {
3421
+ select: args.select,
3422
+ include: args.include,
3423
+ omit: args.omit,
3424
+ where: args.where
3425
+ });
3426
+ }
3427
+ const deleteResult = await this.delete(tx, this.model, args.where, void 0, void 0, selectedFields);
3428
+ if (deleteResult.rows.length === 0) {
3375
3429
  throw new NotFoundError(this.model);
3376
3430
  }
3431
+ return needReadBack ? preDeleteRead : deleteResult.rows[0];
3377
3432
  });
3378
- if (!existing && this.hasPolicyEnabled) {
3433
+ if (!result && this.hasPolicyEnabled) {
3379
3434
  throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
3380
3435
  }
3381
- return existing;
3436
+ return result;
3382
3437
  }
3383
3438
  async runDeleteMany(args) {
3384
3439
  return await this.safeTransaction(async (tx) => {
3385
3440
  const result = await this.delete(tx, this.model, args?.where, args?.limit);
3386
- return result;
3441
+ return {
3442
+ count: result.rows.length
3443
+ };
3387
3444
  });
3388
3445
  }
3389
3446
  };
@@ -3524,29 +3581,31 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
3524
3581
  return (0, import_ts_pattern11.match)(operation).with("update", () => this.runUpdate(this.inputValidator.validateUpdateArgs(this.model, normalizedArgs))).with("updateMany", () => this.runUpdateMany(this.inputValidator.validateUpdateManyArgs(this.model, normalizedArgs))).with("updateManyAndReturn", () => this.runUpdateManyAndReturn(this.inputValidator.validateUpdateManyAndReturnArgs(this.model, normalizedArgs))).with("upsert", () => this.runUpsert(this.inputValidator.validateUpsertArgs(this.model, normalizedArgs))).exhaustive();
3525
3582
  }
3526
3583
  async runUpdate(args) {
3527
- const readBackResult = await this.safeTransaction(async (tx) => {
3528
- const updateResult = await this.update(tx, this.model, args.where, args.data);
3529
- const readFilter = updateResult ?? args.where;
3530
- let readBackResult2 = void 0;
3531
- try {
3532
- readBackResult2 = await this.readUnique(tx, this.model, {
3584
+ const { needReadBack, selectedFields } = this.needReadBack(args);
3585
+ const result = await this.safeTransaction(async (tx) => {
3586
+ const updateResult = await this.update(tx, this.model, args.where, args.data, void 0, void 0, void 0, selectedFields);
3587
+ if (needReadBack) {
3588
+ const readFilter = updateResult ?? args.where;
3589
+ let readBackResult = void 0;
3590
+ readBackResult = await this.readUnique(tx, this.model, {
3533
3591
  select: args.select,
3534
3592
  include: args.include,
3535
3593
  omit: args.omit,
3536
3594
  where: readFilter
3537
3595
  });
3538
- } catch {
3596
+ return readBackResult;
3597
+ } else {
3598
+ return updateResult;
3539
3599
  }
3540
- return readBackResult2;
3541
3600
  });
3542
- if (!readBackResult) {
3601
+ if (!result) {
3543
3602
  if (this.hasPolicyEnabled) {
3544
3603
  throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
3545
3604
  } else {
3546
3605
  return null;
3547
3606
  }
3548
3607
  } else {
3549
- return readBackResult;
3608
+ return result;
3550
3609
  }
3551
3610
  }
3552
3611
  async runUpdateMany(args) {
@@ -3558,19 +3617,27 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
3558
3617
  if (!args) {
3559
3618
  return [];
3560
3619
  }
3620
+ const { needReadBack, selectedFields } = this.needReadBack(args);
3561
3621
  const { readBackResult, updateResult } = await this.safeTransaction(async (tx) => {
3562
- const updateResult2 = await this.updateMany(tx, this.model, args.where, args.data, args.limit, true);
3563
- const readBackResult2 = await this.read(tx, this.model, {
3564
- select: args.select,
3565
- omit: args.omit,
3566
- where: {
3567
- OR: updateResult2.map((item) => getIdValues(this.schema, this.model, item))
3568
- }
3569
- });
3570
- return {
3571
- readBackResult: readBackResult2,
3572
- updateResult: updateResult2
3573
- };
3622
+ const updateResult2 = await this.updateMany(tx, this.model, args.where, args.data, args.limit, true, void 0, selectedFields);
3623
+ if (needReadBack) {
3624
+ const readBackResult2 = await this.read(tx, this.model, {
3625
+ select: args.select,
3626
+ omit: args.omit,
3627
+ where: {
3628
+ OR: updateResult2.map((item) => getIdValues(this.schema, this.model, item))
3629
+ }
3630
+ });
3631
+ return {
3632
+ readBackResult: readBackResult2,
3633
+ updateResult: updateResult2
3634
+ };
3635
+ } else {
3636
+ return {
3637
+ readBackResult: updateResult2,
3638
+ updateResult: updateResult2
3639
+ };
3640
+ }
3574
3641
  });
3575
3642
  if (readBackResult.length < updateResult.length && this.hasPolicyEnabled) {
3576
3643
  throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
@@ -3578,23 +3645,49 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
3578
3645
  return readBackResult;
3579
3646
  }
3580
3647
  async runUpsert(args) {
3648
+ const { needReadBack, selectedFields } = this.needReadBack(args);
3581
3649
  const result = await this.safeTransaction(async (tx) => {
3582
- let mutationResult = await this.update(tx, this.model, args.where, args.update, void 0, true, false);
3650
+ let mutationResult = await this.update(tx, this.model, args.where, args.update, void 0, true, false, selectedFields);
3583
3651
  if (!mutationResult) {
3584
- mutationResult = await this.create(tx, this.model, args.create);
3652
+ mutationResult = await this.create(tx, this.model, args.create, void 0, void 0, selectedFields);
3653
+ }
3654
+ if (needReadBack) {
3655
+ return this.readUnique(tx, this.model, {
3656
+ select: args.select,
3657
+ include: args.include,
3658
+ omit: args.omit,
3659
+ where: getIdValues(this.schema, this.model, mutationResult)
3660
+ });
3661
+ } else {
3662
+ return mutationResult;
3585
3663
  }
3586
- return this.readUnique(tx, this.model, {
3587
- select: args.select,
3588
- include: args.include,
3589
- omit: args.omit,
3590
- where: getIdValues(this.schema, this.model, mutationResult)
3591
- });
3592
3664
  });
3593
3665
  if (!result && this.hasPolicyEnabled) {
3594
3666
  throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
3595
3667
  }
3596
3668
  return result;
3597
3669
  }
3670
+ needReadBack(args) {
3671
+ const baseResult = this.mutationNeedsReadBack(this.model, args);
3672
+ if (baseResult.needReadBack) {
3673
+ return baseResult;
3674
+ }
3675
+ const modelDef = this.requireModel(this.model);
3676
+ const nonRelationFields = Object.entries(modelDef.fields).filter(([_, def]) => !def.relation).map(([name, _]) => name);
3677
+ if (args.data && !Object.keys(args.data).some((field) => nonRelationFields.includes(field))) {
3678
+ return {
3679
+ needReadBack: true,
3680
+ selectedFields: void 0
3681
+ };
3682
+ }
3683
+ if (args.update && !Object.keys(args.update).some((field) => nonRelationFields.includes(field))) {
3684
+ return {
3685
+ needReadBack: true,
3686
+ selectedFields: void 0
3687
+ };
3688
+ }
3689
+ return baseResult;
3690
+ }
3598
3691
  };
3599
3692
 
3600
3693
  // src/client/crud/validator/index.ts
@@ -5598,7 +5691,7 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends import_kysely7.
5598
5691
  try {
5599
5692
  if (this.isMutationNode(compiledQuery.query) && !this.driver.isTransactionConnection(connection)) {
5600
5693
  await this.driver.beginTransaction(connection, {
5601
- isolationLevel: TransactionIsolationLevel.RepeatableRead
5694
+ isolationLevel: TransactionIsolationLevel.ReadCommitted
5602
5695
  });
5603
5696
  startedTx = true;
5604
5697
  }