@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.js CHANGED
@@ -1106,7 +1106,7 @@ var runOnSharedTx = async (state, body) => {
1106
1106
  throw e;
1107
1107
  }
1108
1108
  };
1109
- var runMutation = async (db, context, info, txCtx, body) => {
1109
+ var runMutation = async (db, context, info, txCtx, body, forceTx) => {
1110
1110
  const contextIsObject = context !== null && (typeof context === "object" || typeof context === "function");
1111
1111
  const stateKey = contextIsObject ? context : info.operation;
1112
1112
  let state = txCtx?.states.get(stateKey);
@@ -1115,7 +1115,7 @@ var runMutation = async (db, context, info, txCtx, body) => {
1115
1115
  return body(context[drizzleExecutorKey]);
1116
1116
  }
1117
1117
  if (!txCtx || info.operation.operation !== "mutation") {
1118
- return body(db);
1118
+ return forceTx ? db.transaction((tx) => body(tx)) : body(db);
1119
1119
  }
1120
1120
  const keys = /* @__PURE__ */ new Set();
1121
1121
  const allKnown = collectRootMutationKeys(
@@ -1130,10 +1130,28 @@ var runMutation = async (db, context, info, txCtx, body) => {
1130
1130
  txCtx.states.set(stateKey, state);
1131
1131
  }
1132
1132
  if (state.kind === "passthrough") {
1133
- return body(resolveExecutor(db, context));
1133
+ const executor = resolveExecutor(db, context);
1134
+ return forceTx && executor === db ? db.transaction((tx) => body(tx)) : body(executor);
1134
1135
  }
1135
1136
  return runOnSharedTx(state, body);
1136
1137
  };
1138
+ var normalizeWriteHooks = (hooks) => {
1139
+ if (!hooks) {
1140
+ return void 0;
1141
+ }
1142
+ if (typeof hooks === "function") {
1143
+ return { after: hooks };
1144
+ }
1145
+ const resolved = { before: hooks.before, after: hooks.after };
1146
+ return resolved.before || resolved.after ? resolved : void 0;
1147
+ };
1148
+ var runWriteHook = (hooks, position, payload) => {
1149
+ const hook = position === "before" ? hooks?.before : hooks?.after;
1150
+ if (!hook) {
1151
+ return void 0;
1152
+ }
1153
+ return Promise.resolve(hook({ ...payload, position, rows: payload.rows ?? [] }));
1154
+ };
1137
1155
  var batchedPaginatedRelationQuery = async (db, targetTable, foreignCol, whereCondition, orderByArg, limit, offset, pkNames, orderCtx, whereArgs) => {
1138
1156
  const cols = getColumns2(targetTable);
1139
1157
  const orderExprs = [
@@ -1177,14 +1195,8 @@ var createRelationResolverFactory = (db, tables, nullOrdering, filterCtx, limits
1177
1195
  if (localValue == null) {
1178
1196
  return isOne ? null : [];
1179
1197
  }
1180
- const {
1181
- where: whereArg,
1182
- orderBy: orderByArg,
1183
- limit: requestedLimit,
1184
- offset,
1185
- after,
1186
- deleted
1187
- } = args ?? {};
1198
+ const { where: whereArg, limit: requestedLimit, offset, after, deleted } = args ?? {};
1199
+ const orderByArg = isOne ? args?.orderBy : withDefaultOrderBy(args ?? {}, targetTableName, policies?.defaultOrderBy).orderBy;
1188
1200
  const limit = applyLimitPolicy(requestedLimit, limitPolicy, `${tableName}.${relationName}`);
1189
1201
  const distinct = (args ?? {}).distinct?.length ? (args ?? {}).distinct : void 0;
1190
1202
  const cursorSelected = !isOne && !!info && selectsCursorField(info, targetTable);
@@ -1316,6 +1328,13 @@ var inputFieldDocs = (docs, column, tableName, columnName, fieldType) => {
1316
1328
  }
1317
1329
  return resolved;
1318
1330
  };
1331
+ var withDefaultOrderBy = (args, tableName, defaults) => {
1332
+ if (!defaults || args?.orderBy != null) {
1333
+ return args;
1334
+ }
1335
+ const fallback = defaults(tableName);
1336
+ return fallback ? { ...args, orderBy: fallback } : args;
1337
+ };
1319
1338
  var applyLimitPolicy = (limit, policy, fieldName) => {
1320
1339
  if (!policy) {
1321
1340
  return limit ?? void 0;
@@ -2782,10 +2801,12 @@ var withScope = (scope, tableName, table, condition, mode) => {
2782
2801
  const predicate = scope?.on(tableName, table, mode);
2783
2802
  return predicate ? and(condition, predicate) : condition;
2784
2803
  };
2785
- var bindPolicies = (policies, filterCtx) => policies?.scope || policies?.contextValues || policies?.softDelete ? {
2804
+ var bindPolicies = (policies, filterCtx) => policies?.scope || policies?.contextValues || policies?.softDelete || policies?.onWrite || policies?.defaultOrderBy ? {
2786
2805
  scope: policies.scope || policies.softDelete ? (context) => resolveScope(policies, context, filterCtx) : void 0,
2787
2806
  contextValues: policies.contextValues,
2788
- softDelete: policies.softDelete
2807
+ softDelete: policies.softDelete,
2808
+ onWrite: policies.onWrite,
2809
+ defaultOrderBy: policies.defaultOrderBy
2789
2810
  } : void 0;
2790
2811
  var applyContextValues = (values, hooks, context) => {
2791
2812
  if (!hooks) {
@@ -2814,7 +2835,7 @@ var stripContextValues = (values, hooks) => {
2814
2835
  }
2815
2836
  return values;
2816
2837
  };
2817
- var extractRelationsParamsInner = (relationMap, tables, tableName, typeName, originField, typeNameMapper, _isInitial = false, filterCtx, limits, scope) => {
2838
+ var extractRelationsParamsInner = (relationMap, tables, tableName, typeName, originField, typeNameMapper, _isInitial = false, filterCtx, limits, scope, defaultOrderBy) => {
2818
2839
  const relationsForTable = relationMap[tableName];
2819
2840
  if (!relationsForTable) {
2820
2841
  return void 0;
@@ -2856,7 +2877,7 @@ var extractRelationsParamsInner = (relationMap, tables, tableName, typeName, ori
2856
2877
  const thisRecord = {};
2857
2878
  thisRecord.columns = columns;
2858
2879
  const relationField = Object.values(baseField).find((e) => e.name === relName);
2859
- const relationArgs = relationField?.args;
2880
+ const relationArgs = is3(relEntry.relation, One2) ? relationField?.args : relationField && withDefaultOrderBy(relationField.args ?? {}, targetTableName, defaultOrderBy);
2860
2881
  const offset = relationArgs?.offset ?? void 0;
2861
2882
  const limit = is3(relEntry.relation, One2) ? relationArgs?.limit ?? void 0 : applyLimitPolicy(relationArgs?.limit, limits?.(targetTableName), `${tableName}.${relName}`);
2862
2883
  const relWhere = relationArgs?.where;
@@ -2885,14 +2906,15 @@ var extractRelationsParamsInner = (relationMap, tables, tableName, typeName, ori
2885
2906
  false,
2886
2907
  filterCtx,
2887
2908
  limits,
2888
- scope
2909
+ scope,
2910
+ defaultOrderBy
2889
2911
  ) : void 0;
2890
2912
  thisRecord.with = relWith;
2891
2913
  args[relName] = thisRecord;
2892
2914
  }
2893
2915
  return args;
2894
2916
  };
2895
- var extractRelationsParams = (relationMap, tables, tableName, info, typeName, typeNameMapper, filterCtx, limits, scope) => {
2917
+ var extractRelationsParams = (relationMap, tables, tableName, info, typeName, typeNameMapper, filterCtx, limits, scope, defaultOrderBy) => {
2896
2918
  if (!info) {
2897
2919
  return void 0;
2898
2920
  }
@@ -2906,7 +2928,8 @@ var extractRelationsParams = (relationMap, tables, tableName, info, typeName, ty
2906
2928
  true,
2907
2929
  filterCtx,
2908
2930
  limits,
2909
- scope
2931
+ scope,
2932
+ defaultOrderBy
2910
2933
  );
2911
2934
  };
2912
2935
  var pruneNonEagerRelations = (relationMap, shouldEagerLoad) => {
@@ -3317,7 +3340,8 @@ var prepareMutationRelationColumns = (params) => {
3317
3340
  typeNameMapper,
3318
3341
  void 0,
3319
3342
  params.limits,
3320
- params.scope
3343
+ params.scope,
3344
+ params.defaultOrderBy
3321
3345
  ) : void 0;
3322
3346
  const hasRelations = !!(withParams && Object.keys(withParams).length);
3323
3347
  const baseColumns = extractSelectedColumnsFromTreeSQLFormat(parsedInfo.fieldsByTypeName[typeName], table, {
@@ -3659,7 +3683,8 @@ var runRelationalSelect = async (opts) => {
3659
3683
  typeNameMapper,
3660
3684
  filterCtx,
3661
3685
  opts.limits,
3662
- scope
3686
+ scope,
3687
+ opts.defaultOrderBy
3663
3688
  ) : void 0
3664
3689
  };
3665
3690
  if (single) {
@@ -4297,7 +4322,8 @@ var generateSelectArray = (db, tableName, tables, relationMap, orderArgs, filter
4297
4322
  );
4298
4323
  return {
4299
4324
  name: fieldName,
4300
- resolver: async (_source, args, context, info) => {
4325
+ resolver: async (_source, rawArgs, context, info) => {
4326
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
4301
4327
  try {
4302
4328
  const parsedInfo = parseResolveInfo2(info, { deep: true });
4303
4329
  const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
@@ -4315,6 +4341,7 @@ var generateSelectArray = (db, tableName, tables, relationMap, orderArgs, filter
4315
4341
  single: false,
4316
4342
  filterCtx,
4317
4343
  limits,
4344
+ defaultOrderBy: policies?.defaultOrderBy,
4318
4345
  scope: policies?.scope?.(context),
4319
4346
  pkNames,
4320
4347
  db: executor,
@@ -4340,7 +4367,8 @@ var generateSelectSingle = (db, tableName, tables, relationMap, orderArgs, filte
4340
4367
  const pkNames = mysqlPrimaryKeyPropNames(table);
4341
4368
  return {
4342
4369
  name: fieldName,
4343
- resolver: async (_source, args, context, info) => {
4370
+ resolver: async (_source, rawArgs, context, info) => {
4371
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
4344
4372
  try {
4345
4373
  const parsedInfo = parseResolveInfo2(info, { deep: true });
4346
4374
  const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
@@ -4357,6 +4385,7 @@ var generateSelectSingle = (db, tableName, tables, relationMap, orderArgs, filte
4357
4385
  single: true,
4358
4386
  filterCtx,
4359
4387
  limits,
4388
+ defaultOrderBy: policies?.defaultOrderBy,
4360
4389
  scope: policies?.scope?.(context),
4361
4390
  pkNames,
4362
4391
  db: executor
@@ -4374,22 +4403,49 @@ var generateInsertArray = (db, tableName, table, baseType, fieldName, txCtx, pol
4374
4403
  type: new GraphQLNonNull5(new GraphQLList5(new GraphQLNonNull5(baseType)))
4375
4404
  }
4376
4405
  };
4406
+ const hooks = policies?.onWrite?.(tableName, "insert");
4377
4407
  return {
4378
4408
  name: fieldName,
4379
4409
  resolver: async (_source, args, context, info) => {
4380
4410
  try {
4381
- return await runMutation(db, context, info, txCtx, async (executor) => {
4382
- const input = applyContextValuesAll(
4383
- remapFromGraphQLArrayInput(args.values, table),
4384
- policies?.contextValues?.(tableName),
4385
- context
4386
- );
4387
- if (!input.length) {
4388
- throw new GraphQLError6("No values were provided!");
4389
- }
4390
- await executor.insert(table).values(input);
4391
- return { isSuccess: true };
4392
- });
4411
+ return await runMutation(
4412
+ db,
4413
+ context,
4414
+ info,
4415
+ txCtx,
4416
+ async (executor) => {
4417
+ const input = applyContextValuesAll(
4418
+ remapFromGraphQLArrayInput(args.values, table),
4419
+ policies?.contextValues?.(tableName),
4420
+ context
4421
+ );
4422
+ if (!input.length) {
4423
+ throw new GraphQLError6("No values were provided!");
4424
+ }
4425
+ await runWriteHook(hooks, "before", {
4426
+ table: tableName,
4427
+ operation: "insert",
4428
+ single: false,
4429
+ args,
4430
+ context,
4431
+ info,
4432
+ tx: executor
4433
+ });
4434
+ await executor.insert(table).values(input);
4435
+ await runWriteHook(hooks, "after", {
4436
+ table: tableName,
4437
+ operation: "insert",
4438
+ single: false,
4439
+ args,
4440
+ rows: [],
4441
+ context,
4442
+ info,
4443
+ tx: executor
4444
+ });
4445
+ return { isSuccess: true };
4446
+ },
4447
+ !!hooks
4448
+ );
4393
4449
  } catch (e) {
4394
4450
  throw toGraphQLError(e);
4395
4451
  }
@@ -4403,19 +4459,46 @@ var generateInsertSingle = (db, tableName, table, baseType, fieldName, txCtx, po
4403
4459
  type: new GraphQLNonNull5(baseType)
4404
4460
  }
4405
4461
  };
4462
+ const hooks = policies?.onWrite?.(tableName, "insert");
4406
4463
  return {
4407
4464
  name: fieldName,
4408
4465
  resolver: async (_source, args, context, info) => {
4409
4466
  try {
4410
- return await runMutation(db, context, info, txCtx, async (executor) => {
4411
- const input = applyContextValues(
4412
- remapFromGraphQLSingleInput(args.values, table),
4413
- policies?.contextValues?.(tableName),
4414
- context
4415
- );
4416
- await executor.insert(table).values(input);
4417
- return { isSuccess: true };
4418
- });
4467
+ return await runMutation(
4468
+ db,
4469
+ context,
4470
+ info,
4471
+ txCtx,
4472
+ async (executor) => {
4473
+ await runWriteHook(hooks, "before", {
4474
+ table: tableName,
4475
+ operation: "insert",
4476
+ single: true,
4477
+ args,
4478
+ context,
4479
+ info,
4480
+ tx: executor
4481
+ });
4482
+ const input = applyContextValues(
4483
+ remapFromGraphQLSingleInput(args.values, table),
4484
+ policies?.contextValues?.(tableName),
4485
+ context
4486
+ );
4487
+ await executor.insert(table).values(input);
4488
+ await runWriteHook(hooks, "after", {
4489
+ table: tableName,
4490
+ operation: "insert",
4491
+ single: true,
4492
+ args,
4493
+ rows: [],
4494
+ context,
4495
+ info,
4496
+ tx: executor
4497
+ });
4498
+ return { isSuccess: true };
4499
+ },
4500
+ !!hooks
4501
+ );
4419
4502
  } catch (e) {
4420
4503
  throw toGraphQLError(e);
4421
4504
  }
@@ -4434,35 +4517,62 @@ var generateUpsert = (db, tableName, table, baseType, onConflictType, fieldName,
4434
4517
  }
4435
4518
  };
4436
4519
  const pkNames = mysqlPrimaryKeyPropNames(table);
4520
+ const hooks = policies?.onWrite?.(tableName, "upsert");
4437
4521
  return {
4438
4522
  name: fieldName,
4439
4523
  resolver: async (_source, args, context, info) => {
4440
4524
  try {
4441
- return await runMutation(db, context, info, txCtx, async (executor) => {
4442
- const input = applyContextValuesAll(
4443
- single ? [remapFromGraphQLSingleInput(args.values, table)] : remapFromGraphQLArrayInput(args.values, table),
4444
- policies?.contextValues?.(tableName),
4445
- context
4446
- );
4447
- if (!input.length) {
4448
- throw new GraphQLError6("No values were provided!");
4449
- }
4450
- const plan = resolveConflictPlan({
4451
- table,
4452
- values: input,
4453
- onConflict: args.onConflict,
4454
- pkNames,
4455
- uniqueSets: [],
4456
- excludedRef: mysqlValuesColumnRef,
4457
- withTarget: false
4458
- });
4459
- if (plan.action === "NOTHING") {
4460
- await executor.insert(table).ignore().values(input);
4461
- } else {
4462
- await executor.insert(table).values(input).onDuplicateKeyUpdate({ set: plan.set });
4463
- }
4464
- return { isSuccess: true };
4465
- });
4525
+ return await runMutation(
4526
+ db,
4527
+ context,
4528
+ info,
4529
+ txCtx,
4530
+ async (executor) => {
4531
+ const input = applyContextValuesAll(
4532
+ single ? [remapFromGraphQLSingleInput(args.values, table)] : remapFromGraphQLArrayInput(args.values, table),
4533
+ policies?.contextValues?.(tableName),
4534
+ context
4535
+ );
4536
+ if (!input.length) {
4537
+ throw new GraphQLError6("No values were provided!");
4538
+ }
4539
+ await runWriteHook(hooks, "before", {
4540
+ table: tableName,
4541
+ operation: "upsert",
4542
+ single,
4543
+ args,
4544
+ context,
4545
+ info,
4546
+ tx: executor
4547
+ });
4548
+ const plan = resolveConflictPlan({
4549
+ table,
4550
+ values: input,
4551
+ onConflict: args.onConflict,
4552
+ pkNames,
4553
+ uniqueSets: [],
4554
+ excludedRef: mysqlValuesColumnRef,
4555
+ withTarget: false
4556
+ });
4557
+ if (plan.action === "NOTHING") {
4558
+ await executor.insert(table).ignore().values(input);
4559
+ } else {
4560
+ await executor.insert(table).values(input).onDuplicateKeyUpdate({ set: plan.set });
4561
+ }
4562
+ await runWriteHook(hooks, "after", {
4563
+ table: tableName,
4564
+ operation: "upsert",
4565
+ single,
4566
+ args,
4567
+ rows: [],
4568
+ context,
4569
+ info,
4570
+ tx: executor
4571
+ });
4572
+ return { isSuccess: true };
4573
+ },
4574
+ !!hooks
4575
+ );
4466
4576
  } catch (e) {
4467
4577
  throw toGraphQLError(e);
4468
4578
  }
@@ -4479,37 +4589,64 @@ var generateUpdate = (db, tableName, table, setArgs, filterArgs, fieldName, sing
4479
4589
  type: single || requireWhere ? new GraphQLNonNull5(filterArgs) : filterArgs
4480
4590
  }
4481
4591
  };
4592
+ const hooks = policies?.onWrite?.(tableName, "update");
4482
4593
  return {
4483
4594
  name: fieldName,
4484
4595
  resolver: async (_source, args, context, info) => {
4485
4596
  try {
4486
- return await runMutation(db, context, info, txCtx, async (executor) => {
4487
- const { where, set } = args;
4488
- const scope = policies?.scope?.(context);
4489
- const input = stripContextValues(
4490
- remapUpdateInput(set, table, tableName),
4491
- policies?.contextValues?.(tableName)
4492
- );
4493
- if (!Object.keys(input).length) {
4494
- throw new GraphQLError6("Unable to update with no values specified!");
4495
- }
4496
- const relationCtx = relationFilterCtx(filterCtx, tableName);
4497
- const filters = withScope(
4498
- scope,
4499
- tableName,
4500
- table,
4501
- single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
4502
- );
4503
- if (single) {
4504
- await assertSingleMatch(executor, table, filters, fieldName);
4505
- }
4506
- let query = executor.update(table).set(input);
4507
- if (filters) {
4508
- query = query.where(filters);
4509
- }
4510
- await query;
4511
- return { isSuccess: true };
4512
- });
4597
+ return await runMutation(
4598
+ db,
4599
+ context,
4600
+ info,
4601
+ txCtx,
4602
+ async (executor) => {
4603
+ const { where, set } = args;
4604
+ const scope = policies?.scope?.(context);
4605
+ const input = stripContextValues(
4606
+ remapUpdateInput(set, table, tableName),
4607
+ policies?.contextValues?.(tableName)
4608
+ );
4609
+ if (!Object.keys(input).length) {
4610
+ throw new GraphQLError6("Unable to update with no values specified!");
4611
+ }
4612
+ await runWriteHook(hooks, "before", {
4613
+ table: tableName,
4614
+ operation: "update",
4615
+ single,
4616
+ args,
4617
+ context,
4618
+ info,
4619
+ tx: executor
4620
+ });
4621
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
4622
+ const filters = withScope(
4623
+ scope,
4624
+ tableName,
4625
+ table,
4626
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
4627
+ );
4628
+ if (single) {
4629
+ await assertSingleMatch(executor, table, filters, fieldName);
4630
+ }
4631
+ let query = executor.update(table).set(input);
4632
+ if (filters) {
4633
+ query = query.where(filters);
4634
+ }
4635
+ await query;
4636
+ await runWriteHook(hooks, "after", {
4637
+ table: tableName,
4638
+ operation: "update",
4639
+ single,
4640
+ args,
4641
+ rows: [],
4642
+ context,
4643
+ info,
4644
+ tx: executor
4645
+ });
4646
+ return { isSuccess: true };
4647
+ },
4648
+ !!hooks
4649
+ );
4513
4650
  } catch (e) {
4514
4651
  throw toGraphQLError(e);
4515
4652
  }
@@ -4523,43 +4660,70 @@ var generateUpdateMany = (db, tableName, table, updateManyInput, fieldName, filt
4523
4660
  type: new GraphQLNonNull5(new GraphQLList5(new GraphQLNonNull5(updateManyInput)))
4524
4661
  }
4525
4662
  };
4663
+ const hooks = policies?.onWrite?.(tableName, "updateMany");
4526
4664
  return {
4527
4665
  name: fieldName,
4528
4666
  resolver: async (_source, args, context, info) => {
4529
4667
  try {
4530
- return await runMutation(db, context, info, txCtx, async (executor) => {
4531
- const { updates } = args;
4532
- if (!updates.length) {
4533
- throw new GraphQLError6("No updates were provided!");
4534
- }
4535
- const scope = policies?.scope?.(context);
4536
- const contextColumns = policies?.contextValues?.(tableName);
4537
- const entries = updates.map(({ where, set }) => {
4538
- const input = stripContextValues(remapUpdateInput(set, table, tableName), contextColumns);
4539
- if (!Object.keys(input).length) {
4540
- throw new GraphQLError6("Unable to update with no values specified!");
4668
+ return await runMutation(
4669
+ db,
4670
+ context,
4671
+ info,
4672
+ txCtx,
4673
+ async (executor) => {
4674
+ const { updates } = args;
4675
+ if (!updates.length) {
4676
+ throw new GraphQLError6("No updates were provided!");
4541
4677
  }
4542
- return {
4543
- set: input,
4544
- filters: withScope(
4545
- scope,
4546
- tableName,
4547
- table,
4548
- where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
4549
- )
4550
- };
4551
- });
4552
- await executor.transaction(async (tx) => {
4553
- for (const entry of entries) {
4554
- let query = tx.update(table).set(entry.set);
4555
- if (entry.filters) {
4556
- query = query.where(entry.filters);
4678
+ await runWriteHook(hooks, "before", {
4679
+ table: tableName,
4680
+ operation: "updateMany",
4681
+ single: false,
4682
+ args,
4683
+ context,
4684
+ info,
4685
+ tx: executor
4686
+ });
4687
+ const scope = policies?.scope?.(context);
4688
+ const contextColumns = policies?.contextValues?.(tableName);
4689
+ const entries = updates.map(({ where, set }) => {
4690
+ const input = stripContextValues(remapUpdateInput(set, table, tableName), contextColumns);
4691
+ if (!Object.keys(input).length) {
4692
+ throw new GraphQLError6("Unable to update with no values specified!");
4557
4693
  }
4558
- await query;
4559
- }
4560
- });
4561
- return { isSuccess: true };
4562
- });
4694
+ return {
4695
+ set: input,
4696
+ filters: withScope(
4697
+ scope,
4698
+ tableName,
4699
+ table,
4700
+ where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
4701
+ )
4702
+ };
4703
+ });
4704
+ await executor.transaction(async (tx) => {
4705
+ for (const entry of entries) {
4706
+ let query = tx.update(table).set(entry.set);
4707
+ if (entry.filters) {
4708
+ query = query.where(entry.filters);
4709
+ }
4710
+ await query;
4711
+ }
4712
+ });
4713
+ await runWriteHook(hooks, "after", {
4714
+ table: tableName,
4715
+ operation: "updateMany",
4716
+ single: false,
4717
+ args,
4718
+ rows: [],
4719
+ context,
4720
+ info,
4721
+ tx: executor
4722
+ });
4723
+ return { isSuccess: true };
4724
+ },
4725
+ !!hooks
4726
+ );
4563
4727
  } catch (e) {
4564
4728
  throw toGraphQLError(e);
4565
4729
  }
@@ -4569,36 +4733,64 @@ var generateUpdateMany = (db, tableName, table, updateManyInput, fieldName, filt
4569
4733
  };
4570
4734
  var generateDelete = (db, tableName, table, filterArgs, fieldName, single, requireWhere, filterCtx, txCtx, policies, restore = false) => {
4571
4735
  const softDelete = policies?.softDelete?.(tableName);
4736
+ const operation = restore ? "restore" : "delete";
4572
4737
  const queryArgs = {
4573
4738
  where: {
4574
4739
  type: single || requireWhere ? new GraphQLNonNull5(filterArgs) : filterArgs
4575
4740
  }
4576
4741
  };
4742
+ const hooks = policies?.onWrite?.(tableName, operation);
4577
4743
  return {
4578
4744
  name: fieldName,
4579
4745
  resolver: async (_source, args, context, info) => {
4580
4746
  try {
4581
- return await runMutation(db, context, info, txCtx, async (executor) => {
4582
- const { where } = args;
4583
- const scope = policies?.scope?.(context);
4584
- const relationCtx = relationFilterCtx(filterCtx, tableName);
4585
- const filters = withScope(
4586
- scope,
4587
- tableName,
4588
- table,
4589
- single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
4590
- restore ? "ONLY" : void 0
4591
- );
4592
- if (single) {
4593
- await assertSingleMatch(executor, table, filters, fieldName);
4594
- }
4595
- let query = softDelete ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
4596
- if (filters) {
4597
- query = query.where(filters);
4598
- }
4599
- await query;
4600
- return { isSuccess: true };
4601
- });
4747
+ return await runMutation(
4748
+ db,
4749
+ context,
4750
+ info,
4751
+ txCtx,
4752
+ async (executor) => {
4753
+ await runWriteHook(hooks, "before", {
4754
+ table: tableName,
4755
+ operation,
4756
+ single,
4757
+ args,
4758
+ context,
4759
+ info,
4760
+ tx: executor
4761
+ });
4762
+ const { where } = args;
4763
+ const scope = policies?.scope?.(context);
4764
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
4765
+ const filters = withScope(
4766
+ scope,
4767
+ tableName,
4768
+ table,
4769
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
4770
+ restore ? "ONLY" : void 0
4771
+ );
4772
+ if (single) {
4773
+ await assertSingleMatch(executor, table, filters, fieldName);
4774
+ }
4775
+ let query = softDelete ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
4776
+ if (filters) {
4777
+ query = query.where(filters);
4778
+ }
4779
+ await query;
4780
+ await runWriteHook(hooks, "after", {
4781
+ table: tableName,
4782
+ operation,
4783
+ single,
4784
+ args,
4785
+ rows: [],
4786
+ context,
4787
+ info,
4788
+ tx: executor
4789
+ });
4790
+ return { isSuccess: true };
4791
+ },
4792
+ !!hooks
4793
+ );
4602
4794
  } catch (e) {
4603
4795
  throw toGraphQLError(e);
4604
4796
  }
@@ -5074,7 +5266,7 @@ import {
5074
5266
  import { parseResolveInfo as parseResolveInfo3 } from "graphql-parse-resolve-info";
5075
5267
 
5076
5268
  // src/util/builders/nested-writes.ts
5077
- import { and as and3, eq as eq3, getColumns as getColumns4, is as is5, One as One4 } from "drizzle-orm";
5269
+ import { and as and3, Column, eq as eq3, getColumns as getColumns4, inArray as inArray3, is as is5, One as One4 } from "drizzle-orm";
5078
5270
  import {
5079
5271
  GraphQLBoolean as GraphQLBoolean4,
5080
5272
  GraphQLError as GraphQLError7,
@@ -5083,6 +5275,64 @@ import {
5083
5275
  GraphQLNonNull as GraphQLNonNull6
5084
5276
  } from "graphql";
5085
5277
  var isOptionalOnInsert = (column) => !column.notNull || !!column.hasDefault || !!column.defaultFn;
5278
+ var propNameOf = (table, column) => {
5279
+ if (!column) {
5280
+ return void 0;
5281
+ }
5282
+ for (const [propName, candidate] of Object.entries(getColumns4(table))) {
5283
+ if (candidate === column) {
5284
+ return propName;
5285
+ }
5286
+ }
5287
+ return void 0;
5288
+ };
5289
+ var throughColumn = (entry) => entry && is5(entry, Column) ? entry : entry?._?.column;
5290
+ var buildThroughPlan = (relationName, relation, table, targetTableName, targetTable) => {
5291
+ if (is5(relation, One4)) {
5292
+ return void 0;
5293
+ }
5294
+ const junction = relation.throughTable;
5295
+ const sourceEntries = relation.through?.source;
5296
+ const targetEntries = relation.through?.target;
5297
+ if (!junction || sourceEntries?.length !== 1 || targetEntries?.length !== 1) {
5298
+ return void 0;
5299
+ }
5300
+ if (relation.sourceColumns?.length !== 1 || relation.targetColumns?.length !== 1) {
5301
+ return void 0;
5302
+ }
5303
+ const localCol = relation.sourceColumns[0];
5304
+ const foreignCol = relation.targetColumns[0];
5305
+ const localColPropName = propNameOf(table, localCol);
5306
+ const foreignColPropName = propNameOf(targetTable, foreignCol);
5307
+ const sourceColPropName = propNameOf(junction, throughColumn(sourceEntries[0]));
5308
+ const targetColPropName = propNameOf(junction, throughColumn(targetEntries[0]));
5309
+ if (!localColPropName || !foreignColPropName || !sourceColPropName || !targetColPropName) {
5310
+ return void 0;
5311
+ }
5312
+ const junctionColumns = getColumns4(junction);
5313
+ const sourceCol = junctionColumns[sourceColPropName];
5314
+ const targetCol = junctionColumns[targetColPropName];
5315
+ const unsuppliable = Object.entries(junctionColumns).some(
5316
+ ([propName, column]) => propName !== sourceColPropName && propName !== targetColPropName && !isOptionalOnInsert(column)
5317
+ );
5318
+ if (unsuppliable) {
5319
+ return void 0;
5320
+ }
5321
+ return {
5322
+ relationName,
5323
+ targetTableName,
5324
+ targetTable,
5325
+ localColPropName,
5326
+ foreignColPropName,
5327
+ foreignCol,
5328
+ localCol,
5329
+ isOne: false,
5330
+ // The link is written after the parent row exists, exactly like a child-side foreign key.
5331
+ fkSide: "child",
5332
+ canDetach: true,
5333
+ through: { table: junction, sourceColPropName, targetColPropName, sourceCol, targetCol }
5334
+ };
5335
+ };
5086
5336
  var buildNestedWritePlans = (tables, relationMap, resolveUniqueSets, resolvePrimaryKeys, extractJoinColumns) => {
5087
5337
  const uniqueCache = /* @__PURE__ */ new Map();
5088
5338
  const singleColumnUniques = (tableName, table) => {
@@ -5112,14 +5362,18 @@ var buildNestedWritePlans = (tables, relationMap, resolveUniqueSets, resolvePrim
5112
5362
  const tablePlans = {};
5113
5363
  for (const [relationName, relEntry] of Object.entries(relations)) {
5114
5364
  const relation = relEntry.relation;
5115
- if (relation.through) {
5116
- continue;
5117
- }
5118
5365
  const targetTableName = relEntry.targetTableName;
5119
5366
  const targetTable = tables[targetTableName];
5120
5367
  if (!targetTable) {
5121
5368
  continue;
5122
5369
  }
5370
+ if (relation.through) {
5371
+ const throughPlan = buildThroughPlan(relationName, relation, table, targetTableName, targetTable);
5372
+ if (throughPlan) {
5373
+ tablePlans[relationName] = throughPlan;
5374
+ }
5375
+ continue;
5376
+ }
5123
5377
  const joinColumns = extractJoinColumns(relEntry, table, targetTable);
5124
5378
  if (!joinColumns) {
5125
5379
  continue;
@@ -5204,11 +5458,31 @@ var createNestedWriteTypes = (params) => {
5204
5458
  return cached;
5205
5459
  }
5206
5460
  const filters = targetFilters(plan);
5207
- const payload = payloadType(tableName, typeName, plan);
5208
5461
  const targetTypeName = resolveTypeName(plan.targetTableName, typeNameMapper);
5209
5462
  const fields = {};
5210
- if (plan.isOne) {
5211
- fields["create"] = { type: payload, description: `Insert a ${targetTypeName} row and attach it` };
5463
+ if (plan.through) {
5464
+ if (!filters) {
5465
+ return void 0;
5466
+ }
5467
+ fields["connect"] = {
5468
+ type: listOf(filters),
5469
+ description: `Link every existing ${targetTypeName} row these match. Already-linked rows are left alone.`
5470
+ };
5471
+ if (forUpdate) {
5472
+ fields["disconnect"] = {
5473
+ type: listOf(filters),
5474
+ description: `Unlink every linked ${targetTypeName} row these match, leaving the rows in place`
5475
+ };
5476
+ fields["set"] = {
5477
+ type: listOf(filters),
5478
+ description: `Replace the whole set: unlink everything linked, then link every ${targetTypeName} row these match. \`set: []\` clears the relation. Applied before \`disconnect\` and \`connect\`.`
5479
+ };
5480
+ }
5481
+ } else if (plan.isOne) {
5482
+ fields["create"] = {
5483
+ type: payloadType(tableName, typeName, plan),
5484
+ description: `Insert a ${targetTypeName} row and attach it`
5485
+ };
5212
5486
  if (filters) {
5213
5487
  fields["connect"] = {
5214
5488
  type: filters,
@@ -5222,7 +5496,10 @@ var createNestedWriteTypes = (params) => {
5222
5496
  };
5223
5497
  }
5224
5498
  } else {
5225
- fields["create"] = { type: listOf(payload), description: `Insert these ${targetTypeName} rows and attach them` };
5499
+ fields["create"] = {
5500
+ type: listOf(payloadType(tableName, typeName, plan)),
5501
+ description: `Insert these ${targetTypeName} rows and attach them`
5502
+ };
5226
5503
  if (filters) {
5227
5504
  fields["connect"] = {
5228
5505
  type: listOf(filters),
@@ -5304,6 +5581,48 @@ var createNestedWriteRuntime = (params) => {
5304
5581
  );
5305
5582
  }
5306
5583
  };
5584
+ const selectedTargetKeys = async (executor, plan, filter, operation, scope) => {
5585
+ const rows = await executor.select().from(plan.targetTable).where(conditionOf(plan, filter, operation, scope));
5586
+ return rows.map((row) => row[plan.foreignColPropName]).filter((value) => value !== void 0 && value !== null);
5587
+ };
5588
+ const applyThroughOps = async (executor, plan, key, op, scope) => {
5589
+ const through = plan.through;
5590
+ const unlinkAll = () => executor.delete(through.table).where(eq3(through.sourceCol, key));
5591
+ const link = async (operands, operation) => {
5592
+ const existing = new Set(
5593
+ (await executor.select().from(through.table).where(eq3(through.sourceCol, key))).map(
5594
+ (row) => row[through.targetColPropName]
5595
+ )
5596
+ );
5597
+ const rows = [];
5598
+ for (const filter of operands) {
5599
+ for (const targetKey of await selectedTargetKeys(executor, plan, filter, operation, scope)) {
5600
+ if (!existing.has(targetKey)) {
5601
+ existing.add(targetKey);
5602
+ rows.push({ [through.sourceColPropName]: key, [through.targetColPropName]: targetKey });
5603
+ }
5604
+ }
5605
+ }
5606
+ if (rows.length) {
5607
+ await executor.insert(through.table).values(rows);
5608
+ }
5609
+ };
5610
+ if (op["set"] !== void 0 && op["set"] !== null) {
5611
+ await unlinkAll();
5612
+ await link(asArray(op["set"]), "set");
5613
+ }
5614
+ if (op["disconnect"] !== void 0 && op["disconnect"] !== null) {
5615
+ for (const filter of asArray(op["disconnect"])) {
5616
+ const targetKeys = await selectedTargetKeys(executor, plan, filter, "disconnect", scope);
5617
+ if (targetKeys.length) {
5618
+ await executor.delete(through.table).where(and3(eq3(through.sourceCol, key), inArray3(through.targetCol, targetKeys)));
5619
+ }
5620
+ }
5621
+ }
5622
+ if (op["connect"] !== void 0 && op["connect"] !== null) {
5623
+ await link(asArray(op["connect"]), "connect");
5624
+ }
5625
+ };
5307
5626
  const detachAll = async (executor, plan, key, scope) => executor.update(plan.targetTable).set({ [plan.foreignColPropName]: null }).where(withScope(scope, plan.targetTableName, plan.targetTable, eq3(plan.foreignCol, key)));
5308
5627
  return {
5309
5628
  enabled: (tableName) => !!plans[tableName],
@@ -5400,6 +5719,10 @@ var createNestedWriteRuntime = (params) => {
5400
5719
  `Drizzle-GraphQL Error: cannot write through '${relationName}': the ${tableName} row has no '${plan.localColPropName}' value to attach to.`
5401
5720
  );
5402
5721
  }
5722
+ if (plan.through) {
5723
+ await applyThroughOps(executor, plan, key, op, scope);
5724
+ continue;
5725
+ }
5403
5726
  if (op["set"] !== void 0) {
5404
5727
  await detachAll(executor, plan, key, scope);
5405
5728
  for (const filter of asArray(op["set"])) {
@@ -5482,7 +5805,8 @@ var generateSelectArray2 = (db, tableName, tables, relationMap, orderArgs, filte
5482
5805
  );
5483
5806
  return {
5484
5807
  name: fieldName,
5485
- resolver: async (_source, args, context, info) => {
5808
+ resolver: async (_source, rawArgs, context, info) => {
5809
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
5486
5810
  try {
5487
5811
  const parsedInfo = parseResolveInfo3(info, { deep: true });
5488
5812
  const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
@@ -5503,6 +5827,7 @@ var generateSelectArray2 = (db, tableName, tables, relationMap, orderArgs, filte
5503
5827
  single: false,
5504
5828
  filterCtx,
5505
5829
  limits,
5830
+ defaultOrderBy: policies?.defaultOrderBy,
5506
5831
  pkNames,
5507
5832
  db: executor,
5508
5833
  scope,
@@ -5612,7 +5937,8 @@ var generateSelectSingle2 = (db, tableName, tables, relationMap, orderArgs, filt
5612
5937
  const pkNames = pgPrimaryKeyPropNames(table);
5613
5938
  return {
5614
5939
  name: fieldName,
5615
- resolver: async (_source, args, context, info) => {
5940
+ resolver: async (_source, rawArgs, context, info) => {
5941
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
5616
5942
  try {
5617
5943
  const parsedInfo = parseResolveInfo3(info, { deep: true });
5618
5944
  const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
@@ -5631,6 +5957,7 @@ var generateSelectSingle2 = (db, tableName, tables, relationMap, orderArgs, filt
5631
5957
  single: true,
5632
5958
  filterCtx,
5633
5959
  limits,
5960
+ defaultOrderBy: policies?.defaultOrderBy,
5634
5961
  pkNames,
5635
5962
  db: executor,
5636
5963
  scope
@@ -5679,58 +6006,86 @@ var generateInsertArray2 = (db, tableName, table, tables, relationMap, baseType,
5679
6006
  }
5680
6007
  };
5681
6008
  const pkNames = pgPrimaryKeyPropNames(table);
6009
+ const hooks = policies?.onWrite?.(tableName, "insert");
5682
6010
  return {
5683
6011
  name: fieldName,
5684
6012
  resolver: async (_source, args, context, info) => {
5685
6013
  try {
5686
- return await runMutation(db, context, info, txCtx, async (executor) => {
5687
- if (!args.values.length) {
5688
- throw new GraphQLError8("No values were provided!");
5689
- }
5690
- const entries = nested?.enabled(tableName) ? args.values.map((values) => nested.split(tableName, values)) : void 0;
5691
- const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
5692
- const contextColumns = policies?.contextValues?.(tableName);
5693
- const scope = policies?.scope?.(context);
5694
- const input = nestedEntries ? [] : applyContextValuesAll(
5695
- remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : args.values, table),
5696
- contextColumns,
5697
- context
5698
- );
5699
- const parsedInfo = parseResolveInfo3(info, {
5700
- deep: true
5701
- });
5702
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
5703
- relationMap,
5704
- tables,
5705
- tableName,
5706
- typeName,
5707
- typeNameMapper,
5708
- table,
5709
- pkNames,
5710
- parsedInfo,
5711
- limits,
5712
- scope
5713
- });
5714
- const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
5715
- const runInsert = async (target, values) => {
5716
- let query = target.insert(table).values(values).returning(returning);
5717
- if (conflictDoNothing) {
5718
- query = query.onConflictDoNothing();
6014
+ return await runMutation(
6015
+ db,
6016
+ context,
6017
+ info,
6018
+ txCtx,
6019
+ async (executor) => {
6020
+ if (!args.values.length) {
6021
+ throw new GraphQLError8("No values were provided!");
5719
6022
  }
5720
- return await query;
5721
- };
5722
- const result = nestedEntries ? await writeWithNestedOps({
5723
- executor,
5724
- runtime: nested,
5725
- tableName,
5726
- entries: nestedEntries,
5727
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
5728
- write: (tx, values) => runInsert(tx, [values]),
5729
- context
5730
- }) : await runInsert(executor, input);
5731
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
5732
- return remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
5733
- });
6023
+ await runWriteHook(hooks, "before", {
6024
+ table: tableName,
6025
+ operation: "insert",
6026
+ single: false,
6027
+ args,
6028
+ context,
6029
+ info,
6030
+ tx: executor
6031
+ });
6032
+ const entries = nested?.enabled(tableName) ? args.values.map((values) => nested.split(tableName, values)) : void 0;
6033
+ const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
6034
+ const contextColumns = policies?.contextValues?.(tableName);
6035
+ const scope = policies?.scope?.(context);
6036
+ const input = nestedEntries ? [] : applyContextValuesAll(
6037
+ remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : args.values, table),
6038
+ contextColumns,
6039
+ context
6040
+ );
6041
+ const parsedInfo = parseResolveInfo3(info, {
6042
+ deep: true
6043
+ });
6044
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6045
+ relationMap,
6046
+ tables,
6047
+ tableName,
6048
+ typeName,
6049
+ typeNameMapper,
6050
+ table,
6051
+ pkNames,
6052
+ parsedInfo,
6053
+ limits,
6054
+ scope,
6055
+ defaultOrderBy: policies?.defaultOrderBy
6056
+ });
6057
+ const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
6058
+ const runInsert = async (target, values) => {
6059
+ let query = target.insert(table).values(values).returning(returning);
6060
+ if (conflictDoNothing) {
6061
+ query = query.onConflictDoNothing();
6062
+ }
6063
+ return await query;
6064
+ };
6065
+ const result = nestedEntries ? await writeWithNestedOps({
6066
+ executor,
6067
+ runtime: nested,
6068
+ tableName,
6069
+ entries: nestedEntries,
6070
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6071
+ write: (tx, values) => runInsert(tx, [values]),
6072
+ context
6073
+ }) : await runInsert(executor, input);
6074
+ await runWriteHook(hooks, "after", {
6075
+ table: tableName,
6076
+ operation: "insert",
6077
+ single: false,
6078
+ args,
6079
+ rows: result,
6080
+ context,
6081
+ info,
6082
+ tx: executor
6083
+ });
6084
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6085
+ return remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
6086
+ },
6087
+ !!hooks
6088
+ );
5734
6089
  } catch (e) {
5735
6090
  throw toGraphQLError(e);
5736
6091
  }
@@ -5745,61 +6100,89 @@ var generateInsertSingle2 = (db, tableName, table, tables, relationMap, baseType
5745
6100
  }
5746
6101
  };
5747
6102
  const pkNames = pgPrimaryKeyPropNames(table);
6103
+ const hooks = policies?.onWrite?.(tableName, "insert");
5748
6104
  return {
5749
6105
  name: fieldName,
5750
6106
  resolver: async (_source, args, context, info) => {
5751
6107
  try {
5752
- return await runMutation(db, context, info, txCtx, async (executor) => {
5753
- const entry = nested?.enabled(tableName) ? nested.split(tableName, args.values) : void 0;
5754
- const nestedEntry = entry && nested.hasOps(entry.ops) ? entry : void 0;
5755
- const contextColumns = policies?.contextValues?.(tableName);
5756
- const scope = policies?.scope?.(context);
5757
- const input = nestedEntry ? {} : applyContextValues(
5758
- remapFromGraphQLSingleInput(entry ? entry.columns : args.values, table),
5759
- contextColumns,
5760
- context
5761
- );
5762
- const parsedInfo = parseResolveInfo3(info, {
5763
- deep: true
5764
- });
5765
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
5766
- relationMap,
5767
- tables,
5768
- tableName,
5769
- typeName,
5770
- typeNameMapper,
5771
- table,
5772
- pkNames,
5773
- parsedInfo,
5774
- limits,
5775
- scope
5776
- });
5777
- const returning = nestedEntry ? nested.withJoinColumns(tableName, nestedEntry.ops, { ...columns }, table) : columns;
5778
- const runInsert = async (target, values) => {
5779
- let query = target.insert(table).values(values).returning(returning);
5780
- if (conflictDoNothing) {
5781
- query = query.onConflictDoNothing();
5782
- }
5783
- return await query;
5784
- };
5785
- const result = nestedEntry ? await writeWithNestedOps({
5786
- executor,
5787
- runtime: nested,
5788
- tableName,
5789
- entries: [nestedEntry],
5790
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
5791
- write: runInsert,
5792
- context
5793
- }) : await runInsert(executor, input);
5794
- if (!result[0]) {
5795
- if (!conflictDoNothing) {
5796
- throw new GraphQLError8(`${fieldName}: the insert returned no row.`);
6108
+ return await runMutation(
6109
+ db,
6110
+ context,
6111
+ info,
6112
+ txCtx,
6113
+ async (executor) => {
6114
+ await runWriteHook(hooks, "before", {
6115
+ table: tableName,
6116
+ operation: "insert",
6117
+ single: true,
6118
+ args,
6119
+ context,
6120
+ info,
6121
+ tx: executor
6122
+ });
6123
+ const entry = nested?.enabled(tableName) ? nested.split(tableName, args.values) : void 0;
6124
+ const nestedEntry = entry && nested.hasOps(entry.ops) ? entry : void 0;
6125
+ const contextColumns = policies?.contextValues?.(tableName);
6126
+ const scope = policies?.scope?.(context);
6127
+ const input = nestedEntry ? {} : applyContextValues(
6128
+ remapFromGraphQLSingleInput(entry ? entry.columns : args.values, table),
6129
+ contextColumns,
6130
+ context
6131
+ );
6132
+ const parsedInfo = parseResolveInfo3(info, {
6133
+ deep: true
6134
+ });
6135
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6136
+ relationMap,
6137
+ tables,
6138
+ tableName,
6139
+ typeName,
6140
+ typeNameMapper,
6141
+ table,
6142
+ pkNames,
6143
+ parsedInfo,
6144
+ limits,
6145
+ scope,
6146
+ defaultOrderBy: policies?.defaultOrderBy
6147
+ });
6148
+ const returning = nestedEntry ? nested.withJoinColumns(tableName, nestedEntry.ops, { ...columns }, table) : columns;
6149
+ const runInsert = async (target, values) => {
6150
+ let query = target.insert(table).values(values).returning(returning);
6151
+ if (conflictDoNothing) {
6152
+ query = query.onConflictDoNothing();
6153
+ }
6154
+ return await query;
6155
+ };
6156
+ const result = nestedEntry ? await writeWithNestedOps({
6157
+ executor,
6158
+ runtime: nested,
6159
+ tableName,
6160
+ entries: [nestedEntry],
6161
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6162
+ write: runInsert,
6163
+ context
6164
+ }) : await runInsert(executor, input);
6165
+ await runWriteHook(hooks, "after", {
6166
+ table: tableName,
6167
+ operation: "insert",
6168
+ single: true,
6169
+ args,
6170
+ rows: result,
6171
+ context,
6172
+ info,
6173
+ tx: executor
6174
+ });
6175
+ if (!result[0]) {
6176
+ if (!conflictDoNothing) {
6177
+ throw new GraphQLError8(`${fieldName}: the insert returned no row.`);
6178
+ }
6179
+ return void 0;
5797
6180
  }
5798
- return void 0;
5799
- }
5800
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
5801
- return remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap);
5802
- });
6181
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6182
+ return remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap);
6183
+ },
6184
+ !!hooks
6185
+ );
5803
6186
  } catch (e) {
5804
6187
  throw toGraphQLError(e);
5805
6188
  }
@@ -5818,69 +6201,97 @@ var generateUpsert2 = (db, tableName, table, tables, relationMap, baseType, onCo
5818
6201
  }
5819
6202
  };
5820
6203
  const pkNames = pgPrimaryKeyPropNames(table);
6204
+ const hooks = policies?.onWrite?.(tableName, "upsert");
5821
6205
  return {
5822
6206
  name: fieldName,
5823
6207
  resolver: async (_source, args, context, info) => {
5824
6208
  try {
5825
- return await runMutation(db, context, info, txCtx, async (executor) => {
5826
- const supplied = single ? [args.values] : args.values;
5827
- if (!supplied.length) {
5828
- throw new GraphQLError8("No values were provided!");
5829
- }
5830
- const entries = nested?.enabled(tableName) ? supplied.map((values) => nested.split(tableName, values)) : void 0;
5831
- const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
5832
- const contextColumns = policies?.contextValues?.(tableName);
5833
- const scope = policies?.scope?.(context);
5834
- const input = nestedEntries ? [] : applyContextValuesAll(
5835
- remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : supplied, table),
5836
- contextColumns,
5837
- context
5838
- );
5839
- const parsedInfo = parseResolveInfo3(info, { deep: true });
5840
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
5841
- relationMap,
5842
- tables,
5843
- tableName,
5844
- typeName,
5845
- typeNameMapper,
5846
- table,
5847
- pkNames,
5848
- parsedInfo,
5849
- limits,
5850
- scope
5851
- });
5852
- const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
5853
- const runUpsert = async (target, values) => {
5854
- const plan = resolveConflictPlan({
6209
+ return await runMutation(
6210
+ db,
6211
+ context,
6212
+ info,
6213
+ txCtx,
6214
+ async (executor) => {
6215
+ const supplied = single ? [args.values] : args.values;
6216
+ if (!supplied.length) {
6217
+ throw new GraphQLError8("No values were provided!");
6218
+ }
6219
+ await runWriteHook(hooks, "before", {
6220
+ table: tableName,
6221
+ operation: "upsert",
6222
+ single,
6223
+ args,
6224
+ context,
6225
+ info,
6226
+ tx: executor
6227
+ });
6228
+ const entries = nested?.enabled(tableName) ? supplied.map((values) => nested.split(tableName, values)) : void 0;
6229
+ const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
6230
+ const contextColumns = policies?.contextValues?.(tableName);
6231
+ const scope = policies?.scope?.(context);
6232
+ const input = nestedEntries ? [] : applyContextValuesAll(
6233
+ remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : supplied, table),
6234
+ contextColumns,
6235
+ context
6236
+ );
6237
+ const parsedInfo = parseResolveInfo3(info, { deep: true });
6238
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6239
+ relationMap,
6240
+ tables,
6241
+ tableName,
6242
+ typeName,
6243
+ typeNameMapper,
5855
6244
  table,
5856
- values,
5857
- onConflict: args.onConflict,
5858
6245
  pkNames,
5859
- uniqueSets,
5860
- excludedRef: excludedColumnRef,
5861
- withTarget: true,
5862
- buildWhere: (where) => extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName))
6246
+ parsedInfo,
6247
+ limits,
6248
+ scope,
6249
+ defaultOrderBy: policies?.defaultOrderBy
5863
6250
  });
5864
- let query = target.insert(table).values(values).returning(returning);
5865
- const setWhere = withScope(scope, tableName, table, plan.setWhere);
5866
- query = plan.action === "NOTHING" ? query.onConflictDoNothing(plan.target ? { target: plan.target } : void 0) : query.onConflictDoUpdate({ target: plan.target, set: plan.set, setWhere });
5867
- return await query;
5868
- };
5869
- const result = nestedEntries ? await writeWithNestedOps({
5870
- executor,
5871
- runtime: nested,
5872
- tableName,
5873
- entries: nestedEntries,
5874
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
5875
- write: (tx, values) => runUpsert(tx, [values]),
5876
- context
5877
- }) : await runUpsert(executor, input);
5878
- if (single && !result[0]) {
5879
- return void 0;
5880
- }
5881
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
5882
- return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
5883
- });
6251
+ const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
6252
+ const runUpsert = async (target, values) => {
6253
+ const plan = resolveConflictPlan({
6254
+ table,
6255
+ values,
6256
+ onConflict: args.onConflict,
6257
+ pkNames,
6258
+ uniqueSets,
6259
+ excludedRef: excludedColumnRef,
6260
+ withTarget: true,
6261
+ buildWhere: (where) => extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName))
6262
+ });
6263
+ let query = target.insert(table).values(values).returning(returning);
6264
+ const setWhere = withScope(scope, tableName, table, plan.setWhere);
6265
+ query = plan.action === "NOTHING" ? query.onConflictDoNothing(plan.target ? { target: plan.target } : void 0) : query.onConflictDoUpdate({ target: plan.target, set: plan.set, setWhere });
6266
+ return await query;
6267
+ };
6268
+ const result = nestedEntries ? await writeWithNestedOps({
6269
+ executor,
6270
+ runtime: nested,
6271
+ tableName,
6272
+ entries: nestedEntries,
6273
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6274
+ write: (tx, values) => runUpsert(tx, [values]),
6275
+ context
6276
+ }) : await runUpsert(executor, input);
6277
+ await runWriteHook(hooks, "after", {
6278
+ table: tableName,
6279
+ operation: "upsert",
6280
+ single,
6281
+ args,
6282
+ rows: result,
6283
+ context,
6284
+ info,
6285
+ tx: executor
6286
+ });
6287
+ if (single && !result[0]) {
6288
+ return void 0;
6289
+ }
6290
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6291
+ return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
6292
+ },
6293
+ !!hooks
6294
+ );
5884
6295
  } catch (e) {
5885
6296
  throw toGraphQLError(e);
5886
6297
  }
@@ -5898,75 +6309,103 @@ var generateUpdate2 = (db, tableName, table, tables, relationMap, setArgs, filte
5898
6309
  }
5899
6310
  };
5900
6311
  const pkNames = pgPrimaryKeyPropNames(table);
6312
+ const hooks = policies?.onWrite?.(tableName, "update");
5901
6313
  return {
5902
6314
  name: fieldName,
5903
6315
  resolver: async (_source, args, context, info) => {
5904
6316
  try {
5905
- return await runMutation(db, context, info, txCtx, async (executor) => {
5906
- const { where, set } = args;
5907
- const scope = policies?.scope?.(context);
5908
- const parsedInfo = parseResolveInfo3(info, {
5909
- deep: true
5910
- });
5911
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
5912
- relationMap,
5913
- tables,
5914
- tableName,
5915
- typeName,
5916
- typeNameMapper,
5917
- table,
5918
- pkNames,
5919
- parsedInfo,
5920
- limits,
5921
- scope
5922
- });
5923
- const entry = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
5924
- const nestedOps = entry && nested.hasOps(entry.ops) ? entry.ops : void 0;
5925
- const input = stripContextValues(
5926
- remapUpdateInput(entry ? entry.columns : set, table, tableName),
5927
- policies?.contextValues?.(tableName)
5928
- );
5929
- if (!Object.keys(input).length && !nestedOps) {
5930
- throw new GraphQLError8("Unable to update with no values specified!");
5931
- }
5932
- const relationCtx = relationFilterCtx(filterCtx, tableName);
5933
- const filters = withScope(
5934
- scope,
5935
- tableName,
5936
- table,
5937
- single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
5938
- );
5939
- if (single) {
5940
- await assertSingleMatch(executor, table, filters, fieldName);
5941
- }
5942
- const returning = nestedOps ? nested.withJoinColumns(tableName, nestedOps, { ...columns }, table) : columns;
5943
- const runUpdate = async (target, values) => {
5944
- const writes = Object.keys(values).length > 0;
5945
- let query = writes ? target.update(table).set(values) : target.select(returning).from(table);
5946
- if (filters) {
5947
- query = query.where(filters);
6317
+ return await runMutation(
6318
+ db,
6319
+ context,
6320
+ info,
6321
+ txCtx,
6322
+ async (executor) => {
6323
+ const { where, set } = args;
6324
+ const scope = policies?.scope?.(context);
6325
+ await runWriteHook(hooks, "before", {
6326
+ table: tableName,
6327
+ operation: "update",
6328
+ single,
6329
+ args,
6330
+ context,
6331
+ info,
6332
+ tx: executor
6333
+ });
6334
+ const parsedInfo = parseResolveInfo3(info, {
6335
+ deep: true
6336
+ });
6337
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6338
+ relationMap,
6339
+ tables,
6340
+ tableName,
6341
+ typeName,
6342
+ typeNameMapper,
6343
+ table,
6344
+ pkNames,
6345
+ parsedInfo,
6346
+ limits,
6347
+ scope,
6348
+ defaultOrderBy: policies?.defaultOrderBy
6349
+ });
6350
+ const entry = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
6351
+ const nestedOps = entry && nested.hasOps(entry.ops) ? entry.ops : void 0;
6352
+ const input = stripContextValues(
6353
+ remapUpdateInput(entry ? entry.columns : set, table, tableName),
6354
+ policies?.contextValues?.(tableName)
6355
+ );
6356
+ if (!Object.keys(input).length && !nestedOps) {
6357
+ throw new GraphQLError8("Unable to update with no values specified!");
5948
6358
  }
5949
- return await (writes ? query.returning(returning) : query);
5950
- };
5951
- const result = nestedOps ? await updateWithNestedOps({
5952
- executor,
5953
- runtime: nested,
5954
- tableName,
5955
- columns: input,
5956
- ops: nestedOps,
5957
- remapValues: (values) => values,
5958
- write: runUpdate,
5959
- context
5960
- }) : await runUpdate(executor, input);
5961
- if (single && result.length > 1) {
5962
- throw new GraphQLError8(`${fieldName}: 'where' matched more than one row!`);
5963
- }
5964
- if (single && !result[0]) {
5965
- return void 0;
5966
- }
5967
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
5968
- return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
5969
- });
6359
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
6360
+ const filters = withScope(
6361
+ scope,
6362
+ tableName,
6363
+ table,
6364
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
6365
+ );
6366
+ if (single) {
6367
+ await assertSingleMatch(executor, table, filters, fieldName);
6368
+ }
6369
+ const returning = nestedOps ? nested.withJoinColumns(tableName, nestedOps, { ...columns }, table) : columns;
6370
+ const runUpdate = async (target, values) => {
6371
+ const writes = Object.keys(values).length > 0;
6372
+ let query = writes ? target.update(table).set(values) : target.select(returning).from(table);
6373
+ if (filters) {
6374
+ query = query.where(filters);
6375
+ }
6376
+ return await (writes ? query.returning(returning) : query);
6377
+ };
6378
+ const result = nestedOps ? await updateWithNestedOps({
6379
+ executor,
6380
+ runtime: nested,
6381
+ tableName,
6382
+ columns: input,
6383
+ ops: nestedOps,
6384
+ remapValues: (values) => values,
6385
+ write: runUpdate,
6386
+ context
6387
+ }) : await runUpdate(executor, input);
6388
+ await runWriteHook(hooks, "after", {
6389
+ table: tableName,
6390
+ operation: "update",
6391
+ single,
6392
+ args,
6393
+ rows: result,
6394
+ context,
6395
+ info,
6396
+ tx: executor
6397
+ });
6398
+ if (single && result.length > 1) {
6399
+ throw new GraphQLError8(`${fieldName}: 'where' matched more than one row!`);
6400
+ }
6401
+ if (single && !result[0]) {
6402
+ return void 0;
6403
+ }
6404
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6405
+ return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
6406
+ },
6407
+ !!hooks
6408
+ );
5970
6409
  } catch (e) {
5971
6410
  throw toGraphQLError(e);
5972
6411
  }
@@ -5981,94 +6420,122 @@ var generateUpdateMany2 = (db, tableName, table, tables, relationMap, updateMany
5981
6420
  }
5982
6421
  };
5983
6422
  const pkNames = pgPrimaryKeyPropNames(table);
6423
+ const hooks = policies?.onWrite?.(tableName, "updateMany");
5984
6424
  return {
5985
6425
  name: fieldName,
5986
6426
  resolver: async (_source, args, context, info) => {
5987
6427
  try {
5988
- return await runMutation(db, context, info, txCtx, async (executor) => {
5989
- const { updates } = args;
5990
- if (!updates.length) {
5991
- throw new GraphQLError8("No updates were provided!");
5992
- }
5993
- const scope = policies?.scope?.(context);
5994
- const contextColumns = policies?.contextValues?.(tableName);
5995
- const parsedInfo = parseResolveInfo3(info, {
5996
- deep: true
5997
- });
5998
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
5999
- relationMap,
6000
- tables,
6001
- tableName,
6002
- typeName,
6003
- typeNameMapper,
6004
- table,
6005
- pkNames,
6006
- parsedInfo,
6007
- limits,
6008
- scope
6009
- });
6010
- const entries = updates.map(({ where, set }) => {
6011
- const split = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
6012
- const ops = split && nested.hasOps(split.ops) ? split.ops : void 0;
6013
- const input = stripContextValues(
6014
- remapUpdateInput(split ? split.columns : set, table, tableName),
6015
- contextColumns
6016
- );
6017
- if (!Object.keys(input).length && !ops) {
6018
- throw new GraphQLError8("Unable to update with no values specified!");
6428
+ return await runMutation(
6429
+ db,
6430
+ context,
6431
+ info,
6432
+ txCtx,
6433
+ async (executor) => {
6434
+ const { updates } = args;
6435
+ if (!updates.length) {
6436
+ throw new GraphQLError8("No updates were provided!");
6019
6437
  }
6020
- return {
6021
- set: input,
6022
- ops,
6023
- filters: withScope(
6024
- scope,
6025
- tableName,
6026
- table,
6027
- where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
6028
- )
6029
- };
6030
- });
6031
- const returning = entries.some((entry) => entry.ops) ? nested.withJoinColumns(
6032
- tableName,
6033
- mergedOps(entries.map((entry) => ({ ops: entry.ops ?? {} }))),
6034
- {
6035
- ...columns
6036
- },
6037
- table
6038
- ) : columns;
6039
- const perEntry = await executor.transaction(async (tx) => {
6040
- const results = [];
6041
- for (const entry of entries) {
6042
- const values = entry.ops ? { ...entry.set, ...await nested.applyParentSide(tx, tableName, entry.ops, context) } : entry.set;
6043
- const writes = Object.keys(values).length > 0;
6044
- let query = writes ? tx.update(table).set(values) : tx.select(returning).from(table);
6045
- if (entry.filters) {
6046
- query = query.where(entry.filters);
6438
+ await runWriteHook(hooks, "before", {
6439
+ table: tableName,
6440
+ operation: "updateMany",
6441
+ single: false,
6442
+ args,
6443
+ context,
6444
+ info,
6445
+ tx: executor
6446
+ });
6447
+ const scope = policies?.scope?.(context);
6448
+ const contextColumns = policies?.contextValues?.(tableName);
6449
+ const parsedInfo = parseResolveInfo3(info, {
6450
+ deep: true
6451
+ });
6452
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6453
+ relationMap,
6454
+ tables,
6455
+ tableName,
6456
+ typeName,
6457
+ typeNameMapper,
6458
+ table,
6459
+ pkNames,
6460
+ parsedInfo,
6461
+ limits,
6462
+ scope,
6463
+ defaultOrderBy: policies?.defaultOrderBy
6464
+ });
6465
+ const entries = updates.map(({ where, set }) => {
6466
+ const split = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
6467
+ const ops = split && nested.hasOps(split.ops) ? split.ops : void 0;
6468
+ const input = stripContextValues(
6469
+ remapUpdateInput(split ? split.columns : set, table, tableName),
6470
+ contextColumns
6471
+ );
6472
+ if (!Object.keys(input).length && !ops) {
6473
+ throw new GraphQLError8("Unable to update with no values specified!");
6047
6474
  }
6048
- const rows = await (writes ? query.returning(returning) : query);
6049
- if (entry.ops) {
6050
- await nested.applyChildSide(tx, tableName, entry.ops, rows, context);
6475
+ return {
6476
+ set: input,
6477
+ ops,
6478
+ filters: withScope(
6479
+ scope,
6480
+ tableName,
6481
+ table,
6482
+ where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
6483
+ )
6484
+ };
6485
+ });
6486
+ const returning = entries.some((entry) => entry.ops) ? nested.withJoinColumns(
6487
+ tableName,
6488
+ mergedOps(entries.map((entry) => ({ ops: entry.ops ?? {} }))),
6489
+ {
6490
+ ...columns
6491
+ },
6492
+ table
6493
+ ) : columns;
6494
+ const perEntry = await executor.transaction(async (tx) => {
6495
+ const results = [];
6496
+ for (const entry of entries) {
6497
+ const values = entry.ops ? { ...entry.set, ...await nested.applyParentSide(tx, tableName, entry.ops, context) } : entry.set;
6498
+ const writes = Object.keys(values).length > 0;
6499
+ let query = writes ? tx.update(table).set(values) : tx.select(returning).from(table);
6500
+ if (entry.filters) {
6501
+ query = query.where(entry.filters);
6502
+ }
6503
+ const rows = await (writes ? query.returning(returning) : query);
6504
+ if (entry.ops) {
6505
+ await nested.applyChildSide(tx, tableName, entry.ops, rows, context);
6506
+ }
6507
+ results.push(rows);
6051
6508
  }
6052
- results.push(rows);
6053
- }
6054
- return results;
6055
- });
6056
- const flatRows = perEntry.flat();
6057
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, flatRows, pkNames, withParams) : flatRows;
6058
- const output = [];
6059
- let offset = 0;
6060
- for (const rows of perEntry) {
6061
- if (!rows.length) {
6062
- output.push(null);
6063
- continue;
6064
- }
6065
- for (let i = 0; i < rows.length; i++) {
6066
- output.push(remapToGraphQLSingleOutput(enriched[offset + i], tableName, table, relationMap));
6509
+ return results;
6510
+ });
6511
+ const flatRows = perEntry.flat();
6512
+ await runWriteHook(hooks, "after", {
6513
+ table: tableName,
6514
+ operation: "updateMany",
6515
+ single: false,
6516
+ args,
6517
+ rows: flatRows,
6518
+ context,
6519
+ info,
6520
+ tx: executor
6521
+ });
6522
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, flatRows, pkNames, withParams) : flatRows;
6523
+ const output = [];
6524
+ let offset = 0;
6525
+ for (const rows of perEntry) {
6526
+ if (!rows.length) {
6527
+ output.push(null);
6528
+ continue;
6529
+ }
6530
+ for (let i = 0; i < rows.length; i++) {
6531
+ output.push(remapToGraphQLSingleOutput(enriched[offset + i], tableName, table, relationMap));
6532
+ }
6533
+ offset += rows.length;
6067
6534
  }
6068
- offset += rows.length;
6069
- }
6070
- return output;
6071
- });
6535
+ return output;
6536
+ },
6537
+ !!hooks
6538
+ );
6072
6539
  } catch (e) {
6073
6540
  throw toGraphQLError(e);
6074
6541
  }
@@ -6078,6 +6545,8 @@ var generateUpdateMany2 = (db, tableName, table, tables, relationMap, updateMany
6078
6545
  };
6079
6546
  var generateDelete2 = (db, tableName, table, filterArgs, fieldName, typeName, single, requireWhere, filterCtx, selectionCtx, txCtx, policies, restore = false) => {
6080
6547
  const softDelete = policies?.softDelete?.(tableName);
6548
+ const operation = restore ? "restore" : "delete";
6549
+ const hooks = policies?.onWrite?.(tableName, operation);
6081
6550
  const queryArgs = {
6082
6551
  where: {
6083
6552
  type: single || requireWhere ? new GraphQLNonNull7(filterArgs) : filterArgs
@@ -6087,42 +6556,68 @@ var generateDelete2 = (db, tableName, table, filterArgs, fieldName, typeName, si
6087
6556
  name: fieldName,
6088
6557
  resolver: async (_source, args, context, info) => {
6089
6558
  try {
6090
- return await runMutation(db, context, info, txCtx, async (executor) => {
6091
- const { where } = args;
6092
- const scope = policies?.scope?.(context);
6093
- const parsedInfo = parseResolveInfo3(info, {
6094
- deep: true
6095
- });
6096
- const columns = extractSelectedColumnsFromTreeSQLFormat(
6097
- parsedInfo.fieldsByTypeName[typeName],
6098
- table,
6099
- selectionCtx
6100
- );
6101
- const relationCtx = relationFilterCtx(filterCtx, tableName);
6102
- const filters = withScope(
6103
- scope,
6104
- tableName,
6105
- table,
6106
- single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
6107
- restore ? "ONLY" : void 0
6108
- );
6109
- if (single) {
6110
- await assertSingleMatch(executor, table, filters, fieldName);
6111
- }
6112
- let query = softDelete ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
6113
- if (filters) {
6114
- query = query.where(filters);
6115
- }
6116
- query = query.returning(columns);
6117
- const result = await query;
6118
- if (single && result.length > 1) {
6119
- throw new GraphQLError8(`${fieldName}: 'where' matched more than one row!`);
6120
- }
6121
- if (single) {
6122
- return result[0] ? remapToGraphQLSingleOutput(result[0], tableName, table) : void 0;
6123
- }
6124
- return remapToGraphQLArrayOutput(result, tableName, table);
6125
- });
6559
+ return await runMutation(
6560
+ db,
6561
+ context,
6562
+ info,
6563
+ txCtx,
6564
+ async (executor) => {
6565
+ const { where } = args;
6566
+ const scope = policies?.scope?.(context);
6567
+ await runWriteHook(hooks, "before", {
6568
+ table: tableName,
6569
+ operation,
6570
+ single,
6571
+ args,
6572
+ context,
6573
+ info,
6574
+ tx: executor
6575
+ });
6576
+ const parsedInfo = parseResolveInfo3(info, {
6577
+ deep: true
6578
+ });
6579
+ const columns = extractSelectedColumnsFromTreeSQLFormat(
6580
+ parsedInfo.fieldsByTypeName[typeName],
6581
+ table,
6582
+ selectionCtx
6583
+ );
6584
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
6585
+ const filters = withScope(
6586
+ scope,
6587
+ tableName,
6588
+ table,
6589
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
6590
+ restore ? "ONLY" : void 0
6591
+ );
6592
+ if (single) {
6593
+ await assertSingleMatch(executor, table, filters, fieldName);
6594
+ }
6595
+ let query = softDelete ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
6596
+ if (filters) {
6597
+ query = query.where(filters);
6598
+ }
6599
+ query = query.returning(columns);
6600
+ const result = await query;
6601
+ await runWriteHook(hooks, "after", {
6602
+ table: tableName,
6603
+ operation,
6604
+ single,
6605
+ args,
6606
+ rows: result,
6607
+ context,
6608
+ info,
6609
+ tx: executor
6610
+ });
6611
+ if (single && result.length > 1) {
6612
+ throw new GraphQLError8(`${fieldName}: 'where' matched more than one row!`);
6613
+ }
6614
+ if (single) {
6615
+ return result[0] ? remapToGraphQLSingleOutput(result[0], tableName, table) : void 0;
6616
+ }
6617
+ return remapToGraphQLArrayOutput(result, tableName, table);
6618
+ },
6619
+ !!hooks
6620
+ );
6126
6621
  } catch (e) {
6127
6622
  throw toGraphQLError(e);
6128
6623
  }
@@ -6774,7 +7269,8 @@ var generateSelectArray3 = (db, tableName, tables, relationMap, orderArgs, filte
6774
7269
  );
6775
7270
  return {
6776
7271
  name: fieldName,
6777
- resolver: async (_source, args, context, info) => {
7272
+ resolver: async (_source, rawArgs, context, info) => {
7273
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
6778
7274
  try {
6779
7275
  const parsedInfo = parseResolveInfo4(info, { deep: true });
6780
7276
  const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
@@ -6792,6 +7288,7 @@ var generateSelectArray3 = (db, tableName, tables, relationMap, orderArgs, filte
6792
7288
  single: false,
6793
7289
  filterCtx,
6794
7290
  limits,
7291
+ defaultOrderBy: policies?.defaultOrderBy,
6795
7292
  pkNames,
6796
7293
  db: executor,
6797
7294
  scope: policies?.scope?.(context),
@@ -6817,7 +7314,8 @@ var generateSelectSingle3 = (db, tableName, tables, relationMap, orderArgs, filt
6817
7314
  const pkNames = sqlitePrimaryKeyPropNames(table);
6818
7315
  return {
6819
7316
  name: fieldName,
6820
- resolver: async (_source, args, context, info) => {
7317
+ resolver: async (_source, rawArgs, context, info) => {
7318
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
6821
7319
  try {
6822
7320
  const parsedInfo = parseResolveInfo4(info, { deep: true });
6823
7321
  const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
@@ -6834,6 +7332,7 @@ var generateSelectSingle3 = (db, tableName, tables, relationMap, orderArgs, filt
6834
7332
  single: true,
6835
7333
  filterCtx,
6836
7334
  limits,
7335
+ defaultOrderBy: policies?.defaultOrderBy,
6837
7336
  pkNames,
6838
7337
  db: executor,
6839
7338
  scope: policies?.scope?.(context)
@@ -6853,58 +7352,86 @@ var generateInsertArray3 = (db, tableName, table, tables, relationMap, baseType,
6853
7352
  }
6854
7353
  };
6855
7354
  const pkNames = sqlitePrimaryKeyPropNames(table);
7355
+ const hooks = policies?.onWrite?.(tableName, "insert");
6856
7356
  return {
6857
7357
  name: fieldName,
6858
7358
  resolver: async (_source, args, context, info) => {
6859
7359
  try {
6860
- return await runMutation(db, context, info, txCtx, async (executor) => {
6861
- if (!args.values.length) {
6862
- throw new GraphQLError9("No values were provided!");
6863
- }
6864
- const entries = nested?.enabled(tableName) ? args.values.map((values) => nested.split(tableName, values)) : void 0;
6865
- const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
6866
- const contextColumns = policies?.contextValues?.(tableName);
6867
- const scope = policies?.scope?.(context);
6868
- const input = nestedEntries ? [] : applyContextValuesAll(
6869
- remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : args.values, table),
6870
- contextColumns,
6871
- context
6872
- );
6873
- const parsedInfo = parseResolveInfo4(info, {
6874
- deep: true
6875
- });
6876
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6877
- relationMap,
6878
- tables,
6879
- tableName,
6880
- typeName,
6881
- typeNameMapper,
6882
- table,
6883
- pkNames,
6884
- parsedInfo,
6885
- limits,
6886
- scope
6887
- });
6888
- const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
6889
- const runInsert = async (target, values) => {
6890
- let query = target.insert(table).values(values).returning(returning);
6891
- if (conflictDoNothing) {
6892
- query = query.onConflictDoNothing();
7360
+ return await runMutation(
7361
+ db,
7362
+ context,
7363
+ info,
7364
+ txCtx,
7365
+ async (executor) => {
7366
+ if (!args.values.length) {
7367
+ throw new GraphQLError9("No values were provided!");
6893
7368
  }
6894
- return await query;
6895
- };
6896
- const result = nestedEntries ? await writeWithNestedOps({
6897
- executor,
6898
- runtime: nested,
6899
- tableName,
6900
- entries: nestedEntries,
6901
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6902
- write: (tx, values) => runInsert(tx, [values]),
6903
- context
6904
- }) : await runInsert(executor, input);
6905
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6906
- return remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
6907
- });
7369
+ await runWriteHook(hooks, "before", {
7370
+ table: tableName,
7371
+ operation: "insert",
7372
+ single: false,
7373
+ args,
7374
+ context,
7375
+ info,
7376
+ tx: executor
7377
+ });
7378
+ const entries = nested?.enabled(tableName) ? args.values.map((values) => nested.split(tableName, values)) : void 0;
7379
+ const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
7380
+ const contextColumns = policies?.contextValues?.(tableName);
7381
+ const scope = policies?.scope?.(context);
7382
+ const input = nestedEntries ? [] : applyContextValuesAll(
7383
+ remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : args.values, table),
7384
+ contextColumns,
7385
+ context
7386
+ );
7387
+ const parsedInfo = parseResolveInfo4(info, {
7388
+ deep: true
7389
+ });
7390
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7391
+ relationMap,
7392
+ tables,
7393
+ tableName,
7394
+ typeName,
7395
+ typeNameMapper,
7396
+ table,
7397
+ pkNames,
7398
+ parsedInfo,
7399
+ limits,
7400
+ scope,
7401
+ defaultOrderBy: policies?.defaultOrderBy
7402
+ });
7403
+ const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
7404
+ const runInsert = async (target, values) => {
7405
+ let query = target.insert(table).values(values).returning(returning);
7406
+ if (conflictDoNothing) {
7407
+ query = query.onConflictDoNothing();
7408
+ }
7409
+ return await query;
7410
+ };
7411
+ const result = nestedEntries ? await writeWithNestedOps({
7412
+ executor,
7413
+ runtime: nested,
7414
+ tableName,
7415
+ entries: nestedEntries,
7416
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
7417
+ write: (tx, values) => runInsert(tx, [values]),
7418
+ context
7419
+ }) : await runInsert(executor, input);
7420
+ await runWriteHook(hooks, "after", {
7421
+ table: tableName,
7422
+ operation: "insert",
7423
+ single: false,
7424
+ args,
7425
+ rows: result,
7426
+ context,
7427
+ info,
7428
+ tx: executor
7429
+ });
7430
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7431
+ return remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
7432
+ },
7433
+ !!hooks
7434
+ );
6908
7435
  } catch (e) {
6909
7436
  throw toGraphQLError(e);
6910
7437
  }
@@ -6919,61 +7446,89 @@ var generateInsertSingle3 = (db, tableName, table, tables, relationMap, baseType
6919
7446
  }
6920
7447
  };
6921
7448
  const pkNames = sqlitePrimaryKeyPropNames(table);
7449
+ const hooks = policies?.onWrite?.(tableName, "insert");
6922
7450
  return {
6923
7451
  name: fieldName,
6924
7452
  resolver: async (_source, args, context, info) => {
6925
7453
  try {
6926
- return await runMutation(db, context, info, txCtx, async (executor) => {
6927
- const entry = nested?.enabled(tableName) ? nested.split(tableName, args.values) : void 0;
6928
- const nestedEntry = entry && nested.hasOps(entry.ops) ? entry : void 0;
6929
- const contextColumns = policies?.contextValues?.(tableName);
6930
- const scope = policies?.scope?.(context);
6931
- const input = nestedEntry ? {} : applyContextValues(
6932
- remapFromGraphQLSingleInput(entry ? entry.columns : args.values, table),
6933
- contextColumns,
6934
- context
6935
- );
6936
- const parsedInfo = parseResolveInfo4(info, {
6937
- deep: true
6938
- });
6939
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6940
- relationMap,
6941
- tables,
6942
- tableName,
6943
- typeName,
6944
- typeNameMapper,
6945
- table,
6946
- pkNames,
6947
- parsedInfo,
6948
- limits,
6949
- scope
6950
- });
6951
- const returning = nestedEntry ? nested.withJoinColumns(tableName, nestedEntry.ops, { ...columns }, table) : columns;
6952
- const runInsert = async (target, values) => {
6953
- let query = target.insert(table).values(values).returning(returning);
6954
- if (conflictDoNothing) {
6955
- query = query.onConflictDoNothing();
6956
- }
6957
- return await query;
6958
- };
6959
- const result = nestedEntry ? await writeWithNestedOps({
6960
- executor,
6961
- runtime: nested,
6962
- tableName,
6963
- entries: [nestedEntry],
6964
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6965
- write: runInsert,
6966
- context
6967
- }) : await runInsert(executor, input);
6968
- if (!result[0]) {
6969
- if (!conflictDoNothing) {
6970
- throw new GraphQLError9(`${fieldName}: the insert returned no row.`);
7454
+ return await runMutation(
7455
+ db,
7456
+ context,
7457
+ info,
7458
+ txCtx,
7459
+ async (executor) => {
7460
+ await runWriteHook(hooks, "before", {
7461
+ table: tableName,
7462
+ operation: "insert",
7463
+ single: true,
7464
+ args,
7465
+ context,
7466
+ info,
7467
+ tx: executor
7468
+ });
7469
+ const entry = nested?.enabled(tableName) ? nested.split(tableName, args.values) : void 0;
7470
+ const nestedEntry = entry && nested.hasOps(entry.ops) ? entry : void 0;
7471
+ const contextColumns = policies?.contextValues?.(tableName);
7472
+ const scope = policies?.scope?.(context);
7473
+ const input = nestedEntry ? {} : applyContextValues(
7474
+ remapFromGraphQLSingleInput(entry ? entry.columns : args.values, table),
7475
+ contextColumns,
7476
+ context
7477
+ );
7478
+ const parsedInfo = parseResolveInfo4(info, {
7479
+ deep: true
7480
+ });
7481
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7482
+ relationMap,
7483
+ tables,
7484
+ tableName,
7485
+ typeName,
7486
+ typeNameMapper,
7487
+ table,
7488
+ pkNames,
7489
+ parsedInfo,
7490
+ limits,
7491
+ scope,
7492
+ defaultOrderBy: policies?.defaultOrderBy
7493
+ });
7494
+ const returning = nestedEntry ? nested.withJoinColumns(tableName, nestedEntry.ops, { ...columns }, table) : columns;
7495
+ const runInsert = async (target, values) => {
7496
+ let query = target.insert(table).values(values).returning(returning);
7497
+ if (conflictDoNothing) {
7498
+ query = query.onConflictDoNothing();
7499
+ }
7500
+ return await query;
7501
+ };
7502
+ const result = nestedEntry ? await writeWithNestedOps({
7503
+ executor,
7504
+ runtime: nested,
7505
+ tableName,
7506
+ entries: [nestedEntry],
7507
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
7508
+ write: runInsert,
7509
+ context
7510
+ }) : await runInsert(executor, input);
7511
+ await runWriteHook(hooks, "after", {
7512
+ table: tableName,
7513
+ operation: "insert",
7514
+ single: true,
7515
+ args,
7516
+ rows: result,
7517
+ context,
7518
+ info,
7519
+ tx: executor
7520
+ });
7521
+ if (!result[0]) {
7522
+ if (!conflictDoNothing) {
7523
+ throw new GraphQLError9(`${fieldName}: the insert returned no row.`);
7524
+ }
7525
+ return void 0;
6971
7526
  }
6972
- return void 0;
6973
- }
6974
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6975
- return remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap);
6976
- });
7527
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7528
+ return remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap);
7529
+ },
7530
+ !!hooks
7531
+ );
6977
7532
  } catch (e) {
6978
7533
  throw toGraphQLError(e);
6979
7534
  }
@@ -6992,69 +7547,97 @@ var generateUpsert3 = (db, tableName, table, tables, relationMap, baseType, onCo
6992
7547
  }
6993
7548
  };
6994
7549
  const pkNames = sqlitePrimaryKeyPropNames(table);
7550
+ const hooks = policies?.onWrite?.(tableName, "upsert");
6995
7551
  return {
6996
7552
  name: fieldName,
6997
7553
  resolver: async (_source, args, context, info) => {
6998
7554
  try {
6999
- return await runMutation(db, context, info, txCtx, async (executor) => {
7000
- const supplied = single ? [args.values] : args.values;
7001
- if (!supplied.length) {
7002
- throw new GraphQLError9("No values were provided!");
7003
- }
7004
- const entries = nested?.enabled(tableName) ? supplied.map((values) => nested.split(tableName, values)) : void 0;
7005
- const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
7006
- const contextColumns = policies?.contextValues?.(tableName);
7007
- const scope = policies?.scope?.(context);
7008
- const input = nestedEntries ? [] : applyContextValuesAll(
7009
- remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : supplied, table),
7010
- contextColumns,
7011
- context
7012
- );
7013
- const parsedInfo = parseResolveInfo4(info, { deep: true });
7014
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7015
- relationMap,
7016
- tables,
7017
- tableName,
7018
- typeName,
7019
- typeNameMapper,
7020
- table,
7021
- pkNames,
7022
- parsedInfo,
7023
- limits,
7024
- scope
7025
- });
7026
- const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
7027
- const runUpsert = async (target, values) => {
7028
- const plan = resolveConflictPlan({
7555
+ return await runMutation(
7556
+ db,
7557
+ context,
7558
+ info,
7559
+ txCtx,
7560
+ async (executor) => {
7561
+ const supplied = single ? [args.values] : args.values;
7562
+ if (!supplied.length) {
7563
+ throw new GraphQLError9("No values were provided!");
7564
+ }
7565
+ await runWriteHook(hooks, "before", {
7566
+ table: tableName,
7567
+ operation: "upsert",
7568
+ single,
7569
+ args,
7570
+ context,
7571
+ info,
7572
+ tx: executor
7573
+ });
7574
+ const entries = nested?.enabled(tableName) ? supplied.map((values) => nested.split(tableName, values)) : void 0;
7575
+ const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
7576
+ const contextColumns = policies?.contextValues?.(tableName);
7577
+ const scope = policies?.scope?.(context);
7578
+ const input = nestedEntries ? [] : applyContextValuesAll(
7579
+ remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : supplied, table),
7580
+ contextColumns,
7581
+ context
7582
+ );
7583
+ const parsedInfo = parseResolveInfo4(info, { deep: true });
7584
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7585
+ relationMap,
7586
+ tables,
7587
+ tableName,
7588
+ typeName,
7589
+ typeNameMapper,
7029
7590
  table,
7030
- values,
7031
- onConflict: args.onConflict,
7032
7591
  pkNames,
7033
- uniqueSets,
7034
- excludedRef: excludedColumnRef,
7035
- withTarget: true,
7036
- buildWhere: (where) => extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName))
7592
+ parsedInfo,
7593
+ limits,
7594
+ scope,
7595
+ defaultOrderBy: policies?.defaultOrderBy
7037
7596
  });
7038
- let query = target.insert(table).values(values).returning(returning);
7039
- const setWhere = withScope(scope, tableName, table, plan.setWhere);
7040
- query = plan.action === "NOTHING" ? query.onConflictDoNothing(plan.target ? { target: plan.target } : void 0) : query.onConflictDoUpdate({ target: plan.target, set: plan.set, setWhere });
7041
- return await query;
7042
- };
7043
- const result = nestedEntries ? await writeWithNestedOps({
7044
- executor,
7045
- runtime: nested,
7046
- tableName,
7047
- entries: nestedEntries,
7048
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
7049
- write: (tx, values) => runUpsert(tx, [values]),
7050
- context
7051
- }) : await runUpsert(executor, input);
7052
- if (single && !result[0]) {
7053
- return void 0;
7054
- }
7055
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7056
- return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
7057
- });
7597
+ const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
7598
+ const runUpsert = async (target, values) => {
7599
+ const plan = resolveConflictPlan({
7600
+ table,
7601
+ values,
7602
+ onConflict: args.onConflict,
7603
+ pkNames,
7604
+ uniqueSets,
7605
+ excludedRef: excludedColumnRef,
7606
+ withTarget: true,
7607
+ buildWhere: (where) => extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName))
7608
+ });
7609
+ let query = target.insert(table).values(values).returning(returning);
7610
+ const setWhere = withScope(scope, tableName, table, plan.setWhere);
7611
+ query = plan.action === "NOTHING" ? query.onConflictDoNothing(plan.target ? { target: plan.target } : void 0) : query.onConflictDoUpdate({ target: plan.target, set: plan.set, setWhere });
7612
+ return await query;
7613
+ };
7614
+ const result = nestedEntries ? await writeWithNestedOps({
7615
+ executor,
7616
+ runtime: nested,
7617
+ tableName,
7618
+ entries: nestedEntries,
7619
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
7620
+ write: (tx, values) => runUpsert(tx, [values]),
7621
+ context
7622
+ }) : await runUpsert(executor, input);
7623
+ await runWriteHook(hooks, "after", {
7624
+ table: tableName,
7625
+ operation: "upsert",
7626
+ single,
7627
+ args,
7628
+ rows: result,
7629
+ context,
7630
+ info,
7631
+ tx: executor
7632
+ });
7633
+ if (single && !result[0]) {
7634
+ return void 0;
7635
+ }
7636
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7637
+ return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
7638
+ },
7639
+ !!hooks
7640
+ );
7058
7641
  } catch (e) {
7059
7642
  throw toGraphQLError(e);
7060
7643
  }
@@ -7072,75 +7655,103 @@ var generateUpdate3 = (db, tableName, table, tables, relationMap, setArgs, filte
7072
7655
  }
7073
7656
  };
7074
7657
  const pkNames = sqlitePrimaryKeyPropNames(table);
7658
+ const hooks = policies?.onWrite?.(tableName, "update");
7075
7659
  return {
7076
7660
  name: fieldName,
7077
7661
  resolver: async (_source, args, context, info) => {
7078
7662
  try {
7079
- return await runMutation(db, context, info, txCtx, async (executor) => {
7080
- const { where, set } = args;
7081
- const scope = policies?.scope?.(context);
7082
- const parsedInfo = parseResolveInfo4(info, {
7083
- deep: true
7084
- });
7085
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7086
- relationMap,
7087
- tables,
7088
- tableName,
7089
- typeName,
7090
- typeNameMapper,
7091
- table,
7092
- pkNames,
7093
- parsedInfo,
7094
- limits,
7095
- scope
7096
- });
7097
- const entry = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
7098
- const nestedOps = entry && nested.hasOps(entry.ops) ? entry.ops : void 0;
7099
- const input = stripContextValues(
7100
- remapUpdateInput(entry ? entry.columns : set, table, tableName),
7101
- policies?.contextValues?.(tableName)
7102
- );
7103
- if (!Object.keys(input).length && !nestedOps) {
7104
- throw new GraphQLError9("Unable to update with no values specified!");
7105
- }
7106
- const relationCtx = relationFilterCtx(filterCtx, tableName);
7107
- const filters = withScope(
7108
- scope,
7109
- tableName,
7110
- table,
7111
- single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
7112
- );
7113
- if (single) {
7114
- await assertSingleMatch(executor, table, filters, fieldName);
7115
- }
7116
- const returning = nestedOps ? nested.withJoinColumns(tableName, nestedOps, { ...columns }, table) : columns;
7117
- const runUpdate = async (target, values) => {
7118
- const writes = Object.keys(values).length > 0;
7119
- let query = writes ? target.update(table).set(values) : target.select(returning).from(table);
7120
- if (filters) {
7121
- query = query.where(filters);
7663
+ return await runMutation(
7664
+ db,
7665
+ context,
7666
+ info,
7667
+ txCtx,
7668
+ async (executor) => {
7669
+ await runWriteHook(hooks, "before", {
7670
+ table: tableName,
7671
+ operation: "update",
7672
+ single,
7673
+ args,
7674
+ context,
7675
+ info,
7676
+ tx: executor
7677
+ });
7678
+ const { where, set } = args;
7679
+ const scope = policies?.scope?.(context);
7680
+ const parsedInfo = parseResolveInfo4(info, {
7681
+ deep: true
7682
+ });
7683
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7684
+ relationMap,
7685
+ tables,
7686
+ tableName,
7687
+ typeName,
7688
+ typeNameMapper,
7689
+ table,
7690
+ pkNames,
7691
+ parsedInfo,
7692
+ limits,
7693
+ scope,
7694
+ defaultOrderBy: policies?.defaultOrderBy
7695
+ });
7696
+ const entry = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
7697
+ const nestedOps = entry && nested.hasOps(entry.ops) ? entry.ops : void 0;
7698
+ const input = stripContextValues(
7699
+ remapUpdateInput(entry ? entry.columns : set, table, tableName),
7700
+ policies?.contextValues?.(tableName)
7701
+ );
7702
+ if (!Object.keys(input).length && !nestedOps) {
7703
+ throw new GraphQLError9("Unable to update with no values specified!");
7122
7704
  }
7123
- return await (writes ? query.returning(returning) : query);
7124
- };
7125
- const result = nestedOps ? await updateWithNestedOps({
7126
- executor,
7127
- runtime: nested,
7128
- tableName,
7129
- columns: input,
7130
- ops: nestedOps,
7131
- remapValues: (values) => values,
7132
- write: runUpdate,
7133
- context
7134
- }) : await runUpdate(executor, input);
7135
- if (single && result.length > 1) {
7136
- throw new GraphQLError9(`${fieldName}: 'where' matched more than one row!`);
7137
- }
7138
- if (single && !result[0]) {
7139
- return void 0;
7140
- }
7141
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7142
- return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
7143
- });
7705
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
7706
+ const filters = withScope(
7707
+ scope,
7708
+ tableName,
7709
+ table,
7710
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
7711
+ );
7712
+ if (single) {
7713
+ await assertSingleMatch(executor, table, filters, fieldName);
7714
+ }
7715
+ const returning = nestedOps ? nested.withJoinColumns(tableName, nestedOps, { ...columns }, table) : columns;
7716
+ const runUpdate = async (target, values) => {
7717
+ const writes = Object.keys(values).length > 0;
7718
+ let query = writes ? target.update(table).set(values) : target.select(returning).from(table);
7719
+ if (filters) {
7720
+ query = query.where(filters);
7721
+ }
7722
+ return await (writes ? query.returning(returning) : query);
7723
+ };
7724
+ const result = nestedOps ? await updateWithNestedOps({
7725
+ executor,
7726
+ runtime: nested,
7727
+ tableName,
7728
+ columns: input,
7729
+ ops: nestedOps,
7730
+ remapValues: (values) => values,
7731
+ write: runUpdate,
7732
+ context
7733
+ }) : await runUpdate(executor, input);
7734
+ await runWriteHook(hooks, "after", {
7735
+ table: tableName,
7736
+ operation: "update",
7737
+ single,
7738
+ args,
7739
+ rows: result,
7740
+ context,
7741
+ info,
7742
+ tx: executor
7743
+ });
7744
+ if (single && result.length > 1) {
7745
+ throw new GraphQLError9(`${fieldName}: 'where' matched more than one row!`);
7746
+ }
7747
+ if (single && !result[0]) {
7748
+ return void 0;
7749
+ }
7750
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7751
+ return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
7752
+ },
7753
+ !!hooks
7754
+ );
7144
7755
  } catch (e) {
7145
7756
  throw toGraphQLError(e);
7146
7757
  }
@@ -7155,122 +7766,150 @@ var generateUpdateMany3 = (db, tableName, table, tables, relationMap, updateMany
7155
7766
  }
7156
7767
  };
7157
7768
  const pkNames = sqlitePrimaryKeyPropNames(table);
7769
+ const hooks = policies?.onWrite?.(tableName, "updateMany");
7158
7770
  return {
7159
7771
  name: fieldName,
7160
7772
  resolver: async (_source, args, context, info) => {
7161
7773
  try {
7162
- return await runMutation(db, context, info, txCtx, async (executor) => {
7163
- const { updates } = args;
7164
- if (!updates.length) {
7165
- throw new GraphQLError9("No updates were provided!");
7166
- }
7167
- const scope = policies?.scope?.(context);
7168
- const contextColumns = policies?.contextValues?.(tableName);
7169
- const parsedInfo = parseResolveInfo4(info, {
7170
- deep: true
7171
- });
7172
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7173
- relationMap,
7174
- tables,
7175
- tableName,
7176
- typeName,
7177
- typeNameMapper,
7178
- table,
7179
- pkNames,
7180
- parsedInfo,
7181
- limits,
7182
- scope
7183
- });
7184
- const entries = updates.map(({ where, set }) => {
7185
- const split = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
7186
- const ops = split && nested.hasOps(split.ops) ? split.ops : void 0;
7187
- const input = stripContextValues(
7188
- remapUpdateInput(split ? split.columns : set, table, tableName),
7189
- contextColumns
7190
- );
7191
- if (!Object.keys(input).length && !ops) {
7192
- throw new GraphQLError9("Unable to update with no values specified!");
7774
+ return await runMutation(
7775
+ db,
7776
+ context,
7777
+ info,
7778
+ txCtx,
7779
+ async (executor) => {
7780
+ const { updates } = args;
7781
+ if (!updates.length) {
7782
+ throw new GraphQLError9("No updates were provided!");
7193
7783
  }
7194
- return {
7195
- set: input,
7196
- ops,
7197
- filters: withScope(
7198
- scope,
7199
- tableName,
7200
- table,
7201
- where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
7202
- )
7784
+ await runWriteHook(hooks, "before", {
7785
+ table: tableName,
7786
+ operation: "updateMany",
7787
+ single: false,
7788
+ args,
7789
+ context,
7790
+ info,
7791
+ tx: executor
7792
+ });
7793
+ const scope = policies?.scope?.(context);
7794
+ const contextColumns = policies?.contextValues?.(tableName);
7795
+ const parsedInfo = parseResolveInfo4(info, {
7796
+ deep: true
7797
+ });
7798
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7799
+ relationMap,
7800
+ tables,
7801
+ tableName,
7802
+ typeName,
7803
+ typeNameMapper,
7804
+ table,
7805
+ pkNames,
7806
+ parsedInfo,
7807
+ limits,
7808
+ scope,
7809
+ defaultOrderBy: policies?.defaultOrderBy
7810
+ });
7811
+ const entries = updates.map(({ where, set }) => {
7812
+ const split = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
7813
+ const ops = split && nested.hasOps(split.ops) ? split.ops : void 0;
7814
+ const input = stripContextValues(
7815
+ remapUpdateInput(split ? split.columns : set, table, tableName),
7816
+ contextColumns
7817
+ );
7818
+ if (!Object.keys(input).length && !ops) {
7819
+ throw new GraphQLError9("Unable to update with no values specified!");
7820
+ }
7821
+ return {
7822
+ set: input,
7823
+ ops,
7824
+ filters: withScope(
7825
+ scope,
7826
+ tableName,
7827
+ table,
7828
+ where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
7829
+ )
7830
+ };
7831
+ });
7832
+ const anyNested = entries.some((entry) => entry.ops);
7833
+ const returning = anyNested ? nested.withJoinColumns(
7834
+ tableName,
7835
+ mergedOps(entries.map((entry) => ({ ops: entry.ops ?? {} }))),
7836
+ { ...columns },
7837
+ table
7838
+ ) : columns;
7839
+ const runEntry = (tx, entry) => {
7840
+ let query = tx.update(table).set(entry.set);
7841
+ if (entry.filters) {
7842
+ query = query.where(entry.filters);
7843
+ }
7844
+ return query.returning(returning).all();
7203
7845
  };
7204
- });
7205
- const anyNested = entries.some((entry) => entry.ops);
7206
- const returning = anyNested ? nested.withJoinColumns(
7207
- tableName,
7208
- mergedOps(entries.map((entry) => ({ ops: entry.ops ?? {} }))),
7209
- { ...columns },
7210
- table
7211
- ) : columns;
7212
- const runEntry = (tx, entry) => {
7213
- let query = tx.update(table).set(entry.set);
7214
- if (entry.filters) {
7215
- query = query.where(entry.filters);
7216
- }
7217
- return query.returning(returning).all();
7218
- };
7219
- const runNestedEntry = async (tx, entry) => {
7220
- const values = entry.ops ? { ...entry.set, ...await nested.applyParentSide(tx, tableName, entry.ops, context) } : entry.set;
7221
- const writes = Object.keys(values).length > 0;
7222
- let query = writes ? tx.update(table).set(values) : tx.select(returning).from(table);
7223
- if (entry.filters) {
7224
- query = query.where(entry.filters);
7225
- }
7226
- const rows = await (writes ? query.returning(returning) : query);
7227
- if (entry.ops) {
7228
- await nested.applyChildSide(tx, tableName, entry.ops, rows, context);
7229
- }
7230
- return rows;
7231
- };
7232
- const perEntry = await executor.transaction((tx) => {
7233
- if (anyNested) {
7234
- return (async () => {
7235
- const results2 = [];
7236
- for (const entry of entries) {
7237
- results2.push(await runNestedEntry(tx, entry));
7238
- }
7239
- return results2;
7240
- })();
7241
- }
7242
- const first = runEntry(tx, entries[0]);
7243
- if (typeof first?.then === "function") {
7244
- return (async () => {
7245
- const results2 = [await first];
7246
- for (let i = 1; i < entries.length; i++) {
7247
- results2.push(await runEntry(tx, entries[i]));
7248
- }
7249
- return results2;
7250
- })();
7251
- }
7252
- const results = [first];
7253
- for (let i = 1; i < entries.length; i++) {
7254
- results.push(runEntry(tx, entries[i]));
7255
- }
7256
- return results;
7257
- });
7258
- const flatRows = perEntry.flat();
7259
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, flatRows, pkNames, withParams) : flatRows;
7260
- const output = [];
7261
- let offset = 0;
7262
- for (const rows of perEntry) {
7263
- if (!rows.length) {
7264
- output.push(null);
7265
- continue;
7266
- }
7267
- for (let i = 0; i < rows.length; i++) {
7268
- output.push(remapToGraphQLSingleOutput(enriched[offset + i], tableName, table, relationMap));
7846
+ const runNestedEntry = async (tx, entry) => {
7847
+ const values = entry.ops ? { ...entry.set, ...await nested.applyParentSide(tx, tableName, entry.ops, context) } : entry.set;
7848
+ const writes = Object.keys(values).length > 0;
7849
+ let query = writes ? tx.update(table).set(values) : tx.select(returning).from(table);
7850
+ if (entry.filters) {
7851
+ query = query.where(entry.filters);
7852
+ }
7853
+ const rows = await (writes ? query.returning(returning) : query);
7854
+ if (entry.ops) {
7855
+ await nested.applyChildSide(tx, tableName, entry.ops, rows, context);
7856
+ }
7857
+ return rows;
7858
+ };
7859
+ const perEntry = await executor.transaction((tx) => {
7860
+ if (anyNested) {
7861
+ return (async () => {
7862
+ const results2 = [];
7863
+ for (const entry of entries) {
7864
+ results2.push(await runNestedEntry(tx, entry));
7865
+ }
7866
+ return results2;
7867
+ })();
7868
+ }
7869
+ const first = runEntry(tx, entries[0]);
7870
+ if (typeof first?.then === "function") {
7871
+ return (async () => {
7872
+ const results2 = [await first];
7873
+ for (let i = 1; i < entries.length; i++) {
7874
+ results2.push(await runEntry(tx, entries[i]));
7875
+ }
7876
+ return results2;
7877
+ })();
7878
+ }
7879
+ const results = [first];
7880
+ for (let i = 1; i < entries.length; i++) {
7881
+ results.push(runEntry(tx, entries[i]));
7882
+ }
7883
+ return results;
7884
+ });
7885
+ const flatRows = perEntry.flat();
7886
+ await runWriteHook(hooks, "after", {
7887
+ table: tableName,
7888
+ operation: "updateMany",
7889
+ single: false,
7890
+ args,
7891
+ rows: flatRows,
7892
+ context,
7893
+ info,
7894
+ tx: executor
7895
+ });
7896
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, flatRows, pkNames, withParams) : flatRows;
7897
+ const output = [];
7898
+ let offset = 0;
7899
+ for (const rows of perEntry) {
7900
+ if (!rows.length) {
7901
+ output.push(null);
7902
+ continue;
7903
+ }
7904
+ for (let i = 0; i < rows.length; i++) {
7905
+ output.push(remapToGraphQLSingleOutput(enriched[offset + i], tableName, table, relationMap));
7906
+ }
7907
+ offset += rows.length;
7269
7908
  }
7270
- offset += rows.length;
7271
- }
7272
- return output;
7273
- });
7909
+ return output;
7910
+ },
7911
+ !!hooks
7912
+ );
7274
7913
  } catch (e) {
7275
7914
  throw toGraphQLError(e);
7276
7915
  }
@@ -7280,51 +7919,79 @@ var generateUpdateMany3 = (db, tableName, table, tables, relationMap, updateMany
7280
7919
  };
7281
7920
  var generateDelete3 = (db, tableName, table, filterArgs, fieldName, typeName, single, requireWhere, filterCtx, selectionCtx, txCtx, policies, restore = false) => {
7282
7921
  const softDelete = policies?.softDelete?.(tableName);
7922
+ const operation = restore ? "restore" : "delete";
7283
7923
  const queryArgs = {
7284
7924
  where: {
7285
7925
  type: single || requireWhere ? new GraphQLNonNull8(filterArgs) : filterArgs
7286
7926
  }
7287
7927
  };
7928
+ const hooks = policies?.onWrite?.(tableName, operation);
7288
7929
  return {
7289
7930
  name: fieldName,
7290
7931
  resolver: async (_source, args, context, info) => {
7291
7932
  try {
7292
- return await runMutation(db, context, info, txCtx, async (executor) => {
7293
- const { where } = args;
7294
- const scope = policies?.scope?.(context);
7295
- const parsedInfo = parseResolveInfo4(info, {
7296
- deep: true
7297
- });
7298
- const columns = extractSelectedColumnsFromTreeSQLFormat(
7299
- parsedInfo.fieldsByTypeName[typeName],
7300
- table,
7301
- selectionCtx
7302
- );
7303
- const relationCtx = relationFilterCtx(filterCtx, tableName);
7304
- const filters = withScope(
7305
- scope,
7306
- tableName,
7307
- table,
7308
- single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
7309
- restore ? "ONLY" : void 0
7310
- );
7311
- if (single) {
7312
- await assertSingleMatch(executor, table, filters, fieldName);
7313
- }
7314
- let query = softDelete ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
7315
- if (filters) {
7316
- query = query.where(filters);
7317
- }
7318
- query = query.returning(columns);
7319
- const result = await query;
7320
- if (single && result.length > 1) {
7321
- throw new GraphQLError9(`${fieldName}: 'where' matched more than one row!`);
7322
- }
7323
- if (single) {
7324
- return result[0] ? remapToGraphQLSingleOutput(result[0], tableName, table) : void 0;
7325
- }
7326
- return remapToGraphQLArrayOutput(result, tableName, table);
7327
- });
7933
+ return await runMutation(
7934
+ db,
7935
+ context,
7936
+ info,
7937
+ txCtx,
7938
+ async (executor) => {
7939
+ await runWriteHook(hooks, "before", {
7940
+ table: tableName,
7941
+ operation,
7942
+ single,
7943
+ args,
7944
+ context,
7945
+ info,
7946
+ tx: executor
7947
+ });
7948
+ const { where } = args;
7949
+ const scope = policies?.scope?.(context);
7950
+ const parsedInfo = parseResolveInfo4(info, {
7951
+ deep: true
7952
+ });
7953
+ const columns = extractSelectedColumnsFromTreeSQLFormat(
7954
+ parsedInfo.fieldsByTypeName[typeName],
7955
+ table,
7956
+ selectionCtx
7957
+ );
7958
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
7959
+ const filters = withScope(
7960
+ scope,
7961
+ tableName,
7962
+ table,
7963
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, fieldName, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
7964
+ restore ? "ONLY" : void 0
7965
+ );
7966
+ if (single) {
7967
+ await assertSingleMatch(executor, table, filters, fieldName);
7968
+ }
7969
+ let query = softDelete ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
7970
+ if (filters) {
7971
+ query = query.where(filters);
7972
+ }
7973
+ query = query.returning(columns);
7974
+ const result = await query;
7975
+ await runWriteHook(hooks, "after", {
7976
+ table: tableName,
7977
+ operation,
7978
+ single,
7979
+ args,
7980
+ rows: result,
7981
+ context,
7982
+ info,
7983
+ tx: executor
7984
+ });
7985
+ if (single && result.length > 1) {
7986
+ throw new GraphQLError9(`${fieldName}: 'where' matched more than one row!`);
7987
+ }
7988
+ if (single) {
7989
+ return result[0] ? remapToGraphQLSingleOutput(result[0], tableName, table) : void 0;
7990
+ }
7991
+ return remapToGraphQLArrayOutput(result, tableName, table);
7992
+ },
7993
+ !!hooks
7994
+ );
7328
7995
  } catch (e) {
7329
7996
  throw toGraphQLError(e);
7330
7997
  }
@@ -8154,6 +8821,46 @@ var buildSchema = (db, config) => {
8154
8821
  limitPolicyCache.set(tableName, resolved);
8155
8822
  return resolved;
8156
8823
  } : void 0;
8824
+ const defaultsConfig = config?.defaults;
8825
+ const defaultOrderByByTable = /* @__PURE__ */ new Map();
8826
+ if (defaultsConfig) {
8827
+ const defaultsTableNames = new Set(tableKeys);
8828
+ for (const [tableName, tableDefaults] of Object.entries(defaultsConfig)) {
8829
+ if (!defaultsTableNames.has(tableName)) {
8830
+ throw new Error(
8831
+ `Drizzle-GraphQL Error: config.defaults names '${tableName}', which is not a table in the Drizzle schema.`
8832
+ );
8833
+ }
8834
+ const orderBy = tableDefaults?.orderBy;
8835
+ if (!orderBy || !Object.keys(orderBy).length) {
8836
+ continue;
8837
+ }
8838
+ const columns = getColumns6(schema[tableName]);
8839
+ const normalized = {};
8840
+ for (const [columnName, entry] of Object.entries(orderBy)) {
8841
+ if (!columns[columnName]) {
8842
+ throw new Error(
8843
+ `Drizzle-GraphQL Error: config.defaults.${tableName}.orderBy names '${columnName}', which is not a column of '${tableName}'.`
8844
+ );
8845
+ }
8846
+ const direction = typeof entry === "string" ? entry : entry?.direction;
8847
+ if (direction !== "asc" && direction !== "desc") {
8848
+ throw new Error(
8849
+ `Drizzle-GraphQL Error: config.defaults.${tableName}.orderBy.${columnName} must be 'asc', 'desc', or { direction, priority? }.`
8850
+ );
8851
+ }
8852
+ const priority = typeof entry === "string" ? void 0 : entry?.priority;
8853
+ if (priority !== void 0 && !Number.isInteger(priority)) {
8854
+ throw new Error(
8855
+ `Drizzle-GraphQL Error: config.defaults.${tableName}.orderBy.${columnName}.priority must be an integer.`
8856
+ );
8857
+ }
8858
+ normalized[columnName] = priority === void 0 ? { direction } : { direction, priority };
8859
+ }
8860
+ defaultOrderByByTable.set(tableName, normalized);
8861
+ }
8862
+ }
8863
+ const defaultOrderBy = defaultOrderByByTable.size ? (tableName) => defaultOrderByByTable.get(tableName) : void 0;
8157
8864
  const scopeConfig = config?.scope;
8158
8865
  const contextValuesConfig = config?.contextValues;
8159
8866
  if (scopeConfig || contextValuesConfig) {
@@ -8209,10 +8916,37 @@ var buildSchema = (db, config) => {
8209
8916
  }
8210
8917
  }
8211
8918
  }
8212
- const policies = scopeConfig || contextValuesConfig || softDeleteInfos.size ? {
8919
+ const onWriteConfig = config?.onWrite;
8920
+ const writeHooks = /* @__PURE__ */ new Map();
8921
+ let globalWriteHooks;
8922
+ if (onWriteConfig) {
8923
+ const isGlobal = typeof onWriteConfig === "function" || typeof onWriteConfig.before === "function" || typeof onWriteConfig.after === "function";
8924
+ if (isGlobal) {
8925
+ globalWriteHooks = normalizeWriteHooks(onWriteConfig);
8926
+ } else {
8927
+ const tableNames = new Set(tableKeys);
8928
+ for (const [tableName, hooks] of Object.entries(onWriteConfig)) {
8929
+ if (!tableNames.has(tableName)) {
8930
+ throw new Error(
8931
+ `Drizzle-GraphQL Error: config.onWrite names '${tableName}', which is not a table in the Drizzle schema.`
8932
+ );
8933
+ }
8934
+ if (typeof hooks !== "function" && typeof hooks !== "object") {
8935
+ throw new Error(
8936
+ `Drizzle-GraphQL Error: config.onWrite.${tableName} must be a function or an object with 'before' and/or 'after'.`
8937
+ );
8938
+ }
8939
+ writeHooks.set(tableName, normalizeWriteHooks(hooks));
8940
+ }
8941
+ }
8942
+ }
8943
+ const onWrite = globalWriteHooks || writeHooks.size ? (tableName) => globalWriteHooks ?? writeHooks.get(tableName) : void 0;
8944
+ const policies = scopeConfig || contextValuesConfig || softDeleteInfos.size || onWrite || defaultOrderBy ? {
8213
8945
  scope: scopeConfig ? (tableName) => scopeConfig[tableName] : void 0,
8214
8946
  contextValues: contextValuesConfig ? (tableName) => contextValuesConfig[tableName] : void 0,
8215
- softDelete: softDeleteInfos.size ? (tableName) => softDeleteInfos.get(tableName) : void 0
8947
+ softDelete: softDeleteInfos.size ? (tableName) => softDeleteInfos.get(tableName) : void 0,
8948
+ onWrite,
8949
+ defaultOrderBy
8216
8950
  } : void 0;
8217
8951
  const exclude = config?.exclude;
8218
8952
  if (exclude) {