@vantreeseba/drizzle-graphql 7.7.0 → 7.9.0

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
@@ -1095,7 +1095,7 @@ var runOnSharedTx = async (state, body) => {
1095
1095
  throw e;
1096
1096
  }
1097
1097
  };
1098
- var runMutation = async (db, context, info, txCtx, body) => {
1098
+ var runMutation = async (db, context, info, txCtx, body, forceTx) => {
1099
1099
  const contextIsObject = context !== null && (typeof context === "object" || typeof context === "function");
1100
1100
  const stateKey = contextIsObject ? context : info.operation;
1101
1101
  let state = txCtx?.states.get(stateKey);
@@ -1104,7 +1104,7 @@ var runMutation = async (db, context, info, txCtx, body) => {
1104
1104
  return body(context[drizzleExecutorKey]);
1105
1105
  }
1106
1106
  if (!txCtx || info.operation.operation !== "mutation") {
1107
- return body(db);
1107
+ return forceTx ? db.transaction((tx) => body(tx)) : body(db);
1108
1108
  }
1109
1109
  const keys = /* @__PURE__ */ new Set();
1110
1110
  const allKnown = collectRootMutationKeys(
@@ -1119,10 +1119,28 @@ var runMutation = async (db, context, info, txCtx, body) => {
1119
1119
  txCtx.states.set(stateKey, state);
1120
1120
  }
1121
1121
  if (state.kind === "passthrough") {
1122
- return body(resolveExecutor(db, context));
1122
+ const executor = resolveExecutor(db, context);
1123
+ return forceTx && executor === db ? db.transaction((tx) => body(tx)) : body(executor);
1123
1124
  }
1124
1125
  return runOnSharedTx(state, body);
1125
1126
  };
1127
+ var normalizeWriteHooks = (hooks) => {
1128
+ if (!hooks) {
1129
+ return void 0;
1130
+ }
1131
+ if (typeof hooks === "function") {
1132
+ return { after: hooks };
1133
+ }
1134
+ const resolved = { before: hooks.before, after: hooks.after };
1135
+ return resolved.before || resolved.after ? resolved : void 0;
1136
+ };
1137
+ var runWriteHook = (hooks, position, payload) => {
1138
+ const hook = position === "before" ? hooks?.before : hooks?.after;
1139
+ if (!hook) {
1140
+ return void 0;
1141
+ }
1142
+ return Promise.resolve(hook({ ...payload, position, rows: payload.rows ?? [] }));
1143
+ };
1126
1144
  var batchedPaginatedRelationQuery = async (db, targetTable, foreignCol, whereCondition, orderByArg, limit, offset, pkNames, orderCtx, whereArgs) => {
1127
1145
  const cols = (0, import_drizzle_orm4.getColumns)(targetTable);
1128
1146
  const orderExprs = [
@@ -1166,14 +1184,8 @@ var createRelationResolverFactory = (db, tables, nullOrdering, filterCtx, limits
1166
1184
  if (localValue == null) {
1167
1185
  return isOne ? null : [];
1168
1186
  }
1169
- const {
1170
- where: whereArg,
1171
- orderBy: orderByArg,
1172
- limit: requestedLimit,
1173
- offset,
1174
- after,
1175
- deleted
1176
- } = args ?? {};
1187
+ const { where: whereArg, limit: requestedLimit, offset, after, deleted } = args ?? {};
1188
+ const orderByArg = isOne ? args?.orderBy : withDefaultOrderBy(args ?? {}, targetTableName, policies?.defaultOrderBy).orderBy;
1177
1189
  const limit = applyLimitPolicy(requestedLimit, limitPolicy, `${tableName}.${relationName}`);
1178
1190
  const distinct = (args ?? {}).distinct?.length ? (args ?? {}).distinct : void 0;
1179
1191
  const cursorSelected = !isOne && !!info && selectsCursorField(info, targetTable);
@@ -1305,6 +1317,13 @@ var inputFieldDocs = (docs, column, tableName, columnName, fieldType) => {
1305
1317
  }
1306
1318
  return resolved;
1307
1319
  };
1320
+ var withDefaultOrderBy = (args, tableName, defaults) => {
1321
+ if (!defaults || args?.orderBy != null) {
1322
+ return args;
1323
+ }
1324
+ const fallback = defaults(tableName);
1325
+ return fallback ? { ...args, orderBy: fallback } : args;
1326
+ };
1308
1327
  var applyLimitPolicy = (limit, policy, fieldName) => {
1309
1328
  if (!policy) {
1310
1329
  return limit ?? void 0;
@@ -2771,10 +2790,12 @@ var withScope = (scope, tableName, table, condition, mode) => {
2771
2790
  const predicate = scope?.on(tableName, table, mode);
2772
2791
  return predicate ? (0, import_drizzle_orm4.and)(condition, predicate) : condition;
2773
2792
  };
2774
- var bindPolicies = (policies, filterCtx) => policies?.scope || policies?.contextValues || policies?.softDelete ? {
2793
+ var bindPolicies = (policies, filterCtx) => policies?.scope || policies?.contextValues || policies?.softDelete || policies?.onWrite || policies?.defaultOrderBy ? {
2775
2794
  scope: policies.scope || policies.softDelete ? (context) => resolveScope(policies, context, filterCtx) : void 0,
2776
2795
  contextValues: policies.contextValues,
2777
- softDelete: policies.softDelete
2796
+ softDelete: policies.softDelete,
2797
+ onWrite: policies.onWrite,
2798
+ defaultOrderBy: policies.defaultOrderBy
2778
2799
  } : void 0;
2779
2800
  var applyContextValues = (values, hooks, context) => {
2780
2801
  if (!hooks) {
@@ -2803,7 +2824,7 @@ var stripContextValues = (values, hooks) => {
2803
2824
  }
2804
2825
  return values;
2805
2826
  };
2806
- var extractRelationsParamsInner = (relationMap, tables, tableName, typeName, originField, typeNameMapper, _isInitial = false, filterCtx, limits, scope) => {
2827
+ var extractRelationsParamsInner = (relationMap, tables, tableName, typeName, originField, typeNameMapper, _isInitial = false, filterCtx, limits, scope, defaultOrderBy) => {
2807
2828
  const relationsForTable = relationMap[tableName];
2808
2829
  if (!relationsForTable) {
2809
2830
  return void 0;
@@ -2845,7 +2866,7 @@ var extractRelationsParamsInner = (relationMap, tables, tableName, typeName, ori
2845
2866
  const thisRecord = {};
2846
2867
  thisRecord.columns = columns;
2847
2868
  const relationField = Object.values(baseField).find((e) => e.name === relName);
2848
- const relationArgs = relationField?.args;
2869
+ const relationArgs = (0, import_drizzle_orm4.is)(relEntry.relation, import_drizzle_orm4.One) ? relationField?.args : relationField && withDefaultOrderBy(relationField.args ?? {}, targetTableName, defaultOrderBy);
2849
2870
  const offset = relationArgs?.offset ?? void 0;
2850
2871
  const limit = (0, import_drizzle_orm4.is)(relEntry.relation, import_drizzle_orm4.One) ? relationArgs?.limit ?? void 0 : applyLimitPolicy(relationArgs?.limit, limits?.(targetTableName), `${tableName}.${relName}`);
2851
2872
  const relWhere = relationArgs?.where;
@@ -2874,14 +2895,15 @@ var extractRelationsParamsInner = (relationMap, tables, tableName, typeName, ori
2874
2895
  false,
2875
2896
  filterCtx,
2876
2897
  limits,
2877
- scope
2898
+ scope,
2899
+ defaultOrderBy
2878
2900
  ) : void 0;
2879
2901
  thisRecord.with = relWith;
2880
2902
  args[relName] = thisRecord;
2881
2903
  }
2882
2904
  return args;
2883
2905
  };
2884
- var extractRelationsParams = (relationMap, tables, tableName, info, typeName, typeNameMapper, filterCtx, limits, scope) => {
2906
+ var extractRelationsParams = (relationMap, tables, tableName, info, typeName, typeNameMapper, filterCtx, limits, scope, defaultOrderBy) => {
2885
2907
  if (!info) {
2886
2908
  return void 0;
2887
2909
  }
@@ -2895,7 +2917,8 @@ var extractRelationsParams = (relationMap, tables, tableName, info, typeName, ty
2895
2917
  true,
2896
2918
  filterCtx,
2897
2919
  limits,
2898
- scope
2920
+ scope,
2921
+ defaultOrderBy
2899
2922
  );
2900
2923
  };
2901
2924
  var pruneNonEagerRelations = (relationMap, shouldEagerLoad) => {
@@ -3306,7 +3329,8 @@ var prepareMutationRelationColumns = (params) => {
3306
3329
  typeNameMapper,
3307
3330
  void 0,
3308
3331
  params.limits,
3309
- params.scope
3332
+ params.scope,
3333
+ params.defaultOrderBy
3310
3334
  ) : void 0;
3311
3335
  const hasRelations = !!(withParams && Object.keys(withParams).length);
3312
3336
  const baseColumns = extractSelectedColumnsFromTreeSQLFormat(parsedInfo.fieldsByTypeName[typeName], table, {
@@ -3648,7 +3672,8 @@ var runRelationalSelect = async (opts) => {
3648
3672
  typeNameMapper,
3649
3673
  filterCtx,
3650
3674
  opts.limits,
3651
- scope
3675
+ scope,
3676
+ opts.defaultOrderBy
3652
3677
  ) : void 0
3653
3678
  };
3654
3679
  if (single) {
@@ -4254,7 +4279,8 @@ var generateSelectArray = (db, tableName, tables, relationMap, orderArgs, filter
4254
4279
  );
4255
4280
  return {
4256
4281
  name: fieldName,
4257
- resolver: async (_source, args, context, info) => {
4282
+ resolver: async (_source, rawArgs, context, info) => {
4283
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
4258
4284
  try {
4259
4285
  const parsedInfo = (0, import_graphql_parse_resolve_info2.parseResolveInfo)(info, { deep: true });
4260
4286
  const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
@@ -4272,6 +4298,7 @@ var generateSelectArray = (db, tableName, tables, relationMap, orderArgs, filter
4272
4298
  single: false,
4273
4299
  filterCtx,
4274
4300
  limits,
4301
+ defaultOrderBy: policies?.defaultOrderBy,
4275
4302
  scope: policies?.scope?.(context),
4276
4303
  pkNames,
4277
4304
  db: executor,
@@ -4297,7 +4324,8 @@ var generateSelectSingle = (db, tableName, tables, relationMap, orderArgs, filte
4297
4324
  const pkNames = mysqlPrimaryKeyPropNames(table);
4298
4325
  return {
4299
4326
  name: fieldName,
4300
- resolver: async (_source, args, context, info) => {
4327
+ resolver: async (_source, rawArgs, context, info) => {
4328
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
4301
4329
  try {
4302
4330
  const parsedInfo = (0, import_graphql_parse_resolve_info2.parseResolveInfo)(info, { deep: true });
4303
4331
  const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
@@ -4314,6 +4342,7 @@ var generateSelectSingle = (db, tableName, tables, relationMap, orderArgs, filte
4314
4342
  single: true,
4315
4343
  filterCtx,
4316
4344
  limits,
4345
+ defaultOrderBy: policies?.defaultOrderBy,
4317
4346
  scope: policies?.scope?.(context),
4318
4347
  pkNames,
4319
4348
  db: executor
@@ -4331,22 +4360,49 @@ var generateInsertArray = (db, tableName, table, baseType, fieldName, txCtx, pol
4331
4360
  type: new import_graphql7.GraphQLNonNull(new import_graphql7.GraphQLList(new import_graphql7.GraphQLNonNull(baseType)))
4332
4361
  }
4333
4362
  };
4363
+ const hooks = policies?.onWrite?.(tableName, "insert");
4334
4364
  return {
4335
4365
  name: fieldName,
4336
4366
  resolver: async (_source, args, context, info) => {
4337
4367
  try {
4338
- return await runMutation(db, context, info, txCtx, async (executor) => {
4339
- const input = applyContextValuesAll(
4340
- remapFromGraphQLArrayInput(args.values, table),
4341
- policies?.contextValues?.(tableName),
4342
- context
4343
- );
4344
- if (!input.length) {
4345
- throw new import_graphql7.GraphQLError("No values were provided!");
4346
- }
4347
- await executor.insert(table).values(input);
4348
- return { isSuccess: true };
4349
- });
4368
+ return await runMutation(
4369
+ db,
4370
+ context,
4371
+ info,
4372
+ txCtx,
4373
+ async (executor) => {
4374
+ const input = applyContextValuesAll(
4375
+ remapFromGraphQLArrayInput(args.values, table),
4376
+ policies?.contextValues?.(tableName),
4377
+ context
4378
+ );
4379
+ if (!input.length) {
4380
+ throw new import_graphql7.GraphQLError("No values were provided!");
4381
+ }
4382
+ await runWriteHook(hooks, "before", {
4383
+ table: tableName,
4384
+ operation: "insert",
4385
+ single: false,
4386
+ args,
4387
+ context,
4388
+ info,
4389
+ tx: executor
4390
+ });
4391
+ await executor.insert(table).values(input);
4392
+ await runWriteHook(hooks, "after", {
4393
+ table: tableName,
4394
+ operation: "insert",
4395
+ single: false,
4396
+ args,
4397
+ rows: [],
4398
+ context,
4399
+ info,
4400
+ tx: executor
4401
+ });
4402
+ return { isSuccess: true };
4403
+ },
4404
+ !!hooks
4405
+ );
4350
4406
  } catch (e) {
4351
4407
  throw toGraphQLError(e);
4352
4408
  }
@@ -4360,19 +4416,46 @@ var generateInsertSingle = (db, tableName, table, baseType, fieldName, txCtx, po
4360
4416
  type: new import_graphql7.GraphQLNonNull(baseType)
4361
4417
  }
4362
4418
  };
4419
+ const hooks = policies?.onWrite?.(tableName, "insert");
4363
4420
  return {
4364
4421
  name: fieldName,
4365
4422
  resolver: async (_source, args, context, info) => {
4366
4423
  try {
4367
- return await runMutation(db, context, info, txCtx, async (executor) => {
4368
- const input = applyContextValues(
4369
- remapFromGraphQLSingleInput(args.values, table),
4370
- policies?.contextValues?.(tableName),
4371
- context
4372
- );
4373
- await executor.insert(table).values(input);
4374
- return { isSuccess: true };
4375
- });
4424
+ return await runMutation(
4425
+ db,
4426
+ context,
4427
+ info,
4428
+ txCtx,
4429
+ async (executor) => {
4430
+ await runWriteHook(hooks, "before", {
4431
+ table: tableName,
4432
+ operation: "insert",
4433
+ single: true,
4434
+ args,
4435
+ context,
4436
+ info,
4437
+ tx: executor
4438
+ });
4439
+ const input = applyContextValues(
4440
+ remapFromGraphQLSingleInput(args.values, table),
4441
+ policies?.contextValues?.(tableName),
4442
+ context
4443
+ );
4444
+ await executor.insert(table).values(input);
4445
+ await runWriteHook(hooks, "after", {
4446
+ table: tableName,
4447
+ operation: "insert",
4448
+ single: true,
4449
+ args,
4450
+ rows: [],
4451
+ context,
4452
+ info,
4453
+ tx: executor
4454
+ });
4455
+ return { isSuccess: true };
4456
+ },
4457
+ !!hooks
4458
+ );
4376
4459
  } catch (e) {
4377
4460
  throw toGraphQLError(e);
4378
4461
  }
@@ -4391,35 +4474,62 @@ var generateUpsert = (db, tableName, table, baseType, onConflictType, fieldName,
4391
4474
  }
4392
4475
  };
4393
4476
  const pkNames = mysqlPrimaryKeyPropNames(table);
4477
+ const hooks = policies?.onWrite?.(tableName, "upsert");
4394
4478
  return {
4395
4479
  name: fieldName,
4396
4480
  resolver: async (_source, args, context, info) => {
4397
4481
  try {
4398
- return await runMutation(db, context, info, txCtx, async (executor) => {
4399
- const input = applyContextValuesAll(
4400
- single ? [remapFromGraphQLSingleInput(args.values, table)] : remapFromGraphQLArrayInput(args.values, table),
4401
- policies?.contextValues?.(tableName),
4402
- context
4403
- );
4404
- if (!input.length) {
4405
- throw new import_graphql7.GraphQLError("No values were provided!");
4406
- }
4407
- const plan = resolveConflictPlan({
4408
- table,
4409
- values: input,
4410
- onConflict: args.onConflict,
4411
- pkNames,
4412
- uniqueSets: [],
4413
- excludedRef: mysqlValuesColumnRef,
4414
- withTarget: false
4415
- });
4416
- if (plan.action === "NOTHING") {
4417
- await executor.insert(table).ignore().values(input);
4418
- } else {
4419
- await executor.insert(table).values(input).onDuplicateKeyUpdate({ set: plan.set });
4420
- }
4421
- return { isSuccess: true };
4422
- });
4482
+ return await runMutation(
4483
+ db,
4484
+ context,
4485
+ info,
4486
+ txCtx,
4487
+ async (executor) => {
4488
+ const input = applyContextValuesAll(
4489
+ single ? [remapFromGraphQLSingleInput(args.values, table)] : remapFromGraphQLArrayInput(args.values, table),
4490
+ policies?.contextValues?.(tableName),
4491
+ context
4492
+ );
4493
+ if (!input.length) {
4494
+ throw new import_graphql7.GraphQLError("No values were provided!");
4495
+ }
4496
+ await runWriteHook(hooks, "before", {
4497
+ table: tableName,
4498
+ operation: "upsert",
4499
+ single,
4500
+ args,
4501
+ context,
4502
+ info,
4503
+ tx: executor
4504
+ });
4505
+ const plan = resolveConflictPlan({
4506
+ table,
4507
+ values: input,
4508
+ onConflict: args.onConflict,
4509
+ pkNames,
4510
+ uniqueSets: [],
4511
+ excludedRef: mysqlValuesColumnRef,
4512
+ withTarget: false
4513
+ });
4514
+ if (plan.action === "NOTHING") {
4515
+ await executor.insert(table).ignore().values(input);
4516
+ } else {
4517
+ await executor.insert(table).values(input).onDuplicateKeyUpdate({ set: plan.set });
4518
+ }
4519
+ await runWriteHook(hooks, "after", {
4520
+ table: tableName,
4521
+ operation: "upsert",
4522
+ single,
4523
+ args,
4524
+ rows: [],
4525
+ context,
4526
+ info,
4527
+ tx: executor
4528
+ });
4529
+ return { isSuccess: true };
4530
+ },
4531
+ !!hooks
4532
+ );
4423
4533
  } catch (e) {
4424
4534
  throw toGraphQLError(e);
4425
4535
  }
@@ -4436,37 +4546,64 @@ var generateUpdate = (db, tableName, table, setArgs, filterArgs, fieldName, sing
4436
4546
  type: single || requireWhere ? new import_graphql7.GraphQLNonNull(filterArgs) : filterArgs
4437
4547
  }
4438
4548
  };
4549
+ const hooks = policies?.onWrite?.(tableName, "update");
4439
4550
  return {
4440
4551
  name: fieldName,
4441
4552
  resolver: async (_source, args, context, info) => {
4442
4553
  try {
4443
- return await runMutation(db, context, info, txCtx, async (executor) => {
4444
- const { where, set } = args;
4445
- const scope = policies?.scope?.(context);
4446
- const input = stripContextValues(
4447
- remapUpdateInput(set, table, tableName),
4448
- policies?.contextValues?.(tableName)
4449
- );
4450
- if (!Object.keys(input).length) {
4451
- throw new import_graphql7.GraphQLError("Unable to update with no values specified!");
4452
- }
4453
- const relationCtx = relationFilterCtx(filterCtx, tableName);
4454
- const filters = withScope(
4455
- scope,
4456
- tableName,
4457
- table,
4458
- single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
4459
- );
4460
- if (single) {
4461
- await assertSingleMatch(executor, table, filters, fieldName);
4462
- }
4463
- let query = executor.update(table).set(input);
4464
- if (filters) {
4465
- query = query.where(filters);
4466
- }
4467
- await query;
4468
- return { isSuccess: true };
4469
- });
4554
+ return await runMutation(
4555
+ db,
4556
+ context,
4557
+ info,
4558
+ txCtx,
4559
+ async (executor) => {
4560
+ const { where, set } = args;
4561
+ const scope = policies?.scope?.(context);
4562
+ const input = stripContextValues(
4563
+ remapUpdateInput(set, table, tableName),
4564
+ policies?.contextValues?.(tableName)
4565
+ );
4566
+ if (!Object.keys(input).length) {
4567
+ throw new import_graphql7.GraphQLError("Unable to update with no values specified!");
4568
+ }
4569
+ await runWriteHook(hooks, "before", {
4570
+ table: tableName,
4571
+ operation: "update",
4572
+ single,
4573
+ args,
4574
+ context,
4575
+ info,
4576
+ tx: executor
4577
+ });
4578
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
4579
+ const filters = withScope(
4580
+ scope,
4581
+ tableName,
4582
+ table,
4583
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
4584
+ );
4585
+ if (single) {
4586
+ await assertSingleMatch(executor, table, filters, fieldName);
4587
+ }
4588
+ let query = executor.update(table).set(input);
4589
+ if (filters) {
4590
+ query = query.where(filters);
4591
+ }
4592
+ await query;
4593
+ await runWriteHook(hooks, "after", {
4594
+ table: tableName,
4595
+ operation: "update",
4596
+ single,
4597
+ args,
4598
+ rows: [],
4599
+ context,
4600
+ info,
4601
+ tx: executor
4602
+ });
4603
+ return { isSuccess: true };
4604
+ },
4605
+ !!hooks
4606
+ );
4470
4607
  } catch (e) {
4471
4608
  throw toGraphQLError(e);
4472
4609
  }
@@ -4480,43 +4617,70 @@ var generateUpdateMany = (db, tableName, table, updateManyInput, fieldName, filt
4480
4617
  type: new import_graphql7.GraphQLNonNull(new import_graphql7.GraphQLList(new import_graphql7.GraphQLNonNull(updateManyInput)))
4481
4618
  }
4482
4619
  };
4620
+ const hooks = policies?.onWrite?.(tableName, "updateMany");
4483
4621
  return {
4484
4622
  name: fieldName,
4485
4623
  resolver: async (_source, args, context, info) => {
4486
4624
  try {
4487
- return await runMutation(db, context, info, txCtx, async (executor) => {
4488
- const { updates } = args;
4489
- if (!updates.length) {
4490
- throw new import_graphql7.GraphQLError("No updates were provided!");
4491
- }
4492
- const scope = policies?.scope?.(context);
4493
- const contextColumns = policies?.contextValues?.(tableName);
4494
- const entries = updates.map(({ where, set }) => {
4495
- const input = stripContextValues(remapUpdateInput(set, table, tableName), contextColumns);
4496
- if (!Object.keys(input).length) {
4497
- throw new import_graphql7.GraphQLError("Unable to update with no values specified!");
4625
+ return await runMutation(
4626
+ db,
4627
+ context,
4628
+ info,
4629
+ txCtx,
4630
+ async (executor) => {
4631
+ const { updates } = args;
4632
+ if (!updates.length) {
4633
+ throw new import_graphql7.GraphQLError("No updates were provided!");
4498
4634
  }
4499
- return {
4500
- set: input,
4501
- filters: withScope(
4502
- scope,
4503
- tableName,
4504
- table,
4505
- where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
4506
- )
4507
- };
4508
- });
4509
- await executor.transaction(async (tx) => {
4510
- for (const entry of entries) {
4511
- let query = tx.update(table).set(entry.set);
4512
- if (entry.filters) {
4513
- query = query.where(entry.filters);
4635
+ await runWriteHook(hooks, "before", {
4636
+ table: tableName,
4637
+ operation: "updateMany",
4638
+ single: false,
4639
+ args,
4640
+ context,
4641
+ info,
4642
+ tx: executor
4643
+ });
4644
+ const scope = policies?.scope?.(context);
4645
+ const contextColumns = policies?.contextValues?.(tableName);
4646
+ const entries = updates.map(({ where, set }) => {
4647
+ const input = stripContextValues(remapUpdateInput(set, table, tableName), contextColumns);
4648
+ if (!Object.keys(input).length) {
4649
+ throw new import_graphql7.GraphQLError("Unable to update with no values specified!");
4514
4650
  }
4515
- await query;
4516
- }
4517
- });
4518
- return { isSuccess: true };
4519
- });
4651
+ return {
4652
+ set: input,
4653
+ filters: withScope(
4654
+ scope,
4655
+ tableName,
4656
+ table,
4657
+ where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
4658
+ )
4659
+ };
4660
+ });
4661
+ await executor.transaction(async (tx) => {
4662
+ for (const entry of entries) {
4663
+ let query = tx.update(table).set(entry.set);
4664
+ if (entry.filters) {
4665
+ query = query.where(entry.filters);
4666
+ }
4667
+ await query;
4668
+ }
4669
+ });
4670
+ await runWriteHook(hooks, "after", {
4671
+ table: tableName,
4672
+ operation: "updateMany",
4673
+ single: false,
4674
+ args,
4675
+ rows: [],
4676
+ context,
4677
+ info,
4678
+ tx: executor
4679
+ });
4680
+ return { isSuccess: true };
4681
+ },
4682
+ !!hooks
4683
+ );
4520
4684
  } catch (e) {
4521
4685
  throw toGraphQLError(e);
4522
4686
  }
@@ -4526,36 +4690,64 @@ var generateUpdateMany = (db, tableName, table, updateManyInput, fieldName, filt
4526
4690
  };
4527
4691
  var generateDelete = (db, tableName, table, filterArgs, fieldName, single, requireWhere, filterCtx, txCtx, policies, restore = false) => {
4528
4692
  const softDelete = policies?.softDelete?.(tableName);
4693
+ const operation = restore ? "restore" : "delete";
4529
4694
  const queryArgs = {
4530
4695
  where: {
4531
4696
  type: single || requireWhere ? new import_graphql7.GraphQLNonNull(filterArgs) : filterArgs
4532
4697
  }
4533
4698
  };
4699
+ const hooks = policies?.onWrite?.(tableName, operation);
4534
4700
  return {
4535
4701
  name: fieldName,
4536
4702
  resolver: async (_source, args, context, info) => {
4537
4703
  try {
4538
- return await runMutation(db, context, info, txCtx, async (executor) => {
4539
- const { where } = args;
4540
- const scope = policies?.scope?.(context);
4541
- const relationCtx = relationFilterCtx(filterCtx, tableName);
4542
- const filters = withScope(
4543
- scope,
4544
- tableName,
4545
- table,
4546
- single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
4547
- restore ? "ONLY" : void 0
4548
- );
4549
- if (single) {
4550
- await assertSingleMatch(executor, table, filters, fieldName);
4551
- }
4552
- let query = softDelete ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
4553
- if (filters) {
4554
- query = query.where(filters);
4555
- }
4556
- await query;
4557
- return { isSuccess: true };
4558
- });
4704
+ return await runMutation(
4705
+ db,
4706
+ context,
4707
+ info,
4708
+ txCtx,
4709
+ async (executor) => {
4710
+ await runWriteHook(hooks, "before", {
4711
+ table: tableName,
4712
+ operation,
4713
+ single,
4714
+ args,
4715
+ context,
4716
+ info,
4717
+ tx: executor
4718
+ });
4719
+ const { where } = args;
4720
+ const scope = policies?.scope?.(context);
4721
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
4722
+ const filters = withScope(
4723
+ scope,
4724
+ tableName,
4725
+ table,
4726
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
4727
+ restore ? "ONLY" : void 0
4728
+ );
4729
+ if (single) {
4730
+ await assertSingleMatch(executor, table, filters, fieldName);
4731
+ }
4732
+ let query = softDelete ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
4733
+ if (filters) {
4734
+ query = query.where(filters);
4735
+ }
4736
+ await query;
4737
+ await runWriteHook(hooks, "after", {
4738
+ table: tableName,
4739
+ operation,
4740
+ single,
4741
+ args,
4742
+ rows: [],
4743
+ context,
4744
+ info,
4745
+ tx: executor
4746
+ });
4747
+ return { isSuccess: true };
4748
+ },
4749
+ !!hooks
4750
+ );
4559
4751
  } catch (e) {
4560
4752
  throw toGraphQLError(e);
4561
4753
  }
@@ -5029,6 +5221,64 @@ var import_graphql_parse_resolve_info3 = require("graphql-parse-resolve-info");
5029
5221
  var import_drizzle_orm7 = require("drizzle-orm");
5030
5222
  var import_graphql8 = require("graphql");
5031
5223
  var isOptionalOnInsert = (column) => !column.notNull || !!column.hasDefault || !!column.defaultFn;
5224
+ var propNameOf = (table, column) => {
5225
+ if (!column) {
5226
+ return void 0;
5227
+ }
5228
+ for (const [propName, candidate] of Object.entries((0, import_drizzle_orm7.getColumns)(table))) {
5229
+ if (candidate === column) {
5230
+ return propName;
5231
+ }
5232
+ }
5233
+ return void 0;
5234
+ };
5235
+ var throughColumn = (entry) => entry && (0, import_drizzle_orm7.is)(entry, import_drizzle_orm7.Column) ? entry : entry?._?.column;
5236
+ var buildThroughPlan = (relationName, relation, table, targetTableName, targetTable) => {
5237
+ if ((0, import_drizzle_orm7.is)(relation, import_drizzle_orm7.One)) {
5238
+ return void 0;
5239
+ }
5240
+ const junction = relation.throughTable;
5241
+ const sourceEntries = relation.through?.source;
5242
+ const targetEntries = relation.through?.target;
5243
+ if (!junction || sourceEntries?.length !== 1 || targetEntries?.length !== 1) {
5244
+ return void 0;
5245
+ }
5246
+ if (relation.sourceColumns?.length !== 1 || relation.targetColumns?.length !== 1) {
5247
+ return void 0;
5248
+ }
5249
+ const localCol = relation.sourceColumns[0];
5250
+ const foreignCol = relation.targetColumns[0];
5251
+ const localColPropName = propNameOf(table, localCol);
5252
+ const foreignColPropName = propNameOf(targetTable, foreignCol);
5253
+ const sourceColPropName = propNameOf(junction, throughColumn(sourceEntries[0]));
5254
+ const targetColPropName = propNameOf(junction, throughColumn(targetEntries[0]));
5255
+ if (!localColPropName || !foreignColPropName || !sourceColPropName || !targetColPropName) {
5256
+ return void 0;
5257
+ }
5258
+ const junctionColumns = (0, import_drizzle_orm7.getColumns)(junction);
5259
+ const sourceCol = junctionColumns[sourceColPropName];
5260
+ const targetCol = junctionColumns[targetColPropName];
5261
+ const unsuppliable = Object.entries(junctionColumns).some(
5262
+ ([propName, column]) => propName !== sourceColPropName && propName !== targetColPropName && !isOptionalOnInsert(column)
5263
+ );
5264
+ if (unsuppliable) {
5265
+ return void 0;
5266
+ }
5267
+ return {
5268
+ relationName,
5269
+ targetTableName,
5270
+ targetTable,
5271
+ localColPropName,
5272
+ foreignColPropName,
5273
+ foreignCol,
5274
+ localCol,
5275
+ isOne: false,
5276
+ // The link is written after the parent row exists, exactly like a child-side foreign key.
5277
+ fkSide: "child",
5278
+ canDetach: true,
5279
+ through: { table: junction, sourceColPropName, targetColPropName, sourceCol, targetCol }
5280
+ };
5281
+ };
5032
5282
  var buildNestedWritePlans = (tables, relationMap, resolveUniqueSets, resolvePrimaryKeys, extractJoinColumns) => {
5033
5283
  const uniqueCache = /* @__PURE__ */ new Map();
5034
5284
  const singleColumnUniques = (tableName, table) => {
@@ -5058,14 +5308,18 @@ var buildNestedWritePlans = (tables, relationMap, resolveUniqueSets, resolvePrim
5058
5308
  const tablePlans = {};
5059
5309
  for (const [relationName, relEntry] of Object.entries(relations)) {
5060
5310
  const relation = relEntry.relation;
5061
- if (relation.through) {
5062
- continue;
5063
- }
5064
5311
  const targetTableName = relEntry.targetTableName;
5065
5312
  const targetTable = tables[targetTableName];
5066
5313
  if (!targetTable) {
5067
5314
  continue;
5068
5315
  }
5316
+ if (relation.through) {
5317
+ const throughPlan = buildThroughPlan(relationName, relation, table, targetTableName, targetTable);
5318
+ if (throughPlan) {
5319
+ tablePlans[relationName] = throughPlan;
5320
+ }
5321
+ continue;
5322
+ }
5069
5323
  const joinColumns = extractJoinColumns(relEntry, table, targetTable);
5070
5324
  if (!joinColumns) {
5071
5325
  continue;
@@ -5150,11 +5404,31 @@ var createNestedWriteTypes = (params) => {
5150
5404
  return cached;
5151
5405
  }
5152
5406
  const filters = targetFilters(plan);
5153
- const payload = payloadType(tableName, typeName, plan);
5154
5407
  const targetTypeName = resolveTypeName(plan.targetTableName, typeNameMapper);
5155
5408
  const fields = {};
5156
- if (plan.isOne) {
5157
- fields["create"] = { type: payload, description: `Insert a ${targetTypeName} row and attach it` };
5409
+ if (plan.through) {
5410
+ if (!filters) {
5411
+ return void 0;
5412
+ }
5413
+ fields["connect"] = {
5414
+ type: listOf(filters),
5415
+ description: `Link every existing ${targetTypeName} row these match. Already-linked rows are left alone.`
5416
+ };
5417
+ if (forUpdate) {
5418
+ fields["disconnect"] = {
5419
+ type: listOf(filters),
5420
+ description: `Unlink every linked ${targetTypeName} row these match, leaving the rows in place`
5421
+ };
5422
+ fields["set"] = {
5423
+ type: listOf(filters),
5424
+ description: `Replace the whole set: unlink everything linked, then link every ${targetTypeName} row these match. \`set: []\` clears the relation. Applied before \`disconnect\` and \`connect\`.`
5425
+ };
5426
+ }
5427
+ } else if (plan.isOne) {
5428
+ fields["create"] = {
5429
+ type: payloadType(tableName, typeName, plan),
5430
+ description: `Insert a ${targetTypeName} row and attach it`
5431
+ };
5158
5432
  if (filters) {
5159
5433
  fields["connect"] = {
5160
5434
  type: filters,
@@ -5168,7 +5442,10 @@ var createNestedWriteTypes = (params) => {
5168
5442
  };
5169
5443
  }
5170
5444
  } else {
5171
- fields["create"] = { type: listOf(payload), description: `Insert these ${targetTypeName} rows and attach them` };
5445
+ fields["create"] = {
5446
+ type: listOf(payloadType(tableName, typeName, plan)),
5447
+ description: `Insert these ${targetTypeName} rows and attach them`
5448
+ };
5172
5449
  if (filters) {
5173
5450
  fields["connect"] = {
5174
5451
  type: listOf(filters),
@@ -5250,6 +5527,48 @@ var createNestedWriteRuntime = (params) => {
5250
5527
  );
5251
5528
  }
5252
5529
  };
5530
+ const selectedTargetKeys = async (executor, plan, filter, operation, scope) => {
5531
+ const rows = await executor.select().from(plan.targetTable).where(conditionOf(plan, filter, operation, scope));
5532
+ return rows.map((row) => row[plan.foreignColPropName]).filter((value) => value !== void 0 && value !== null);
5533
+ };
5534
+ const applyThroughOps = async (executor, plan, key, op, scope) => {
5535
+ const through = plan.through;
5536
+ const unlinkAll = () => executor.delete(through.table).where((0, import_drizzle_orm7.eq)(through.sourceCol, key));
5537
+ const link = async (operands, operation) => {
5538
+ const existing = new Set(
5539
+ (await executor.select().from(through.table).where((0, import_drizzle_orm7.eq)(through.sourceCol, key))).map(
5540
+ (row) => row[through.targetColPropName]
5541
+ )
5542
+ );
5543
+ const rows = [];
5544
+ for (const filter of operands) {
5545
+ for (const targetKey of await selectedTargetKeys(executor, plan, filter, operation, scope)) {
5546
+ if (!existing.has(targetKey)) {
5547
+ existing.add(targetKey);
5548
+ rows.push({ [through.sourceColPropName]: key, [through.targetColPropName]: targetKey });
5549
+ }
5550
+ }
5551
+ }
5552
+ if (rows.length) {
5553
+ await executor.insert(through.table).values(rows);
5554
+ }
5555
+ };
5556
+ if (op["set"] !== void 0 && op["set"] !== null) {
5557
+ await unlinkAll();
5558
+ await link(asArray(op["set"]), "set");
5559
+ }
5560
+ if (op["disconnect"] !== void 0 && op["disconnect"] !== null) {
5561
+ for (const filter of asArray(op["disconnect"])) {
5562
+ const targetKeys = await selectedTargetKeys(executor, plan, filter, "disconnect", scope);
5563
+ if (targetKeys.length) {
5564
+ await executor.delete(through.table).where((0, import_drizzle_orm7.and)((0, import_drizzle_orm7.eq)(through.sourceCol, key), (0, import_drizzle_orm7.inArray)(through.targetCol, targetKeys)));
5565
+ }
5566
+ }
5567
+ }
5568
+ if (op["connect"] !== void 0 && op["connect"] !== null) {
5569
+ await link(asArray(op["connect"]), "connect");
5570
+ }
5571
+ };
5253
5572
  const detachAll = async (executor, plan, key, scope) => executor.update(plan.targetTable).set({ [plan.foreignColPropName]: null }).where(withScope(scope, plan.targetTableName, plan.targetTable, (0, import_drizzle_orm7.eq)(plan.foreignCol, key)));
5254
5573
  return {
5255
5574
  enabled: (tableName) => !!plans[tableName],
@@ -5346,6 +5665,10 @@ var createNestedWriteRuntime = (params) => {
5346
5665
  `Drizzle-GraphQL Error: cannot write through '${relationName}': the ${tableName} row has no '${plan.localColPropName}' value to attach to.`
5347
5666
  );
5348
5667
  }
5668
+ if (plan.through) {
5669
+ await applyThroughOps(executor, plan, key, op, scope);
5670
+ continue;
5671
+ }
5349
5672
  if (op["set"] !== void 0) {
5350
5673
  await detachAll(executor, plan, key, scope);
5351
5674
  for (const filter of asArray(op["set"])) {
@@ -5428,7 +5751,8 @@ var generateSelectArray2 = (db, tableName, tables, relationMap, orderArgs, filte
5428
5751
  );
5429
5752
  return {
5430
5753
  name: fieldName,
5431
- resolver: async (_source, args, context, info) => {
5754
+ resolver: async (_source, rawArgs, context, info) => {
5755
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
5432
5756
  try {
5433
5757
  const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, { deep: true });
5434
5758
  const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
@@ -5449,6 +5773,7 @@ var generateSelectArray2 = (db, tableName, tables, relationMap, orderArgs, filte
5449
5773
  single: false,
5450
5774
  filterCtx,
5451
5775
  limits,
5776
+ defaultOrderBy: policies?.defaultOrderBy,
5452
5777
  pkNames,
5453
5778
  db: executor,
5454
5779
  scope,
@@ -5558,7 +5883,8 @@ var generateSelectSingle2 = (db, tableName, tables, relationMap, orderArgs, filt
5558
5883
  const pkNames = pgPrimaryKeyPropNames(table);
5559
5884
  return {
5560
5885
  name: fieldName,
5561
- resolver: async (_source, args, context, info) => {
5886
+ resolver: async (_source, rawArgs, context, info) => {
5887
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
5562
5888
  try {
5563
5889
  const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, { deep: true });
5564
5890
  const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
@@ -5577,6 +5903,7 @@ var generateSelectSingle2 = (db, tableName, tables, relationMap, orderArgs, filt
5577
5903
  single: true,
5578
5904
  filterCtx,
5579
5905
  limits,
5906
+ defaultOrderBy: policies?.defaultOrderBy,
5580
5907
  pkNames,
5581
5908
  db: executor,
5582
5909
  scope
@@ -5625,58 +5952,86 @@ var generateInsertArray2 = (db, tableName, table, tables, relationMap, baseType,
5625
5952
  }
5626
5953
  };
5627
5954
  const pkNames = pgPrimaryKeyPropNames(table);
5955
+ const hooks = policies?.onWrite?.(tableName, "insert");
5628
5956
  return {
5629
5957
  name: fieldName,
5630
5958
  resolver: async (_source, args, context, info) => {
5631
5959
  try {
5632
- return await runMutation(db, context, info, txCtx, async (executor) => {
5633
- if (!args.values.length) {
5634
- throw new import_graphql9.GraphQLError("No values were provided!");
5635
- }
5636
- const entries = nested?.enabled(tableName) ? args.values.map((values) => nested.split(tableName, values)) : void 0;
5637
- const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
5638
- const contextColumns = policies?.contextValues?.(tableName);
5639
- const scope = policies?.scope?.(context);
5640
- const input = nestedEntries ? [] : applyContextValuesAll(
5641
- remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : args.values, table),
5642
- contextColumns,
5643
- context
5644
- );
5645
- const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, {
5646
- deep: true
5647
- });
5648
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
5649
- relationMap,
5650
- tables,
5651
- tableName,
5652
- typeName,
5653
- typeNameMapper,
5654
- table,
5655
- pkNames,
5656
- parsedInfo,
5657
- limits,
5658
- scope
5659
- });
5660
- const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
5661
- const runInsert = async (target, values) => {
5662
- let query = target.insert(table).values(values).returning(returning);
5663
- if (conflictDoNothing) {
5664
- query = query.onConflictDoNothing();
5960
+ return await runMutation(
5961
+ db,
5962
+ context,
5963
+ info,
5964
+ txCtx,
5965
+ async (executor) => {
5966
+ if (!args.values.length) {
5967
+ throw new import_graphql9.GraphQLError("No values were provided!");
5665
5968
  }
5666
- return await query;
5667
- };
5668
- const result = nestedEntries ? await writeWithNestedOps({
5669
- executor,
5670
- runtime: nested,
5671
- tableName,
5672
- entries: nestedEntries,
5673
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
5674
- write: (tx, values) => runInsert(tx, [values]),
5675
- context
5676
- }) : await runInsert(executor, input);
5677
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
5678
- return remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
5679
- });
5969
+ await runWriteHook(hooks, "before", {
5970
+ table: tableName,
5971
+ operation: "insert",
5972
+ single: false,
5973
+ args,
5974
+ context,
5975
+ info,
5976
+ tx: executor
5977
+ });
5978
+ const entries = nested?.enabled(tableName) ? args.values.map((values) => nested.split(tableName, values)) : void 0;
5979
+ const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
5980
+ const contextColumns = policies?.contextValues?.(tableName);
5981
+ const scope = policies?.scope?.(context);
5982
+ const input = nestedEntries ? [] : applyContextValuesAll(
5983
+ remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : args.values, table),
5984
+ contextColumns,
5985
+ context
5986
+ );
5987
+ const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, {
5988
+ deep: true
5989
+ });
5990
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
5991
+ relationMap,
5992
+ tables,
5993
+ tableName,
5994
+ typeName,
5995
+ typeNameMapper,
5996
+ table,
5997
+ pkNames,
5998
+ parsedInfo,
5999
+ limits,
6000
+ scope,
6001
+ defaultOrderBy: policies?.defaultOrderBy
6002
+ });
6003
+ const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
6004
+ const runInsert = async (target, values) => {
6005
+ let query = target.insert(table).values(values).returning(returning);
6006
+ if (conflictDoNothing) {
6007
+ query = query.onConflictDoNothing();
6008
+ }
6009
+ return await query;
6010
+ };
6011
+ const result = nestedEntries ? await writeWithNestedOps({
6012
+ executor,
6013
+ runtime: nested,
6014
+ tableName,
6015
+ entries: nestedEntries,
6016
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6017
+ write: (tx, values) => runInsert(tx, [values]),
6018
+ context
6019
+ }) : await runInsert(executor, input);
6020
+ await runWriteHook(hooks, "after", {
6021
+ table: tableName,
6022
+ operation: "insert",
6023
+ single: false,
6024
+ args,
6025
+ rows: result,
6026
+ context,
6027
+ info,
6028
+ tx: executor
6029
+ });
6030
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6031
+ return remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
6032
+ },
6033
+ !!hooks
6034
+ );
5680
6035
  } catch (e) {
5681
6036
  throw toGraphQLError(e);
5682
6037
  }
@@ -5691,61 +6046,89 @@ var generateInsertSingle2 = (db, tableName, table, tables, relationMap, baseType
5691
6046
  }
5692
6047
  };
5693
6048
  const pkNames = pgPrimaryKeyPropNames(table);
6049
+ const hooks = policies?.onWrite?.(tableName, "insert");
5694
6050
  return {
5695
6051
  name: fieldName,
5696
6052
  resolver: async (_source, args, context, info) => {
5697
6053
  try {
5698
- return await runMutation(db, context, info, txCtx, async (executor) => {
5699
- const entry = nested?.enabled(tableName) ? nested.split(tableName, args.values) : void 0;
5700
- const nestedEntry = entry && nested.hasOps(entry.ops) ? entry : void 0;
5701
- const contextColumns = policies?.contextValues?.(tableName);
5702
- const scope = policies?.scope?.(context);
5703
- const input = nestedEntry ? {} : applyContextValues(
5704
- remapFromGraphQLSingleInput(entry ? entry.columns : args.values, table),
5705
- contextColumns,
5706
- context
5707
- );
5708
- const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, {
5709
- deep: true
5710
- });
5711
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
5712
- relationMap,
5713
- tables,
5714
- tableName,
5715
- typeName,
5716
- typeNameMapper,
5717
- table,
5718
- pkNames,
5719
- parsedInfo,
5720
- limits,
5721
- scope
5722
- });
5723
- const returning = nestedEntry ? nested.withJoinColumns(tableName, nestedEntry.ops, { ...columns }, table) : columns;
5724
- const runInsert = async (target, values) => {
5725
- let query = target.insert(table).values(values).returning(returning);
5726
- if (conflictDoNothing) {
5727
- query = query.onConflictDoNothing();
5728
- }
5729
- return await query;
5730
- };
5731
- const result = nestedEntry ? await writeWithNestedOps({
5732
- executor,
5733
- runtime: nested,
5734
- tableName,
5735
- entries: [nestedEntry],
5736
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
5737
- write: runInsert,
5738
- context
5739
- }) : await runInsert(executor, input);
5740
- if (!result[0]) {
5741
- if (!conflictDoNothing) {
5742
- throw new import_graphql9.GraphQLError(`${fieldName}: the insert returned no row.`);
6054
+ return await runMutation(
6055
+ db,
6056
+ context,
6057
+ info,
6058
+ txCtx,
6059
+ async (executor) => {
6060
+ await runWriteHook(hooks, "before", {
6061
+ table: tableName,
6062
+ operation: "insert",
6063
+ single: true,
6064
+ args,
6065
+ context,
6066
+ info,
6067
+ tx: executor
6068
+ });
6069
+ const entry = nested?.enabled(tableName) ? nested.split(tableName, args.values) : void 0;
6070
+ const nestedEntry = entry && nested.hasOps(entry.ops) ? entry : void 0;
6071
+ const contextColumns = policies?.contextValues?.(tableName);
6072
+ const scope = policies?.scope?.(context);
6073
+ const input = nestedEntry ? {} : applyContextValues(
6074
+ remapFromGraphQLSingleInput(entry ? entry.columns : args.values, table),
6075
+ contextColumns,
6076
+ context
6077
+ );
6078
+ const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, {
6079
+ deep: true
6080
+ });
6081
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6082
+ relationMap,
6083
+ tables,
6084
+ tableName,
6085
+ typeName,
6086
+ typeNameMapper,
6087
+ table,
6088
+ pkNames,
6089
+ parsedInfo,
6090
+ limits,
6091
+ scope,
6092
+ defaultOrderBy: policies?.defaultOrderBy
6093
+ });
6094
+ const returning = nestedEntry ? nested.withJoinColumns(tableName, nestedEntry.ops, { ...columns }, table) : columns;
6095
+ const runInsert = async (target, values) => {
6096
+ let query = target.insert(table).values(values).returning(returning);
6097
+ if (conflictDoNothing) {
6098
+ query = query.onConflictDoNothing();
6099
+ }
6100
+ return await query;
6101
+ };
6102
+ const result = nestedEntry ? await writeWithNestedOps({
6103
+ executor,
6104
+ runtime: nested,
6105
+ tableName,
6106
+ entries: [nestedEntry],
6107
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6108
+ write: runInsert,
6109
+ context
6110
+ }) : await runInsert(executor, input);
6111
+ await runWriteHook(hooks, "after", {
6112
+ table: tableName,
6113
+ operation: "insert",
6114
+ single: true,
6115
+ args,
6116
+ rows: result,
6117
+ context,
6118
+ info,
6119
+ tx: executor
6120
+ });
6121
+ if (!result[0]) {
6122
+ if (!conflictDoNothing) {
6123
+ throw new import_graphql9.GraphQLError(`${fieldName}: the insert returned no row.`);
6124
+ }
6125
+ return void 0;
5743
6126
  }
5744
- return void 0;
5745
- }
5746
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
5747
- return remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap);
5748
- });
6127
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6128
+ return remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap);
6129
+ },
6130
+ !!hooks
6131
+ );
5749
6132
  } catch (e) {
5750
6133
  throw toGraphQLError(e);
5751
6134
  }
@@ -5764,69 +6147,97 @@ var generateUpsert2 = (db, tableName, table, tables, relationMap, baseType, onCo
5764
6147
  }
5765
6148
  };
5766
6149
  const pkNames = pgPrimaryKeyPropNames(table);
6150
+ const hooks = policies?.onWrite?.(tableName, "upsert");
5767
6151
  return {
5768
6152
  name: fieldName,
5769
6153
  resolver: async (_source, args, context, info) => {
5770
6154
  try {
5771
- return await runMutation(db, context, info, txCtx, async (executor) => {
5772
- const supplied = single ? [args.values] : args.values;
5773
- if (!supplied.length) {
5774
- throw new import_graphql9.GraphQLError("No values were provided!");
5775
- }
5776
- const entries = nested?.enabled(tableName) ? supplied.map((values) => nested.split(tableName, values)) : void 0;
5777
- const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
5778
- const contextColumns = policies?.contextValues?.(tableName);
5779
- const scope = policies?.scope?.(context);
5780
- const input = nestedEntries ? [] : applyContextValuesAll(
5781
- remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : supplied, table),
5782
- contextColumns,
5783
- context
5784
- );
5785
- const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, { deep: true });
5786
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
5787
- relationMap,
5788
- tables,
5789
- tableName,
5790
- typeName,
5791
- typeNameMapper,
5792
- table,
5793
- pkNames,
5794
- parsedInfo,
5795
- limits,
5796
- scope
5797
- });
5798
- const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
5799
- const runUpsert = async (target, values) => {
5800
- const plan = resolveConflictPlan({
6155
+ return await runMutation(
6156
+ db,
6157
+ context,
6158
+ info,
6159
+ txCtx,
6160
+ async (executor) => {
6161
+ const supplied = single ? [args.values] : args.values;
6162
+ if (!supplied.length) {
6163
+ throw new import_graphql9.GraphQLError("No values were provided!");
6164
+ }
6165
+ await runWriteHook(hooks, "before", {
6166
+ table: tableName,
6167
+ operation: "upsert",
6168
+ single,
6169
+ args,
6170
+ context,
6171
+ info,
6172
+ tx: executor
6173
+ });
6174
+ const entries = nested?.enabled(tableName) ? supplied.map((values) => nested.split(tableName, values)) : void 0;
6175
+ const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
6176
+ const contextColumns = policies?.contextValues?.(tableName);
6177
+ const scope = policies?.scope?.(context);
6178
+ const input = nestedEntries ? [] : applyContextValuesAll(
6179
+ remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : supplied, table),
6180
+ contextColumns,
6181
+ context
6182
+ );
6183
+ const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, { deep: true });
6184
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6185
+ relationMap,
6186
+ tables,
6187
+ tableName,
6188
+ typeName,
6189
+ typeNameMapper,
5801
6190
  table,
5802
- values,
5803
- onConflict: args.onConflict,
5804
6191
  pkNames,
5805
- uniqueSets,
5806
- excludedRef: excludedColumnRef,
5807
- withTarget: true,
5808
- buildWhere: (where) => extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName))
6192
+ parsedInfo,
6193
+ limits,
6194
+ scope,
6195
+ defaultOrderBy: policies?.defaultOrderBy
5809
6196
  });
5810
- let query = target.insert(table).values(values).returning(returning);
5811
- const setWhere = withScope(scope, tableName, table, plan.setWhere);
5812
- query = plan.action === "NOTHING" ? query.onConflictDoNothing(plan.target ? { target: plan.target } : void 0) : query.onConflictDoUpdate({ target: plan.target, set: plan.set, setWhere });
5813
- return await query;
5814
- };
5815
- const result = nestedEntries ? await writeWithNestedOps({
5816
- executor,
5817
- runtime: nested,
5818
- tableName,
5819
- entries: nestedEntries,
5820
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
5821
- write: (tx, values) => runUpsert(tx, [values]),
5822
- context
5823
- }) : await runUpsert(executor, input);
5824
- if (single && !result[0]) {
5825
- return void 0;
5826
- }
5827
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
5828
- return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
5829
- });
6197
+ const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
6198
+ const runUpsert = async (target, values) => {
6199
+ const plan = resolveConflictPlan({
6200
+ table,
6201
+ values,
6202
+ onConflict: args.onConflict,
6203
+ pkNames,
6204
+ uniqueSets,
6205
+ excludedRef: excludedColumnRef,
6206
+ withTarget: true,
6207
+ buildWhere: (where) => extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName))
6208
+ });
6209
+ let query = target.insert(table).values(values).returning(returning);
6210
+ const setWhere = withScope(scope, tableName, table, plan.setWhere);
6211
+ query = plan.action === "NOTHING" ? query.onConflictDoNothing(plan.target ? { target: plan.target } : void 0) : query.onConflictDoUpdate({ target: plan.target, set: plan.set, setWhere });
6212
+ return await query;
6213
+ };
6214
+ const result = nestedEntries ? await writeWithNestedOps({
6215
+ executor,
6216
+ runtime: nested,
6217
+ tableName,
6218
+ entries: nestedEntries,
6219
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6220
+ write: (tx, values) => runUpsert(tx, [values]),
6221
+ context
6222
+ }) : await runUpsert(executor, input);
6223
+ await runWriteHook(hooks, "after", {
6224
+ table: tableName,
6225
+ operation: "upsert",
6226
+ single,
6227
+ args,
6228
+ rows: result,
6229
+ context,
6230
+ info,
6231
+ tx: executor
6232
+ });
6233
+ if (single && !result[0]) {
6234
+ return void 0;
6235
+ }
6236
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6237
+ return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
6238
+ },
6239
+ !!hooks
6240
+ );
5830
6241
  } catch (e) {
5831
6242
  throw toGraphQLError(e);
5832
6243
  }
@@ -5844,75 +6255,103 @@ var generateUpdate2 = (db, tableName, table, tables, relationMap, setArgs, filte
5844
6255
  }
5845
6256
  };
5846
6257
  const pkNames = pgPrimaryKeyPropNames(table);
6258
+ const hooks = policies?.onWrite?.(tableName, "update");
5847
6259
  return {
5848
6260
  name: fieldName,
5849
6261
  resolver: async (_source, args, context, info) => {
5850
6262
  try {
5851
- return await runMutation(db, context, info, txCtx, async (executor) => {
5852
- const { where, set } = args;
5853
- const scope = policies?.scope?.(context);
5854
- const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, {
5855
- deep: true
5856
- });
5857
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
5858
- relationMap,
5859
- tables,
5860
- tableName,
5861
- typeName,
5862
- typeNameMapper,
5863
- table,
5864
- pkNames,
5865
- parsedInfo,
5866
- limits,
5867
- scope
5868
- });
5869
- const entry = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
5870
- const nestedOps = entry && nested.hasOps(entry.ops) ? entry.ops : void 0;
5871
- const input = stripContextValues(
5872
- remapUpdateInput(entry ? entry.columns : set, table, tableName),
5873
- policies?.contextValues?.(tableName)
5874
- );
5875
- if (!Object.keys(input).length && !nestedOps) {
5876
- throw new import_graphql9.GraphQLError("Unable to update with no values specified!");
5877
- }
5878
- const relationCtx = relationFilterCtx(filterCtx, tableName);
5879
- const filters = withScope(
5880
- scope,
5881
- tableName,
5882
- table,
5883
- single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
5884
- );
5885
- if (single) {
5886
- await assertSingleMatch(executor, table, filters, fieldName);
5887
- }
5888
- const returning = nestedOps ? nested.withJoinColumns(tableName, nestedOps, { ...columns }, table) : columns;
5889
- const runUpdate = async (target, values) => {
5890
- const writes = Object.keys(values).length > 0;
5891
- let query = writes ? target.update(table).set(values) : target.select(returning).from(table);
5892
- if (filters) {
5893
- query = query.where(filters);
6263
+ return await runMutation(
6264
+ db,
6265
+ context,
6266
+ info,
6267
+ txCtx,
6268
+ async (executor) => {
6269
+ const { where, set } = args;
6270
+ const scope = policies?.scope?.(context);
6271
+ await runWriteHook(hooks, "before", {
6272
+ table: tableName,
6273
+ operation: "update",
6274
+ single,
6275
+ args,
6276
+ context,
6277
+ info,
6278
+ tx: executor
6279
+ });
6280
+ const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, {
6281
+ deep: true
6282
+ });
6283
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6284
+ relationMap,
6285
+ tables,
6286
+ tableName,
6287
+ typeName,
6288
+ typeNameMapper,
6289
+ table,
6290
+ pkNames,
6291
+ parsedInfo,
6292
+ limits,
6293
+ scope,
6294
+ defaultOrderBy: policies?.defaultOrderBy
6295
+ });
6296
+ const entry = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
6297
+ const nestedOps = entry && nested.hasOps(entry.ops) ? entry.ops : void 0;
6298
+ const input = stripContextValues(
6299
+ remapUpdateInput(entry ? entry.columns : set, table, tableName),
6300
+ policies?.contextValues?.(tableName)
6301
+ );
6302
+ if (!Object.keys(input).length && !nestedOps) {
6303
+ throw new import_graphql9.GraphQLError("Unable to update with no values specified!");
5894
6304
  }
5895
- return await (writes ? query.returning(returning) : query);
5896
- };
5897
- const result = nestedOps ? await updateWithNestedOps({
5898
- executor,
5899
- runtime: nested,
5900
- tableName,
5901
- columns: input,
5902
- ops: nestedOps,
5903
- remapValues: (values) => values,
5904
- write: runUpdate,
5905
- context
5906
- }) : await runUpdate(executor, input);
5907
- if (single && result.length > 1) {
5908
- throw new import_graphql9.GraphQLError(`${fieldName}: 'where' matched more than one row!`);
5909
- }
5910
- if (single && !result[0]) {
5911
- return void 0;
5912
- }
5913
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
5914
- return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
5915
- });
6305
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
6306
+ const filters = withScope(
6307
+ scope,
6308
+ tableName,
6309
+ table,
6310
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
6311
+ );
6312
+ if (single) {
6313
+ await assertSingleMatch(executor, table, filters, fieldName);
6314
+ }
6315
+ const returning = nestedOps ? nested.withJoinColumns(tableName, nestedOps, { ...columns }, table) : columns;
6316
+ const runUpdate = async (target, values) => {
6317
+ const writes = Object.keys(values).length > 0;
6318
+ let query = writes ? target.update(table).set(values) : target.select(returning).from(table);
6319
+ if (filters) {
6320
+ query = query.where(filters);
6321
+ }
6322
+ return await (writes ? query.returning(returning) : query);
6323
+ };
6324
+ const result = nestedOps ? await updateWithNestedOps({
6325
+ executor,
6326
+ runtime: nested,
6327
+ tableName,
6328
+ columns: input,
6329
+ ops: nestedOps,
6330
+ remapValues: (values) => values,
6331
+ write: runUpdate,
6332
+ context
6333
+ }) : await runUpdate(executor, input);
6334
+ await runWriteHook(hooks, "after", {
6335
+ table: tableName,
6336
+ operation: "update",
6337
+ single,
6338
+ args,
6339
+ rows: result,
6340
+ context,
6341
+ info,
6342
+ tx: executor
6343
+ });
6344
+ if (single && result.length > 1) {
6345
+ throw new import_graphql9.GraphQLError(`${fieldName}: 'where' matched more than one row!`);
6346
+ }
6347
+ if (single && !result[0]) {
6348
+ return void 0;
6349
+ }
6350
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6351
+ return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
6352
+ },
6353
+ !!hooks
6354
+ );
5916
6355
  } catch (e) {
5917
6356
  throw toGraphQLError(e);
5918
6357
  }
@@ -5927,94 +6366,122 @@ var generateUpdateMany2 = (db, tableName, table, tables, relationMap, updateMany
5927
6366
  }
5928
6367
  };
5929
6368
  const pkNames = pgPrimaryKeyPropNames(table);
6369
+ const hooks = policies?.onWrite?.(tableName, "updateMany");
5930
6370
  return {
5931
6371
  name: fieldName,
5932
6372
  resolver: async (_source, args, context, info) => {
5933
6373
  try {
5934
- return await runMutation(db, context, info, txCtx, async (executor) => {
5935
- const { updates } = args;
5936
- if (!updates.length) {
5937
- throw new import_graphql9.GraphQLError("No updates were provided!");
5938
- }
5939
- const scope = policies?.scope?.(context);
5940
- const contextColumns = policies?.contextValues?.(tableName);
5941
- const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, {
5942
- deep: true
5943
- });
5944
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
5945
- relationMap,
5946
- tables,
5947
- tableName,
5948
- typeName,
5949
- typeNameMapper,
5950
- table,
5951
- pkNames,
5952
- parsedInfo,
5953
- limits,
5954
- scope
5955
- });
5956
- const entries = updates.map(({ where, set }) => {
5957
- const split = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
5958
- const ops = split && nested.hasOps(split.ops) ? split.ops : void 0;
5959
- const input = stripContextValues(
5960
- remapUpdateInput(split ? split.columns : set, table, tableName),
5961
- contextColumns
5962
- );
5963
- if (!Object.keys(input).length && !ops) {
5964
- throw new import_graphql9.GraphQLError("Unable to update with no values specified!");
6374
+ return await runMutation(
6375
+ db,
6376
+ context,
6377
+ info,
6378
+ txCtx,
6379
+ async (executor) => {
6380
+ const { updates } = args;
6381
+ if (!updates.length) {
6382
+ throw new import_graphql9.GraphQLError("No updates were provided!");
5965
6383
  }
5966
- return {
5967
- set: input,
5968
- ops,
5969
- filters: withScope(
5970
- scope,
5971
- tableName,
5972
- table,
5973
- where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
5974
- )
5975
- };
5976
- });
5977
- const returning = entries.some((entry) => entry.ops) ? nested.withJoinColumns(
5978
- tableName,
5979
- mergedOps(entries.map((entry) => ({ ops: entry.ops ?? {} }))),
5980
- {
5981
- ...columns
5982
- },
5983
- table
5984
- ) : columns;
5985
- const perEntry = await executor.transaction(async (tx) => {
5986
- const results = [];
5987
- for (const entry of entries) {
5988
- const values = entry.ops ? { ...entry.set, ...await nested.applyParentSide(tx, tableName, entry.ops, context) } : entry.set;
5989
- const writes = Object.keys(values).length > 0;
5990
- let query = writes ? tx.update(table).set(values) : tx.select(returning).from(table);
5991
- if (entry.filters) {
5992
- query = query.where(entry.filters);
6384
+ await runWriteHook(hooks, "before", {
6385
+ table: tableName,
6386
+ operation: "updateMany",
6387
+ single: false,
6388
+ args,
6389
+ context,
6390
+ info,
6391
+ tx: executor
6392
+ });
6393
+ const scope = policies?.scope?.(context);
6394
+ const contextColumns = policies?.contextValues?.(tableName);
6395
+ const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, {
6396
+ deep: true
6397
+ });
6398
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6399
+ relationMap,
6400
+ tables,
6401
+ tableName,
6402
+ typeName,
6403
+ typeNameMapper,
6404
+ table,
6405
+ pkNames,
6406
+ parsedInfo,
6407
+ limits,
6408
+ scope,
6409
+ defaultOrderBy: policies?.defaultOrderBy
6410
+ });
6411
+ const entries = updates.map(({ where, set }) => {
6412
+ const split = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
6413
+ const ops = split && nested.hasOps(split.ops) ? split.ops : void 0;
6414
+ const input = stripContextValues(
6415
+ remapUpdateInput(split ? split.columns : set, table, tableName),
6416
+ contextColumns
6417
+ );
6418
+ if (!Object.keys(input).length && !ops) {
6419
+ throw new import_graphql9.GraphQLError("Unable to update with no values specified!");
5993
6420
  }
5994
- const rows = await (writes ? query.returning(returning) : query);
5995
- if (entry.ops) {
5996
- await nested.applyChildSide(tx, tableName, entry.ops, rows, context);
6421
+ return {
6422
+ set: input,
6423
+ ops,
6424
+ filters: withScope(
6425
+ scope,
6426
+ tableName,
6427
+ table,
6428
+ where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
6429
+ )
6430
+ };
6431
+ });
6432
+ const returning = entries.some((entry) => entry.ops) ? nested.withJoinColumns(
6433
+ tableName,
6434
+ mergedOps(entries.map((entry) => ({ ops: entry.ops ?? {} }))),
6435
+ {
6436
+ ...columns
6437
+ },
6438
+ table
6439
+ ) : columns;
6440
+ const perEntry = await executor.transaction(async (tx) => {
6441
+ const results = [];
6442
+ for (const entry of entries) {
6443
+ const values = entry.ops ? { ...entry.set, ...await nested.applyParentSide(tx, tableName, entry.ops, context) } : entry.set;
6444
+ const writes = Object.keys(values).length > 0;
6445
+ let query = writes ? tx.update(table).set(values) : tx.select(returning).from(table);
6446
+ if (entry.filters) {
6447
+ query = query.where(entry.filters);
6448
+ }
6449
+ const rows = await (writes ? query.returning(returning) : query);
6450
+ if (entry.ops) {
6451
+ await nested.applyChildSide(tx, tableName, entry.ops, rows, context);
6452
+ }
6453
+ results.push(rows);
5997
6454
  }
5998
- results.push(rows);
5999
- }
6000
- return results;
6001
- });
6002
- const flatRows = perEntry.flat();
6003
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, flatRows, pkNames, withParams) : flatRows;
6004
- const output = [];
6005
- let offset = 0;
6006
- for (const rows of perEntry) {
6007
- if (!rows.length) {
6008
- output.push(null);
6009
- continue;
6010
- }
6011
- for (let i = 0; i < rows.length; i++) {
6012
- output.push(remapToGraphQLSingleOutput(enriched[offset + i], tableName, table, relationMap));
6455
+ return results;
6456
+ });
6457
+ const flatRows = perEntry.flat();
6458
+ await runWriteHook(hooks, "after", {
6459
+ table: tableName,
6460
+ operation: "updateMany",
6461
+ single: false,
6462
+ args,
6463
+ rows: flatRows,
6464
+ context,
6465
+ info,
6466
+ tx: executor
6467
+ });
6468
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, flatRows, pkNames, withParams) : flatRows;
6469
+ const output = [];
6470
+ let offset = 0;
6471
+ for (const rows of perEntry) {
6472
+ if (!rows.length) {
6473
+ output.push(null);
6474
+ continue;
6475
+ }
6476
+ for (let i = 0; i < rows.length; i++) {
6477
+ output.push(remapToGraphQLSingleOutput(enriched[offset + i], tableName, table, relationMap));
6478
+ }
6479
+ offset += rows.length;
6013
6480
  }
6014
- offset += rows.length;
6015
- }
6016
- return output;
6017
- });
6481
+ return output;
6482
+ },
6483
+ !!hooks
6484
+ );
6018
6485
  } catch (e) {
6019
6486
  throw toGraphQLError(e);
6020
6487
  }
@@ -6024,6 +6491,8 @@ var generateUpdateMany2 = (db, tableName, table, tables, relationMap, updateMany
6024
6491
  };
6025
6492
  var generateDelete2 = (db, tableName, table, filterArgs, fieldName, typeName, single, requireWhere, filterCtx, selectionCtx, txCtx, policies, restore = false) => {
6026
6493
  const softDelete = policies?.softDelete?.(tableName);
6494
+ const operation = restore ? "restore" : "delete";
6495
+ const hooks = policies?.onWrite?.(tableName, operation);
6027
6496
  const queryArgs = {
6028
6497
  where: {
6029
6498
  type: single || requireWhere ? new import_graphql9.GraphQLNonNull(filterArgs) : filterArgs
@@ -6033,42 +6502,68 @@ var generateDelete2 = (db, tableName, table, filterArgs, fieldName, typeName, si
6033
6502
  name: fieldName,
6034
6503
  resolver: async (_source, args, context, info) => {
6035
6504
  try {
6036
- return await runMutation(db, context, info, txCtx, async (executor) => {
6037
- const { where } = args;
6038
- const scope = policies?.scope?.(context);
6039
- const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, {
6040
- deep: true
6041
- });
6042
- const columns = extractSelectedColumnsFromTreeSQLFormat(
6043
- parsedInfo.fieldsByTypeName[typeName],
6044
- table,
6045
- selectionCtx
6046
- );
6047
- const relationCtx = relationFilterCtx(filterCtx, tableName);
6048
- const filters = withScope(
6049
- scope,
6050
- tableName,
6051
- table,
6052
- single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
6053
- restore ? "ONLY" : void 0
6054
- );
6055
- if (single) {
6056
- await assertSingleMatch(executor, table, filters, fieldName);
6057
- }
6058
- let query = softDelete ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
6059
- if (filters) {
6060
- query = query.where(filters);
6061
- }
6062
- query = query.returning(columns);
6063
- const result = await query;
6064
- if (single && result.length > 1) {
6065
- throw new import_graphql9.GraphQLError(`${fieldName}: 'where' matched more than one row!`);
6066
- }
6067
- if (single) {
6068
- return result[0] ? remapToGraphQLSingleOutput(result[0], tableName, table) : void 0;
6069
- }
6070
- return remapToGraphQLArrayOutput(result, tableName, table);
6071
- });
6505
+ return await runMutation(
6506
+ db,
6507
+ context,
6508
+ info,
6509
+ txCtx,
6510
+ async (executor) => {
6511
+ const { where } = args;
6512
+ const scope = policies?.scope?.(context);
6513
+ await runWriteHook(hooks, "before", {
6514
+ table: tableName,
6515
+ operation,
6516
+ single,
6517
+ args,
6518
+ context,
6519
+ info,
6520
+ tx: executor
6521
+ });
6522
+ const parsedInfo = (0, import_graphql_parse_resolve_info3.parseResolveInfo)(info, {
6523
+ deep: true
6524
+ });
6525
+ const columns = extractSelectedColumnsFromTreeSQLFormat(
6526
+ parsedInfo.fieldsByTypeName[typeName],
6527
+ table,
6528
+ selectionCtx
6529
+ );
6530
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
6531
+ const filters = withScope(
6532
+ scope,
6533
+ tableName,
6534
+ table,
6535
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
6536
+ restore ? "ONLY" : void 0
6537
+ );
6538
+ if (single) {
6539
+ await assertSingleMatch(executor, table, filters, fieldName);
6540
+ }
6541
+ let query = softDelete ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
6542
+ if (filters) {
6543
+ query = query.where(filters);
6544
+ }
6545
+ query = query.returning(columns);
6546
+ const result = await query;
6547
+ await runWriteHook(hooks, "after", {
6548
+ table: tableName,
6549
+ operation,
6550
+ single,
6551
+ args,
6552
+ rows: result,
6553
+ context,
6554
+ info,
6555
+ tx: executor
6556
+ });
6557
+ if (single && result.length > 1) {
6558
+ throw new import_graphql9.GraphQLError(`${fieldName}: 'where' matched more than one row!`);
6559
+ }
6560
+ if (single) {
6561
+ return result[0] ? remapToGraphQLSingleOutput(result[0], tableName, table) : void 0;
6562
+ }
6563
+ return remapToGraphQLArrayOutput(result, tableName, table);
6564
+ },
6565
+ !!hooks
6566
+ );
6072
6567
  } catch (e) {
6073
6568
  throw toGraphQLError(e);
6074
6569
  }
@@ -6715,7 +7210,8 @@ var generateSelectArray3 = (db, tableName, tables, relationMap, orderArgs, filte
6715
7210
  );
6716
7211
  return {
6717
7212
  name: fieldName,
6718
- resolver: async (_source, args, context, info) => {
7213
+ resolver: async (_source, rawArgs, context, info) => {
7214
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
6719
7215
  try {
6720
7216
  const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, { deep: true });
6721
7217
  const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
@@ -6733,6 +7229,7 @@ var generateSelectArray3 = (db, tableName, tables, relationMap, orderArgs, filte
6733
7229
  single: false,
6734
7230
  filterCtx,
6735
7231
  limits,
7232
+ defaultOrderBy: policies?.defaultOrderBy,
6736
7233
  pkNames,
6737
7234
  db: executor,
6738
7235
  scope: policies?.scope?.(context),
@@ -6758,7 +7255,8 @@ var generateSelectSingle3 = (db, tableName, tables, relationMap, orderArgs, filt
6758
7255
  const pkNames = sqlitePrimaryKeyPropNames(table);
6759
7256
  return {
6760
7257
  name: fieldName,
6761
- resolver: async (_source, args, context, info) => {
7258
+ resolver: async (_source, rawArgs, context, info) => {
7259
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
6762
7260
  try {
6763
7261
  const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, { deep: true });
6764
7262
  const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
@@ -6775,6 +7273,7 @@ var generateSelectSingle3 = (db, tableName, tables, relationMap, orderArgs, filt
6775
7273
  single: true,
6776
7274
  filterCtx,
6777
7275
  limits,
7276
+ defaultOrderBy: policies?.defaultOrderBy,
6778
7277
  pkNames,
6779
7278
  db: executor,
6780
7279
  scope: policies?.scope?.(context)
@@ -6794,58 +7293,86 @@ var generateInsertArray3 = (db, tableName, table, tables, relationMap, baseType,
6794
7293
  }
6795
7294
  };
6796
7295
  const pkNames = sqlitePrimaryKeyPropNames(table);
7296
+ const hooks = policies?.onWrite?.(tableName, "insert");
6797
7297
  return {
6798
7298
  name: fieldName,
6799
7299
  resolver: async (_source, args, context, info) => {
6800
7300
  try {
6801
- return await runMutation(db, context, info, txCtx, async (executor) => {
6802
- if (!args.values.length) {
6803
- throw new import_graphql10.GraphQLError("No values were provided!");
6804
- }
6805
- const entries = nested?.enabled(tableName) ? args.values.map((values) => nested.split(tableName, values)) : void 0;
6806
- const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
6807
- const contextColumns = policies?.contextValues?.(tableName);
6808
- const scope = policies?.scope?.(context);
6809
- const input = nestedEntries ? [] : applyContextValuesAll(
6810
- remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : args.values, table),
6811
- contextColumns,
6812
- context
6813
- );
6814
- const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, {
6815
- deep: true
6816
- });
6817
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6818
- relationMap,
6819
- tables,
6820
- tableName,
6821
- typeName,
6822
- typeNameMapper,
6823
- table,
6824
- pkNames,
6825
- parsedInfo,
6826
- limits,
6827
- scope
6828
- });
6829
- const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
6830
- const runInsert = async (target, values) => {
6831
- let query = target.insert(table).values(values).returning(returning);
6832
- if (conflictDoNothing) {
6833
- query = query.onConflictDoNothing();
7301
+ return await runMutation(
7302
+ db,
7303
+ context,
7304
+ info,
7305
+ txCtx,
7306
+ async (executor) => {
7307
+ if (!args.values.length) {
7308
+ throw new import_graphql10.GraphQLError("No values were provided!");
6834
7309
  }
6835
- return await query;
6836
- };
6837
- const result = nestedEntries ? await writeWithNestedOps({
6838
- executor,
6839
- runtime: nested,
6840
- tableName,
6841
- entries: nestedEntries,
6842
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6843
- write: (tx, values) => runInsert(tx, [values]),
6844
- context
6845
- }) : await runInsert(executor, input);
6846
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6847
- return remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
6848
- });
7310
+ await runWriteHook(hooks, "before", {
7311
+ table: tableName,
7312
+ operation: "insert",
7313
+ single: false,
7314
+ args,
7315
+ context,
7316
+ info,
7317
+ tx: executor
7318
+ });
7319
+ const entries = nested?.enabled(tableName) ? args.values.map((values) => nested.split(tableName, values)) : void 0;
7320
+ const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
7321
+ const contextColumns = policies?.contextValues?.(tableName);
7322
+ const scope = policies?.scope?.(context);
7323
+ const input = nestedEntries ? [] : applyContextValuesAll(
7324
+ remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : args.values, table),
7325
+ contextColumns,
7326
+ context
7327
+ );
7328
+ const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, {
7329
+ deep: true
7330
+ });
7331
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7332
+ relationMap,
7333
+ tables,
7334
+ tableName,
7335
+ typeName,
7336
+ typeNameMapper,
7337
+ table,
7338
+ pkNames,
7339
+ parsedInfo,
7340
+ limits,
7341
+ scope,
7342
+ defaultOrderBy: policies?.defaultOrderBy
7343
+ });
7344
+ const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
7345
+ const runInsert = async (target, values) => {
7346
+ let query = target.insert(table).values(values).returning(returning);
7347
+ if (conflictDoNothing) {
7348
+ query = query.onConflictDoNothing();
7349
+ }
7350
+ return await query;
7351
+ };
7352
+ const result = nestedEntries ? await writeWithNestedOps({
7353
+ executor,
7354
+ runtime: nested,
7355
+ tableName,
7356
+ entries: nestedEntries,
7357
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
7358
+ write: (tx, values) => runInsert(tx, [values]),
7359
+ context
7360
+ }) : await runInsert(executor, input);
7361
+ await runWriteHook(hooks, "after", {
7362
+ table: tableName,
7363
+ operation: "insert",
7364
+ single: false,
7365
+ args,
7366
+ rows: result,
7367
+ context,
7368
+ info,
7369
+ tx: executor
7370
+ });
7371
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7372
+ return remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
7373
+ },
7374
+ !!hooks
7375
+ );
6849
7376
  } catch (e) {
6850
7377
  throw toGraphQLError(e);
6851
7378
  }
@@ -6860,61 +7387,89 @@ var generateInsertSingle3 = (db, tableName, table, tables, relationMap, baseType
6860
7387
  }
6861
7388
  };
6862
7389
  const pkNames = sqlitePrimaryKeyPropNames(table);
7390
+ const hooks = policies?.onWrite?.(tableName, "insert");
6863
7391
  return {
6864
7392
  name: fieldName,
6865
7393
  resolver: async (_source, args, context, info) => {
6866
7394
  try {
6867
- return await runMutation(db, context, info, txCtx, async (executor) => {
6868
- const entry = nested?.enabled(tableName) ? nested.split(tableName, args.values) : void 0;
6869
- const nestedEntry = entry && nested.hasOps(entry.ops) ? entry : void 0;
6870
- const contextColumns = policies?.contextValues?.(tableName);
6871
- const scope = policies?.scope?.(context);
6872
- const input = nestedEntry ? {} : applyContextValues(
6873
- remapFromGraphQLSingleInput(entry ? entry.columns : args.values, table),
6874
- contextColumns,
6875
- context
6876
- );
6877
- const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, {
6878
- deep: true
6879
- });
6880
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6881
- relationMap,
6882
- tables,
6883
- tableName,
6884
- typeName,
6885
- typeNameMapper,
6886
- table,
6887
- pkNames,
6888
- parsedInfo,
6889
- limits,
6890
- scope
6891
- });
6892
- const returning = nestedEntry ? nested.withJoinColumns(tableName, nestedEntry.ops, { ...columns }, table) : columns;
6893
- const runInsert = async (target, values) => {
6894
- let query = target.insert(table).values(values).returning(returning);
6895
- if (conflictDoNothing) {
6896
- query = query.onConflictDoNothing();
6897
- }
6898
- return await query;
6899
- };
6900
- const result = nestedEntry ? await writeWithNestedOps({
6901
- executor,
6902
- runtime: nested,
6903
- tableName,
6904
- entries: [nestedEntry],
6905
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6906
- write: runInsert,
6907
- context
6908
- }) : await runInsert(executor, input);
6909
- if (!result[0]) {
6910
- if (!conflictDoNothing) {
6911
- throw new import_graphql10.GraphQLError(`${fieldName}: the insert returned no row.`);
7395
+ return await runMutation(
7396
+ db,
7397
+ context,
7398
+ info,
7399
+ txCtx,
7400
+ async (executor) => {
7401
+ await runWriteHook(hooks, "before", {
7402
+ table: tableName,
7403
+ operation: "insert",
7404
+ single: true,
7405
+ args,
7406
+ context,
7407
+ info,
7408
+ tx: executor
7409
+ });
7410
+ const entry = nested?.enabled(tableName) ? nested.split(tableName, args.values) : void 0;
7411
+ const nestedEntry = entry && nested.hasOps(entry.ops) ? entry : void 0;
7412
+ const contextColumns = policies?.contextValues?.(tableName);
7413
+ const scope = policies?.scope?.(context);
7414
+ const input = nestedEntry ? {} : applyContextValues(
7415
+ remapFromGraphQLSingleInput(entry ? entry.columns : args.values, table),
7416
+ contextColumns,
7417
+ context
7418
+ );
7419
+ const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, {
7420
+ deep: true
7421
+ });
7422
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7423
+ relationMap,
7424
+ tables,
7425
+ tableName,
7426
+ typeName,
7427
+ typeNameMapper,
7428
+ table,
7429
+ pkNames,
7430
+ parsedInfo,
7431
+ limits,
7432
+ scope,
7433
+ defaultOrderBy: policies?.defaultOrderBy
7434
+ });
7435
+ const returning = nestedEntry ? nested.withJoinColumns(tableName, nestedEntry.ops, { ...columns }, table) : columns;
7436
+ const runInsert = async (target, values) => {
7437
+ let query = target.insert(table).values(values).returning(returning);
7438
+ if (conflictDoNothing) {
7439
+ query = query.onConflictDoNothing();
7440
+ }
7441
+ return await query;
7442
+ };
7443
+ const result = nestedEntry ? await writeWithNestedOps({
7444
+ executor,
7445
+ runtime: nested,
7446
+ tableName,
7447
+ entries: [nestedEntry],
7448
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
7449
+ write: runInsert,
7450
+ context
7451
+ }) : await runInsert(executor, input);
7452
+ await runWriteHook(hooks, "after", {
7453
+ table: tableName,
7454
+ operation: "insert",
7455
+ single: true,
7456
+ args,
7457
+ rows: result,
7458
+ context,
7459
+ info,
7460
+ tx: executor
7461
+ });
7462
+ if (!result[0]) {
7463
+ if (!conflictDoNothing) {
7464
+ throw new import_graphql10.GraphQLError(`${fieldName}: the insert returned no row.`);
7465
+ }
7466
+ return void 0;
6912
7467
  }
6913
- return void 0;
6914
- }
6915
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6916
- return remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap);
6917
- });
7468
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7469
+ return remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap);
7470
+ },
7471
+ !!hooks
7472
+ );
6918
7473
  } catch (e) {
6919
7474
  throw toGraphQLError(e);
6920
7475
  }
@@ -6933,69 +7488,97 @@ var generateUpsert3 = (db, tableName, table, tables, relationMap, baseType, onCo
6933
7488
  }
6934
7489
  };
6935
7490
  const pkNames = sqlitePrimaryKeyPropNames(table);
7491
+ const hooks = policies?.onWrite?.(tableName, "upsert");
6936
7492
  return {
6937
7493
  name: fieldName,
6938
7494
  resolver: async (_source, args, context, info) => {
6939
7495
  try {
6940
- return await runMutation(db, context, info, txCtx, async (executor) => {
6941
- const supplied = single ? [args.values] : args.values;
6942
- if (!supplied.length) {
6943
- throw new import_graphql10.GraphQLError("No values were provided!");
6944
- }
6945
- const entries = nested?.enabled(tableName) ? supplied.map((values) => nested.split(tableName, values)) : void 0;
6946
- const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
6947
- const contextColumns = policies?.contextValues?.(tableName);
6948
- const scope = policies?.scope?.(context);
6949
- const input = nestedEntries ? [] : applyContextValuesAll(
6950
- remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : supplied, table),
6951
- contextColumns,
6952
- context
6953
- );
6954
- const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, { deep: true });
6955
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6956
- relationMap,
6957
- tables,
6958
- tableName,
6959
- typeName,
6960
- typeNameMapper,
6961
- table,
6962
- pkNames,
6963
- parsedInfo,
6964
- limits,
6965
- scope
6966
- });
6967
- const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
6968
- const runUpsert = async (target, values) => {
6969
- const plan = resolveConflictPlan({
7496
+ return await runMutation(
7497
+ db,
7498
+ context,
7499
+ info,
7500
+ txCtx,
7501
+ async (executor) => {
7502
+ const supplied = single ? [args.values] : args.values;
7503
+ if (!supplied.length) {
7504
+ throw new import_graphql10.GraphQLError("No values were provided!");
7505
+ }
7506
+ await runWriteHook(hooks, "before", {
7507
+ table: tableName,
7508
+ operation: "upsert",
7509
+ single,
7510
+ args,
7511
+ context,
7512
+ info,
7513
+ tx: executor
7514
+ });
7515
+ const entries = nested?.enabled(tableName) ? supplied.map((values) => nested.split(tableName, values)) : void 0;
7516
+ const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
7517
+ const contextColumns = policies?.contextValues?.(tableName);
7518
+ const scope = policies?.scope?.(context);
7519
+ const input = nestedEntries ? [] : applyContextValuesAll(
7520
+ remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : supplied, table),
7521
+ contextColumns,
7522
+ context
7523
+ );
7524
+ const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, { deep: true });
7525
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7526
+ relationMap,
7527
+ tables,
7528
+ tableName,
7529
+ typeName,
7530
+ typeNameMapper,
6970
7531
  table,
6971
- values,
6972
- onConflict: args.onConflict,
6973
7532
  pkNames,
6974
- uniqueSets,
6975
- excludedRef: excludedColumnRef,
6976
- withTarget: true,
6977
- buildWhere: (where) => extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName))
7533
+ parsedInfo,
7534
+ limits,
7535
+ scope,
7536
+ defaultOrderBy: policies?.defaultOrderBy
6978
7537
  });
6979
- let query = target.insert(table).values(values).returning(returning);
6980
- const setWhere = withScope(scope, tableName, table, plan.setWhere);
6981
- query = plan.action === "NOTHING" ? query.onConflictDoNothing(plan.target ? { target: plan.target } : void 0) : query.onConflictDoUpdate({ target: plan.target, set: plan.set, setWhere });
6982
- return await query;
6983
- };
6984
- const result = nestedEntries ? await writeWithNestedOps({
6985
- executor,
6986
- runtime: nested,
6987
- tableName,
6988
- entries: nestedEntries,
6989
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6990
- write: (tx, values) => runUpsert(tx, [values]),
6991
- context
6992
- }) : await runUpsert(executor, input);
6993
- if (single && !result[0]) {
6994
- return void 0;
6995
- }
6996
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6997
- return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
6998
- });
7538
+ const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
7539
+ const runUpsert = async (target, values) => {
7540
+ const plan = resolveConflictPlan({
7541
+ table,
7542
+ values,
7543
+ onConflict: args.onConflict,
7544
+ pkNames,
7545
+ uniqueSets,
7546
+ excludedRef: excludedColumnRef,
7547
+ withTarget: true,
7548
+ buildWhere: (where) => extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName))
7549
+ });
7550
+ let query = target.insert(table).values(values).returning(returning);
7551
+ const setWhere = withScope(scope, tableName, table, plan.setWhere);
7552
+ query = plan.action === "NOTHING" ? query.onConflictDoNothing(plan.target ? { target: plan.target } : void 0) : query.onConflictDoUpdate({ target: plan.target, set: plan.set, setWhere });
7553
+ return await query;
7554
+ };
7555
+ const result = nestedEntries ? await writeWithNestedOps({
7556
+ executor,
7557
+ runtime: nested,
7558
+ tableName,
7559
+ entries: nestedEntries,
7560
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
7561
+ write: (tx, values) => runUpsert(tx, [values]),
7562
+ context
7563
+ }) : await runUpsert(executor, input);
7564
+ await runWriteHook(hooks, "after", {
7565
+ table: tableName,
7566
+ operation: "upsert",
7567
+ single,
7568
+ args,
7569
+ rows: result,
7570
+ context,
7571
+ info,
7572
+ tx: executor
7573
+ });
7574
+ if (single && !result[0]) {
7575
+ return void 0;
7576
+ }
7577
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7578
+ return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
7579
+ },
7580
+ !!hooks
7581
+ );
6999
7582
  } catch (e) {
7000
7583
  throw toGraphQLError(e);
7001
7584
  }
@@ -7013,75 +7596,103 @@ var generateUpdate3 = (db, tableName, table, tables, relationMap, setArgs, filte
7013
7596
  }
7014
7597
  };
7015
7598
  const pkNames = sqlitePrimaryKeyPropNames(table);
7599
+ const hooks = policies?.onWrite?.(tableName, "update");
7016
7600
  return {
7017
7601
  name: fieldName,
7018
7602
  resolver: async (_source, args, context, info) => {
7019
7603
  try {
7020
- return await runMutation(db, context, info, txCtx, async (executor) => {
7021
- const { where, set } = args;
7022
- const scope = policies?.scope?.(context);
7023
- const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, {
7024
- deep: true
7025
- });
7026
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7027
- relationMap,
7028
- tables,
7029
- tableName,
7030
- typeName,
7031
- typeNameMapper,
7032
- table,
7033
- pkNames,
7034
- parsedInfo,
7035
- limits,
7036
- scope
7037
- });
7038
- const entry = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
7039
- const nestedOps = entry && nested.hasOps(entry.ops) ? entry.ops : void 0;
7040
- const input = stripContextValues(
7041
- remapUpdateInput(entry ? entry.columns : set, table, tableName),
7042
- policies?.contextValues?.(tableName)
7043
- );
7044
- if (!Object.keys(input).length && !nestedOps) {
7045
- throw new import_graphql10.GraphQLError("Unable to update with no values specified!");
7046
- }
7047
- const relationCtx = relationFilterCtx(filterCtx, tableName);
7048
- const filters = withScope(
7049
- scope,
7050
- tableName,
7051
- table,
7052
- single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
7053
- );
7054
- if (single) {
7055
- await assertSingleMatch(executor, table, filters, fieldName);
7056
- }
7057
- const returning = nestedOps ? nested.withJoinColumns(tableName, nestedOps, { ...columns }, table) : columns;
7058
- const runUpdate = async (target, values) => {
7059
- const writes = Object.keys(values).length > 0;
7060
- let query = writes ? target.update(table).set(values) : target.select(returning).from(table);
7061
- if (filters) {
7062
- query = query.where(filters);
7604
+ return await runMutation(
7605
+ db,
7606
+ context,
7607
+ info,
7608
+ txCtx,
7609
+ async (executor) => {
7610
+ await runWriteHook(hooks, "before", {
7611
+ table: tableName,
7612
+ operation: "update",
7613
+ single,
7614
+ args,
7615
+ context,
7616
+ info,
7617
+ tx: executor
7618
+ });
7619
+ const { where, set } = args;
7620
+ const scope = policies?.scope?.(context);
7621
+ const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, {
7622
+ deep: true
7623
+ });
7624
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7625
+ relationMap,
7626
+ tables,
7627
+ tableName,
7628
+ typeName,
7629
+ typeNameMapper,
7630
+ table,
7631
+ pkNames,
7632
+ parsedInfo,
7633
+ limits,
7634
+ scope,
7635
+ defaultOrderBy: policies?.defaultOrderBy
7636
+ });
7637
+ const entry = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
7638
+ const nestedOps = entry && nested.hasOps(entry.ops) ? entry.ops : void 0;
7639
+ const input = stripContextValues(
7640
+ remapUpdateInput(entry ? entry.columns : set, table, tableName),
7641
+ policies?.contextValues?.(tableName)
7642
+ );
7643
+ if (!Object.keys(input).length && !nestedOps) {
7644
+ throw new import_graphql10.GraphQLError("Unable to update with no values specified!");
7063
7645
  }
7064
- return await (writes ? query.returning(returning) : query);
7065
- };
7066
- const result = nestedOps ? await updateWithNestedOps({
7067
- executor,
7068
- runtime: nested,
7069
- tableName,
7070
- columns: input,
7071
- ops: nestedOps,
7072
- remapValues: (values) => values,
7073
- write: runUpdate,
7074
- context
7075
- }) : await runUpdate(executor, input);
7076
- if (single && result.length > 1) {
7077
- throw new import_graphql10.GraphQLError(`${fieldName}: 'where' matched more than one row!`);
7078
- }
7079
- if (single && !result[0]) {
7080
- return void 0;
7081
- }
7082
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7083
- return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
7084
- });
7646
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
7647
+ const filters = withScope(
7648
+ scope,
7649
+ tableName,
7650
+ table,
7651
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
7652
+ );
7653
+ if (single) {
7654
+ await assertSingleMatch(executor, table, filters, fieldName);
7655
+ }
7656
+ const returning = nestedOps ? nested.withJoinColumns(tableName, nestedOps, { ...columns }, table) : columns;
7657
+ const runUpdate = async (target, values) => {
7658
+ const writes = Object.keys(values).length > 0;
7659
+ let query = writes ? target.update(table).set(values) : target.select(returning).from(table);
7660
+ if (filters) {
7661
+ query = query.where(filters);
7662
+ }
7663
+ return await (writes ? query.returning(returning) : query);
7664
+ };
7665
+ const result = nestedOps ? await updateWithNestedOps({
7666
+ executor,
7667
+ runtime: nested,
7668
+ tableName,
7669
+ columns: input,
7670
+ ops: nestedOps,
7671
+ remapValues: (values) => values,
7672
+ write: runUpdate,
7673
+ context
7674
+ }) : await runUpdate(executor, input);
7675
+ await runWriteHook(hooks, "after", {
7676
+ table: tableName,
7677
+ operation: "update",
7678
+ single,
7679
+ args,
7680
+ rows: result,
7681
+ context,
7682
+ info,
7683
+ tx: executor
7684
+ });
7685
+ if (single && result.length > 1) {
7686
+ throw new import_graphql10.GraphQLError(`${fieldName}: 'where' matched more than one row!`);
7687
+ }
7688
+ if (single && !result[0]) {
7689
+ return void 0;
7690
+ }
7691
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7692
+ return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
7693
+ },
7694
+ !!hooks
7695
+ );
7085
7696
  } catch (e) {
7086
7697
  throw toGraphQLError(e);
7087
7698
  }
@@ -7096,122 +7707,150 @@ var generateUpdateMany3 = (db, tableName, table, tables, relationMap, updateMany
7096
7707
  }
7097
7708
  };
7098
7709
  const pkNames = sqlitePrimaryKeyPropNames(table);
7710
+ const hooks = policies?.onWrite?.(tableName, "updateMany");
7099
7711
  return {
7100
7712
  name: fieldName,
7101
7713
  resolver: async (_source, args, context, info) => {
7102
7714
  try {
7103
- return await runMutation(db, context, info, txCtx, async (executor) => {
7104
- const { updates } = args;
7105
- if (!updates.length) {
7106
- throw new import_graphql10.GraphQLError("No updates were provided!");
7107
- }
7108
- const scope = policies?.scope?.(context);
7109
- const contextColumns = policies?.contextValues?.(tableName);
7110
- const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, {
7111
- deep: true
7112
- });
7113
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7114
- relationMap,
7115
- tables,
7116
- tableName,
7117
- typeName,
7118
- typeNameMapper,
7119
- table,
7120
- pkNames,
7121
- parsedInfo,
7122
- limits,
7123
- scope
7124
- });
7125
- const entries = updates.map(({ where, set }) => {
7126
- const split = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
7127
- const ops = split && nested.hasOps(split.ops) ? split.ops : void 0;
7128
- const input = stripContextValues(
7129
- remapUpdateInput(split ? split.columns : set, table, tableName),
7130
- contextColumns
7131
- );
7132
- if (!Object.keys(input).length && !ops) {
7133
- throw new import_graphql10.GraphQLError("Unable to update with no values specified!");
7715
+ return await runMutation(
7716
+ db,
7717
+ context,
7718
+ info,
7719
+ txCtx,
7720
+ async (executor) => {
7721
+ const { updates } = args;
7722
+ if (!updates.length) {
7723
+ throw new import_graphql10.GraphQLError("No updates were provided!");
7134
7724
  }
7135
- return {
7136
- set: input,
7137
- ops,
7138
- filters: withScope(
7139
- scope,
7140
- tableName,
7141
- table,
7142
- where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
7143
- )
7725
+ await runWriteHook(hooks, "before", {
7726
+ table: tableName,
7727
+ operation: "updateMany",
7728
+ single: false,
7729
+ args,
7730
+ context,
7731
+ info,
7732
+ tx: executor
7733
+ });
7734
+ const scope = policies?.scope?.(context);
7735
+ const contextColumns = policies?.contextValues?.(tableName);
7736
+ const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, {
7737
+ deep: true
7738
+ });
7739
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7740
+ relationMap,
7741
+ tables,
7742
+ tableName,
7743
+ typeName,
7744
+ typeNameMapper,
7745
+ table,
7746
+ pkNames,
7747
+ parsedInfo,
7748
+ limits,
7749
+ scope,
7750
+ defaultOrderBy: policies?.defaultOrderBy
7751
+ });
7752
+ const entries = updates.map(({ where, set }) => {
7753
+ const split = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
7754
+ const ops = split && nested.hasOps(split.ops) ? split.ops : void 0;
7755
+ const input = stripContextValues(
7756
+ remapUpdateInput(split ? split.columns : set, table, tableName),
7757
+ contextColumns
7758
+ );
7759
+ if (!Object.keys(input).length && !ops) {
7760
+ throw new import_graphql10.GraphQLError("Unable to update with no values specified!");
7761
+ }
7762
+ return {
7763
+ set: input,
7764
+ ops,
7765
+ filters: withScope(
7766
+ scope,
7767
+ tableName,
7768
+ table,
7769
+ where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
7770
+ )
7771
+ };
7772
+ });
7773
+ const anyNested = entries.some((entry) => entry.ops);
7774
+ const returning = anyNested ? nested.withJoinColumns(
7775
+ tableName,
7776
+ mergedOps(entries.map((entry) => ({ ops: entry.ops ?? {} }))),
7777
+ { ...columns },
7778
+ table
7779
+ ) : columns;
7780
+ const runEntry = (tx, entry) => {
7781
+ let query = tx.update(table).set(entry.set);
7782
+ if (entry.filters) {
7783
+ query = query.where(entry.filters);
7784
+ }
7785
+ return query.returning(returning).all();
7144
7786
  };
7145
- });
7146
- const anyNested = entries.some((entry) => entry.ops);
7147
- const returning = anyNested ? nested.withJoinColumns(
7148
- tableName,
7149
- mergedOps(entries.map((entry) => ({ ops: entry.ops ?? {} }))),
7150
- { ...columns },
7151
- table
7152
- ) : columns;
7153
- const runEntry = (tx, entry) => {
7154
- let query = tx.update(table).set(entry.set);
7155
- if (entry.filters) {
7156
- query = query.where(entry.filters);
7157
- }
7158
- return query.returning(returning).all();
7159
- };
7160
- const runNestedEntry = async (tx, entry) => {
7161
- const values = entry.ops ? { ...entry.set, ...await nested.applyParentSide(tx, tableName, entry.ops, context) } : entry.set;
7162
- const writes = Object.keys(values).length > 0;
7163
- let query = writes ? tx.update(table).set(values) : tx.select(returning).from(table);
7164
- if (entry.filters) {
7165
- query = query.where(entry.filters);
7166
- }
7167
- const rows = await (writes ? query.returning(returning) : query);
7168
- if (entry.ops) {
7169
- await nested.applyChildSide(tx, tableName, entry.ops, rows, context);
7170
- }
7171
- return rows;
7172
- };
7173
- const perEntry = await executor.transaction((tx) => {
7174
- if (anyNested) {
7175
- return (async () => {
7176
- const results2 = [];
7177
- for (const entry of entries) {
7178
- results2.push(await runNestedEntry(tx, entry));
7179
- }
7180
- return results2;
7181
- })();
7182
- }
7183
- const first = runEntry(tx, entries[0]);
7184
- if (typeof first?.then === "function") {
7185
- return (async () => {
7186
- const results2 = [await first];
7187
- for (let i = 1; i < entries.length; i++) {
7188
- results2.push(await runEntry(tx, entries[i]));
7189
- }
7190
- return results2;
7191
- })();
7192
- }
7193
- const results = [first];
7194
- for (let i = 1; i < entries.length; i++) {
7195
- results.push(runEntry(tx, entries[i]));
7196
- }
7197
- return results;
7198
- });
7199
- const flatRows = perEntry.flat();
7200
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, flatRows, pkNames, withParams) : flatRows;
7201
- const output = [];
7202
- let offset = 0;
7203
- for (const rows of perEntry) {
7204
- if (!rows.length) {
7205
- output.push(null);
7206
- continue;
7207
- }
7208
- for (let i = 0; i < rows.length; i++) {
7209
- output.push(remapToGraphQLSingleOutput(enriched[offset + i], tableName, table, relationMap));
7787
+ const runNestedEntry = async (tx, entry) => {
7788
+ const values = entry.ops ? { ...entry.set, ...await nested.applyParentSide(tx, tableName, entry.ops, context) } : entry.set;
7789
+ const writes = Object.keys(values).length > 0;
7790
+ let query = writes ? tx.update(table).set(values) : tx.select(returning).from(table);
7791
+ if (entry.filters) {
7792
+ query = query.where(entry.filters);
7793
+ }
7794
+ const rows = await (writes ? query.returning(returning) : query);
7795
+ if (entry.ops) {
7796
+ await nested.applyChildSide(tx, tableName, entry.ops, rows, context);
7797
+ }
7798
+ return rows;
7799
+ };
7800
+ const perEntry = await executor.transaction((tx) => {
7801
+ if (anyNested) {
7802
+ return (async () => {
7803
+ const results2 = [];
7804
+ for (const entry of entries) {
7805
+ results2.push(await runNestedEntry(tx, entry));
7806
+ }
7807
+ return results2;
7808
+ })();
7809
+ }
7810
+ const first = runEntry(tx, entries[0]);
7811
+ if (typeof first?.then === "function") {
7812
+ return (async () => {
7813
+ const results2 = [await first];
7814
+ for (let i = 1; i < entries.length; i++) {
7815
+ results2.push(await runEntry(tx, entries[i]));
7816
+ }
7817
+ return results2;
7818
+ })();
7819
+ }
7820
+ const results = [first];
7821
+ for (let i = 1; i < entries.length; i++) {
7822
+ results.push(runEntry(tx, entries[i]));
7823
+ }
7824
+ return results;
7825
+ });
7826
+ const flatRows = perEntry.flat();
7827
+ await runWriteHook(hooks, "after", {
7828
+ table: tableName,
7829
+ operation: "updateMany",
7830
+ single: false,
7831
+ args,
7832
+ rows: flatRows,
7833
+ context,
7834
+ info,
7835
+ tx: executor
7836
+ });
7837
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, flatRows, pkNames, withParams) : flatRows;
7838
+ const output = [];
7839
+ let offset = 0;
7840
+ for (const rows of perEntry) {
7841
+ if (!rows.length) {
7842
+ output.push(null);
7843
+ continue;
7844
+ }
7845
+ for (let i = 0; i < rows.length; i++) {
7846
+ output.push(remapToGraphQLSingleOutput(enriched[offset + i], tableName, table, relationMap));
7847
+ }
7848
+ offset += rows.length;
7210
7849
  }
7211
- offset += rows.length;
7212
- }
7213
- return output;
7214
- });
7850
+ return output;
7851
+ },
7852
+ !!hooks
7853
+ );
7215
7854
  } catch (e) {
7216
7855
  throw toGraphQLError(e);
7217
7856
  }
@@ -7221,51 +7860,79 @@ var generateUpdateMany3 = (db, tableName, table, tables, relationMap, updateMany
7221
7860
  };
7222
7861
  var generateDelete3 = (db, tableName, table, filterArgs, fieldName, typeName, single, requireWhere, filterCtx, selectionCtx, txCtx, policies, restore = false) => {
7223
7862
  const softDelete = policies?.softDelete?.(tableName);
7863
+ const operation = restore ? "restore" : "delete";
7224
7864
  const queryArgs = {
7225
7865
  where: {
7226
7866
  type: single || requireWhere ? new import_graphql10.GraphQLNonNull(filterArgs) : filterArgs
7227
7867
  }
7228
7868
  };
7869
+ const hooks = policies?.onWrite?.(tableName, operation);
7229
7870
  return {
7230
7871
  name: fieldName,
7231
7872
  resolver: async (_source, args, context, info) => {
7232
7873
  try {
7233
- return await runMutation(db, context, info, txCtx, async (executor) => {
7234
- const { where } = args;
7235
- const scope = policies?.scope?.(context);
7236
- const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, {
7237
- deep: true
7238
- });
7239
- const columns = extractSelectedColumnsFromTreeSQLFormat(
7240
- parsedInfo.fieldsByTypeName[typeName],
7241
- table,
7242
- selectionCtx
7243
- );
7244
- const relationCtx = relationFilterCtx(filterCtx, tableName);
7245
- const filters = withScope(
7246
- scope,
7247
- tableName,
7248
- table,
7249
- single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
7250
- restore ? "ONLY" : void 0
7251
- );
7252
- if (single) {
7253
- await assertSingleMatch(executor, table, filters, fieldName);
7254
- }
7255
- let query = softDelete ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
7256
- if (filters) {
7257
- query = query.where(filters);
7258
- }
7259
- query = query.returning(columns);
7260
- const result = await query;
7261
- if (single && result.length > 1) {
7262
- throw new import_graphql10.GraphQLError(`${fieldName}: 'where' matched more than one row!`);
7263
- }
7264
- if (single) {
7265
- return result[0] ? remapToGraphQLSingleOutput(result[0], tableName, table) : void 0;
7266
- }
7267
- return remapToGraphQLArrayOutput(result, tableName, table);
7268
- });
7874
+ return await runMutation(
7875
+ db,
7876
+ context,
7877
+ info,
7878
+ txCtx,
7879
+ async (executor) => {
7880
+ await runWriteHook(hooks, "before", {
7881
+ table: tableName,
7882
+ operation,
7883
+ single,
7884
+ args,
7885
+ context,
7886
+ info,
7887
+ tx: executor
7888
+ });
7889
+ const { where } = args;
7890
+ const scope = policies?.scope?.(context);
7891
+ const parsedInfo = (0, import_graphql_parse_resolve_info4.parseResolveInfo)(info, {
7892
+ deep: true
7893
+ });
7894
+ const columns = extractSelectedColumnsFromTreeSQLFormat(
7895
+ parsedInfo.fieldsByTypeName[typeName],
7896
+ table,
7897
+ selectionCtx
7898
+ );
7899
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
7900
+ const filters = withScope(
7901
+ scope,
7902
+ tableName,
7903
+ table,
7904
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
7905
+ restore ? "ONLY" : void 0
7906
+ );
7907
+ if (single) {
7908
+ await assertSingleMatch(executor, table, filters, fieldName);
7909
+ }
7910
+ let query = softDelete ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
7911
+ if (filters) {
7912
+ query = query.where(filters);
7913
+ }
7914
+ query = query.returning(columns);
7915
+ const result = await query;
7916
+ await runWriteHook(hooks, "after", {
7917
+ table: tableName,
7918
+ operation,
7919
+ single,
7920
+ args,
7921
+ rows: result,
7922
+ context,
7923
+ info,
7924
+ tx: executor
7925
+ });
7926
+ if (single && result.length > 1) {
7927
+ throw new import_graphql10.GraphQLError(`${fieldName}: 'where' matched more than one row!`);
7928
+ }
7929
+ if (single) {
7930
+ return result[0] ? remapToGraphQLSingleOutput(result[0], tableName, table) : void 0;
7931
+ }
7932
+ return remapToGraphQLArrayOutput(result, tableName, table);
7933
+ },
7934
+ !!hooks
7935
+ );
7269
7936
  } catch (e) {
7270
7937
  throw toGraphQLError(e);
7271
7938
  }
@@ -8095,6 +8762,46 @@ var buildSchema = (db, config) => {
8095
8762
  limitPolicyCache.set(tableName, resolved);
8096
8763
  return resolved;
8097
8764
  } : void 0;
8765
+ const defaultsConfig = config?.defaults;
8766
+ const defaultOrderByByTable = /* @__PURE__ */ new Map();
8767
+ if (defaultsConfig) {
8768
+ const defaultsTableNames = new Set(tableKeys);
8769
+ for (const [tableName, tableDefaults] of Object.entries(defaultsConfig)) {
8770
+ if (!defaultsTableNames.has(tableName)) {
8771
+ throw new Error(
8772
+ `Drizzle-GraphQL Error: config.defaults names '${tableName}', which is not a table in the Drizzle schema.`
8773
+ );
8774
+ }
8775
+ const orderBy = tableDefaults?.orderBy;
8776
+ if (!orderBy || !Object.keys(orderBy).length) {
8777
+ continue;
8778
+ }
8779
+ const columns = (0, import_drizzle_orm11.getColumns)(schema[tableName]);
8780
+ const normalized = {};
8781
+ for (const [columnName, entry] of Object.entries(orderBy)) {
8782
+ if (!columns[columnName]) {
8783
+ throw new Error(
8784
+ `Drizzle-GraphQL Error: config.defaults.${tableName}.orderBy names '${columnName}', which is not a column of '${tableName}'.`
8785
+ );
8786
+ }
8787
+ const direction = typeof entry === "string" ? entry : entry?.direction;
8788
+ if (direction !== "asc" && direction !== "desc") {
8789
+ throw new Error(
8790
+ `Drizzle-GraphQL Error: config.defaults.${tableName}.orderBy.${columnName} must be 'asc', 'desc', or { direction, priority? }.`
8791
+ );
8792
+ }
8793
+ const priority = typeof entry === "string" ? void 0 : entry?.priority;
8794
+ if (priority !== void 0 && !Number.isInteger(priority)) {
8795
+ throw new Error(
8796
+ `Drizzle-GraphQL Error: config.defaults.${tableName}.orderBy.${columnName}.priority must be an integer.`
8797
+ );
8798
+ }
8799
+ normalized[columnName] = priority === void 0 ? { direction } : { direction, priority };
8800
+ }
8801
+ defaultOrderByByTable.set(tableName, normalized);
8802
+ }
8803
+ }
8804
+ const defaultOrderBy = defaultOrderByByTable.size ? (tableName) => defaultOrderByByTable.get(tableName) : void 0;
8098
8805
  const scopeConfig = config?.scope;
8099
8806
  const contextValuesConfig = config?.contextValues;
8100
8807
  if (scopeConfig || contextValuesConfig) {
@@ -8150,10 +8857,37 @@ var buildSchema = (db, config) => {
8150
8857
  }
8151
8858
  }
8152
8859
  }
8153
- const policies = scopeConfig || contextValuesConfig || softDeleteInfos.size ? {
8860
+ const onWriteConfig = config?.onWrite;
8861
+ const writeHooks = /* @__PURE__ */ new Map();
8862
+ let globalWriteHooks;
8863
+ if (onWriteConfig) {
8864
+ const isGlobal = typeof onWriteConfig === "function" || typeof onWriteConfig.before === "function" || typeof onWriteConfig.after === "function";
8865
+ if (isGlobal) {
8866
+ globalWriteHooks = normalizeWriteHooks(onWriteConfig);
8867
+ } else {
8868
+ const tableNames = new Set(tableKeys);
8869
+ for (const [tableName, hooks] of Object.entries(onWriteConfig)) {
8870
+ if (!tableNames.has(tableName)) {
8871
+ throw new Error(
8872
+ `Drizzle-GraphQL Error: config.onWrite names '${tableName}', which is not a table in the Drizzle schema.`
8873
+ );
8874
+ }
8875
+ if (typeof hooks !== "function" && typeof hooks !== "object") {
8876
+ throw new Error(
8877
+ `Drizzle-GraphQL Error: config.onWrite.${tableName} must be a function or an object with 'before' and/or 'after'.`
8878
+ );
8879
+ }
8880
+ writeHooks.set(tableName, normalizeWriteHooks(hooks));
8881
+ }
8882
+ }
8883
+ }
8884
+ const onWrite = globalWriteHooks || writeHooks.size ? (tableName) => globalWriteHooks ?? writeHooks.get(tableName) : void 0;
8885
+ const policies = scopeConfig || contextValuesConfig || softDeleteInfos.size || onWrite || defaultOrderBy ? {
8154
8886
  scope: scopeConfig ? (tableName) => scopeConfig[tableName] : void 0,
8155
8887
  contextValues: contextValuesConfig ? (tableName) => contextValuesConfig[tableName] : void 0,
8156
- softDelete: softDeleteInfos.size ? (tableName) => softDeleteInfos.get(tableName) : void 0
8888
+ softDelete: softDeleteInfos.size ? (tableName) => softDeleteInfos.get(tableName) : void 0,
8889
+ onWrite,
8890
+ defaultOrderBy
8157
8891
  } : void 0;
8158
8892
  const exclude = config?.exclude;
8159
8893
  if (exclude) {