@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.js CHANGED
@@ -1891,7 +1891,7 @@ var BaseOperationHandler = class {
1891
1891
  buildCountSelection(query, model, parentAlias, payload) {
1892
1892
  return query.select((eb) => this.dialect.buildCountJson(model, eb, parentAlias, payload).as("_count"));
1893
1893
  }
1894
- async create(kysely, model, data, fromRelation, creatingForDelegate = false) {
1894
+ async create(kysely, model, data, fromRelation, creatingForDelegate = false, returnFields) {
1895
1895
  const modelDef = this.requireModel(model);
1896
1896
  if (modelDef.isDelegate && !creatingForDelegate) {
1897
1897
  throw new QueryError(`Model "${this.model}" is a delegate and cannot be created directly.`);
@@ -1944,8 +1944,8 @@ var BaseOperationHandler = class {
1944
1944
  createFields = baseCreateResult.remainingFields;
1945
1945
  }
1946
1946
  const updatedData = this.fillGeneratedAndDefaultValues(modelDef, createFields);
1947
- const idFields = requireIdFields(this.schema, model);
1948
- 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({
1947
+ returnFields = returnFields ?? requireIdFields(this.schema, model);
1948
+ 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({
1949
1949
  model,
1950
1950
  operation: "create"
1951
1951
  }));
@@ -2150,7 +2150,7 @@ var BaseOperationHandler = class {
2150
2150
  }
2151
2151
  }
2152
2152
  }
2153
- async createMany(kysely, model, input, returnData, fromRelation) {
2153
+ async createMany(kysely, model, input, returnData, fromRelation, fieldsToReturn) {
2154
2154
  if (!input.data || Array.isArray(input.data) && input.data.length === 0) {
2155
2155
  return returnData ? [] : {
2156
2156
  count: 0
@@ -2219,8 +2219,8 @@ var BaseOperationHandler = class {
2219
2219
  count: Number(result.numAffectedRows)
2220
2220
  };
2221
2221
  } else {
2222
- const idFields = requireIdFields(this.schema, model);
2223
- const result = await query.returning(idFields).execute();
2222
+ fieldsToReturn = fieldsToReturn ?? requireIdFields(this.schema, model);
2223
+ const result = await query.returning(fieldsToReturn).execute();
2224
2224
  return result;
2225
2225
  }
2226
2226
  }
@@ -2300,7 +2300,7 @@ var BaseOperationHandler = class {
2300
2300
  return void 0;
2301
2301
  }
2302
2302
  }
2303
- async update(kysely, model, where, data, fromRelation, allowRelationUpdate = true, throwIfNotFound = true) {
2303
+ async update(kysely, model, where, data, fromRelation, allowRelationUpdate = true, throwIfNotFound = true, fieldsToReturn) {
2304
2304
  if (!data || typeof data !== "object") {
2305
2305
  throw new InternalError("data must be an object");
2306
2306
  }
@@ -2406,8 +2406,8 @@ var BaseOperationHandler = class {
2406
2406
  if (!hasFieldUpdate) {
2407
2407
  return combinedWhere;
2408
2408
  } else {
2409
- const idFields = requireIdFields(this.schema, model);
2410
- const query = kysely.updateTable(model).where(() => this.dialect.buildFilter(model, model, combinedWhere)).set(updateFields).returning(idFields).modifyEnd(this.makeContextComment({
2409
+ fieldsToReturn = fieldsToReturn ?? requireIdFields(this.schema, model);
2410
+ const query = kysely.updateTable(model).where(() => this.dialect.buildFilter(model, model, combinedWhere)).set(updateFields).returning(fieldsToReturn).modifyEnd(this.makeContextComment({
2411
2411
  model,
2412
2412
  operation: "update"
2413
2413
  }));
@@ -2499,7 +2499,7 @@ var BaseOperationHandler = class {
2499
2499
  makeContextComment(_context) {
2500
2500
  return sql4``;
2501
2501
  }
2502
- async updateMany(kysely, model, where, data, limit, returnData, filterModel) {
2502
+ async updateMany(kysely, model, where, data, limit, returnData, filterModel, fieldsToReturn) {
2503
2503
  if (typeof data !== "object") {
2504
2504
  throw new InternalError("data must be an object");
2505
2505
  }
@@ -2556,8 +2556,8 @@ var BaseOperationHandler = class {
2556
2556
  count: Number(result.numAffectedRows)
2557
2557
  };
2558
2558
  } else {
2559
- const idFields = requireIdFields(this.schema, model);
2560
- const finalQuery = query.returning(idFields);
2559
+ fieldsToReturn = fieldsToReturn ?? requireIdFields(this.schema, model);
2560
+ const finalQuery = query.returning(fieldsToReturn);
2561
2561
  const result = await this.executeQuery(kysely, finalQuery, "update");
2562
2562
  return result.rows;
2563
2563
  }
@@ -2961,7 +2961,7 @@ var BaseOperationHandler = class {
2961
2961
  });
2962
2962
  }
2963
2963
  }
2964
- if (throwForNotFound && expectedDeleteCount > deleteResult.count) {
2964
+ if (throwForNotFound && expectedDeleteCount > deleteResult.rows.length) {
2965
2965
  throw new NotFoundError(deleteFromModel);
2966
2966
  }
2967
2967
  }
@@ -2969,7 +2969,7 @@ var BaseOperationHandler = class {
2969
2969
  return enumerate(data).map((item) => flattenCompoundUniqueFilters(this.schema, model, item));
2970
2970
  }
2971
2971
  // #endregion
2972
- async delete(kysely, model, where, limit, filterModel) {
2972
+ async delete(kysely, model, where, limit, filterModel, fieldsToReturn) {
2973
2973
  filterModel ??= model;
2974
2974
  const modelDef = this.requireModel(model);
2975
2975
  if (modelDef.baseModel) {
@@ -2978,7 +2978,8 @@ var BaseOperationHandler = class {
2978
2978
  }
2979
2979
  return this.processBaseModelDelete(kysely, modelDef.baseModel, where, limit, filterModel);
2980
2980
  }
2981
- let query = kysely.deleteFrom(model);
2981
+ fieldsToReturn = fieldsToReturn ?? requireIdFields(this.schema, model);
2982
+ let query = kysely.deleteFrom(model).returning(fieldsToReturn);
2982
2983
  let needIdFilter = false;
2983
2984
  if (limit !== void 0 && !this.dialect.supportsDeleteWithLimit) {
2984
2985
  needIdFilter = true;
@@ -2998,10 +2999,7 @@ var BaseOperationHandler = class {
2998
2999
  model,
2999
3000
  operation: "delete"
3000
3001
  }));
3001
- const result = await this.executeQuery(kysely, query, "delete");
3002
- return {
3003
- count: Number(result.numAffectedRows)
3004
- };
3002
+ return this.executeQuery(kysely, query, "delete");
3005
3003
  }
3006
3004
  async processDelegateRelationDelete(kysely, modelDef, where, limit) {
3007
3005
  for (const fieldDef of Object.values(modelDef.fields)) {
@@ -3055,7 +3053,7 @@ var BaseOperationHandler = class {
3055
3053
  return callback(this.kysely);
3056
3054
  } else {
3057
3055
  let txBuilder = this.kysely.transaction();
3058
- txBuilder = txBuilder.setIsolationLevel(isolationLevel ?? TransactionIsolationLevel.RepeatableRead);
3056
+ txBuilder = txBuilder.setIsolationLevel(isolationLevel ?? TransactionIsolationLevel.ReadCommitted);
3059
3057
  return txBuilder.execute(callback);
3060
3058
  }
3061
3059
  }
@@ -3107,6 +3105,48 @@ var BaseOperationHandler = class {
3107
3105
  }
3108
3106
  return result.rows[0];
3109
3107
  }
3108
+ mutationNeedsReadBack(model, args) {
3109
+ if (this.hasPolicyEnabled) {
3110
+ return {
3111
+ needReadBack: true,
3112
+ selectedFields: void 0
3113
+ };
3114
+ }
3115
+ if (args.include && typeof args.include === "object" && Object.keys(args.include).length > 0) {
3116
+ return {
3117
+ needReadBack: true,
3118
+ selectedFields: void 0
3119
+ };
3120
+ }
3121
+ const modelDef = this.requireModel(model);
3122
+ if (modelDef.baseModel || modelDef.isDelegate) {
3123
+ return {
3124
+ needReadBack: true,
3125
+ selectedFields: void 0
3126
+ };
3127
+ }
3128
+ const allFields = Object.keys(modelDef.fields);
3129
+ const relationFields = Object.values(modelDef.fields).filter((f) => f.relation).map((f) => f.name);
3130
+ const computedFields = Object.values(modelDef.fields).filter((f) => f.computed).map((f) => f.name);
3131
+ const omit = Object.entries(args.omit ?? {}).filter(([, v]) => v).map(([k]) => k);
3132
+ const allFieldsSelected = [];
3133
+ if (!args.select || typeof args.select !== "object") {
3134
+ allFieldsSelected.push(...allFields.filter((f) => !relationFields.includes(f) && !omit.includes(f)));
3135
+ } else {
3136
+ allFieldsSelected.push(...Object.entries(args.select).filter(([k, v]) => v && !omit.includes(k)).map(([k]) => k));
3137
+ }
3138
+ if (allFieldsSelected.some((f) => relationFields.includes(f) || computedFields.includes(f))) {
3139
+ return {
3140
+ needReadBack: true,
3141
+ selectedFields: void 0
3142
+ };
3143
+ } else {
3144
+ return {
3145
+ needReadBack: false,
3146
+ selectedFields: allFieldsSelected
3147
+ };
3148
+ }
3149
+ }
3110
3150
  };
3111
3151
 
3112
3152
  // src/client/crud/operations/aggregate.ts
@@ -3267,14 +3307,19 @@ var CreateOperationHandler = class extends BaseOperationHandler {
3267
3307
  }).exhaustive();
3268
3308
  }
3269
3309
  async runCreate(args) {
3310
+ const { needReadBack, selectedFields } = this.mutationNeedsReadBack(this.model, args);
3270
3311
  const result = await this.safeTransaction(async (tx) => {
3271
- const createResult = await this.create(tx, this.model, args.data);
3272
- return this.readUnique(tx, this.model, {
3273
- select: args.select,
3274
- include: args.include,
3275
- omit: args.omit,
3276
- where: getIdValues(this.schema, this.model, createResult)
3277
- });
3312
+ const createResult = await this.create(tx, this.model, args.data, void 0, false, selectedFields);
3313
+ if (needReadBack) {
3314
+ return this.readUnique(tx, this.model, {
3315
+ select: args.select,
3316
+ include: args.include,
3317
+ omit: args.omit,
3318
+ where: getIdValues(this.schema, this.model, createResult)
3319
+ });
3320
+ } else {
3321
+ return createResult;
3322
+ }
3278
3323
  });
3279
3324
  if (!result && this.hasPolicyEnabled) {
3280
3325
  throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, `result is not allowed to be read back`);
@@ -3293,15 +3338,20 @@ var CreateOperationHandler = class extends BaseOperationHandler {
3293
3338
  if (args === void 0) {
3294
3339
  return [];
3295
3340
  }
3341
+ const { needReadBack, selectedFields } = this.mutationNeedsReadBack(this.model, args);
3296
3342
  return this.safeTransaction(async (tx) => {
3297
- const createResult = await this.createMany(tx, this.model, args, true);
3298
- return this.read(tx, this.model, {
3299
- select: args.select,
3300
- omit: args.omit,
3301
- where: {
3302
- OR: createResult.map((item) => getIdValues(this.schema, this.model, item))
3303
- }
3304
- });
3343
+ const createResult = await this.createMany(tx, this.model, args, true, void 0, selectedFields);
3344
+ if (needReadBack) {
3345
+ return this.read(tx, this.model, {
3346
+ select: args.select,
3347
+ omit: args.omit,
3348
+ where: {
3349
+ OR: createResult.map((item) => getIdValues(this.schema, this.model, item))
3350
+ }
3351
+ });
3352
+ } else {
3353
+ return createResult;
3354
+ }
3305
3355
  });
3306
3356
  }
3307
3357
  };
@@ -3317,27 +3367,34 @@ var DeleteOperationHandler = class extends BaseOperationHandler {
3317
3367
  return match9(operation).with("delete", () => this.runDelete(this.inputValidator.validateDeleteArgs(this.model, normalizedArgs))).with("deleteMany", () => this.runDeleteMany(this.inputValidator.validateDeleteManyArgs(this.model, normalizedArgs))).exhaustive();
3318
3368
  }
3319
3369
  async runDelete(args) {
3320
- const existing = await this.readUnique(this.kysely, this.model, {
3321
- select: args.select,
3322
- include: args.include,
3323
- omit: args.omit,
3324
- where: args.where
3325
- });
3326
- await this.safeTransaction(async (tx) => {
3327
- const result = await this.delete(tx, this.model, args.where);
3328
- if (result.count === 0) {
3370
+ const { needReadBack, selectedFields } = this.mutationNeedsReadBack(this.model, args);
3371
+ const result = await this.safeTransaction(async (tx) => {
3372
+ let preDeleteRead = void 0;
3373
+ if (needReadBack) {
3374
+ preDeleteRead = await this.readUnique(tx, this.model, {
3375
+ select: args.select,
3376
+ include: args.include,
3377
+ omit: args.omit,
3378
+ where: args.where
3379
+ });
3380
+ }
3381
+ const deleteResult = await this.delete(tx, this.model, args.where, void 0, void 0, selectedFields);
3382
+ if (deleteResult.rows.length === 0) {
3329
3383
  throw new NotFoundError(this.model);
3330
3384
  }
3385
+ return needReadBack ? preDeleteRead : deleteResult.rows[0];
3331
3386
  });
3332
- if (!existing && this.hasPolicyEnabled) {
3387
+ if (!result && this.hasPolicyEnabled) {
3333
3388
  throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
3334
3389
  }
3335
- return existing;
3390
+ return result;
3336
3391
  }
3337
3392
  async runDeleteMany(args) {
3338
3393
  return await this.safeTransaction(async (tx) => {
3339
3394
  const result = await this.delete(tx, this.model, args?.where, args?.limit);
3340
- return result;
3395
+ return {
3396
+ count: result.rows.length
3397
+ };
3341
3398
  });
3342
3399
  }
3343
3400
  };
@@ -3478,29 +3535,31 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
3478
3535
  return match11(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();
3479
3536
  }
3480
3537
  async runUpdate(args) {
3481
- const readBackResult = await this.safeTransaction(async (tx) => {
3482
- const updateResult = await this.update(tx, this.model, args.where, args.data);
3483
- const readFilter = updateResult ?? args.where;
3484
- let readBackResult2 = void 0;
3485
- try {
3486
- readBackResult2 = await this.readUnique(tx, this.model, {
3538
+ const { needReadBack, selectedFields } = this.needReadBack(args);
3539
+ const result = await this.safeTransaction(async (tx) => {
3540
+ const updateResult = await this.update(tx, this.model, args.where, args.data, void 0, void 0, void 0, selectedFields);
3541
+ if (needReadBack) {
3542
+ const readFilter = updateResult ?? args.where;
3543
+ let readBackResult = void 0;
3544
+ readBackResult = await this.readUnique(tx, this.model, {
3487
3545
  select: args.select,
3488
3546
  include: args.include,
3489
3547
  omit: args.omit,
3490
3548
  where: readFilter
3491
3549
  });
3492
- } catch {
3550
+ return readBackResult;
3551
+ } else {
3552
+ return updateResult;
3493
3553
  }
3494
- return readBackResult2;
3495
3554
  });
3496
- if (!readBackResult) {
3555
+ if (!result) {
3497
3556
  if (this.hasPolicyEnabled) {
3498
3557
  throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
3499
3558
  } else {
3500
3559
  return null;
3501
3560
  }
3502
3561
  } else {
3503
- return readBackResult;
3562
+ return result;
3504
3563
  }
3505
3564
  }
3506
3565
  async runUpdateMany(args) {
@@ -3512,19 +3571,27 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
3512
3571
  if (!args) {
3513
3572
  return [];
3514
3573
  }
3574
+ const { needReadBack, selectedFields } = this.needReadBack(args);
3515
3575
  const { readBackResult, updateResult } = await this.safeTransaction(async (tx) => {
3516
- const updateResult2 = await this.updateMany(tx, this.model, args.where, args.data, args.limit, true);
3517
- const readBackResult2 = await this.read(tx, this.model, {
3518
- select: args.select,
3519
- omit: args.omit,
3520
- where: {
3521
- OR: updateResult2.map((item) => getIdValues(this.schema, this.model, item))
3522
- }
3523
- });
3524
- return {
3525
- readBackResult: readBackResult2,
3526
- updateResult: updateResult2
3527
- };
3576
+ const updateResult2 = await this.updateMany(tx, this.model, args.where, args.data, args.limit, true, void 0, selectedFields);
3577
+ if (needReadBack) {
3578
+ const readBackResult2 = await this.read(tx, this.model, {
3579
+ select: args.select,
3580
+ omit: args.omit,
3581
+ where: {
3582
+ OR: updateResult2.map((item) => getIdValues(this.schema, this.model, item))
3583
+ }
3584
+ });
3585
+ return {
3586
+ readBackResult: readBackResult2,
3587
+ updateResult: updateResult2
3588
+ };
3589
+ } else {
3590
+ return {
3591
+ readBackResult: updateResult2,
3592
+ updateResult: updateResult2
3593
+ };
3594
+ }
3528
3595
  });
3529
3596
  if (readBackResult.length < updateResult.length && this.hasPolicyEnabled) {
3530
3597
  throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
@@ -3532,23 +3599,49 @@ var UpdateOperationHandler = class extends BaseOperationHandler {
3532
3599
  return readBackResult;
3533
3600
  }
3534
3601
  async runUpsert(args) {
3602
+ const { needReadBack, selectedFields } = this.needReadBack(args);
3535
3603
  const result = await this.safeTransaction(async (tx) => {
3536
- let mutationResult = await this.update(tx, this.model, args.where, args.update, void 0, true, false);
3604
+ let mutationResult = await this.update(tx, this.model, args.where, args.update, void 0, true, false, selectedFields);
3537
3605
  if (!mutationResult) {
3538
- mutationResult = await this.create(tx, this.model, args.create);
3606
+ mutationResult = await this.create(tx, this.model, args.create, void 0, void 0, selectedFields);
3607
+ }
3608
+ if (needReadBack) {
3609
+ return this.readUnique(tx, this.model, {
3610
+ select: args.select,
3611
+ include: args.include,
3612
+ omit: args.omit,
3613
+ where: getIdValues(this.schema, this.model, mutationResult)
3614
+ });
3615
+ } else {
3616
+ return mutationResult;
3539
3617
  }
3540
- return this.readUnique(tx, this.model, {
3541
- select: args.select,
3542
- include: args.include,
3543
- omit: args.omit,
3544
- where: getIdValues(this.schema, this.model, mutationResult)
3545
- });
3546
3618
  });
3547
3619
  if (!result && this.hasPolicyEnabled) {
3548
3620
  throw new RejectedByPolicyError(this.model, RejectedByPolicyReason.CANNOT_READ_BACK, "result is not allowed to be read back");
3549
3621
  }
3550
3622
  return result;
3551
3623
  }
3624
+ needReadBack(args) {
3625
+ const baseResult = this.mutationNeedsReadBack(this.model, args);
3626
+ if (baseResult.needReadBack) {
3627
+ return baseResult;
3628
+ }
3629
+ const modelDef = this.requireModel(this.model);
3630
+ const nonRelationFields = Object.entries(modelDef.fields).filter(([_, def]) => !def.relation).map(([name, _]) => name);
3631
+ if (args.data && !Object.keys(args.data).some((field) => nonRelationFields.includes(field))) {
3632
+ return {
3633
+ needReadBack: true,
3634
+ selectedFields: void 0
3635
+ };
3636
+ }
3637
+ if (args.update && !Object.keys(args.update).some((field) => nonRelationFields.includes(field))) {
3638
+ return {
3639
+ needReadBack: true,
3640
+ selectedFields: void 0
3641
+ };
3642
+ }
3643
+ return baseResult;
3644
+ }
3552
3645
  };
3553
3646
 
3554
3647
  // src/client/crud/validator/index.ts
@@ -5552,7 +5645,7 @@ var ZenStackQueryExecutor = class _ZenStackQueryExecutor extends DefaultQueryExe
5552
5645
  try {
5553
5646
  if (this.isMutationNode(compiledQuery.query) && !this.driver.isTransactionConnection(connection)) {
5554
5647
  await this.driver.beginTransaction(connection, {
5555
- isolationLevel: TransactionIsolationLevel.RepeatableRead
5648
+ isolationLevel: TransactionIsolationLevel.ReadCommitted
5556
5649
  });
5557
5650
  startedTx = true;
5558
5651
  }