@vantreeseba/drizzle-graphql 8.0.0 → 8.2.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
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- import { is as is14 } from "drizzle-orm";
2
+ import { is as is13 } from "drizzle-orm";
3
3
  import { MySqlDatabase as MySqlDatabase2 } from "drizzle-orm/mysql-core";
4
4
  import { PgAsyncDatabase as PgAsyncDatabase2 } from "drizzle-orm/pg-core";
5
5
  import { BaseSQLiteDatabase as BaseSQLiteDatabase2 } from "drizzle-orm/sqlite-core";
@@ -25,7 +25,12 @@ import { GraphQLEnumType as GraphQLEnumType3 } from "graphql";
25
25
 
26
26
  // src/util/builders/common/errors.ts
27
27
  import { GraphQLError } from "graphql";
28
- var drizzleError = (message, { code, ...context }) => new GraphQLError(message, {
28
+ var drizzleError = (message, {
29
+ code,
30
+ nodes,
31
+ ...context
32
+ }) => new GraphQLError(message, {
33
+ nodes,
29
34
  extensions: Object.keys(context).length ? { code, drizzle: context } : { code }
30
35
  });
31
36
  var withErrorContext = (error, context) => {
@@ -137,7 +142,6 @@ import {
137
142
 
138
143
  // src/util/data-mappers/index.ts
139
144
  import { getTableColumns as getTableColumns2, is as is2, One } from "drizzle-orm";
140
- import { GraphQLError as GraphQLError3 } from "graphql";
141
145
 
142
146
  // src/util/type-converter/index.ts
143
147
  import { extractExtendedColumnType, getTableColumns, is } from "drizzle-orm";
@@ -167,72 +171,77 @@ var singularizeMapper = (tableName) => ({
167
171
  });
168
172
 
169
173
  // src/util/scalars/index.ts
170
- import { GraphQLError as GraphQLError2, GraphQLScalarType, Kind } from "graphql";
174
+ import { GraphQLScalarType, Kind } from "graphql";
171
175
  import { GraphQLDate, GraphQLDateTime, GraphQLJSON, GraphQLUUID } from "graphql-scalars";
172
- var asDecimalString = (value) => {
176
+ var INVALID_INPUT = "DRIZZLE_INVALID_INPUT_VALUE";
177
+ var UNREPRESENTABLE = "DRIZZLE_UNREPRESENTABLE_VALUE";
178
+ var decimalString = (code) => (value) => {
173
179
  if (typeof value === "bigint") {
174
180
  return value.toString();
175
181
  }
176
182
  if (typeof value === "number") {
177
183
  if (!Number.isInteger(value)) {
178
- throw new GraphQLError2(`BigInt cannot represent non-integer value: ${value}`);
184
+ throw drizzleError(`BigInt cannot represent non-integer value: ${value}`, { code });
179
185
  }
180
186
  if (!Number.isSafeInteger(value)) {
181
- throw new GraphQLError2(
182
- `BigInt cannot represent the number ${value} without precision loss \u2014 pass it as a string instead`
187
+ throw drizzleError(
188
+ `BigInt cannot represent the number ${value} without precision loss \u2014 pass it as a string instead`,
189
+ { code }
183
190
  );
184
191
  }
185
192
  return String(value);
186
193
  }
187
194
  if (typeof value === "string") {
188
195
  if (!/^-?\d+$/.test(value)) {
189
- throw new GraphQLError2(`BigInt cannot represent non-integer value: "${value}"`);
196
+ throw drizzleError(`BigInt cannot represent non-integer value: "${value}"`, { code });
190
197
  }
191
198
  return value;
192
199
  }
193
- throw new GraphQLError2(`BigInt cannot represent value: ${JSON.stringify(value)}`);
200
+ throw drizzleError(`BigInt cannot represent value: ${JSON.stringify(value)}`, { code });
194
201
  };
202
+ var parseDecimal = decimalString(INVALID_INPUT);
195
203
  var GraphQLBigIntString = new GraphQLScalarType({
196
204
  name: "BigInt",
197
205
  description: "A 64-bit integer, transported as a decimal string so that values beyond JavaScript's safe integer range survive the round-trip intact.",
198
- serialize: asDecimalString,
199
- parseValue: asDecimalString,
206
+ serialize: decimalString(UNREPRESENTABLE),
207
+ parseValue: parseDecimal,
200
208
  parseLiteral: (ast) => {
201
209
  if (ast.kind !== Kind.STRING && ast.kind !== Kind.INT) {
202
- throw new GraphQLError2(`BigInt cannot represent a ${ast.kind}`, { nodes: ast });
210
+ throw drizzleError(`BigInt cannot represent a ${ast.kind}`, { code: INVALID_INPUT, nodes: ast });
203
211
  }
204
- return asDecimalString(ast.value);
212
+ return parseDecimal(ast.value);
205
213
  }
206
214
  });
207
215
  var numericStringPattern = /^[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?$/;
208
- var asNumericString = (value) => {
216
+ var numericString = (code) => (value) => {
209
217
  if (typeof value === "bigint") {
210
218
  return value.toString();
211
219
  }
212
220
  if (typeof value === "number") {
213
221
  if (!Number.isFinite(value)) {
214
- throw new GraphQLError2(`Decimal cannot represent non-finite value: ${value}`);
222
+ throw drizzleError(`Decimal cannot represent non-finite value: ${value}`, { code });
215
223
  }
216
224
  return String(value);
217
225
  }
218
226
  if (typeof value === "string") {
219
227
  if (!numericStringPattern.test(value)) {
220
- throw new GraphQLError2(`Decimal cannot represent non-numeric value: "${value}"`);
228
+ throw drizzleError(`Decimal cannot represent non-numeric value: "${value}"`, { code });
221
229
  }
222
230
  return value;
223
231
  }
224
- throw new GraphQLError2(`Decimal cannot represent value: ${JSON.stringify(value)}`);
232
+ throw drizzleError(`Decimal cannot represent value: ${JSON.stringify(value)}`, { code });
225
233
  };
234
+ var parseNumeric = numericString(INVALID_INPUT);
226
235
  var GraphQLDecimalString = new GraphQLScalarType({
227
236
  name: "Decimal",
228
237
  description: "An arbitrary-precision decimal, transported as a numeric string so that values beyond JavaScript's double-precision range survive the round-trip intact.",
229
- serialize: asNumericString,
230
- parseValue: asNumericString,
238
+ serialize: numericString(UNREPRESENTABLE),
239
+ parseValue: parseNumeric,
231
240
  parseLiteral: (ast) => {
232
241
  if (ast.kind !== Kind.STRING && ast.kind !== Kind.INT && ast.kind !== Kind.FLOAT) {
233
- throw new GraphQLError2(`Decimal cannot represent a ${ast.kind}`, { nodes: ast });
242
+ throw drizzleError(`Decimal cannot represent a ${ast.kind}`, { code: INVALID_INPUT, nodes: ast });
234
243
  }
235
- return asNumericString(ast.value);
244
+ return parseNumeric(ast.value);
236
245
  }
237
246
  });
238
247
 
@@ -542,7 +551,7 @@ var remapFromGraphQLCore = (value, column, columnName) => {
542
551
  if (isTimestampColumn) {
543
552
  const formatted = new Date(value);
544
553
  if (Number.isNaN(formatted.getTime())) {
545
- throw new GraphQLError3(`Field '${columnName}' is not a valid date!`);
554
+ throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
546
555
  }
547
556
  return formatted;
548
557
  }
@@ -551,7 +560,7 @@ var remapFromGraphQLCore = (value, column, columnName) => {
551
560
  const dateOnly = value.includes("T") ? value.split("T")[0] : value;
552
561
  const check = new Date(dateOnly);
553
562
  if (Number.isNaN(check.getTime())) {
554
- throw new GraphQLError3(`Field '${columnName}' is not a valid date!`);
563
+ throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
555
564
  }
556
565
  return dateOnly;
557
566
  }
@@ -559,7 +568,7 @@ var remapFromGraphQLCore = (value, column, columnName) => {
559
568
  try {
560
569
  return BigInt(value);
561
570
  } catch {
562
- throw new GraphQLError3(`Field '${columnName}' is not a BigInt!`);
571
+ throw drizzleError(`Field '${columnName}' is not a BigInt!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
563
572
  }
564
573
  }
565
574
  if (dataType.includes("json") && column.columnType !== "PgGeometryObject") {
@@ -569,13 +578,13 @@ var remapFromGraphQLCore = (value, column, columnName) => {
569
578
  case "date": {
570
579
  const formatted = new Date(value);
571
580
  if (Number.isNaN(formatted.getTime())) {
572
- throw new GraphQLError3(`Field '${columnName}' is not a valid date!`);
581
+ throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
573
582
  }
574
583
  return formatted;
575
584
  }
576
585
  case "buffer": {
577
586
  if (!Array.isArray(value)) {
578
- throw new GraphQLError3(`Field '${columnName}' is not an array!`);
587
+ throw drizzleError(`Field '${columnName}' is not an array!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
579
588
  }
580
589
  return Buffer.from(value);
581
590
  }
@@ -586,19 +595,23 @@ var remapFromGraphQLCore = (value, column, columnName) => {
586
595
  try {
587
596
  return JSON.parse(value);
588
597
  } catch (e) {
589
- throw new GraphQLError3(
598
+ throw drizzleError(
590
599
  `Invalid JSON in field '${columnName}':
591
- ${e instanceof Error ? e.message : "Unknown error"}`
600
+ ${e instanceof Error ? e.message : "Unknown error"}`,
601
+ {
602
+ code: "DRIZZLE_INVALID_INPUT_VALUE"
603
+ }
592
604
  );
593
605
  }
594
606
  }
595
607
  case "array": {
596
608
  if (!Array.isArray(value)) {
597
- throw new GraphQLError3(`Field '${columnName}' is not an array!`);
609
+ throw drizzleError(`Field '${columnName}' is not an array!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
598
610
  }
599
611
  if (column.columnType === "PgGeometry" && value.length !== 2) {
600
- throw new GraphQLError3(
601
- `Invalid float tuple in field '${columnName}': expected array with length of 2, received ${value.length}`
612
+ throw drizzleError(
613
+ `Invalid float tuple in field '${columnName}': expected array with length of 2, received ${value.length}`,
614
+ { code: "DRIZZLE_INVALID_INPUT_VALUE" }
602
615
  );
603
616
  }
604
617
  return value;
@@ -607,7 +620,7 @@ ${e instanceof Error ? e.message : "Unknown error"}`
607
620
  try {
608
621
  return BigInt(value);
609
622
  } catch (_error) {
610
- throw new GraphQLError3(`Field '${columnName}' is not a BigInt!`);
623
+ throw drizzleError(`Field '${columnName}' is not a BigInt!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
611
624
  }
612
625
  }
613
626
  default: {
@@ -625,7 +638,7 @@ var remapFromGraphQLSingleInput = (queryInput, table) => {
625
638
  } else {
626
639
  const column = getTableColumns2(table)[key];
627
640
  if (!column) {
628
- throw new GraphQLError3(`Unknown column: ${key}`);
641
+ throw drizzleError(`Unknown column: ${key}`, { code: "DRIZZLE_UNKNOWN_COLUMN" });
629
642
  }
630
643
  if (value === null && column.notNull) {
631
644
  delete queryInput[key];
@@ -4258,6 +4271,50 @@ var runWriteHook = (hooks, position, payload) => {
4258
4271
  return Promise.resolve(hook({ ...payload, position, rows: payload.rows ?? [] }));
4259
4272
  };
4260
4273
 
4274
+ // src/util/builders/common/write-scaffold.ts
4275
+ var writeResolver = ({
4276
+ db,
4277
+ tableName,
4278
+ operation,
4279
+ single,
4280
+ fieldName,
4281
+ args: queryArgs,
4282
+ txCtx,
4283
+ policies,
4284
+ run
4285
+ }) => {
4286
+ const hooks = policies?.onWrite?.(tableName, operation);
4287
+ const errorCtx = { table: tableName, operation, field: fieldName };
4288
+ return {
4289
+ name: fieldName,
4290
+ resolver: async (_source, args, context, info) => {
4291
+ try {
4292
+ return await runMutation(
4293
+ db,
4294
+ context,
4295
+ info,
4296
+ txCtx,
4297
+ (executor) => {
4298
+ const payload = { table: tableName, operation, single, args, context, info, tx: executor };
4299
+ return run({
4300
+ executor,
4301
+ args,
4302
+ context,
4303
+ info,
4304
+ before: () => runWriteHook(hooks, "before", payload),
4305
+ after: (rows) => runWriteHook(hooks, "after", { ...payload, rows: rows ?? [] })
4306
+ });
4307
+ },
4308
+ !!hooks
4309
+ );
4310
+ } catch (e) {
4311
+ throw withErrorContext(toGraphQLError(e), errorCtx);
4312
+ }
4313
+ },
4314
+ args: queryArgs
4315
+ };
4316
+ };
4317
+
4261
4318
  // src/util/features.ts
4262
4319
  var featureDefaults = {
4263
4320
  aggregates: true,
@@ -4616,16 +4673,19 @@ var resolveBuildConfig = (config, schema) => {
4616
4673
  };
4617
4674
 
4618
4675
  // src/util/builders/mysql.ts
4619
- import { is as is10, One as One7 } from "drizzle-orm";
4620
4676
  import { getTableConfig, MySqlTable } from "drizzle-orm/mysql-core";
4621
4677
  import {
4622
- GraphQLBoolean as GraphQLBoolean5,
4678
+ GraphQLBoolean as GraphQLBoolean6,
4623
4679
  GraphQLInt as GraphQLInt8,
4624
- GraphQLList as GraphQLList9,
4625
- GraphQLNonNull as GraphQLNonNull13,
4680
+ GraphQLList as GraphQLList11,
4681
+ GraphQLNonNull as GraphQLNonNull15,
4626
4682
  GraphQLObjectType as GraphQLObjectType4
4627
4683
  } from "graphql";
4628
4684
 
4685
+ // src/util/builders/build-context.ts
4686
+ import { is as is11, One as One8 } from "drizzle-orm";
4687
+ import { GraphQLList as GraphQLList10, GraphQLNonNull as GraphQLNonNull14 } from "graphql";
4688
+
4629
4689
  // src/util/builders/aggregates.ts
4630
4690
  import {
4631
4691
  and as and10,
@@ -5148,1760 +5208,1628 @@ var generateGroupBy = (db, tableName, table, typeName, fieldName, filterArgs, gr
5148
5208
  };
5149
5209
  };
5150
5210
 
5151
- // src/util/builders/select.ts
5152
- import { parseResolveInfo as parseResolveInfo2 } from "graphql-parse-resolve-info";
5153
-
5154
- // src/util/builders/errors.ts
5155
- var missingQueryBuilderError = (tableName) => new Error(
5156
- `Drizzle-GraphQL Error: Table '${tableName}' was passed to the drizzle constructor's schema but is missing from its relations config, so drizzle-orm exposes no query builder for it. Include it in the relations you pass to buildRelations/defineRelations, or drop it from the generated schema with config.exclude.tables.`
5157
- );
5158
-
5159
- // src/util/builders/select.ts
5160
- var queryBaseFor = (db, tableName) => {
5161
- const queryBase = db.query[tableName];
5162
- if (!queryBase) {
5163
- throw missingQueryBuilderError(tableName);
5211
+ // src/util/builders/nested-writes.ts
5212
+ import { and as and11, Column, eq as eq8, getColumns as getColumns16, inArray as inArray6, is as is10, One as One7 } from "drizzle-orm";
5213
+ import { GraphQLBoolean as GraphQLBoolean5, GraphQLInputObjectType as GraphQLInputObjectType11, GraphQLList as GraphQLList9, GraphQLNonNull as GraphQLNonNull13 } from "graphql";
5214
+ var isOptionalOnInsert = (column) => !column.notNull || !!column.hasDefault || !!column.defaultFn;
5215
+ var propNameOf = (table, column) => {
5216
+ if (!column) {
5217
+ return void 0;
5164
5218
  }
5165
- return queryBase;
5219
+ for (const [propName, candidate] of Object.entries(getColumns16(table))) {
5220
+ if (candidate === column) {
5221
+ return propName;
5222
+ }
5223
+ }
5224
+ return void 0;
5166
5225
  };
5167
- var createSelectGenerators = (primaryKeyPropNames, nullOrdering) => {
5168
- const generateSelectArray2 = (db, tableName, tables, relationMap, orderArgs, filterArgs, fieldName, typeName, typeNameMapper, filterCtx, distinctEnabled = true, limits, policies, resolveName) => {
5169
- const queryBase = queryBaseFor(db, tableName);
5170
- const table = tables[tableName];
5171
- const limitPolicy = limits?.(tableName);
5172
- const pkNames = primaryKeyPropNames(table);
5173
- const errorCtx = { table: tableName, operation: "select", field: fieldName };
5174
- const queryArgs = selectArrayArgs(
5175
- orderArgs,
5176
- filterArgs,
5177
- distinctEnabled ? generateDistinctEnum(table, typeName, resolveName, tableName) : void 0,
5178
- policies?.softDelete,
5179
- tableName,
5180
- resolveName
5181
- );
5182
- const objectTypeName = resolveObjectTypeName(tableName, typeNameMapper, resolveName);
5183
- return {
5184
- name: fieldName,
5185
- resolver: async (_source, rawArgs, context, info) => {
5186
- const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
5187
- try {
5188
- const parsedInfo = parseResolveInfo2(info, { deep: true });
5189
- const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
5190
- return await runRelationalSelect({
5191
- queryBase: requestQueryBase,
5192
- tables,
5193
- tableName,
5194
- table,
5195
- relationMap,
5196
- typeName: objectTypeName,
5197
- typeNameMapper,
5198
- resolveName,
5199
- parsedInfo,
5200
- ...args,
5201
- limit: applyLimitPolicy(args.limit, limitPolicy),
5202
- single: false,
5203
- filterCtx,
5204
- limits,
5205
- defaultOrderBy: policies?.defaultOrderBy,
5206
- pkNames,
5207
- db: executor,
5208
- scope: policies?.scope?.(context),
5209
- nullOrdering
5210
- });
5211
- } catch (e) {
5212
- throw withErrorContext(toGraphQLError(e), errorCtx);
5213
- }
5214
- },
5215
- args: queryArgs
5216
- };
5217
- };
5218
- const generateSelectSingle2 = (db, tableName, tables, relationMap, orderArgs, filterArgs, fieldName, typeName, typeNameMapper, filterCtx, limits, policies, resolveName) => {
5219
- const queryBase = queryBaseFor(db, tableName);
5220
- const queryArgs = selectSingleArgs(orderArgs, filterArgs, policies?.softDelete, tableName, resolveName);
5221
- const objectTypeName = resolveObjectTypeName(tableName, typeNameMapper, resolveName);
5222
- const table = tables[tableName];
5223
- const pkNames = primaryKeyPropNames(table);
5224
- const errorCtx = { table: tableName, operation: "select", field: fieldName };
5225
- return {
5226
- name: fieldName,
5227
- resolver: async (_source, rawArgs, context, info) => {
5228
- const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
5229
- try {
5230
- const parsedInfo = parseResolveInfo2(info, { deep: true });
5231
- const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
5232
- return await runRelationalSelect({
5233
- queryBase: requestQueryBase,
5234
- tables,
5235
- tableName,
5236
- table,
5237
- relationMap,
5238
- typeName: objectTypeName,
5239
- typeNameMapper,
5240
- resolveName,
5241
- parsedInfo,
5242
- ...args,
5243
- single: true,
5244
- filterCtx,
5245
- limits,
5246
- defaultOrderBy: policies?.defaultOrderBy,
5247
- pkNames,
5248
- db: executor,
5249
- scope: policies?.scope?.(context)
5250
- });
5251
- } catch (e) {
5252
- throw withErrorContext(toGraphQLError(e), errorCtx);
5253
- }
5254
- },
5255
- args: queryArgs
5256
- };
5226
+ var throughColumn = (entry) => entry && is10(entry, Column) ? entry : entry?._?.column;
5227
+ var buildThroughPlan = (relationName, relation, table, targetTableName, targetTable) => {
5228
+ if (is10(relation, One7)) {
5229
+ return void 0;
5230
+ }
5231
+ const junction = relation.throughTable;
5232
+ const sourceEntries = relation.through?.source;
5233
+ const targetEntries = relation.through?.target;
5234
+ if (!junction || sourceEntries?.length !== 1 || targetEntries?.length !== 1) {
5235
+ return void 0;
5236
+ }
5237
+ if (relation.sourceColumns?.length !== 1 || relation.targetColumns?.length !== 1) {
5238
+ return void 0;
5239
+ }
5240
+ const localCol = relation.sourceColumns[0];
5241
+ const foreignCol = relation.targetColumns[0];
5242
+ const localColPropName = propNameOf(table, localCol);
5243
+ const foreignColPropName = propNameOf(targetTable, foreignCol);
5244
+ const sourceColPropName = propNameOf(junction, throughColumn(sourceEntries[0]));
5245
+ const targetColPropName = propNameOf(junction, throughColumn(targetEntries[0]));
5246
+ if (!localColPropName || !foreignColPropName || !sourceColPropName || !targetColPropName) {
5247
+ return void 0;
5248
+ }
5249
+ const junctionColumns = getColumns16(junction);
5250
+ const sourceCol = junctionColumns[sourceColPropName];
5251
+ const targetCol = junctionColumns[targetColPropName];
5252
+ const unsuppliable = Object.entries(junctionColumns).some(
5253
+ ([propName, column]) => propName !== sourceColPropName && propName !== targetColPropName && !isOptionalOnInsert(column)
5254
+ );
5255
+ if (unsuppliable) {
5256
+ return void 0;
5257
+ }
5258
+ return {
5259
+ relationName,
5260
+ targetTableName,
5261
+ targetTable,
5262
+ localColPropName,
5263
+ foreignColPropName,
5264
+ foreignCol,
5265
+ localCol,
5266
+ isOne: false,
5267
+ // The link is written after the parent row exists, exactly like a child-side foreign key.
5268
+ fkSide: "child",
5269
+ canDetach: true,
5270
+ through: { table: junction, sourceColPropName, targetColPropName, sourceCol, targetCol }
5257
5271
  };
5258
- return { generateSelectArray: generateSelectArray2, generateSelectSingle: generateSelectSingle2 };
5259
5272
  };
5260
-
5261
- // src/util/builders/mysql.ts
5262
- var generateInsertArray = (db, tableName, table, baseType, fieldName, txCtx, policies) => {
5263
- const queryArgs = {
5264
- values: {
5265
- type: new GraphQLNonNull13(new GraphQLList9(new GraphQLNonNull13(baseType)))
5273
+ var buildNestedWritePlans = (tables, relationMap, resolveUniqueSets, resolvePrimaryKeys, extractJoinColumns) => {
5274
+ const uniqueCache = /* @__PURE__ */ new Map();
5275
+ const singleColumnUniques = (tableName, table) => {
5276
+ let cached = uniqueCache.get(tableName);
5277
+ if (!cached) {
5278
+ cached = new Set(
5279
+ resolveUniqueSets(table).filter((set) => set.length === 1).map((set) => set[0])
5280
+ );
5281
+ uniqueCache.set(tableName, cached);
5266
5282
  }
5283
+ return cached;
5267
5284
  };
5268
- const hooks = policies?.onWrite?.(tableName, "insert");
5269
- const errorCtx = { table: tableName, operation: "insert", field: fieldName };
5270
- return {
5271
- name: fieldName,
5272
- resolver: async (_source, args, context, info) => {
5273
- try {
5274
- return await runMutation(
5275
- db,
5276
- context,
5277
- info,
5278
- txCtx,
5279
- async (executor) => {
5280
- const input = applyContextValuesAll(
5281
- remapFromGraphQLArrayInput(args.values, table),
5282
- policies?.contextValues?.(tableName),
5283
- context
5284
- );
5285
- if (!input.length) {
5286
- throw drizzleError("No values were provided!", { code: "DRIZZLE_NO_VALUES" });
5287
- }
5288
- await runWriteHook(hooks, "before", {
5289
- table: tableName,
5290
- operation: "insert",
5291
- single: false,
5292
- args,
5293
- context,
5294
- info,
5295
- tx: executor
5296
- });
5297
- await executor.insert(table).values(input);
5298
- await runWriteHook(hooks, "after", {
5299
- table: tableName,
5300
- operation: "insert",
5301
- single: false,
5302
- args,
5303
- rows: [],
5304
- context,
5305
- info,
5306
- tx: executor
5307
- });
5308
- return { isSuccess: true };
5309
- },
5310
- !!hooks
5311
- );
5312
- } catch (e) {
5313
- throw withErrorContext(toGraphQLError(e), errorCtx);
5314
- }
5315
- },
5316
- args: queryArgs
5317
- };
5318
- };
5319
- var generateInsertSingle = (db, tableName, table, baseType, fieldName, txCtx, policies) => {
5320
- const queryArgs = {
5321
- values: {
5322
- type: new GraphQLNonNull13(baseType)
5285
+ const pkCache = /* @__PURE__ */ new Map();
5286
+ const singleColumnPk = (tableName, table) => {
5287
+ if (!pkCache.has(tableName)) {
5288
+ const pk = resolvePrimaryKeys(table);
5289
+ pkCache.set(tableName, pk.length === 1 ? pk[0] : void 0);
5323
5290
  }
5291
+ return pkCache.get(tableName);
5324
5292
  };
5325
- const hooks = policies?.onWrite?.(tableName, "insert");
5326
- const errorCtx = { table: tableName, operation: "insert", field: fieldName };
5327
- return {
5328
- name: fieldName,
5329
- resolver: async (_source, args, context, info) => {
5330
- try {
5331
- return await runMutation(
5332
- db,
5333
- context,
5334
- info,
5335
- txCtx,
5336
- async (executor) => {
5337
- await runWriteHook(hooks, "before", {
5338
- table: tableName,
5339
- operation: "insert",
5340
- single: true,
5341
- args,
5342
- context,
5343
- info,
5344
- tx: executor
5345
- });
5346
- const input = applyContextValues(
5347
- remapFromGraphQLSingleInput(args.values, table),
5348
- policies?.contextValues?.(tableName),
5349
- context
5350
- );
5351
- await executor.insert(table).values(input);
5352
- await runWriteHook(hooks, "after", {
5353
- table: tableName,
5354
- operation: "insert",
5355
- single: true,
5356
- args,
5357
- rows: [],
5358
- context,
5359
- info,
5360
- tx: executor
5361
- });
5362
- return { isSuccess: true };
5363
- },
5364
- !!hooks
5365
- );
5366
- } catch (e) {
5367
- throw withErrorContext(toGraphQLError(e), errorCtx);
5293
+ const plans = {};
5294
+ for (const [tableName, relations] of Object.entries(relationMap)) {
5295
+ const table = tables[tableName];
5296
+ if (!table) {
5297
+ continue;
5298
+ }
5299
+ const tablePlans = {};
5300
+ for (const [relationName, relEntry] of Object.entries(relations)) {
5301
+ const relation = relEntry.relation;
5302
+ const targetTableName = relEntry.targetTableName;
5303
+ const targetTable = tables[targetTableName];
5304
+ if (!targetTable) {
5305
+ continue;
5368
5306
  }
5369
- },
5370
- args: queryArgs
5371
- };
5307
+ if (relation.through) {
5308
+ const throughPlan = buildThroughPlan(relationName, relation, table, targetTableName, targetTable);
5309
+ if (throughPlan) {
5310
+ tablePlans[relationName] = throughPlan;
5311
+ }
5312
+ continue;
5313
+ }
5314
+ const joinColumns = extractJoinColumns(relEntry, table, targetTable);
5315
+ if (!joinColumns) {
5316
+ continue;
5317
+ }
5318
+ const { localColPropName, foreignCol, foreignColPropName } = joinColumns;
5319
+ const localCol = getColumns16(table)[localColPropName];
5320
+ if (!localCol) {
5321
+ continue;
5322
+ }
5323
+ const isOne = is10(relation, One7);
5324
+ const localIsPk = singleColumnPk(tableName, table) === localColPropName;
5325
+ const foreignIsPk = singleColumnPk(targetTableName, targetTable) === foreignColPropName;
5326
+ const localIsUnique = singleColumnUniques(tableName, table).has(localColPropName);
5327
+ const foreignIsUnique = singleColumnUniques(targetTableName, targetTable).has(foreignColPropName);
5328
+ let fkSide;
5329
+ if (!isOne) {
5330
+ fkSide = "child";
5331
+ } else if (foreignIsPk && !localIsPk) {
5332
+ fkSide = "parent";
5333
+ } else if (localIsPk) {
5334
+ fkSide = "child";
5335
+ } else if (foreignIsUnique) {
5336
+ fkSide = "parent";
5337
+ } else if (localIsUnique) {
5338
+ fkSide = "child";
5339
+ } else {
5340
+ continue;
5341
+ }
5342
+ const fkColumn = fkSide === "child" ? foreignCol : localCol;
5343
+ tablePlans[relationName] = {
5344
+ relationName,
5345
+ targetTableName,
5346
+ targetTable,
5347
+ localColPropName,
5348
+ foreignColPropName,
5349
+ foreignCol,
5350
+ localCol,
5351
+ isOne,
5352
+ fkSide,
5353
+ canDetach: !fkColumn.notNull
5354
+ };
5355
+ }
5356
+ if (Object.keys(tablePlans).length) {
5357
+ plans[tableName] = tablePlans;
5358
+ }
5359
+ }
5360
+ return plans;
5372
5361
  };
5373
- var generateUpsert = (db, tableName, table, baseType, onConflictType, fieldName, single, txCtx, policies) => {
5374
- const queryArgs = {
5375
- values: {
5376
- type: single ? new GraphQLNonNull13(baseType) : new GraphQLNonNull13(new GraphQLList9(new GraphQLNonNull13(baseType)))
5377
- },
5378
- onConflict: {
5379
- type: onConflictType,
5380
- description: "How a conflicting row is resolved. Defaults to overwriting it."
5362
+ var NO_COLUMNS = /* @__PURE__ */ new Set();
5363
+ var createNestedWriteTypes = (params) => {
5364
+ const { plans, cacheCtx, typeNameMapper } = params;
5365
+ const wrapperCache = /* @__PURE__ */ new Map();
5366
+ const payloadCache = /* @__PURE__ */ new Map();
5367
+ const payloadType = (tableName, typeName, plan) => {
5368
+ const key = `${tableName}.${plan.relationName}`;
5369
+ const cached = payloadCache.get(key);
5370
+ if (cached) {
5371
+ return cached;
5381
5372
  }
5373
+ const omitted = plan.fkSide === "child" ? plan.foreignColPropName : void 0;
5374
+ const contextColumns = cacheCtx.contextValuesOf?.(plan.targetTableName);
5375
+ const fields = Object.fromEntries(
5376
+ Object.entries(visibleColumns(plan.targetTable)).filter(([columnName]) => columnName !== omitted && !contextColumns?.[columnName]).map(([columnName, column]) => [
5377
+ columnName,
5378
+ drizzleColumnToGraphQLType(column, columnName, plan.targetTableName, false, true, true)
5379
+ ])
5380
+ );
5381
+ const type = new GraphQLInputObjectType11({
5382
+ name: cacheCtx.typeName({
5383
+ kind: "nestedWriteInput",
5384
+ defaultName: `${typeName}${capitalize(plan.relationName)}NestedCreatePayloadInput`,
5385
+ table: tableName,
5386
+ operation: plan.relationName
5387
+ }),
5388
+ description: omitted === void 0 ? `A new ${resolveTypeName(plan.targetTableName, typeNameMapper)} row for ${typeName}.${plan.relationName}` : `A new ${resolveTypeName(plan.targetTableName, typeNameMapper)} row for ${typeName}.${plan.relationName}. \`${omitted}\` is set from the ${typeName} row this is written with.`,
5389
+ fields
5390
+ });
5391
+ payloadCache.set(key, type);
5392
+ return type;
5382
5393
  };
5383
- const pkNames = mysqlPrimaryKeyPropNames(table);
5384
- const hooks = policies?.onWrite?.(tableName, "upsert");
5385
- const errorCtx = { table: tableName, operation: "upsert", field: fieldName };
5386
- return {
5387
- name: fieldName,
5388
- resolver: async (_source, args, context, info) => {
5389
- try {
5390
- return await runMutation(
5391
- db,
5392
- context,
5393
- info,
5394
- txCtx,
5395
- async (executor) => {
5396
- const input = applyContextValuesAll(
5397
- single ? [remapFromGraphQLSingleInput(args.values, table)] : remapFromGraphQLArrayInput(args.values, table),
5398
- policies?.contextValues?.(tableName),
5399
- context
5400
- );
5401
- if (!input.length) {
5402
- throw drizzleError("No values were provided!", { code: "DRIZZLE_NO_VALUES" });
5403
- }
5404
- await runWriteHook(hooks, "before", {
5405
- table: tableName,
5406
- operation: "upsert",
5407
- single,
5408
- args,
5409
- context,
5410
- info,
5411
- tx: executor
5412
- });
5413
- const plan = resolveConflictPlan({
5414
- table,
5415
- values: input,
5416
- onConflict: args.onConflict,
5417
- pkNames,
5418
- uniqueSets: [],
5419
- excludedRef: mysqlValuesColumnRef,
5420
- withTarget: false
5421
- });
5422
- if (plan.action === "NOTHING") {
5423
- await executor.insert(table).ignore().values(input);
5424
- } else {
5425
- await executor.insert(table).values(input).onDuplicateKeyUpdate({ set: plan.set });
5426
- }
5427
- await runWriteHook(hooks, "after", {
5428
- table: tableName,
5429
- operation: "upsert",
5430
- single,
5431
- args,
5432
- rows: [],
5433
- context,
5434
- info,
5435
- tx: executor
5436
- });
5437
- return { isSuccess: true };
5438
- },
5439
- !!hooks
5440
- );
5441
- } catch (e) {
5442
- throw withErrorContext(toGraphQLError(e), errorCtx);
5394
+ const targetFilters = (plan) => cacheCtx.filterTypeCache.get(plan.targetTable);
5395
+ const listOf = (type) => new GraphQLList9(new GraphQLNonNull13(type));
5396
+ const wrapperType = (tableName, typeName, plan, forUpdate) => {
5397
+ const key = `${tableName}.${plan.relationName}.${forUpdate ? "update" : "create"}`;
5398
+ const cached = wrapperCache.get(key);
5399
+ if (cached) {
5400
+ return cached;
5401
+ }
5402
+ const filters = targetFilters(plan);
5403
+ const targetTypeName = resolveTypeName(plan.targetTableName, typeNameMapper);
5404
+ const fields = {};
5405
+ if (plan.through) {
5406
+ if (!filters) {
5407
+ return void 0;
5443
5408
  }
5444
- },
5445
- args: queryArgs
5409
+ fields["connect"] = {
5410
+ type: listOf(filters),
5411
+ description: `Link every existing ${targetTypeName} row these match. Already-linked rows are left alone.`
5412
+ };
5413
+ if (forUpdate) {
5414
+ fields["disconnect"] = {
5415
+ type: listOf(filters),
5416
+ description: `Unlink every linked ${targetTypeName} row these match, leaving the rows in place`
5417
+ };
5418
+ fields["set"] = {
5419
+ type: listOf(filters),
5420
+ description: `Replace the whole set: unlink everything linked, then link every ${targetTypeName} row these match. \`set: []\` clears the relation. Applied before \`disconnect\` and \`connect\`.`
5421
+ };
5422
+ }
5423
+ } else if (plan.isOne) {
5424
+ fields["create"] = {
5425
+ type: payloadType(tableName, typeName, plan),
5426
+ description: `Insert a ${targetTypeName} row and attach it`
5427
+ };
5428
+ if (filters) {
5429
+ fields["connect"] = {
5430
+ type: filters,
5431
+ description: `Attach the existing ${targetTypeName} row this matches. Must match exactly one row.`
5432
+ };
5433
+ }
5434
+ if (forUpdate && plan.canDetach) {
5435
+ fields["disconnect"] = {
5436
+ type: GraphQLBoolean5,
5437
+ description: `Detach the currently attached ${targetTypeName} row, leaving it in place`
5438
+ };
5439
+ }
5440
+ } else {
5441
+ fields["create"] = {
5442
+ type: listOf(payloadType(tableName, typeName, plan)),
5443
+ description: `Insert these ${targetTypeName} rows and attach them`
5444
+ };
5445
+ if (filters) {
5446
+ fields["connect"] = {
5447
+ type: listOf(filters),
5448
+ description: `Attach every existing ${targetTypeName} row these match`
5449
+ };
5450
+ if (forUpdate && plan.canDetach) {
5451
+ fields["disconnect"] = {
5452
+ type: listOf(filters),
5453
+ description: `Detach every attached ${targetTypeName} row these match, leaving the rows in place`
5454
+ };
5455
+ fields["set"] = {
5456
+ type: listOf(filters),
5457
+ description: `Replace the whole set: detach everything attached, then attach every ${targetTypeName} row these match. Applied before \`disconnect\`, \`connect\` and \`create\`.`
5458
+ };
5459
+ }
5460
+ }
5461
+ }
5462
+ const type = new GraphQLInputObjectType11({
5463
+ name: cacheCtx.typeName({
5464
+ kind: "nestedWriteInput",
5465
+ defaultName: `${typeName}${capitalize(plan.relationName)}Nested${forUpdate ? "Update" : "Create"}Input`,
5466
+ table: tableName,
5467
+ operation: plan.relationName
5468
+ }),
5469
+ description: `Writes through ${typeName}.${plan.relationName}`,
5470
+ fields
5471
+ });
5472
+ wrapperCache.set(key, type);
5473
+ return type;
5446
5474
  };
5447
- };
5448
- var generateUpdate = (db, tableName, table, setArgs, filterArgs, fieldName, single, requireWhere, filterCtx, txCtx, policies) => {
5449
- const queryArgs = {
5450
- set: {
5451
- type: new GraphQLNonNull13(setArgs)
5452
- },
5453
- where: {
5454
- type: single || requireWhere ? new GraphQLNonNull13(filterArgs) : filterArgs
5475
+ const relationFields = (tableName, typeName, forUpdate) => {
5476
+ const tablePlans = plans[tableName];
5477
+ if (!tablePlans) {
5478
+ return {};
5455
5479
  }
5480
+ return Object.fromEntries(
5481
+ Object.values(tablePlans).flatMap((plan) => {
5482
+ const wrapper = wrapperType(tableName, typeName, plan, forUpdate);
5483
+ return wrapper ? [[plan.relationName, { type: wrapper, description: `Writes through ${typeName}.${plan.relationName}` }]] : [];
5484
+ })
5485
+ );
5456
5486
  };
5457
- const hooks = policies?.onWrite?.(tableName, "update");
5458
- const errorCtx = { table: tableName, operation: "update", field: fieldName };
5459
5487
  return {
5460
- name: fieldName,
5461
- resolver: async (_source, args, context, info) => {
5462
- try {
5463
- return await runMutation(
5464
- db,
5465
- context,
5466
- info,
5467
- txCtx,
5468
- async (executor) => {
5469
- const { where, set } = args;
5470
- const scope = policies?.scope?.(context);
5471
- const input = stripContextValues(
5472
- remapUpdateInput(set, table, tableName),
5473
- policies?.contextValues?.(tableName)
5474
- );
5475
- if (!Object.keys(input).length) {
5476
- throw drizzleError("Unable to update with no values specified!", { code: "DRIZZLE_NO_VALUES" });
5477
- }
5478
- await runWriteHook(hooks, "before", {
5479
- table: tableName,
5480
- operation: "update",
5481
- single,
5482
- args,
5483
- context,
5484
- info,
5485
- tx: executor
5486
- });
5487
- const relationCtx = relationFilterCtx(filterCtx, tableName);
5488
- const filters = withScope(
5489
- scope,
5490
- tableName,
5491
- table,
5492
- single || requireWhere ? extractRequiredFilters(table, tableName, where, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
5493
- );
5494
- if (single) {
5495
- await assertSingleMatch(executor, table, filters);
5496
- }
5497
- let query = executor.update(table).set(input);
5498
- if (filters) {
5499
- query = query.where(filters);
5500
- }
5501
- await query;
5502
- await runWriteHook(hooks, "after", {
5503
- table: tableName,
5504
- operation: "update",
5505
- single,
5506
- args,
5507
- rows: [],
5508
- context,
5509
- info,
5510
- tx: executor
5511
- });
5512
- return { isSuccess: true };
5513
- },
5514
- !!hooks
5515
- );
5516
- } catch (e) {
5517
- throw withErrorContext(toGraphQLError(e), errorCtx);
5488
+ createFields: (tableName, typeName) => relationFields(tableName, typeName, false),
5489
+ updateFields: (tableName, typeName) => relationFields(tableName, typeName, true),
5490
+ relaxedColumns: (tableName) => {
5491
+ const tablePlans = plans[tableName];
5492
+ if (!tablePlans) {
5493
+ return NO_COLUMNS;
5518
5494
  }
5519
- },
5520
- args: queryArgs
5495
+ const relaxed = /* @__PURE__ */ new Set();
5496
+ for (const plan of Object.values(tablePlans)) {
5497
+ if (plan.fkSide === "parent" && !isOptionalOnInsert(plan.localCol)) {
5498
+ relaxed.add(plan.localColPropName);
5499
+ }
5500
+ }
5501
+ return relaxed.size ? relaxed : NO_COLUMNS;
5502
+ }
5521
5503
  };
5522
5504
  };
5523
- var generateUpdateMany = (db, tableName, table, updateManyInput, fieldName, filterCtx, txCtx, policies) => {
5524
- const queryArgs = {
5525
- updates: {
5526
- type: new GraphQLNonNull13(new GraphQLList9(new GraphQLNonNull13(updateManyInput)))
5505
+ var mergedOps = (entries) => Object.assign({}, ...entries.map((entry) => entry.ops));
5506
+ var asArray = (value) => Array.isArray(value) ? value : value === void 0 ? [] : [value];
5507
+ var createNestedWriteRuntime = (params) => {
5508
+ const { plans, filterCtx, policies, contextValues } = params;
5509
+ const conditionOf = (plan, filter, operation, scope) => {
5510
+ const condition = extractFilters(
5511
+ plan.targetTable,
5512
+ plan.targetTableName,
5513
+ filter,
5514
+ relationFilterCtx(filterCtx, plan.targetTableName)
5515
+ );
5516
+ if (!condition) {
5517
+ throw drizzleError(
5518
+ `Drizzle-GraphQL Error: '${operation}' on '${plan.relationName}' needs a filter that selects rows \u2014 it was given one that matches everything.`,
5519
+ { code: "DRIZZLE_NESTED_WRITE_INVALID" }
5520
+ );
5527
5521
  }
5522
+ return withScope(scope, plan.targetTableName, plan.targetTable, condition);
5528
5523
  };
5529
- const hooks = policies?.onWrite?.(tableName, "updateMany");
5530
- const errorCtx = { table: tableName, operation: "updateMany", field: fieldName };
5531
- return {
5532
- name: fieldName,
5533
- resolver: async (_source, args, context, info) => {
5534
- try {
5535
- return await runMutation(
5536
- db,
5537
- context,
5538
- info,
5539
- txCtx,
5540
- async (executor) => {
5541
- const { updates } = args;
5542
- if (!updates.length) {
5543
- throw drizzleError("No updates were provided!", { code: "DRIZZLE_NO_VALUES" });
5544
- }
5545
- await runWriteHook(hooks, "before", {
5546
- table: tableName,
5547
- operation: "updateMany",
5548
- single: false,
5549
- args,
5550
- context,
5551
- info,
5552
- tx: executor
5553
- });
5554
- const scope = policies?.scope?.(context);
5555
- const contextColumns = policies?.contextValues?.(tableName);
5556
- const entries = updates.map(({ where, set }) => {
5557
- const input = stripContextValues(remapUpdateInput(set, table, tableName), contextColumns);
5558
- if (!Object.keys(input).length) {
5559
- throw drizzleError("Unable to update with no values specified!", { code: "DRIZZLE_NO_VALUES" });
5560
- }
5561
- return {
5562
- set: input,
5563
- filters: withScope(
5564
- scope,
5565
- tableName,
5566
- table,
5567
- where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
5568
- )
5569
- };
5570
- });
5571
- await executor.transaction(async (tx) => {
5572
- for (const entry of entries) {
5573
- let query = tx.update(table).set(entry.set);
5574
- if (entry.filters) {
5575
- query = query.where(entry.filters);
5576
- }
5577
- await query;
5578
- }
5579
- });
5580
- await runWriteHook(hooks, "after", {
5581
- table: tableName,
5582
- operation: "updateMany",
5583
- single: false,
5584
- args,
5585
- rows: [],
5586
- context,
5587
- info,
5588
- tx: executor
5589
- });
5590
- return { isSuccess: true };
5591
- },
5592
- !!hooks
5593
- );
5594
- } catch (e) {
5595
- throw withErrorContext(toGraphQLError(e), errorCtx);
5596
- }
5597
- },
5598
- args: queryArgs
5524
+ const assertSingleOperation = (plan, op) => {
5525
+ const supplied = ["create", "connect", "disconnect"].filter((key) => op[key] !== void 0 && op[key] !== null);
5526
+ if (supplied.length > 1) {
5527
+ throw drizzleError(
5528
+ `Drizzle-GraphQL Error: '${plan.relationName}' takes one of ${supplied.join(", ")} at a time \u2014 it holds a single row.`,
5529
+ { code: "DRIZZLE_NESTED_WRITE_INVALID" }
5530
+ );
5531
+ }
5599
5532
  };
5600
- };
5601
- var generateDelete = (db, tableName, table, filterArgs, fieldName, single, requireWhere, filterCtx, txCtx, policies, restore = false) => {
5602
- const softDelete = policies?.softDelete?.(tableName);
5603
- const operation = restore ? "restore" : "delete";
5604
- const canHardDelete = !restore && softDelete?.hardDelete === true;
5605
- const queryArgs = {
5606
- where: {
5607
- type: single || requireWhere ? new GraphQLNonNull13(filterArgs) : filterArgs
5608
- },
5609
- ...canHardDelete ? { hard: hardDeleteArg } : {}
5533
+ const selectedTargetKeys = async (executor, plan, filter, operation, scope) => {
5534
+ const rows = await executor.select().from(plan.targetTable).where(conditionOf(plan, filter, operation, scope));
5535
+ return rows.map((row) => row[plan.foreignColPropName]).filter((value) => value !== void 0 && value !== null);
5610
5536
  };
5611
- const hooks = policies?.onWrite?.(tableName, operation);
5612
- const errorCtx = { table: tableName, operation, field: fieldName };
5613
- return {
5614
- name: fieldName,
5615
- resolver: async (_source, args, context, info) => {
5616
- try {
5617
- return await runMutation(
5618
- db,
5619
- context,
5620
- info,
5621
- txCtx,
5622
- async (executor) => {
5623
- await runWriteHook(hooks, "before", {
5624
- table: tableName,
5625
- operation,
5626
- single,
5627
- args,
5628
- context,
5629
- info,
5630
- tx: executor
5631
- });
5632
- const { where } = args;
5633
- const hard = canHardDelete && args.hard === true;
5634
- const scope = policies?.scope?.(context);
5635
- const relationCtx = relationFilterCtx(filterCtx, tableName);
5636
- const filters = withScope(
5637
- scope,
5638
- tableName,
5639
- table,
5640
- single || requireWhere ? extractRequiredFilters(table, tableName, where, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
5641
- // A hard delete reads at INCLUDE: the rows it mostly exists to remove are the
5642
- // ones already marked, which the default EXCLUDE could not reach at all.
5643
- restore ? "ONLY" : hard ? "INCLUDE" : void 0
5644
- );
5645
- if (single) {
5646
- await assertSingleMatch(executor, table, filters);
5647
- }
5648
- let query = softDelete && !hard ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
5649
- if (filters) {
5650
- query = query.where(filters);
5651
- }
5652
- await query;
5653
- await runWriteHook(hooks, "after", {
5654
- table: tableName,
5655
- operation,
5656
- single,
5657
- args,
5658
- rows: [],
5659
- context,
5660
- info,
5661
- tx: executor
5662
- });
5663
- return { isSuccess: true };
5664
- },
5665
- !!hooks
5666
- );
5667
- } catch (e) {
5668
- throw withErrorContext(toGraphQLError(e), errorCtx);
5537
+ const applyThroughOps = async (executor, plan, key, op, scope) => {
5538
+ const through = plan.through;
5539
+ const unlinkAll = () => executor.delete(through.table).where(eq8(through.sourceCol, key));
5540
+ const link = async (operands, operation) => {
5541
+ const existing = new Set(
5542
+ (await executor.select().from(through.table).where(eq8(through.sourceCol, key))).map(
5543
+ (row) => row[through.targetColPropName]
5544
+ )
5545
+ );
5546
+ const rows = [];
5547
+ for (const filter of operands) {
5548
+ for (const targetKey of await selectedTargetKeys(executor, plan, filter, operation, scope)) {
5549
+ if (!existing.has(targetKey)) {
5550
+ existing.add(targetKey);
5551
+ rows.push({ [through.sourceColPropName]: key, [through.targetColPropName]: targetKey });
5552
+ }
5553
+ }
5554
+ }
5555
+ if (rows.length) {
5556
+ await executor.insert(through.table).values(rows);
5557
+ }
5558
+ };
5559
+ if (op["set"] !== void 0 && op["set"] !== null) {
5560
+ await unlinkAll();
5561
+ await link(asArray(op["set"]), "set");
5562
+ }
5563
+ if (op["disconnect"] !== void 0 && op["disconnect"] !== null) {
5564
+ for (const filter of asArray(op["disconnect"])) {
5565
+ const targetKeys = await selectedTargetKeys(executor, plan, filter, "disconnect", scope);
5566
+ if (targetKeys.length) {
5567
+ await executor.delete(through.table).where(and11(eq8(through.sourceCol, key), inArray6(through.targetCol, targetKeys)));
5568
+ }
5669
5569
  }
5670
- },
5671
- args: queryArgs
5672
- };
5673
- };
5674
- var mysqlPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig);
5675
- var { generateSelectArray, generateSelectSingle } = createSelectGenerators(
5676
- mysqlPrimaryKeyPropNames,
5677
- "nulls-smallest"
5678
- );
5679
- var generateSchemaData = (db, schema, relations, options) => {
5680
- const { relationsDepthLimit, prefixes, suffixes, typeNameMapper, shouldEagerLoad, features, complexity, limits } = options;
5681
- const rawSchema = schema;
5682
- const schemaEntries = Object.entries(rawSchema);
5683
- const excludedTables = new Set(options.exclude?.tables ?? []);
5684
- const tableEntries = schemaEntries.filter(([key, value]) => is10(value, MySqlTable) && !excludedTables.has(key));
5685
- const tables = Object.fromEntries(tableEntries);
5686
- const featureOf = resolveTableFeatures(features);
5687
- const anyTable = (feature) => tableEntries.some(([name]) => featureOf(name)[feature]);
5688
- if (!tableEntries.length) {
5689
- throw new Error(
5690
- "Drizzle-GraphQL Error: No tables detected in Drizzle-ORM's database instance. Did you forget to pass schema to drizzle constructor?"
5691
- );
5692
- }
5693
- if (features.nestedWrites) {
5694
- throw new Error(
5695
- "Drizzle-GraphQL Error: features.nestedWrites is not supported on MySQL \u2014 a nested write needs the parent row it just inserted returned to it, and MySQL has no RETURNING clause."
5696
- );
5697
- }
5698
- registerScalarOverrides(tables, options);
5699
- registerEnumConfig(options);
5700
- registerColumnExclusions(tables, options.exclude);
5701
- const namedRelations = buildNamedRelations(relations ?? {}, tableEntries);
5702
- for (const excluded of excludedTables) {
5703
- delete namedRelations[excluded];
5704
- }
5705
- attachTargetPrimaryKeys(namedRelations, tables, mysqlPrimaryKeyPropNames);
5706
- const eagerRelations = pruneNonEagerRelations(namedRelations, shouldEagerLoad);
5707
- const uniqueKeys = {};
5708
- for (const [tableName, table] of tableEntries) {
5709
- if (!featureOf(tableName).uniqueKeyFilters) {
5710
- continue;
5711
5570
  }
5712
- const taken = /* @__PURE__ */ new Set([...Object.keys(visibleColumns(table)), ...Object.keys(namedRelations[tableName] ?? {})]);
5713
- const map = buildUniqueKeyMap(getUniqueColumnSets(table, getTableConfig), taken);
5714
- if (Object.keys(map).length) {
5715
- uniqueKeys[tableName] = map;
5571
+ if (op["connect"] !== void 0 && op["connect"] !== null) {
5572
+ await link(asArray(op["connect"]), "connect");
5716
5573
  }
5717
- }
5718
- const filterCtx = { tables, relationMap: namedRelations, uniqueKeys };
5719
- const tablePolicies = options.policies;
5720
- const contextValuesOf = tablePolicies?.contextValues;
5721
- const softDeleteOf = tablePolicies?.softDelete;
5722
- const policies = bindPolicies(tablePolicies, filterCtx);
5723
- const resolverFactory = createRelationResolverFactory(
5724
- db,
5725
- tables,
5726
- "nulls-smallest",
5727
- filterCtx,
5728
- limits,
5729
- tablePolicies
5730
- );
5731
- const cacheCtx = {
5732
- typeName: options.typeName ?? ((info) => info.defaultName),
5733
- genericFilterCache: /* @__PURE__ */ new Map(),
5734
- objectTypeCache: /* @__PURE__ */ new Map(),
5735
- relationFieldContainers: /* @__PURE__ */ new Map(),
5736
- fullyBuiltTables: /* @__PURE__ */ new Set(),
5737
- relationTypeCache: /* @__PURE__ */ new Map(),
5738
- selectFieldCache: /* @__PURE__ */ new WeakMap(),
5739
- filterFieldCache: /* @__PURE__ */ new WeakMap(),
5740
- orderTypeCache: /* @__PURE__ */ new WeakMap(),
5741
- filterTypeCache: /* @__PURE__ */ new WeakMap(),
5742
- listRelationFilterCache: /* @__PURE__ */ new Map(),
5743
- aggregateTypeCache: /* @__PURE__ */ new Map(),
5744
- complexity,
5745
- limits,
5746
- docs: options.docs ?? {},
5747
- primaryKeyOf: (name) => tables[name] ? mysqlPrimaryKeyPropNames(tables[name]) : [],
5748
- contextValuesOf,
5749
- softDeleteOf,
5750
- featureOf,
5751
- uniqueKeysOf: (tableName) => uniqueKeys[tableName]
5752
5574
  };
5753
- const relationAggregateFactory = anyTable("relationAggregates") ? createRelationAggregateFactory(db, tables, cacheCtx, typeNameMapper, filterCtx, tablePolicies) : void 0;
5754
- const queries = {};
5755
- const mutations = {};
5756
- const mutationTxCtx = createMutationTxCtx(options.transactions);
5757
- const gqlSchemaTypes = Object.fromEntries(
5758
- Object.entries(tables).map(([tableName, _table]) => [
5759
- tableName,
5760
- generateTableTypes(
5761
- tableName,
5762
- tables,
5763
- namedRelations,
5764
- false,
5765
- relationsDepthLimit,
5766
- cacheCtx,
5767
- typeNameMapper,
5768
- prefixes.insert,
5769
- prefixes.update,
5770
- resolverFactory,
5771
- featureOf(tableName).relationAggregates ? relationAggregateFactory : void 0
5772
- )
5773
- ])
5774
- );
5775
- const mutationReturnType = new GraphQLObjectType4({
5776
- name: cacheCtx.typeName({ kind: "shared", defaultName: "MutationReturn" }),
5777
- fields: {
5778
- isSuccess: {
5779
- type: new GraphQLNonNull13(GraphQLBoolean5)
5575
+ const detachAll = async (executor, plan, key, scope) => executor.update(plan.targetTable).set({ [plan.foreignColPropName]: null }).where(withScope(scope, plan.targetTableName, plan.targetTable, eq8(plan.foreignCol, key)));
5576
+ return {
5577
+ enabled: (tableName) => !!plans[tableName],
5578
+ split: (tableName, values) => {
5579
+ const tablePlans = plans[tableName];
5580
+ if (!tablePlans) {
5581
+ return { columns: values, ops: {} };
5780
5582
  }
5781
- }
5782
- });
5783
- const inputs = {};
5784
- const outputs = {};
5785
- if (["insert", "upsert", "update", "delete"].some((feature) => anyTable(feature))) {
5786
- outputs["MutationReturn"] = mutationReturnType;
5787
- }
5788
- for (const [tableName, tableTypes] of Object.entries(gqlSchemaTypes)) {
5789
- const tableFeatures = featureOf(tableName);
5790
- const drizzleMeta = tableFieldExtensions(tableName, mysqlPrimaryKeyPropNames(schema[tableName]));
5791
- const { insertInput, updateInput, tableFilters, tableOrder } = tableTypes.inputs;
5792
- const { selectSingleOutput, selectArrOutput } = tableTypes.outputs;
5793
- const {
5794
- typeName,
5795
- listFieldName,
5796
- singleFieldName,
5797
- aggregateFieldName,
5798
- groupByFieldName,
5799
- createArrayFieldName,
5800
- createSingleFieldName,
5801
- upsertArrayFieldName,
5802
- upsertSingleFieldName,
5803
- updateFieldName,
5804
- updateManyFieldName,
5805
- updateSingleFieldName,
5806
- updateCountFieldName,
5807
- deleteFieldName,
5808
- deleteSingleFieldName,
5809
- restoreFieldName,
5810
- restoreSingleFieldName,
5811
- deleteCountFieldName
5812
- } = computeResolverFieldNames(tableName, typeNameMapper, prefixes, suffixes);
5813
- const softDeleteInfo = softDeleteOf?.(tableName);
5814
- const selectArrGenerated = generateSelectArray(
5815
- db,
5816
- tableName,
5817
- tables,
5818
- eagerRelations,
5819
- tableOrder,
5820
- tableFilters,
5821
- listFieldName,
5822
- typeName,
5823
- typeNameMapper,
5824
- filterCtx,
5825
- tableFeatures.distinct,
5826
- limits,
5827
- policies,
5828
- cacheCtx.typeName
5829
- );
5830
- const selectSingleGenerated = generateSelectSingle(
5831
- db,
5832
- tableName,
5833
- tables,
5834
- eagerRelations,
5835
- tableOrder,
5836
- tableFilters,
5837
- singleFieldName,
5838
- typeName,
5839
- typeNameMapper,
5840
- filterCtx,
5841
- limits,
5842
- policies,
5843
- cacheCtx.typeName
5844
- );
5845
- const insertArrGenerated = tableFeatures.insert ? generateInsertArray(
5846
- db,
5847
- tableName,
5848
- schema[tableName],
5849
- insertInput,
5850
- createArrayFieldName,
5851
- mutationTxCtx,
5852
- policies
5853
- ) : void 0;
5854
- const insertSingleGenerated = tableFeatures.insert ? generateInsertSingle(
5855
- db,
5856
- tableName,
5857
- schema[tableName],
5858
- insertInput,
5859
- createSingleFieldName,
5860
- mutationTxCtx,
5861
- policies
5862
- ) : void 0;
5863
- const onConflictInput = tableFeatures.upsert ? generateOnConflictInput({
5864
- table: schema[tableName],
5865
- tableName,
5866
- typeName,
5867
- uniqueSets: [],
5868
- tableFilters,
5869
- withTarget: false,
5870
- cacheCtx
5871
- }) : void 0;
5872
- const upsertArrGenerated = onConflictInput ? generateUpsert(
5873
- db,
5874
- tableName,
5875
- schema[tableName],
5876
- insertInput,
5877
- onConflictInput,
5878
- upsertArrayFieldName,
5879
- false,
5880
- mutationTxCtx,
5881
- policies
5882
- ) : void 0;
5883
- const upsertSingleGenerated = onConflictInput ? generateUpsert(
5884
- db,
5885
- tableName,
5886
- schema[tableName],
5887
- insertInput,
5888
- onConflictInput,
5889
- upsertSingleFieldName,
5890
- true,
5891
- mutationTxCtx,
5892
- policies
5893
- ) : void 0;
5894
- const updateGenerated = tableFeatures.update ? generateUpdate(
5895
- db,
5896
- tableName,
5897
- schema[tableName],
5898
- updateInput,
5899
- tableFilters,
5900
- updateFieldName,
5901
- false,
5902
- tableFeatures.requireWhere,
5903
- filterCtx,
5904
- mutationTxCtx,
5905
- policies
5906
- ) : void 0;
5907
- const updateSingleGenerated = tableFeatures.update ? generateUpdate(
5908
- db,
5909
- tableName,
5910
- schema[tableName],
5911
- updateInput,
5912
- tableFilters,
5913
- updateSingleFieldName,
5914
- true,
5915
- tableFeatures.requireWhere,
5916
- filterCtx,
5917
- mutationTxCtx,
5918
- policies
5919
- ) : void 0;
5920
- const updateManyInput = tableFeatures.update && tableFeatures.updateMany ? generateUpdateManyInput({
5921
- tableName,
5922
- typeName,
5923
- updatePrefix: prefixes.update,
5924
- updateInput,
5925
- tableFilters,
5926
- cacheCtx
5927
- }) : void 0;
5928
- const updateManyGenerated = updateManyInput ? generateUpdateMany(
5929
- db,
5930
- tableName,
5931
- schema[tableName],
5932
- updateManyInput,
5933
- updateManyFieldName,
5934
- filterCtx,
5935
- mutationTxCtx,
5936
- policies
5937
- ) : void 0;
5938
- const deleteGenerated = tableFeatures.delete ? generateDelete(
5939
- db,
5940
- tableName,
5941
- schema[tableName],
5942
- tableFilters,
5943
- deleteFieldName,
5944
- false,
5945
- tableFeatures.requireWhere,
5946
- filterCtx,
5947
- mutationTxCtx,
5948
- policies
5949
- ) : void 0;
5950
- const deleteSingleGenerated = tableFeatures.delete ? generateDelete(
5951
- db,
5952
- tableName,
5953
- schema[tableName],
5954
- tableFilters,
5955
- deleteSingleFieldName,
5956
- true,
5957
- tableFeatures.requireWhere,
5958
- filterCtx,
5959
- mutationTxCtx,
5960
- policies
5961
- ) : void 0;
5962
- const restoreGenerated = softDeleteInfo ? generateDelete(
5963
- db,
5964
- tableName,
5965
- schema[tableName],
5966
- tableFilters,
5967
- restoreFieldName,
5968
- false,
5969
- tableFeatures.requireWhere,
5970
- filterCtx,
5971
- mutationTxCtx,
5972
- policies,
5973
- true
5974
- ) : void 0;
5975
- const restoreSingleGenerated = softDeleteInfo ? generateDelete(
5976
- db,
5977
- tableName,
5978
- schema[tableName],
5979
- tableFilters,
5980
- restoreSingleFieldName,
5981
- true,
5982
- tableFeatures.requireWhere,
5983
- filterCtx,
5984
- mutationTxCtx,
5985
- policies,
5986
- true
5987
- ) : void 0;
5988
- const updateCountGenerated = tableFeatures.update && tableFeatures.countMutations ? generateWriteCount({
5989
- db,
5990
- tableName,
5991
- table: schema[tableName],
5992
- kind: "update",
5993
- setArgs: updateInput,
5994
- filterArgs: tableFilters,
5995
- fieldName: updateCountFieldName,
5996
- requireWhere: tableFeatures.requireWhere,
5997
- filterCtx,
5998
- txCtx: mutationTxCtx
5999
- }) : void 0;
6000
- const deleteCountGenerated = tableFeatures.delete && tableFeatures.countMutations ? generateWriteCount({
6001
- db,
6002
- tableName,
6003
- table: schema[tableName],
6004
- kind: "delete",
6005
- filterArgs: tableFilters,
6006
- fieldName: deleteCountFieldName,
6007
- requireWhere: tableFeatures.requireWhere,
6008
- filterCtx,
6009
- txCtx: mutationTxCtx
6010
- }) : void 0;
6011
- const aggregateType = tableFeatures.aggregates ? generateAggregateTypes(schema[tableName], tableName, typeName, cacheCtx) : void 0;
6012
- const aggregateGenerated = tableFeatures.aggregates ? generateAggregate(
6013
- db,
6014
- tableName,
6015
- schema[tableName],
6016
- typeName,
6017
- aggregateFieldName,
6018
- tableFilters,
6019
- filterCtx,
6020
- tablePolicies,
6021
- cacheCtx.typeName
6022
- ) : void 0;
6023
- const groupByType = tableFeatures.aggregates && tableFeatures.groupBy ? generateGroupByType(schema[tableName], tableName, typeName, cacheCtx) : void 0;
6024
- const groupByEnum = groupByType ? generateGroupByEnum(schema[tableName], tableName, typeName, cacheCtx) : void 0;
6025
- const havingInput = groupByEnum ? generateHavingInput(schema[tableName], tableName, typeName, cacheCtx) : void 0;
6026
- const groupByGenerated = groupByType && groupByEnum && havingInput ? generateGroupBy(
6027
- db,
6028
- tableName,
6029
- schema[tableName],
6030
- typeName,
6031
- groupByFieldName,
6032
- tableFilters,
6033
- groupByEnum,
6034
- havingInput,
6035
- filterCtx,
6036
- tablePolicies,
6037
- cacheCtx.typeName
6038
- ) : void 0;
6039
- queries[selectArrGenerated.name] = {
6040
- type: selectArrOutput,
6041
- args: selectArrGenerated.args,
6042
- resolve: selectArrGenerated.resolver,
6043
- extensions: {
6044
- drizzle: drizzleMeta({ kind: "query", operation: "select", single: false, targetArg: "where" }),
6045
- ...complexity ? { complexity: listFieldComplexity(complexity, limits?.(tableName)) } : {}
5583
+ const columns = {};
5584
+ const ops = {};
5585
+ for (const [key, value] of Object.entries(values)) {
5586
+ if (tablePlans[key] && value !== void 0 && value !== null) {
5587
+ ops[key] = value;
5588
+ } else if (!tablePlans[key]) {
5589
+ columns[key] = value;
5590
+ }
6046
5591
  }
6047
- };
6048
- queries[selectSingleGenerated.name] = {
6049
- type: selectSingleOutput,
6050
- args: selectSingleGenerated.args,
6051
- resolve: selectSingleGenerated.resolver,
6052
- extensions: {
6053
- drizzle: drizzleMeta({ kind: "query", operation: "select", single: true, targetArg: "where" })
5592
+ return { columns, ops };
5593
+ },
5594
+ hasOps: (ops) => Object.keys(ops).length > 0,
5595
+ withJoinColumns: (tableName, ops, columns, table) => {
5596
+ const tablePlans = plans[tableName];
5597
+ if (!tablePlans) {
5598
+ return columns;
6054
5599
  }
6055
- };
6056
- if (aggregateGenerated && aggregateType) {
6057
- queries[aggregateGenerated.name] = {
6058
- type: new GraphQLNonNull13(aggregateType),
6059
- args: aggregateGenerated.args,
6060
- resolve: aggregateGenerated.resolver,
6061
- extensions: {
6062
- drizzle: drizzleMeta({ kind: "aggregate", operation: "aggregate", single: true, targetArg: "where" }),
6063
- ...complexity ? { complexity: aggregateFieldComplexity(complexity) } : {}
6064
- }
6065
- };
6066
- }
6067
- if (groupByGenerated && groupByType) {
6068
- queries[groupByGenerated.name] = {
6069
- type: new GraphQLNonNull13(new GraphQLList9(new GraphQLNonNull13(groupByType))),
6070
- args: groupByGenerated.args,
6071
- resolve: groupByGenerated.resolver,
6072
- extensions: {
6073
- drizzle: drizzleMeta({ kind: "aggregate", operation: "groupBy", single: false, targetArg: "where" }),
6074
- ...complexity ? { complexity: aggregateFieldComplexity(complexity) } : {}
5600
+ const allColumns = getColumns16(table);
5601
+ for (const relationName of Object.keys(ops)) {
5602
+ const plan = tablePlans[relationName];
5603
+ if (plan?.fkSide === "child" && !(plan.localColPropName in columns) && allColumns[plan.localColPropName]) {
5604
+ columns[plan.localColPropName] = allColumns[plan.localColPropName];
6075
5605
  }
6076
- };
6077
- }
6078
- const hardDeleteMeta = softDeleteInfo?.hardDelete ? { hardDelete: true } : {};
6079
- const generatedMutations = [
6080
- [insertArrGenerated, { operation: "insert", single: false, targetArg: "values" }],
6081
- [insertSingleGenerated, { operation: "insert", single: true, targetArg: "values" }],
6082
- [upsertArrGenerated, { operation: "upsert", single: false, targetArg: "values" }],
6083
- [upsertSingleGenerated, { operation: "upsert", single: true, targetArg: "values" }],
6084
- [updateGenerated, { operation: "update", single: false, targetArg: "where" }],
6085
- [updateManyGenerated, { operation: "updateMany", single: false, targetArg: "updates" }],
6086
- [updateSingleGenerated, { operation: "update", single: true, targetArg: "where" }],
6087
- [deleteGenerated, { operation: "delete", single: false, targetArg: "where", ...hardDeleteMeta }],
6088
- [deleteSingleGenerated, { operation: "delete", single: true, targetArg: "where", ...hardDeleteMeta }],
6089
- [restoreGenerated, { operation: "restore", single: false, targetArg: "where" }],
6090
- [restoreSingleGenerated, { operation: "restore", single: true, targetArg: "where" }]
6091
- ];
6092
- for (const [generated, meta] of generatedMutations) {
6093
- if (generated) {
6094
- mutations[generated.name] = {
6095
- type: mutationReturnType,
6096
- args: generated.args,
6097
- resolve: generated.resolver,
6098
- extensions: { drizzle: drizzleMeta({ kind: "mutation", ...meta }) }
6099
- };
6100
5606
  }
6101
- }
6102
- if (updateCountGenerated) {
6103
- mutations[updateCountGenerated.name] = {
6104
- type: new GraphQLNonNull13(GraphQLInt8),
6105
- args: updateCountGenerated.args,
6106
- resolve: updateCountGenerated.resolver,
6107
- description: "How many rows the update touched. The rows themselves are not read back, which is the point of this mutation."
6108
- };
6109
- }
6110
- if (deleteCountGenerated) {
6111
- mutations[deleteCountGenerated.name] = {
6112
- type: new GraphQLNonNull13(GraphQLInt8),
6113
- args: deleteCountGenerated.args,
6114
- resolve: deleteCountGenerated.resolver,
6115
- description: "How many rows the delete removed. The rows themselves are not read back, which is the point of this mutation."
6116
- };
6117
- }
6118
- const activeInputs = [
6119
- // The insert input types the upsert mutations too, so either feature keeps it.
6120
- ...tableFeatures.insert || onConflictInput ? [insertInput] : [],
6121
- ...onConflictInput ? [onConflictInput] : [],
6122
- ...tableFeatures.update ? [updateInput] : [],
6123
- ...updateManyInput ? [updateManyInput] : [],
6124
- tableFilters,
6125
- tableOrder
6126
- ];
6127
- activeInputs.forEach((e) => {
6128
- inputs[e.name] = e;
6129
- });
6130
- outputs[selectSingleOutput.name] = selectSingleOutput;
6131
- if (aggregateType) {
6132
- outputs[aggregateType.name] = aggregateType;
6133
- }
6134
- if (groupByType && havingInput) {
6135
- outputs[groupByType.name] = groupByType;
6136
- inputs[havingInput.name] = havingInput;
6137
- }
6138
- }
6139
- if (mutationTxCtx) {
6140
- for (const name of Object.keys(mutations)) {
6141
- mutationTxCtx.fieldNames.add(name);
6142
- }
6143
- }
6144
- const fieldResolvers = {};
6145
- for (const [tableName, tableRelations] of Object.entries(namedRelations)) {
6146
- const relResolvers = {};
6147
- for (const [relName, relEntry] of Object.entries(tableRelations)) {
6148
- const isOne = is10(relEntry.relation ?? relEntry, One7);
6149
- const resolver = resolverFactory({ tableName, relationName: relName, relEntry, isOne });
6150
- if (resolver) {
6151
- relResolvers[relName] = resolver;
5607
+ return columns;
5608
+ },
5609
+ applyParentSide: async (executor, tableName, ops, context) => {
5610
+ const tablePlans = plans[tableName];
5611
+ const patch = {};
5612
+ if (!tablePlans) {
5613
+ return patch;
5614
+ }
5615
+ const scope = resolveScope(policies, context, filterCtx);
5616
+ for (const [relationName, op] of Object.entries(ops)) {
5617
+ const plan = tablePlans[relationName];
5618
+ if (!plan || plan.fkSide !== "parent") {
5619
+ continue;
5620
+ }
5621
+ assertSingleOperation(plan, op);
5622
+ if (op["create"] !== void 0) {
5623
+ const values = applyContextValues(
5624
+ remapFromGraphQLSingleInput({ ...op["create"] }, plan.targetTable),
5625
+ contextValues?.(plan.targetTableName),
5626
+ context
5627
+ );
5628
+ const inserted = await executor.insert(plan.targetTable).values(values).returning();
5629
+ const created = inserted[0];
5630
+ if (!created) {
5631
+ throw drizzleError(
5632
+ `Drizzle-GraphQL Error: 'create' on '${relationName}' inserted no row, so there is nothing to attach.`,
5633
+ { code: "DRIZZLE_NESTED_WRITE_INVALID" }
5634
+ );
5635
+ }
5636
+ patch[plan.localColPropName] = created[plan.foreignColPropName];
5637
+ } else if (op["connect"] !== void 0) {
5638
+ const rows = await executor.select().from(plan.targetTable).where(conditionOf(plan, op["connect"], "connect", scope));
5639
+ if (rows.length !== 1) {
5640
+ throw drizzleError(
5641
+ `Drizzle-GraphQL Error: 'connect' on '${relationName}' matched ${rows.length} rows \u2014 it attaches a single row, so its filter must match exactly one.`,
5642
+ { code: "DRIZZLE_NESTED_WRITE_INVALID" }
5643
+ );
5644
+ }
5645
+ patch[plan.localColPropName] = rows[0][plan.foreignColPropName];
5646
+ } else if (op["disconnect"] === true) {
5647
+ patch[plan.localColPropName] = null;
5648
+ }
5649
+ }
5650
+ return patch;
5651
+ },
5652
+ applyChildSide: async (executor, tableName, ops, parentRows, context) => {
5653
+ const tablePlans = plans[tableName];
5654
+ if (!tablePlans) {
5655
+ return;
5656
+ }
5657
+ const scope = resolveScope(policies, context, filterCtx);
5658
+ for (const [relationName, op] of Object.entries(ops)) {
5659
+ const plan = tablePlans[relationName];
5660
+ if (!plan || plan.fkSide !== "child") {
5661
+ continue;
5662
+ }
5663
+ if (plan.isOne) {
5664
+ assertSingleOperation(plan, op);
5665
+ }
5666
+ for (const parentRow of parentRows) {
5667
+ const key = parentRow?.[plan.localColPropName];
5668
+ if (key === void 0 || key === null) {
5669
+ throw drizzleError(
5670
+ `Drizzle-GraphQL Error: cannot write through '${relationName}': the ${tableName} row has no '${plan.localColPropName}' value to attach to.`,
5671
+ { code: "DRIZZLE_NESTED_WRITE_INVALID" }
5672
+ );
5673
+ }
5674
+ if (plan.through) {
5675
+ await applyThroughOps(executor, plan, key, op, scope);
5676
+ continue;
5677
+ }
5678
+ if (op["set"] !== void 0) {
5679
+ await detachAll(executor, plan, key, scope);
5680
+ for (const filter of asArray(op["set"])) {
5681
+ await executor.update(plan.targetTable).set({ [plan.foreignColPropName]: key }).where(conditionOf(plan, filter, "set", scope));
5682
+ }
5683
+ }
5684
+ if (op["disconnect"] !== void 0) {
5685
+ if (plan.isOne) {
5686
+ if (op["disconnect"] === true) {
5687
+ await detachAll(executor, plan, key, scope);
5688
+ }
5689
+ } else {
5690
+ for (const filter of asArray(op["disconnect"])) {
5691
+ await executor.update(plan.targetTable).set({ [plan.foreignColPropName]: null }).where(and11(eq8(plan.foreignCol, key), conditionOf(plan, filter, "disconnect", scope)));
5692
+ }
5693
+ }
5694
+ }
5695
+ const attaches = op["connect"] !== void 0 || op["create"] !== void 0;
5696
+ if (plan.isOne && attaches && plan.canDetach && op["set"] === void 0) {
5697
+ await detachAll(executor, plan, key, scope);
5698
+ }
5699
+ if (op["connect"] !== void 0) {
5700
+ for (const filter of asArray(op["connect"])) {
5701
+ await executor.update(plan.targetTable).set({ [plan.foreignColPropName]: key }).where(conditionOf(plan, filter, "connect", scope));
5702
+ }
5703
+ }
5704
+ if (op["create"] !== void 0) {
5705
+ const rows = asArray(op["create"]).map((row) => ({
5706
+ ...applyContextValues(
5707
+ remapFromGraphQLSingleInput({ ...row }, plan.targetTable),
5708
+ contextValues?.(plan.targetTableName),
5709
+ context
5710
+ ),
5711
+ [plan.foreignColPropName]: key
5712
+ }));
5713
+ if (rows.length) {
5714
+ await executor.insert(plan.targetTable).values(rows);
5715
+ }
5716
+ }
5717
+ }
6152
5718
  }
6153
5719
  }
6154
- if (Object.keys(relResolvers).length > 0) {
6155
- fieldResolvers[tableName] = relResolvers;
5720
+ };
5721
+ };
5722
+ var writeWithNestedOps = async (params) => {
5723
+ const { executor, runtime, tableName, entries, remapValues, write, context } = params;
5724
+ return executor.transaction(async (tx) => {
5725
+ const rows = [];
5726
+ for (const entry of entries) {
5727
+ const patch = await runtime.applyParentSide(tx, tableName, entry.ops, context);
5728
+ const written = await write(tx, { ...remapValues(entry.columns), ...patch });
5729
+ await runtime.applyChildSide(tx, tableName, entry.ops, written, context);
5730
+ rows.push(...written);
6156
5731
  }
6157
- }
6158
- return { queries, mutations, inputs, types: outputs, fieldResolvers };
5732
+ return rows;
5733
+ });
5734
+ };
5735
+ var updateWithNestedOps = async (params) => {
5736
+ const { executor, runtime, tableName, columns, ops, remapValues, write, context } = params;
5737
+ return executor.transaction(async (tx) => {
5738
+ const patch = await runtime.applyParentSide(tx, tableName, ops, context);
5739
+ const rows = await write(tx, { ...remapValues(columns), ...patch });
5740
+ await runtime.applyChildSide(tx, tableName, ops, rows, context);
5741
+ return rows;
5742
+ });
6159
5743
  };
6160
5744
 
6161
- // src/util/builders/pg.ts
6162
- import { getTableConfig as getTableConfig2, PgTable } from "drizzle-orm/pg-core";
5745
+ // src/util/builders/select.ts
5746
+ import { parseResolveInfo as parseResolveInfo2 } from "graphql-parse-resolve-info";
6163
5747
 
6164
- // src/util/builders/schema-data.ts
6165
- import { is as is12, One as One9 } from "drizzle-orm";
6166
- import { GraphQLInt as GraphQLInt9, GraphQLList as GraphQLList12, GraphQLNonNull as GraphQLNonNull16 } from "graphql";
5748
+ // src/util/builders/errors.ts
5749
+ var missingQueryBuilderError = (tableName) => new Error(
5750
+ `Drizzle-GraphQL Error: Table '${tableName}' was passed to the drizzle constructor's schema but is missing from its relations config, so drizzle-orm exposes no query builder for it. Include it in the relations you pass to buildRelations/defineRelations, or drop it from the generated schema with config.exclude.tables.`
5751
+ );
6167
5752
 
6168
- // src/util/builders/nested-writes.ts
6169
- import { and as and11, Column, eq as eq8, getColumns as getColumns16, inArray as inArray6, is as is11, One as One8 } from "drizzle-orm";
6170
- import { GraphQLBoolean as GraphQLBoolean6, GraphQLInputObjectType as GraphQLInputObjectType11, GraphQLList as GraphQLList10, GraphQLNonNull as GraphQLNonNull14 } from "graphql";
6171
- var isOptionalOnInsert = (column) => !column.notNull || !!column.hasDefault || !!column.defaultFn;
6172
- var propNameOf = (table, column) => {
6173
- if (!column) {
6174
- return void 0;
6175
- }
6176
- for (const [propName, candidate] of Object.entries(getColumns16(table))) {
6177
- if (candidate === column) {
6178
- return propName;
6179
- }
5753
+ // src/util/builders/select.ts
5754
+ var queryBaseFor = (db, tableName) => {
5755
+ const queryBase = db.query[tableName];
5756
+ if (!queryBase) {
5757
+ throw missingQueryBuilderError(tableName);
6180
5758
  }
6181
- return void 0;
5759
+ return queryBase;
6182
5760
  };
6183
- var throughColumn = (entry) => entry && is11(entry, Column) ? entry : entry?._?.column;
6184
- var buildThroughPlan = (relationName, relation, table, targetTableName, targetTable) => {
6185
- if (is11(relation, One8)) {
6186
- return void 0;
6187
- }
6188
- const junction = relation.throughTable;
6189
- const sourceEntries = relation.through?.source;
6190
- const targetEntries = relation.through?.target;
6191
- if (!junction || sourceEntries?.length !== 1 || targetEntries?.length !== 1) {
6192
- return void 0;
6193
- }
6194
- if (relation.sourceColumns?.length !== 1 || relation.targetColumns?.length !== 1) {
6195
- return void 0;
6196
- }
6197
- const localCol = relation.sourceColumns[0];
6198
- const foreignCol = relation.targetColumns[0];
6199
- const localColPropName = propNameOf(table, localCol);
6200
- const foreignColPropName = propNameOf(targetTable, foreignCol);
6201
- const sourceColPropName = propNameOf(junction, throughColumn(sourceEntries[0]));
6202
- const targetColPropName = propNameOf(junction, throughColumn(targetEntries[0]));
6203
- if (!localColPropName || !foreignColPropName || !sourceColPropName || !targetColPropName) {
6204
- return void 0;
6205
- }
6206
- const junctionColumns = getColumns16(junction);
6207
- const sourceCol = junctionColumns[sourceColPropName];
6208
- const targetCol = junctionColumns[targetColPropName];
6209
- const unsuppliable = Object.entries(junctionColumns).some(
6210
- ([propName, column]) => propName !== sourceColPropName && propName !== targetColPropName && !isOptionalOnInsert(column)
6211
- );
6212
- if (unsuppliable) {
6213
- return void 0;
6214
- }
6215
- return {
6216
- relationName,
6217
- targetTableName,
6218
- targetTable,
6219
- localColPropName,
6220
- foreignColPropName,
6221
- foreignCol,
6222
- localCol,
6223
- isOne: false,
6224
- // The link is written after the parent row exists, exactly like a child-side foreign key.
6225
- fkSide: "child",
6226
- canDetach: true,
6227
- through: { table: junction, sourceColPropName, targetColPropName, sourceCol, targetCol }
5761
+ var createSelectGenerators = (primaryKeyPropNames, nullOrdering) => {
5762
+ const generateSelectArray = (db, tableName, tables, relationMap, orderArgs, filterArgs, fieldName, typeName, typeNameMapper, filterCtx, distinctEnabled = true, limits, policies, resolveName) => {
5763
+ const queryBase = queryBaseFor(db, tableName);
5764
+ const table = tables[tableName];
5765
+ const limitPolicy = limits?.(tableName);
5766
+ const pkNames = primaryKeyPropNames(table);
5767
+ const errorCtx = { table: tableName, operation: "select", field: fieldName };
5768
+ const queryArgs = selectArrayArgs(
5769
+ orderArgs,
5770
+ filterArgs,
5771
+ distinctEnabled ? generateDistinctEnum(table, typeName, resolveName, tableName) : void 0,
5772
+ policies?.softDelete,
5773
+ tableName,
5774
+ resolveName
5775
+ );
5776
+ const objectTypeName = resolveObjectTypeName(tableName, typeNameMapper, resolveName);
5777
+ return {
5778
+ name: fieldName,
5779
+ resolver: async (_source, rawArgs, context, info) => {
5780
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
5781
+ try {
5782
+ const parsedInfo = parseResolveInfo2(info, { deep: true });
5783
+ const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
5784
+ return await runRelationalSelect({
5785
+ queryBase: requestQueryBase,
5786
+ tables,
5787
+ tableName,
5788
+ table,
5789
+ relationMap,
5790
+ typeName: objectTypeName,
5791
+ typeNameMapper,
5792
+ resolveName,
5793
+ parsedInfo,
5794
+ ...args,
5795
+ limit: applyLimitPolicy(args.limit, limitPolicy),
5796
+ single: false,
5797
+ filterCtx,
5798
+ limits,
5799
+ defaultOrderBy: policies?.defaultOrderBy,
5800
+ pkNames,
5801
+ db: executor,
5802
+ scope: policies?.scope?.(context),
5803
+ nullOrdering
5804
+ });
5805
+ } catch (e) {
5806
+ throw withErrorContext(toGraphQLError(e), errorCtx);
5807
+ }
5808
+ },
5809
+ args: queryArgs
5810
+ };
5811
+ };
5812
+ const generateSelectSingle = (db, tableName, tables, relationMap, orderArgs, filterArgs, fieldName, typeName, typeNameMapper, filterCtx, limits, policies, resolveName) => {
5813
+ const queryBase = queryBaseFor(db, tableName);
5814
+ const queryArgs = selectSingleArgs(orderArgs, filterArgs, policies?.softDelete, tableName, resolveName);
5815
+ const objectTypeName = resolveObjectTypeName(tableName, typeNameMapper, resolveName);
5816
+ const table = tables[tableName];
5817
+ const pkNames = primaryKeyPropNames(table);
5818
+ const errorCtx = { table: tableName, operation: "select", field: fieldName };
5819
+ return {
5820
+ name: fieldName,
5821
+ resolver: async (_source, rawArgs, context, info) => {
5822
+ const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
5823
+ try {
5824
+ const parsedInfo = parseResolveInfo2(info, { deep: true });
5825
+ const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
5826
+ return await runRelationalSelect({
5827
+ queryBase: requestQueryBase,
5828
+ tables,
5829
+ tableName,
5830
+ table,
5831
+ relationMap,
5832
+ typeName: objectTypeName,
5833
+ typeNameMapper,
5834
+ resolveName,
5835
+ parsedInfo,
5836
+ ...args,
5837
+ single: true,
5838
+ filterCtx,
5839
+ limits,
5840
+ defaultOrderBy: policies?.defaultOrderBy,
5841
+ pkNames,
5842
+ db: executor,
5843
+ scope: policies?.scope?.(context)
5844
+ });
5845
+ } catch (e) {
5846
+ throw withErrorContext(toGraphQLError(e), errorCtx);
5847
+ }
5848
+ },
5849
+ args: queryArgs
5850
+ };
6228
5851
  };
5852
+ return { generateSelectArray, generateSelectSingle };
6229
5853
  };
6230
- var buildNestedWritePlans = (tables, relationMap, resolveUniqueSets, resolvePrimaryKeys, extractJoinColumns) => {
6231
- const uniqueCache = /* @__PURE__ */ new Map();
6232
- const singleColumnUniques = (tableName, table) => {
6233
- let cached = uniqueCache.get(tableName);
6234
- if (!cached) {
6235
- cached = new Set(
6236
- resolveUniqueSets(table).filter((set) => set.length === 1).map((set) => set[0])
5854
+
5855
+ // src/util/builders/build-context.ts
5856
+ var createSchemaBuilder = (adapter) => {
5857
+ const primaryKeyPropNames = adapter.primaryKeyPropNames;
5858
+ const uniqueColumnSets = (table) => getUniqueColumnSets(table, adapter.getTableConfig);
5859
+ const { generateSelectArray, generateSelectSingle } = createSelectGenerators(
5860
+ primaryKeyPropNames,
5861
+ adapter.nullOrdering
5862
+ );
5863
+ const prepareBuild2 = (db, schema, relations, options) => {
5864
+ const { relationsDepthLimit, prefixes, typeNameMapper, shouldEagerLoad, features, complexity, limits } = options;
5865
+ const schemaEntries = Object.entries(schema);
5866
+ const excludedTables = new Set(options.exclude?.tables ?? []);
5867
+ const tableEntries = schemaEntries.filter(
5868
+ ([key, value]) => is11(value, adapter.tableClass) && !excludedTables.has(key)
5869
+ );
5870
+ const tables = Object.fromEntries(tableEntries);
5871
+ const featureOf = resolveTableFeatures(features);
5872
+ const anyTable = (feature) => tableEntries.some(([name]) => featureOf(name)[feature]);
5873
+ if (!tableEntries.length) {
5874
+ throw new Error(
5875
+ "Drizzle-GraphQL Error: No tables detected in Drizzle-ORM's database instance. Did you forget to pass schema to drizzle constructor?"
6237
5876
  );
6238
- uniqueCache.set(tableName, cached);
6239
- }
6240
- return cached;
6241
- };
6242
- const pkCache = /* @__PURE__ */ new Map();
6243
- const singleColumnPk = (tableName, table) => {
6244
- if (!pkCache.has(tableName)) {
6245
- const pk = resolvePrimaryKeys(table);
6246
- pkCache.set(tableName, pk.length === 1 ? pk[0] : void 0);
6247
5877
  }
6248
- return pkCache.get(tableName);
6249
- };
6250
- const plans = {};
6251
- for (const [tableName, relations] of Object.entries(relationMap)) {
6252
- const table = tables[tableName];
6253
- if (!table) {
6254
- continue;
5878
+ registerScalarOverrides(tables, options);
5879
+ registerEnumConfig(options);
5880
+ registerColumnExclusions(tables, options.exclude);
5881
+ const namedRelations = buildNamedRelations(relations ?? {}, tableEntries);
5882
+ for (const excluded of excludedTables) {
5883
+ delete namedRelations[excluded];
6255
5884
  }
6256
- const tablePlans = {};
6257
- for (const [relationName, relEntry] of Object.entries(relations)) {
6258
- const relation = relEntry.relation;
6259
- const targetTableName = relEntry.targetTableName;
6260
- const targetTable = tables[targetTableName];
6261
- if (!targetTable) {
6262
- continue;
6263
- }
6264
- if (relation.through) {
6265
- const throughPlan = buildThroughPlan(relationName, relation, table, targetTableName, targetTable);
6266
- if (throughPlan) {
6267
- tablePlans[relationName] = throughPlan;
6268
- }
6269
- continue;
6270
- }
6271
- const joinColumns = extractJoinColumns(relEntry, table, targetTable);
6272
- if (!joinColumns) {
6273
- continue;
6274
- }
6275
- const { localColPropName, foreignCol, foreignColPropName } = joinColumns;
6276
- const localCol = getColumns16(table)[localColPropName];
6277
- if (!localCol) {
5885
+ attachTargetPrimaryKeys(namedRelations, tables, (table) => primaryKeyPropNames(table));
5886
+ const eagerRelations = pruneNonEagerRelations(namedRelations, shouldEagerLoad);
5887
+ const uniqueKeys = {};
5888
+ for (const [tableName, table] of tableEntries) {
5889
+ if (!featureOf(tableName).uniqueKeyFilters) {
6278
5890
  continue;
6279
5891
  }
6280
- const isOne = is11(relation, One8);
6281
- const localIsPk = singleColumnPk(tableName, table) === localColPropName;
6282
- const foreignIsPk = singleColumnPk(targetTableName, targetTable) === foreignColPropName;
6283
- const localIsUnique = singleColumnUniques(tableName, table).has(localColPropName);
6284
- const foreignIsUnique = singleColumnUniques(targetTableName, targetTable).has(foreignColPropName);
6285
- let fkSide;
6286
- if (!isOne) {
6287
- fkSide = "child";
6288
- } else if (foreignIsPk && !localIsPk) {
6289
- fkSide = "parent";
6290
- } else if (localIsPk) {
6291
- fkSide = "child";
6292
- } else if (foreignIsUnique) {
6293
- fkSide = "parent";
6294
- } else if (localIsUnique) {
6295
- fkSide = "child";
6296
- } else {
6297
- continue;
5892
+ const taken = /* @__PURE__ */ new Set([...Object.keys(visibleColumns(table)), ...Object.keys(namedRelations[tableName] ?? {})]);
5893
+ const map = buildUniqueKeyMap(uniqueColumnSets(table), taken);
5894
+ if (Object.keys(map).length) {
5895
+ uniqueKeys[tableName] = map;
6298
5896
  }
6299
- const fkColumn = fkSide === "child" ? foreignCol : localCol;
6300
- tablePlans[relationName] = {
6301
- relationName,
6302
- targetTableName,
6303
- targetTable,
6304
- localColPropName,
6305
- foreignColPropName,
6306
- foreignCol,
6307
- localCol,
6308
- isOne,
6309
- fkSide,
6310
- canDetach: !fkColumn.notNull
6311
- };
6312
- }
6313
- if (Object.keys(tablePlans).length) {
6314
- plans[tableName] = tablePlans;
6315
- }
6316
- }
6317
- return plans;
6318
- };
6319
- var NO_COLUMNS = /* @__PURE__ */ new Set();
6320
- var createNestedWriteTypes = (params) => {
6321
- const { plans, cacheCtx, typeNameMapper } = params;
6322
- const wrapperCache = /* @__PURE__ */ new Map();
6323
- const payloadCache = /* @__PURE__ */ new Map();
6324
- const payloadType = (tableName, typeName, plan) => {
6325
- const key = `${tableName}.${plan.relationName}`;
6326
- const cached = payloadCache.get(key);
6327
- if (cached) {
6328
- return cached;
6329
5897
  }
6330
- const omitted = plan.fkSide === "child" ? plan.foreignColPropName : void 0;
6331
- const contextColumns = cacheCtx.contextValuesOf?.(plan.targetTableName);
6332
- const fields = Object.fromEntries(
6333
- Object.entries(visibleColumns(plan.targetTable)).filter(([columnName]) => columnName !== omitted && !contextColumns?.[columnName]).map(([columnName, column]) => [
6334
- columnName,
6335
- drizzleColumnToGraphQLType(column, columnName, plan.targetTableName, false, true, true)
6336
- ])
5898
+ const filterCtx = { tables, relationMap: namedRelations, uniqueKeys };
5899
+ const tablePolicies = options.policies;
5900
+ const contextValuesOf = tablePolicies?.contextValues;
5901
+ const softDeleteOf = tablePolicies?.softDelete;
5902
+ const policies = bindPolicies(tablePolicies, filterCtx);
5903
+ const resolverFactory = createRelationResolverFactory(
5904
+ db,
5905
+ tables,
5906
+ adapter.nullOrdering,
5907
+ filterCtx,
5908
+ limits,
5909
+ tablePolicies
6337
5910
  );
6338
- const type = new GraphQLInputObjectType11({
6339
- name: cacheCtx.typeName({
6340
- kind: "nestedWriteInput",
6341
- defaultName: `${typeName}${capitalize(plan.relationName)}NestedCreatePayloadInput`,
6342
- table: tableName,
6343
- operation: plan.relationName
6344
- }),
6345
- description: omitted === void 0 ? `A new ${resolveTypeName(plan.targetTableName, typeNameMapper)} row for ${typeName}.${plan.relationName}` : `A new ${resolveTypeName(plan.targetTableName, typeNameMapper)} row for ${typeName}.${plan.relationName}. \`${omitted}\` is set from the ${typeName} row this is written with.`,
6346
- fields
6347
- });
6348
- payloadCache.set(key, type);
6349
- return type;
6350
- };
6351
- const targetFilters = (plan) => cacheCtx.filterTypeCache.get(plan.targetTable);
6352
- const listOf = (type) => new GraphQLList10(new GraphQLNonNull14(type));
6353
- const wrapperType = (tableName, typeName, plan, forUpdate) => {
6354
- const key = `${tableName}.${plan.relationName}.${forUpdate ? "update" : "create"}`;
6355
- const cached = wrapperCache.get(key);
6356
- if (cached) {
6357
- return cached;
6358
- }
6359
- const filters = targetFilters(plan);
6360
- const targetTypeName = resolveTypeName(plan.targetTableName, typeNameMapper);
6361
- const fields = {};
6362
- if (plan.through) {
6363
- if (!filters) {
6364
- return void 0;
6365
- }
6366
- fields["connect"] = {
6367
- type: listOf(filters),
6368
- description: `Link every existing ${targetTypeName} row these match. Already-linked rows are left alone.`
6369
- };
6370
- if (forUpdate) {
6371
- fields["disconnect"] = {
6372
- type: listOf(filters),
6373
- description: `Unlink every linked ${targetTypeName} row these match, leaving the rows in place`
6374
- };
6375
- fields["set"] = {
6376
- type: listOf(filters),
6377
- description: `Replace the whole set: unlink everything linked, then link every ${targetTypeName} row these match. \`set: []\` clears the relation. Applied before \`disconnect\` and \`connect\`.`
6378
- };
6379
- }
6380
- } else if (plan.isOne) {
6381
- fields["create"] = {
6382
- type: payloadType(tableName, typeName, plan),
6383
- description: `Insert a ${targetTypeName} row and attach it`
6384
- };
6385
- if (filters) {
6386
- fields["connect"] = {
6387
- type: filters,
6388
- description: `Attach the existing ${targetTypeName} row this matches. Must match exactly one row.`
6389
- };
5911
+ const cacheCtx = {
5912
+ typeName: options.typeName ?? ((info) => info.defaultName),
5913
+ genericFilterCache: /* @__PURE__ */ new Map(),
5914
+ objectTypeCache: /* @__PURE__ */ new Map(),
5915
+ relationFieldContainers: /* @__PURE__ */ new Map(),
5916
+ fullyBuiltTables: /* @__PURE__ */ new Set(),
5917
+ relationTypeCache: /* @__PURE__ */ new Map(),
5918
+ selectFieldCache: /* @__PURE__ */ new WeakMap(),
5919
+ filterFieldCache: /* @__PURE__ */ new WeakMap(),
5920
+ orderTypeCache: /* @__PURE__ */ new WeakMap(),
5921
+ filterTypeCache: /* @__PURE__ */ new WeakMap(),
5922
+ listRelationFilterCache: /* @__PURE__ */ new Map(),
5923
+ aggregateTypeCache: /* @__PURE__ */ new Map(),
5924
+ complexity,
5925
+ limits,
5926
+ docs: options.docs ?? {},
5927
+ primaryKeyOf: (name) => tables[name] ? primaryKeyPropNames(tables[name]) : [],
5928
+ contextValuesOf,
5929
+ softDeleteOf,
5930
+ featureOf,
5931
+ uniqueKeysOf: (tableName) => uniqueKeys[tableName]
5932
+ };
5933
+ adapter.preflight?.(db, options);
5934
+ const nestedPlans = features.nestedWrites ? buildNestedWritePlans(
5935
+ tables,
5936
+ namedRelations,
5937
+ (target) => uniqueColumnSets(target),
5938
+ (target) => primaryKeyPropNames(target),
5939
+ extractRelationJoinColumns
5940
+ ) : void 0;
5941
+ const nestedTypes = nestedPlans ? createNestedWriteTypes({ plans: nestedPlans, cacheCtx, typeNameMapper }) : void 0;
5942
+ const nestedRuntime = nestedPlans ? createNestedWriteRuntime({
5943
+ plans: nestedPlans,
5944
+ filterCtx,
5945
+ policies: tablePolicies,
5946
+ contextValues: contextValuesOf
5947
+ }) : void 0;
5948
+ const relationAggregateFactory = anyTable("relationAggregates") ? createRelationAggregateFactory(db, tables, cacheCtx, typeNameMapper, filterCtx, tablePolicies) : void 0;
5949
+ const gqlSchemaTypes = Object.fromEntries(
5950
+ Object.entries(tables).map(([tableName, _table]) => [
5951
+ tableName,
5952
+ generateTableTypes(
5953
+ tableName,
5954
+ tables,
5955
+ namedRelations,
5956
+ adapter.returnsRows,
5957
+ relationsDepthLimit,
5958
+ cacheCtx,
5959
+ typeNameMapper,
5960
+ prefixes.insert,
5961
+ prefixes.update,
5962
+ resolverFactory,
5963
+ featureOf(tableName).relationAggregates ? relationAggregateFactory : void 0,
5964
+ nestedTypes
5965
+ )
5966
+ ])
5967
+ );
5968
+ return {
5969
+ db,
5970
+ schema,
5971
+ options,
5972
+ tables,
5973
+ tableEntries,
5974
+ featureOf,
5975
+ anyTable,
5976
+ namedRelations,
5977
+ eagerRelations,
5978
+ filterCtx,
5979
+ tablePolicies,
5980
+ policies,
5981
+ softDeleteOf,
5982
+ resolverFactory,
5983
+ cacheCtx,
5984
+ nestedRuntime,
5985
+ nestedTypes,
5986
+ // Shared per-request transaction machinery for multi-mutation documents; undefined
5987
+ // unless `transactions: 'auto'`. Its field-name set is filled once all mutations exist.
5988
+ mutationTxCtx: createMutationTxCtx(options.transactions),
5989
+ gqlSchemaTypes,
5990
+ queries: {},
5991
+ mutations: {},
5992
+ inputs: {},
5993
+ outputs: {},
5994
+ limits,
5995
+ typeNameMapper
5996
+ };
5997
+ };
5998
+ const addReadFields2 = (ctx, tableName, names, tableTypes, drizzleMeta) => {
5999
+ const { db, tables, cacheCtx, filterCtx, eagerRelations, policies, tablePolicies, limits, typeNameMapper } = ctx;
6000
+ const { complexity } = ctx.options;
6001
+ const table = tables[tableName];
6002
+ const tableFeatures = ctx.featureOf(tableName);
6003
+ const { tableFilters, tableOrder } = tableTypes.inputs;
6004
+ const { selectSingleOutput, selectArrOutput } = tableTypes.outputs;
6005
+ const { typeName, listFieldName, singleFieldName, aggregateFieldName, groupByFieldName } = names;
6006
+ const selectArrGenerated = generateSelectArray(
6007
+ db,
6008
+ tableName,
6009
+ tables,
6010
+ eagerRelations,
6011
+ tableOrder,
6012
+ tableFilters,
6013
+ listFieldName,
6014
+ typeName,
6015
+ typeNameMapper,
6016
+ filterCtx,
6017
+ tableFeatures.distinct,
6018
+ limits,
6019
+ policies,
6020
+ cacheCtx.typeName
6021
+ );
6022
+ const selectSingleGenerated = generateSelectSingle(
6023
+ db,
6024
+ tableName,
6025
+ tables,
6026
+ eagerRelations,
6027
+ tableOrder,
6028
+ tableFilters,
6029
+ singleFieldName,
6030
+ typeName,
6031
+ typeNameMapper,
6032
+ filterCtx,
6033
+ limits,
6034
+ policies,
6035
+ cacheCtx.typeName
6036
+ );
6037
+ const aggregateType = tableFeatures.aggregates ? generateAggregateTypes(table, tableName, typeName, cacheCtx) : void 0;
6038
+ const aggregateGenerated = tableFeatures.aggregates ? generateAggregate(
6039
+ db,
6040
+ tableName,
6041
+ table,
6042
+ typeName,
6043
+ aggregateFieldName,
6044
+ tableFilters,
6045
+ filterCtx,
6046
+ tablePolicies,
6047
+ cacheCtx.typeName
6048
+ ) : void 0;
6049
+ const groupByType = tableFeatures.aggregates && tableFeatures.groupBy ? generateGroupByType(table, tableName, typeName, cacheCtx) : void 0;
6050
+ const groupByEnum = groupByType ? generateGroupByEnum(table, tableName, typeName, cacheCtx) : void 0;
6051
+ const havingInput = groupByEnum ? generateHavingInput(table, tableName, typeName, cacheCtx) : void 0;
6052
+ const groupByGenerated = groupByType && groupByEnum && havingInput ? generateGroupBy(
6053
+ db,
6054
+ tableName,
6055
+ table,
6056
+ typeName,
6057
+ groupByFieldName,
6058
+ tableFilters,
6059
+ groupByEnum,
6060
+ havingInput,
6061
+ filterCtx,
6062
+ tablePolicies,
6063
+ cacheCtx.typeName
6064
+ ) : void 0;
6065
+ ctx.queries[selectArrGenerated.name] = {
6066
+ type: selectArrOutput,
6067
+ args: selectArrGenerated.args,
6068
+ resolve: selectArrGenerated.resolver,
6069
+ extensions: {
6070
+ drizzle: drizzleMeta({ kind: "query", operation: "select", single: false, targetArg: "where" }),
6071
+ ...complexity ? { complexity: listFieldComplexity(complexity, limits?.(tableName)) } : {}
6390
6072
  }
6391
- if (forUpdate && plan.canDetach) {
6392
- fields["disconnect"] = {
6393
- type: GraphQLBoolean6,
6394
- description: `Detach the currently attached ${targetTypeName} row, leaving it in place`
6395
- };
6073
+ };
6074
+ ctx.queries[selectSingleGenerated.name] = {
6075
+ type: selectSingleOutput,
6076
+ args: selectSingleGenerated.args,
6077
+ resolve: selectSingleGenerated.resolver,
6078
+ extensions: {
6079
+ drizzle: drizzleMeta({ kind: "query", operation: "select", single: true, targetArg: "where" })
6396
6080
  }
6397
- } else {
6398
- fields["create"] = {
6399
- type: listOf(payloadType(tableName, typeName, plan)),
6400
- description: `Insert these ${targetTypeName} rows and attach them`
6401
- };
6402
- if (filters) {
6403
- fields["connect"] = {
6404
- type: listOf(filters),
6405
- description: `Attach every existing ${targetTypeName} row these match`
6406
- };
6407
- if (forUpdate && plan.canDetach) {
6408
- fields["disconnect"] = {
6409
- type: listOf(filters),
6410
- description: `Detach every attached ${targetTypeName} row these match, leaving the rows in place`
6411
- };
6412
- fields["set"] = {
6413
- type: listOf(filters),
6414
- description: `Replace the whole set: detach everything attached, then attach every ${targetTypeName} row these match. Applied before \`disconnect\`, \`connect\` and \`create\`.`
6415
- };
6081
+ };
6082
+ if (aggregateGenerated && aggregateType) {
6083
+ ctx.queries[aggregateGenerated.name] = {
6084
+ type: new GraphQLNonNull14(aggregateType),
6085
+ args: aggregateGenerated.args,
6086
+ resolve: aggregateGenerated.resolver,
6087
+ extensions: {
6088
+ drizzle: drizzleMeta({ kind: "aggregate", operation: "aggregate", single: true, targetArg: "where" }),
6089
+ ...complexity ? { complexity: aggregateFieldComplexity(complexity) } : {}
6416
6090
  }
6417
- }
6091
+ };
6418
6092
  }
6419
- const type = new GraphQLInputObjectType11({
6420
- name: cacheCtx.typeName({
6421
- kind: "nestedWriteInput",
6422
- defaultName: `${typeName}${capitalize(plan.relationName)}Nested${forUpdate ? "Update" : "Create"}Input`,
6423
- table: tableName,
6424
- operation: plan.relationName
6425
- }),
6426
- description: `Writes through ${typeName}.${plan.relationName}`,
6427
- fields
6428
- });
6429
- wrapperCache.set(key, type);
6430
- return type;
6431
- };
6432
- const relationFields = (tableName, typeName, forUpdate) => {
6433
- const tablePlans = plans[tableName];
6434
- if (!tablePlans) {
6435
- return {};
6093
+ if (groupByGenerated && groupByType) {
6094
+ ctx.queries[groupByGenerated.name] = {
6095
+ type: new GraphQLNonNull14(new GraphQLList10(new GraphQLNonNull14(groupByType))),
6096
+ args: groupByGenerated.args,
6097
+ resolve: groupByGenerated.resolver,
6098
+ extensions: {
6099
+ drizzle: drizzleMeta({ kind: "aggregate", operation: "groupBy", single: false, targetArg: "where" }),
6100
+ ...complexity ? { complexity: aggregateFieldComplexity(complexity) } : {}
6101
+ }
6102
+ };
6436
6103
  }
6437
- return Object.fromEntries(
6438
- Object.values(tablePlans).flatMap((plan) => {
6439
- const wrapper = wrapperType(tableName, typeName, plan, forUpdate);
6440
- return wrapper ? [[plan.relationName, { type: wrapper, description: `Writes through ${typeName}.${plan.relationName}` }]] : [];
6441
- })
6442
- );
6104
+ return { aggregateType, groupByType, havingInput };
6443
6105
  };
6444
- return {
6445
- createFields: (tableName, typeName) => relationFields(tableName, typeName, false),
6446
- updateFields: (tableName, typeName) => relationFields(tableName, typeName, true),
6447
- relaxedColumns: (tableName) => {
6448
- const tablePlans = plans[tableName];
6449
- if (!tablePlans) {
6450
- return NO_COLUMNS;
6106
+ const finalizeBuild2 = (ctx) => {
6107
+ if (ctx.mutationTxCtx) {
6108
+ for (const name of Object.keys(ctx.mutations)) {
6109
+ ctx.mutationTxCtx.fieldNames.add(name);
6451
6110
  }
6452
- const relaxed = /* @__PURE__ */ new Set();
6453
- for (const plan of Object.values(tablePlans)) {
6454
- if (plan.fkSide === "parent" && !isOptionalOnInsert(plan.localCol)) {
6455
- relaxed.add(plan.localColPropName);
6111
+ }
6112
+ const fieldResolvers = {};
6113
+ for (const [tableName, tableRelations] of Object.entries(ctx.namedRelations)) {
6114
+ const relResolvers = {};
6115
+ for (const [relName, relEntry] of Object.entries(tableRelations)) {
6116
+ const isOne = is11(relEntry.relation ?? relEntry, One8);
6117
+ const resolver = ctx.resolverFactory({ tableName, relationName: relName, relEntry, isOne });
6118
+ if (resolver) {
6119
+ relResolvers[relName] = resolver;
6456
6120
  }
6457
6121
  }
6458
- return relaxed.size ? relaxed : NO_COLUMNS;
6122
+ if (Object.keys(relResolvers).length > 0) {
6123
+ fieldResolvers[tableName] = relResolvers;
6124
+ }
6459
6125
  }
6460
- };
6126
+ return {
6127
+ queries: ctx.queries,
6128
+ mutations: ctx.mutations,
6129
+ inputs: ctx.inputs,
6130
+ types: ctx.outputs,
6131
+ fieldResolvers
6132
+ };
6133
+ };
6134
+ return { primaryKeyPropNames, uniqueColumnSets, prepareBuild: prepareBuild2, addReadFields: addReadFields2, finalizeBuild: finalizeBuild2 };
6461
6135
  };
6462
- var mergedOps = (entries) => Object.assign({}, ...entries.map((entry) => entry.ops));
6463
- var asArray = (value) => Array.isArray(value) ? value : value === void 0 ? [] : [value];
6464
- var createNestedWriteRuntime = (params) => {
6465
- const { plans, filterCtx, policies, contextValues } = params;
6466
- const conditionOf = (plan, filter, operation, scope) => {
6467
- const condition = extractFilters(
6468
- plan.targetTable,
6469
- plan.targetTableName,
6470
- filter,
6471
- relationFilterCtx(filterCtx, plan.targetTableName)
6136
+
6137
+ // src/util/builders/mysql.ts
6138
+ var isSuccess = { isSuccess: true };
6139
+ var generateInsertArray = (db, tableName, table, baseType, fieldName, txCtx, policies) => writeResolver({
6140
+ db,
6141
+ tableName,
6142
+ operation: "insert",
6143
+ single: false,
6144
+ fieldName,
6145
+ txCtx,
6146
+ policies,
6147
+ args: {
6148
+ values: {
6149
+ type: new GraphQLNonNull15(new GraphQLList11(new GraphQLNonNull15(baseType)))
6150
+ }
6151
+ },
6152
+ run: async ({ executor, args, context, before, after }) => {
6153
+ const input = applyContextValuesAll(
6154
+ remapFromGraphQLArrayInput(args.values, table),
6155
+ policies?.contextValues?.(tableName),
6156
+ context
6472
6157
  );
6473
- if (!condition) {
6474
- throw drizzleError(
6475
- `Drizzle-GraphQL Error: '${operation}' on '${plan.relationName}' needs a filter that selects rows \u2014 it was given one that matches everything.`,
6476
- { code: "DRIZZLE_NESTED_WRITE_INVALID" }
6477
- );
6158
+ if (!input.length) {
6159
+ throw drizzleError("No values were provided!", { code: "DRIZZLE_NO_VALUES" });
6478
6160
  }
6479
- return withScope(scope, plan.targetTableName, plan.targetTable, condition);
6480
- };
6481
- const assertSingleOperation = (plan, op) => {
6482
- const supplied = ["create", "connect", "disconnect"].filter((key) => op[key] !== void 0 && op[key] !== null);
6483
- if (supplied.length > 1) {
6484
- throw drizzleError(
6485
- `Drizzle-GraphQL Error: '${plan.relationName}' takes one of ${supplied.join(", ")} at a time \u2014 it holds a single row.`,
6486
- { code: "DRIZZLE_NESTED_WRITE_INVALID" }
6487
- );
6161
+ await before();
6162
+ await executor.insert(table).values(input);
6163
+ await after();
6164
+ return isSuccess;
6165
+ }
6166
+ });
6167
+ var generateInsertSingle = (db, tableName, table, baseType, fieldName, txCtx, policies) => writeResolver({
6168
+ db,
6169
+ tableName,
6170
+ operation: "insert",
6171
+ single: true,
6172
+ fieldName,
6173
+ txCtx,
6174
+ policies,
6175
+ args: {
6176
+ values: {
6177
+ type: new GraphQLNonNull15(baseType)
6488
6178
  }
6489
- };
6490
- const selectedTargetKeys = async (executor, plan, filter, operation, scope) => {
6491
- const rows = await executor.select().from(plan.targetTable).where(conditionOf(plan, filter, operation, scope));
6492
- return rows.map((row) => row[plan.foreignColPropName]).filter((value) => value !== void 0 && value !== null);
6493
- };
6494
- const applyThroughOps = async (executor, plan, key, op, scope) => {
6495
- const through = plan.through;
6496
- const unlinkAll = () => executor.delete(through.table).where(eq8(through.sourceCol, key));
6497
- const link = async (operands, operation) => {
6498
- const existing = new Set(
6499
- (await executor.select().from(through.table).where(eq8(through.sourceCol, key))).map(
6500
- (row) => row[through.targetColPropName]
6501
- )
6179
+ },
6180
+ run: async ({ executor, args, context, before, after }) => {
6181
+ await before();
6182
+ const input = applyContextValues(
6183
+ remapFromGraphQLSingleInput(args.values, table),
6184
+ policies?.contextValues?.(tableName),
6185
+ context
6186
+ );
6187
+ await executor.insert(table).values(input);
6188
+ await after();
6189
+ return isSuccess;
6190
+ }
6191
+ });
6192
+ var generateUpsert = (db, tableName, table, baseType, onConflictType, fieldName, single, txCtx, policies) => {
6193
+ const pkNames = mysqlPrimaryKeyPropNames(table);
6194
+ return writeResolver({
6195
+ db,
6196
+ tableName,
6197
+ operation: "upsert",
6198
+ single,
6199
+ fieldName,
6200
+ txCtx,
6201
+ policies,
6202
+ args: {
6203
+ values: {
6204
+ type: single ? new GraphQLNonNull15(baseType) : new GraphQLNonNull15(new GraphQLList11(new GraphQLNonNull15(baseType)))
6205
+ },
6206
+ onConflict: {
6207
+ type: onConflictType,
6208
+ description: "How a conflicting row is resolved. Defaults to overwriting it."
6209
+ }
6210
+ },
6211
+ run: async ({ executor, args, context, before, after }) => {
6212
+ const input = applyContextValuesAll(
6213
+ single ? [remapFromGraphQLSingleInput(args.values, table)] : remapFromGraphQLArrayInput(args.values, table),
6214
+ policies?.contextValues?.(tableName),
6215
+ context
6502
6216
  );
6503
- const rows = [];
6504
- for (const filter of operands) {
6505
- for (const targetKey of await selectedTargetKeys(executor, plan, filter, operation, scope)) {
6506
- if (!existing.has(targetKey)) {
6507
- existing.add(targetKey);
6508
- rows.push({ [through.sourceColPropName]: key, [through.targetColPropName]: targetKey });
6509
- }
6510
- }
6217
+ if (!input.length) {
6218
+ throw drizzleError("No values were provided!", { code: "DRIZZLE_NO_VALUES" });
6511
6219
  }
6512
- if (rows.length) {
6513
- await executor.insert(through.table).values(rows);
6220
+ await before();
6221
+ const plan = resolveConflictPlan({
6222
+ table,
6223
+ values: input,
6224
+ onConflict: args.onConflict,
6225
+ pkNames,
6226
+ uniqueSets: [],
6227
+ excludedRef: mysqlValuesColumnRef,
6228
+ withTarget: false
6229
+ });
6230
+ if (plan.action === "NOTHING") {
6231
+ await executor.insert(table).ignore().values(input);
6232
+ } else {
6233
+ await executor.insert(table).values(input).onDuplicateKeyUpdate({ set: plan.set });
6514
6234
  }
6515
- };
6516
- if (op["set"] !== void 0 && op["set"] !== null) {
6517
- await unlinkAll();
6518
- await link(asArray(op["set"]), "set");
6235
+ await after();
6236
+ return isSuccess;
6519
6237
  }
6520
- if (op["disconnect"] !== void 0 && op["disconnect"] !== null) {
6521
- for (const filter of asArray(op["disconnect"])) {
6522
- const targetKeys = await selectedTargetKeys(executor, plan, filter, "disconnect", scope);
6523
- if (targetKeys.length) {
6524
- await executor.delete(through.table).where(and11(eq8(through.sourceCol, key), inArray6(through.targetCol, targetKeys)));
6525
- }
6526
- }
6238
+ });
6239
+ };
6240
+ var generateUpdate = (db, tableName, table, setArgs, filterArgs, fieldName, single, requireWhere, filterCtx, txCtx, policies) => writeResolver({
6241
+ db,
6242
+ tableName,
6243
+ operation: "update",
6244
+ single,
6245
+ fieldName,
6246
+ txCtx,
6247
+ policies,
6248
+ args: {
6249
+ set: {
6250
+ type: new GraphQLNonNull15(setArgs)
6251
+ },
6252
+ where: {
6253
+ type: single || requireWhere ? new GraphQLNonNull15(filterArgs) : filterArgs
6527
6254
  }
6528
- if (op["connect"] !== void 0 && op["connect"] !== null) {
6529
- await link(asArray(op["connect"]), "connect");
6255
+ },
6256
+ run: async ({ executor, args, context, before, after }) => {
6257
+ const { where, set } = args;
6258
+ const scope = policies?.scope?.(context);
6259
+ const input = stripContextValues(remapUpdateInput(set, table, tableName), policies?.contextValues?.(tableName));
6260
+ if (!Object.keys(input).length) {
6261
+ throw drizzleError("Unable to update with no values specified!", { code: "DRIZZLE_NO_VALUES" });
6262
+ }
6263
+ await before();
6264
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
6265
+ const filters = withScope(
6266
+ scope,
6267
+ tableName,
6268
+ table,
6269
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
6270
+ );
6271
+ if (single) {
6272
+ await assertSingleMatch(executor, table, filters);
6530
6273
  }
6531
- };
6532
- const detachAll = async (executor, plan, key, scope) => executor.update(plan.targetTable).set({ [plan.foreignColPropName]: null }).where(withScope(scope, plan.targetTableName, plan.targetTable, eq8(plan.foreignCol, key)));
6533
- return {
6534
- enabled: (tableName) => !!plans[tableName],
6535
- split: (tableName, values) => {
6536
- const tablePlans = plans[tableName];
6537
- if (!tablePlans) {
6538
- return { columns: values, ops: {} };
6539
- }
6540
- const columns = {};
6541
- const ops = {};
6542
- for (const [key, value] of Object.entries(values)) {
6543
- if (tablePlans[key] && value !== void 0 && value !== null) {
6544
- ops[key] = value;
6545
- } else if (!tablePlans[key]) {
6546
- columns[key] = value;
6547
- }
6548
- }
6549
- return { columns, ops };
6550
- },
6551
- hasOps: (ops) => Object.keys(ops).length > 0,
6552
- withJoinColumns: (tableName, ops, columns, table) => {
6553
- const tablePlans = plans[tableName];
6554
- if (!tablePlans) {
6555
- return columns;
6274
+ let query = executor.update(table).set(input);
6275
+ if (filters) {
6276
+ query = query.where(filters);
6277
+ }
6278
+ await query;
6279
+ await after();
6280
+ return isSuccess;
6281
+ }
6282
+ });
6283
+ var generateUpdateMany = (db, tableName, table, updateManyInput, fieldName, filterCtx, txCtx, policies) => writeResolver({
6284
+ db,
6285
+ tableName,
6286
+ operation: "updateMany",
6287
+ single: false,
6288
+ fieldName,
6289
+ txCtx,
6290
+ policies,
6291
+ args: {
6292
+ updates: {
6293
+ type: new GraphQLNonNull15(new GraphQLList11(new GraphQLNonNull15(updateManyInput)))
6294
+ }
6295
+ },
6296
+ run: async ({ executor, args, context, before, after }) => {
6297
+ const { updates } = args;
6298
+ if (!updates.length) {
6299
+ throw drizzleError("No updates were provided!", { code: "DRIZZLE_NO_VALUES" });
6300
+ }
6301
+ await before();
6302
+ const scope = policies?.scope?.(context);
6303
+ const contextColumns = policies?.contextValues?.(tableName);
6304
+ const entries = updates.map(({ where, set }) => {
6305
+ const input = stripContextValues(remapUpdateInput(set, table, tableName), contextColumns);
6306
+ if (!Object.keys(input).length) {
6307
+ throw drizzleError("Unable to update with no values specified!", { code: "DRIZZLE_NO_VALUES" });
6556
6308
  }
6557
- const allColumns = getColumns16(table);
6558
- for (const relationName of Object.keys(ops)) {
6559
- const plan = tablePlans[relationName];
6560
- if (plan?.fkSide === "child" && !(plan.localColPropName in columns) && allColumns[plan.localColPropName]) {
6561
- columns[plan.localColPropName] = allColumns[plan.localColPropName];
6309
+ return {
6310
+ set: input,
6311
+ filters: withScope(
6312
+ scope,
6313
+ tableName,
6314
+ table,
6315
+ where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
6316
+ )
6317
+ };
6318
+ });
6319
+ await executor.transaction(async (tx) => {
6320
+ for (const entry of entries) {
6321
+ let query = tx.update(table).set(entry.set);
6322
+ if (entry.filters) {
6323
+ query = query.where(entry.filters);
6562
6324
  }
6325
+ await query;
6563
6326
  }
6564
- return columns;
6327
+ });
6328
+ await after();
6329
+ return isSuccess;
6330
+ }
6331
+ });
6332
+ var generateDelete = (db, tableName, table, filterArgs, fieldName, single, requireWhere, filterCtx, txCtx, policies, restore = false) => {
6333
+ const softDelete = policies?.softDelete?.(tableName);
6334
+ const operation = restore ? "restore" : "delete";
6335
+ const canHardDelete = !restore && softDelete?.hardDelete === true;
6336
+ return writeResolver({
6337
+ db,
6338
+ tableName,
6339
+ operation,
6340
+ single,
6341
+ fieldName,
6342
+ txCtx,
6343
+ policies,
6344
+ args: {
6345
+ where: {
6346
+ type: single || requireWhere ? new GraphQLNonNull15(filterArgs) : filterArgs
6347
+ },
6348
+ ...canHardDelete ? { hard: hardDeleteArg } : {}
6565
6349
  },
6566
- applyParentSide: async (executor, tableName, ops, context) => {
6567
- const tablePlans = plans[tableName];
6568
- const patch = {};
6569
- if (!tablePlans) {
6570
- return patch;
6350
+ run: async ({ executor, args, context, before, after }) => {
6351
+ await before();
6352
+ const { where } = args;
6353
+ const hard = canHardDelete && args.hard === true;
6354
+ const scope = policies?.scope?.(context);
6355
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
6356
+ const filters = withScope(
6357
+ scope,
6358
+ tableName,
6359
+ table,
6360
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
6361
+ // A hard delete reads at INCLUDE: the rows it mostly exists to remove are the
6362
+ // ones already marked, which the default EXCLUDE could not reach at all.
6363
+ restore ? "ONLY" : hard ? "INCLUDE" : void 0
6364
+ );
6365
+ if (single) {
6366
+ await assertSingleMatch(executor, table, filters);
6571
6367
  }
6572
- const scope = resolveScope(policies, context, filterCtx);
6573
- for (const [relationName, op] of Object.entries(ops)) {
6574
- const plan = tablePlans[relationName];
6575
- if (!plan || plan.fkSide !== "parent") {
6576
- continue;
6577
- }
6578
- assertSingleOperation(plan, op);
6579
- if (op["create"] !== void 0) {
6580
- const values = applyContextValues(
6581
- remapFromGraphQLSingleInput({ ...op["create"] }, plan.targetTable),
6582
- contextValues?.(plan.targetTableName),
6583
- context
6584
- );
6585
- const inserted = await executor.insert(plan.targetTable).values(values).returning();
6586
- const created = inserted[0];
6587
- if (!created) {
6588
- throw drizzleError(
6589
- `Drizzle-GraphQL Error: 'create' on '${relationName}' inserted no row, so there is nothing to attach.`,
6590
- { code: "DRIZZLE_NESTED_WRITE_INVALID" }
6591
- );
6592
- }
6593
- patch[plan.localColPropName] = created[plan.foreignColPropName];
6594
- } else if (op["connect"] !== void 0) {
6595
- const rows = await executor.select().from(plan.targetTable).where(conditionOf(plan, op["connect"], "connect", scope));
6596
- if (rows.length !== 1) {
6597
- throw drizzleError(
6598
- `Drizzle-GraphQL Error: 'connect' on '${relationName}' matched ${rows.length} rows \u2014 it attaches a single row, so its filter must match exactly one.`,
6599
- { code: "DRIZZLE_NESTED_WRITE_INVALID" }
6600
- );
6601
- }
6602
- patch[plan.localColPropName] = rows[0][plan.foreignColPropName];
6603
- } else if (op["disconnect"] === true) {
6604
- patch[plan.localColPropName] = null;
6605
- }
6368
+ let query = softDelete && !hard ? executor.update(table).set({ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted() }) : executor.delete(table);
6369
+ if (filters) {
6370
+ query = query.where(filters);
6606
6371
  }
6607
- return patch;
6608
- },
6609
- applyChildSide: async (executor, tableName, ops, parentRows, context) => {
6610
- const tablePlans = plans[tableName];
6611
- if (!tablePlans) {
6612
- return;
6372
+ await query;
6373
+ await after();
6374
+ return isSuccess;
6375
+ }
6376
+ });
6377
+ };
6378
+ var mysqlPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig);
6379
+ var { prepareBuild, addReadFields, finalizeBuild } = createSchemaBuilder({
6380
+ tableClass: MySqlTable,
6381
+ getTableConfig,
6382
+ primaryKeyPropNames: mysqlPrimaryKeyPropNames,
6383
+ nullOrdering: "nulls-smallest",
6384
+ returnsRows: false,
6385
+ // A nested write reads the key of the row it just wrote back out of the statement that
6386
+ // wrote it, which MySQL has no RETURNING clause for.
6387
+ preflight: (_db, options) => {
6388
+ if (options.features.nestedWrites) {
6389
+ throw new Error(
6390
+ "Drizzle-GraphQL Error: features.nestedWrites is not supported on MySQL \u2014 a nested write needs the parent row it just inserted returned to it, and MySQL has no RETURNING clause."
6391
+ );
6392
+ }
6393
+ }
6394
+ });
6395
+ var generateSchemaData = (db, schema, relations, options) => {
6396
+ const { prefixes, suffixes, typeNameMapper } = options;
6397
+ const ctx = prepareBuild(db, schema, relations, options);
6398
+ const {
6399
+ featureOf,
6400
+ anyTable,
6401
+ filterCtx,
6402
+ policies,
6403
+ softDeleteOf,
6404
+ cacheCtx,
6405
+ mutationTxCtx,
6406
+ gqlSchemaTypes,
6407
+ mutations,
6408
+ inputs,
6409
+ outputs
6410
+ } = ctx;
6411
+ const mutationReturnType = new GraphQLObjectType4({
6412
+ name: cacheCtx.typeName({ kind: "shared", defaultName: "MutationReturn" }),
6413
+ fields: {
6414
+ isSuccess: {
6415
+ type: new GraphQLNonNull15(GraphQLBoolean6)
6613
6416
  }
6614
- const scope = resolveScope(policies, context, filterCtx);
6615
- for (const [relationName, op] of Object.entries(ops)) {
6616
- const plan = tablePlans[relationName];
6617
- if (!plan || plan.fkSide !== "child") {
6618
- continue;
6619
- }
6620
- if (plan.isOne) {
6621
- assertSingleOperation(plan, op);
6622
- }
6623
- for (const parentRow of parentRows) {
6624
- const key = parentRow?.[plan.localColPropName];
6625
- if (key === void 0 || key === null) {
6626
- throw drizzleError(
6627
- `Drizzle-GraphQL Error: cannot write through '${relationName}': the ${tableName} row has no '${plan.localColPropName}' value to attach to.`,
6628
- { code: "DRIZZLE_NESTED_WRITE_INVALID" }
6629
- );
6630
- }
6631
- if (plan.through) {
6632
- await applyThroughOps(executor, plan, key, op, scope);
6633
- continue;
6634
- }
6635
- if (op["set"] !== void 0) {
6636
- await detachAll(executor, plan, key, scope);
6637
- for (const filter of asArray(op["set"])) {
6638
- await executor.update(plan.targetTable).set({ [plan.foreignColPropName]: key }).where(conditionOf(plan, filter, "set", scope));
6639
- }
6640
- }
6641
- if (op["disconnect"] !== void 0) {
6642
- if (plan.isOne) {
6643
- if (op["disconnect"] === true) {
6644
- await detachAll(executor, plan, key, scope);
6645
- }
6646
- } else {
6647
- for (const filter of asArray(op["disconnect"])) {
6648
- await executor.update(plan.targetTable).set({ [plan.foreignColPropName]: null }).where(and11(eq8(plan.foreignCol, key), conditionOf(plan, filter, "disconnect", scope)));
6649
- }
6650
- }
6651
- }
6652
- const attaches = op["connect"] !== void 0 || op["create"] !== void 0;
6653
- if (plan.isOne && attaches && plan.canDetach && op["set"] === void 0) {
6654
- await detachAll(executor, plan, key, scope);
6655
- }
6656
- if (op["connect"] !== void 0) {
6657
- for (const filter of asArray(op["connect"])) {
6658
- await executor.update(plan.targetTable).set({ [plan.foreignColPropName]: key }).where(conditionOf(plan, filter, "connect", scope));
6659
- }
6660
- }
6661
- if (op["create"] !== void 0) {
6662
- const rows = asArray(op["create"]).map((row) => ({
6663
- ...applyContextValues(
6664
- remapFromGraphQLSingleInput({ ...row }, plan.targetTable),
6665
- contextValues?.(plan.targetTableName),
6666
- context
6667
- ),
6668
- [plan.foreignColPropName]: key
6669
- }));
6670
- if (rows.length) {
6671
- await executor.insert(plan.targetTable).values(rows);
6672
- }
6673
- }
6674
- }
6417
+ }
6418
+ });
6419
+ if (["insert", "upsert", "update", "delete"].some((feature) => anyTable(feature))) {
6420
+ outputs["MutationReturn"] = mutationReturnType;
6421
+ }
6422
+ for (const [tableName, tableTypes] of Object.entries(gqlSchemaTypes)) {
6423
+ const tableFeatures = featureOf(tableName);
6424
+ const drizzleMeta = tableFieldExtensions(tableName, mysqlPrimaryKeyPropNames(schema[tableName]));
6425
+ const { insertInput, updateInput, tableFilters, tableOrder } = tableTypes.inputs;
6426
+ const { selectSingleOutput } = tableTypes.outputs;
6427
+ const names = computeResolverFieldNames(tableName, typeNameMapper, prefixes, suffixes);
6428
+ const {
6429
+ typeName,
6430
+ createArrayFieldName,
6431
+ createSingleFieldName,
6432
+ upsertArrayFieldName,
6433
+ upsertSingleFieldName,
6434
+ updateFieldName,
6435
+ updateManyFieldName,
6436
+ updateSingleFieldName,
6437
+ updateCountFieldName,
6438
+ deleteFieldName,
6439
+ deleteSingleFieldName,
6440
+ restoreFieldName,
6441
+ restoreSingleFieldName,
6442
+ deleteCountFieldName
6443
+ } = names;
6444
+ const softDeleteInfo = softDeleteOf?.(tableName);
6445
+ const { aggregateType, groupByType, havingInput } = addReadFields(ctx, tableName, names, tableTypes, drizzleMeta);
6446
+ const insertArrGenerated = tableFeatures.insert ? generateInsertArray(
6447
+ db,
6448
+ tableName,
6449
+ schema[tableName],
6450
+ insertInput,
6451
+ createArrayFieldName,
6452
+ mutationTxCtx,
6453
+ policies
6454
+ ) : void 0;
6455
+ const insertSingleGenerated = tableFeatures.insert ? generateInsertSingle(
6456
+ db,
6457
+ tableName,
6458
+ schema[tableName],
6459
+ insertInput,
6460
+ createSingleFieldName,
6461
+ mutationTxCtx,
6462
+ policies
6463
+ ) : void 0;
6464
+ const onConflictInput = tableFeatures.upsert ? generateOnConflictInput({
6465
+ table: schema[tableName],
6466
+ tableName,
6467
+ typeName,
6468
+ uniqueSets: [],
6469
+ tableFilters,
6470
+ withTarget: false,
6471
+ cacheCtx
6472
+ }) : void 0;
6473
+ const upsertArrGenerated = onConflictInput ? generateUpsert(
6474
+ db,
6475
+ tableName,
6476
+ schema[tableName],
6477
+ insertInput,
6478
+ onConflictInput,
6479
+ upsertArrayFieldName,
6480
+ false,
6481
+ mutationTxCtx,
6482
+ policies
6483
+ ) : void 0;
6484
+ const upsertSingleGenerated = onConflictInput ? generateUpsert(
6485
+ db,
6486
+ tableName,
6487
+ schema[tableName],
6488
+ insertInput,
6489
+ onConflictInput,
6490
+ upsertSingleFieldName,
6491
+ true,
6492
+ mutationTxCtx,
6493
+ policies
6494
+ ) : void 0;
6495
+ const updateGenerated = tableFeatures.update ? generateUpdate(
6496
+ db,
6497
+ tableName,
6498
+ schema[tableName],
6499
+ updateInput,
6500
+ tableFilters,
6501
+ updateFieldName,
6502
+ false,
6503
+ tableFeatures.requireWhere,
6504
+ filterCtx,
6505
+ mutationTxCtx,
6506
+ policies
6507
+ ) : void 0;
6508
+ const updateSingleGenerated = tableFeatures.update ? generateUpdate(
6509
+ db,
6510
+ tableName,
6511
+ schema[tableName],
6512
+ updateInput,
6513
+ tableFilters,
6514
+ updateSingleFieldName,
6515
+ true,
6516
+ tableFeatures.requireWhere,
6517
+ filterCtx,
6518
+ mutationTxCtx,
6519
+ policies
6520
+ ) : void 0;
6521
+ const updateManyInput = tableFeatures.update && tableFeatures.updateMany ? generateUpdateManyInput({
6522
+ tableName,
6523
+ typeName,
6524
+ updatePrefix: prefixes.update,
6525
+ updateInput,
6526
+ tableFilters,
6527
+ cacheCtx
6528
+ }) : void 0;
6529
+ const updateManyGenerated = updateManyInput ? generateUpdateMany(
6530
+ db,
6531
+ tableName,
6532
+ schema[tableName],
6533
+ updateManyInput,
6534
+ updateManyFieldName,
6535
+ filterCtx,
6536
+ mutationTxCtx,
6537
+ policies
6538
+ ) : void 0;
6539
+ const deleteGenerated = tableFeatures.delete ? generateDelete(
6540
+ db,
6541
+ tableName,
6542
+ schema[tableName],
6543
+ tableFilters,
6544
+ deleteFieldName,
6545
+ false,
6546
+ tableFeatures.requireWhere,
6547
+ filterCtx,
6548
+ mutationTxCtx,
6549
+ policies
6550
+ ) : void 0;
6551
+ const deleteSingleGenerated = tableFeatures.delete ? generateDelete(
6552
+ db,
6553
+ tableName,
6554
+ schema[tableName],
6555
+ tableFilters,
6556
+ deleteSingleFieldName,
6557
+ true,
6558
+ tableFeatures.requireWhere,
6559
+ filterCtx,
6560
+ mutationTxCtx,
6561
+ policies
6562
+ ) : void 0;
6563
+ const restoreGenerated = softDeleteInfo ? generateDelete(
6564
+ db,
6565
+ tableName,
6566
+ schema[tableName],
6567
+ tableFilters,
6568
+ restoreFieldName,
6569
+ false,
6570
+ tableFeatures.requireWhere,
6571
+ filterCtx,
6572
+ mutationTxCtx,
6573
+ policies,
6574
+ true
6575
+ ) : void 0;
6576
+ const restoreSingleGenerated = softDeleteInfo ? generateDelete(
6577
+ db,
6578
+ tableName,
6579
+ schema[tableName],
6580
+ tableFilters,
6581
+ restoreSingleFieldName,
6582
+ true,
6583
+ tableFeatures.requireWhere,
6584
+ filterCtx,
6585
+ mutationTxCtx,
6586
+ policies,
6587
+ true
6588
+ ) : void 0;
6589
+ const updateCountGenerated = tableFeatures.update && tableFeatures.countMutations ? generateWriteCount({
6590
+ db,
6591
+ tableName,
6592
+ table: schema[tableName],
6593
+ kind: "update",
6594
+ setArgs: updateInput,
6595
+ filterArgs: tableFilters,
6596
+ fieldName: updateCountFieldName,
6597
+ requireWhere: tableFeatures.requireWhere,
6598
+ filterCtx,
6599
+ txCtx: mutationTxCtx
6600
+ }) : void 0;
6601
+ const deleteCountGenerated = tableFeatures.delete && tableFeatures.countMutations ? generateWriteCount({
6602
+ db,
6603
+ tableName,
6604
+ table: schema[tableName],
6605
+ kind: "delete",
6606
+ filterArgs: tableFilters,
6607
+ fieldName: deleteCountFieldName,
6608
+ requireWhere: tableFeatures.requireWhere,
6609
+ filterCtx,
6610
+ txCtx: mutationTxCtx
6611
+ }) : void 0;
6612
+ const hardDeleteMeta = softDeleteInfo?.hardDelete ? { hardDelete: true } : {};
6613
+ const generatedMutations = [
6614
+ [insertArrGenerated, { operation: "insert", single: false, targetArg: "values" }],
6615
+ [insertSingleGenerated, { operation: "insert", single: true, targetArg: "values" }],
6616
+ [upsertArrGenerated, { operation: "upsert", single: false, targetArg: "values" }],
6617
+ [upsertSingleGenerated, { operation: "upsert", single: true, targetArg: "values" }],
6618
+ [updateGenerated, { operation: "update", single: false, targetArg: "where" }],
6619
+ [updateManyGenerated, { operation: "updateMany", single: false, targetArg: "updates" }],
6620
+ [updateSingleGenerated, { operation: "update", single: true, targetArg: "where" }],
6621
+ [deleteGenerated, { operation: "delete", single: false, targetArg: "where", ...hardDeleteMeta }],
6622
+ [deleteSingleGenerated, { operation: "delete", single: true, targetArg: "where", ...hardDeleteMeta }],
6623
+ [restoreGenerated, { operation: "restore", single: false, targetArg: "where" }],
6624
+ [restoreSingleGenerated, { operation: "restore", single: true, targetArg: "where" }]
6625
+ ];
6626
+ for (const [generated, meta] of generatedMutations) {
6627
+ if (generated) {
6628
+ mutations[generated.name] = {
6629
+ type: mutationReturnType,
6630
+ args: generated.args,
6631
+ resolve: generated.resolver,
6632
+ extensions: { drizzle: drizzleMeta({ kind: "mutation", ...meta }) }
6633
+ };
6675
6634
  }
6676
6635
  }
6677
- };
6678
- };
6679
- var writeWithNestedOps = async (params) => {
6680
- const { executor, runtime, tableName, entries, remapValues, write, context } = params;
6681
- return executor.transaction(async (tx) => {
6682
- const rows = [];
6683
- for (const entry of entries) {
6684
- const patch = await runtime.applyParentSide(tx, tableName, entry.ops, context);
6685
- const written = await write(tx, { ...remapValues(entry.columns), ...patch });
6686
- await runtime.applyChildSide(tx, tableName, entry.ops, written, context);
6687
- rows.push(...written);
6636
+ if (updateCountGenerated) {
6637
+ mutations[updateCountGenerated.name] = {
6638
+ type: new GraphQLNonNull15(GraphQLInt8),
6639
+ args: updateCountGenerated.args,
6640
+ resolve: updateCountGenerated.resolver,
6641
+ description: "How many rows the update touched. The rows themselves are not read back, which is the point of this mutation."
6642
+ };
6688
6643
  }
6689
- return rows;
6690
- });
6691
- };
6692
- var updateWithNestedOps = async (params) => {
6693
- const { executor, runtime, tableName, columns, ops, remapValues, write, context } = params;
6694
- return executor.transaction(async (tx) => {
6695
- const patch = await runtime.applyParentSide(tx, tableName, ops, context);
6696
- const rows = await write(tx, { ...remapValues(columns), ...patch });
6697
- await runtime.applyChildSide(tx, tableName, ops, rows, context);
6698
- return rows;
6699
- });
6644
+ if (deleteCountGenerated) {
6645
+ mutations[deleteCountGenerated.name] = {
6646
+ type: new GraphQLNonNull15(GraphQLInt8),
6647
+ args: deleteCountGenerated.args,
6648
+ resolve: deleteCountGenerated.resolver,
6649
+ description: "How many rows the delete removed. The rows themselves are not read back, which is the point of this mutation."
6650
+ };
6651
+ }
6652
+ const activeInputs = [
6653
+ // The insert input types the upsert mutations too, so either feature keeps it.
6654
+ ...tableFeatures.insert || onConflictInput ? [insertInput] : [],
6655
+ ...onConflictInput ? [onConflictInput] : [],
6656
+ ...tableFeatures.update ? [updateInput] : [],
6657
+ ...updateManyInput ? [updateManyInput] : [],
6658
+ tableFilters,
6659
+ tableOrder
6660
+ ];
6661
+ activeInputs.forEach((e) => {
6662
+ inputs[e.name] = e;
6663
+ });
6664
+ outputs[selectSingleOutput.name] = selectSingleOutput;
6665
+ if (aggregateType) {
6666
+ outputs[aggregateType.name] = aggregateType;
6667
+ }
6668
+ if (groupByType && havingInput) {
6669
+ outputs[groupByType.name] = groupByType;
6670
+ inputs[havingInput.name] = havingInput;
6671
+ }
6672
+ }
6673
+ return finalizeBuild(ctx);
6700
6674
  };
6701
6675
 
6676
+ // src/util/builders/pg.ts
6677
+ import { getTableConfig as getTableConfig2, PgTable } from "drizzle-orm/pg-core";
6678
+
6679
+ // src/util/builders/schema-data.ts
6680
+ import { GraphQLInt as GraphQLInt9, GraphQLList as GraphQLList13, GraphQLNonNull as GraphQLNonNull17 } from "graphql";
6681
+
6702
6682
  // src/util/builders/write-resolvers.ts
6703
- import { GraphQLList as GraphQLList11, GraphQLNonNull as GraphQLNonNull15 } from "graphql";
6683
+ import { GraphQLList as GraphQLList12, GraphQLNonNull as GraphQLNonNull16 } from "graphql";
6704
6684
  import { parseResolveInfo as parseResolveInfo3 } from "graphql-parse-resolve-info";
6705
6685
  var buildWriteResolvers = (primaryKeyPropNames) => {
6706
6686
  const generateInsertArray2 = (db, tableName, table, tables, relationMap, baseType, fieldName, typeName, typeNameMapper, conflictDoNothing = false, txCtx, nested, limits, policies, resolveName) => {
6707
6687
  const queryArgs = {
6708
6688
  values: {
6709
- type: new GraphQLNonNull15(new GraphQLList11(new GraphQLNonNull15(baseType)))
6689
+ type: new GraphQLNonNull16(new GraphQLList12(new GraphQLNonNull16(baseType)))
6710
6690
  }
6711
6691
  };
6712
6692
  const pkNames = primaryKeyPropNames(table);
6713
- const hooks = policies?.onWrite?.(tableName, "insert");
6714
- const errorCtx = { table: tableName, operation: "insert", field: fieldName };
6715
- return {
6716
- name: fieldName,
6717
- resolver: async (_source, args, context, info) => {
6718
- try {
6719
- return await runMutation(
6720
- db,
6721
- context,
6722
- info,
6723
- txCtx,
6724
- async (executor) => {
6725
- if (!args.values.length) {
6726
- throw drizzleError("No values were provided!", { code: "DRIZZLE_NO_VALUES" });
6727
- }
6728
- await runWriteHook(hooks, "before", {
6729
- table: tableName,
6730
- operation: "insert",
6731
- single: false,
6732
- args,
6733
- context,
6734
- info,
6735
- tx: executor
6736
- });
6737
- const entries = nested?.enabled(tableName) ? args.values.map((values) => nested.split(tableName, values)) : void 0;
6738
- const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
6739
- const contextColumns = policies?.contextValues?.(tableName);
6740
- const scope = policies?.scope?.(context);
6741
- const input = nestedEntries ? [] : applyContextValuesAll(
6742
- remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : args.values, table),
6743
- contextColumns,
6744
- context
6745
- );
6746
- const parsedInfo = parseResolveInfo3(info, {
6747
- deep: true
6748
- });
6749
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6750
- relationMap,
6751
- tables,
6752
- tableName,
6753
- typeName,
6754
- typeNameMapper,
6755
- resolveName,
6756
- table,
6757
- pkNames,
6758
- parsedInfo,
6759
- limits,
6760
- scope,
6761
- defaultOrderBy: policies?.defaultOrderBy
6762
- });
6763
- const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
6764
- const runInsert = async (target, values) => {
6765
- let query = target.insert(table).values(values).returning(returning);
6766
- if (conflictDoNothing) {
6767
- query = query.onConflictDoNothing();
6768
- }
6769
- return await query;
6770
- };
6771
- const result = nestedEntries ? await writeWithNestedOps({
6772
- executor,
6773
- runtime: nested,
6774
- tableName,
6775
- entries: nestedEntries,
6776
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6777
- write: (tx, values) => runInsert(tx, [values]),
6778
- context
6779
- }) : await runInsert(executor, input);
6780
- await runWriteHook(hooks, "after", {
6781
- table: tableName,
6782
- operation: "insert",
6783
- single: false,
6784
- args,
6785
- rows: result,
6786
- context,
6787
- info,
6788
- tx: executor
6789
- });
6790
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6791
- return remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
6792
- },
6793
- !!hooks
6794
- );
6795
- } catch (e) {
6796
- throw withErrorContext(toGraphQLError(e), errorCtx);
6693
+ return writeResolver({
6694
+ db,
6695
+ tableName,
6696
+ operation: "insert",
6697
+ single: false,
6698
+ fieldName,
6699
+ txCtx,
6700
+ policies,
6701
+ args: queryArgs,
6702
+ run: async ({ executor, args, context, info, before, after }) => {
6703
+ if (!args.values.length) {
6704
+ throw drizzleError("No values were provided!", { code: "DRIZZLE_NO_VALUES" });
6797
6705
  }
6798
- },
6799
- args: queryArgs
6800
- };
6706
+ await before();
6707
+ const entries = nested?.enabled(tableName) ? args.values.map((values) => nested.split(tableName, values)) : void 0;
6708
+ const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
6709
+ const contextColumns = policies?.contextValues?.(tableName);
6710
+ const scope = policies?.scope?.(context);
6711
+ const input = nestedEntries ? [] : applyContextValuesAll(
6712
+ remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : args.values, table),
6713
+ contextColumns,
6714
+ context
6715
+ );
6716
+ const parsedInfo = parseResolveInfo3(info, {
6717
+ deep: true
6718
+ });
6719
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6720
+ relationMap,
6721
+ tables,
6722
+ tableName,
6723
+ typeName,
6724
+ typeNameMapper,
6725
+ resolveName,
6726
+ table,
6727
+ pkNames,
6728
+ parsedInfo,
6729
+ limits,
6730
+ scope,
6731
+ defaultOrderBy: policies?.defaultOrderBy
6732
+ });
6733
+ const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
6734
+ const runInsert = async (target, values) => {
6735
+ let query = target.insert(table).values(values).returning(returning);
6736
+ if (conflictDoNothing) {
6737
+ query = query.onConflictDoNothing();
6738
+ }
6739
+ return await query;
6740
+ };
6741
+ const result = nestedEntries ? await writeWithNestedOps({
6742
+ executor,
6743
+ runtime: nested,
6744
+ tableName,
6745
+ entries: nestedEntries,
6746
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6747
+ write: (tx, values) => runInsert(tx, [values]),
6748
+ context
6749
+ }) : await runInsert(executor, input);
6750
+ await after(result);
6751
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6752
+ return remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
6753
+ }
6754
+ });
6801
6755
  };
6802
6756
  const generateInsertSingle2 = (db, tableName, table, tables, relationMap, baseType, fieldName, typeName, typeNameMapper, conflictDoNothing = false, txCtx, nested, limits, policies, resolveName) => {
6803
6757
  const queryArgs = {
6804
6758
  values: {
6805
- type: new GraphQLNonNull15(baseType)
6759
+ type: new GraphQLNonNull16(baseType)
6806
6760
  }
6807
6761
  };
6808
6762
  const pkNames = primaryKeyPropNames(table);
6809
- const hooks = policies?.onWrite?.(tableName, "insert");
6810
- const errorCtx = { table: tableName, operation: "insert", field: fieldName };
6811
- return {
6812
- name: fieldName,
6813
- resolver: async (_source, args, context, info) => {
6814
- try {
6815
- return await runMutation(
6816
- db,
6817
- context,
6818
- info,
6819
- txCtx,
6820
- async (executor) => {
6821
- await runWriteHook(hooks, "before", {
6822
- table: tableName,
6823
- operation: "insert",
6824
- single: true,
6825
- args,
6826
- context,
6827
- info,
6828
- tx: executor
6829
- });
6830
- const entry = nested?.enabled(tableName) ? nested.split(tableName, args.values) : void 0;
6831
- const nestedEntry = entry && nested.hasOps(entry.ops) ? entry : void 0;
6832
- const contextColumns = policies?.contextValues?.(tableName);
6833
- const scope = policies?.scope?.(context);
6834
- const input = nestedEntry ? {} : applyContextValues(
6835
- remapFromGraphQLSingleInput(entry ? entry.columns : args.values, table),
6836
- contextColumns,
6837
- context
6838
- );
6839
- const parsedInfo = parseResolveInfo3(info, {
6840
- deep: true
6841
- });
6842
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6843
- relationMap,
6844
- tables,
6845
- tableName,
6846
- typeName,
6847
- typeNameMapper,
6848
- resolveName,
6849
- table,
6850
- pkNames,
6851
- parsedInfo,
6852
- limits,
6853
- scope,
6854
- defaultOrderBy: policies?.defaultOrderBy
6855
- });
6856
- const returning = nestedEntry ? nested.withJoinColumns(tableName, nestedEntry.ops, { ...columns }, table) : columns;
6857
- const runInsert = async (target, values) => {
6858
- let query = target.insert(table).values(values).returning(returning);
6859
- if (conflictDoNothing) {
6860
- query = query.onConflictDoNothing();
6861
- }
6862
- return await query;
6863
- };
6864
- const result = nestedEntry ? await writeWithNestedOps({
6865
- executor,
6866
- runtime: nested,
6867
- tableName,
6868
- entries: [nestedEntry],
6869
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6870
- write: runInsert,
6871
- context
6872
- }) : await runInsert(executor, input);
6873
- await runWriteHook(hooks, "after", {
6874
- table: tableName,
6875
- operation: "insert",
6876
- single: true,
6877
- args,
6878
- rows: result,
6879
- context,
6880
- info,
6881
- tx: executor
6882
- });
6883
- if (!result[0]) {
6884
- if (!conflictDoNothing) {
6885
- throw drizzleError("The insert returned no row.", { code: "DRIZZLE_NO_ROW_RETURNED" });
6886
- }
6887
- return void 0;
6888
- }
6889
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6890
- return remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap);
6891
- },
6892
- !!hooks
6893
- );
6894
- } catch (e) {
6895
- throw withErrorContext(toGraphQLError(e), errorCtx);
6763
+ return writeResolver({
6764
+ db,
6765
+ tableName,
6766
+ operation: "insert",
6767
+ single: true,
6768
+ fieldName,
6769
+ txCtx,
6770
+ policies,
6771
+ args: queryArgs,
6772
+ run: async ({ executor, args, context, info, before, after }) => {
6773
+ await before();
6774
+ const entry = nested?.enabled(tableName) ? nested.split(tableName, args.values) : void 0;
6775
+ const nestedEntry = entry && nested.hasOps(entry.ops) ? entry : void 0;
6776
+ const contextColumns = policies?.contextValues?.(tableName);
6777
+ const scope = policies?.scope?.(context);
6778
+ const input = nestedEntry ? {} : applyContextValues(
6779
+ remapFromGraphQLSingleInput(entry ? entry.columns : args.values, table),
6780
+ contextColumns,
6781
+ context
6782
+ );
6783
+ const parsedInfo = parseResolveInfo3(info, {
6784
+ deep: true
6785
+ });
6786
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6787
+ relationMap,
6788
+ tables,
6789
+ tableName,
6790
+ typeName,
6791
+ typeNameMapper,
6792
+ resolveName,
6793
+ table,
6794
+ pkNames,
6795
+ parsedInfo,
6796
+ limits,
6797
+ scope,
6798
+ defaultOrderBy: policies?.defaultOrderBy
6799
+ });
6800
+ const returning = nestedEntry ? nested.withJoinColumns(tableName, nestedEntry.ops, { ...columns }, table) : columns;
6801
+ const runInsert = async (target, values) => {
6802
+ let query = target.insert(table).values(values).returning(returning);
6803
+ if (conflictDoNothing) {
6804
+ query = query.onConflictDoNothing();
6805
+ }
6806
+ return await query;
6807
+ };
6808
+ const result = nestedEntry ? await writeWithNestedOps({
6809
+ executor,
6810
+ runtime: nested,
6811
+ tableName,
6812
+ entries: [nestedEntry],
6813
+ remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6814
+ write: runInsert,
6815
+ context
6816
+ }) : await runInsert(executor, input);
6817
+ await after(result);
6818
+ if (!result[0]) {
6819
+ if (!conflictDoNothing) {
6820
+ throw drizzleError("The insert returned no row.", { code: "DRIZZLE_NO_ROW_RETURNED" });
6821
+ }
6822
+ return void 0;
6896
6823
  }
6897
- },
6898
- args: queryArgs
6899
- };
6824
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6825
+ return remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap);
6826
+ }
6827
+ });
6900
6828
  };
6901
6829
  const generateUpsert2 = (db, tableName, table, tables, relationMap, baseType, onConflictType, uniqueSets, fieldName, typeName, single, typeNameMapper, filterCtx, txCtx, nested, limits, policies, resolveName) => {
6902
6830
  const queryArgs = {
6903
6831
  values: {
6904
- type: single ? new GraphQLNonNull15(baseType) : new GraphQLNonNull15(new GraphQLList11(new GraphQLNonNull15(baseType)))
6832
+ type: single ? new GraphQLNonNull16(baseType) : new GraphQLNonNull16(new GraphQLList12(new GraphQLNonNull16(baseType)))
6905
6833
  },
6906
6834
  onConflict: {
6907
6835
  type: onConflictType,
@@ -6909,311 +6837,233 @@ var buildWriteResolvers = (primaryKeyPropNames) => {
6909
6837
  }
6910
6838
  };
6911
6839
  const pkNames = primaryKeyPropNames(table);
6912
- const hooks = policies?.onWrite?.(tableName, "upsert");
6913
- const errorCtx = { table: tableName, operation: "upsert", field: fieldName };
6914
- return {
6915
- name: fieldName,
6916
- resolver: async (_source, args, context, info) => {
6917
- try {
6918
- return await runMutation(
6919
- db,
6920
- context,
6921
- info,
6922
- txCtx,
6923
- async (executor) => {
6924
- const supplied = single ? [args.values] : args.values;
6925
- if (!supplied.length) {
6926
- throw drizzleError("No values were provided!", { code: "DRIZZLE_NO_VALUES" });
6927
- }
6928
- await runWriteHook(hooks, "before", {
6929
- table: tableName,
6930
- operation: "upsert",
6931
- single,
6932
- args,
6933
- context,
6934
- info,
6935
- tx: executor
6936
- });
6937
- const entries = nested?.enabled(tableName) ? supplied.map((values) => nested.split(tableName, values)) : void 0;
6938
- const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
6939
- const contextColumns = policies?.contextValues?.(tableName);
6940
- const scope = policies?.scope?.(context);
6941
- const input = nestedEntries ? [] : applyContextValuesAll(
6942
- remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : supplied, table),
6943
- contextColumns,
6944
- context
6945
- );
6946
- const parsedInfo = parseResolveInfo3(info, { deep: true });
6947
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6948
- relationMap,
6949
- tables,
6950
- tableName,
6951
- typeName,
6952
- typeNameMapper,
6953
- resolveName,
6954
- table,
6955
- pkNames,
6956
- parsedInfo,
6957
- limits,
6958
- scope,
6959
- defaultOrderBy: policies?.defaultOrderBy
6960
- });
6961
- const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
6962
- const runUpsert = async (target, values) => {
6963
- const plan = resolveConflictPlan({
6964
- table,
6965
- values,
6966
- onConflict: args.onConflict,
6967
- pkNames,
6968
- uniqueSets,
6969
- excludedRef: excludedColumnRef,
6970
- withTarget: true,
6971
- buildWhere: (where) => extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName))
6972
- });
6973
- let query = target.insert(table).values(values).returning(returning);
6974
- const setWhere = withScope(scope, tableName, table, plan.setWhere);
6975
- query = plan.action === "NOTHING" ? query.onConflictDoNothing(plan.target ? { target: plan.target } : void 0) : query.onConflictDoUpdate({ target: plan.target, set: plan.set, setWhere });
6976
- return await query;
6977
- };
6978
- const result = nestedEntries ? await writeWithNestedOps({
6979
- executor,
6980
- runtime: nested,
6981
- tableName,
6982
- entries: nestedEntries,
6983
- remapValues: (values) => applyContextValues(remapFromGraphQLSingleInput(values, table), contextColumns, context),
6984
- write: (tx, values) => runUpsert(tx, [values]),
6985
- context
6986
- }) : await runUpsert(executor, input);
6987
- await runWriteHook(hooks, "after", {
6988
- table: tableName,
6989
- operation: "upsert",
6990
- single,
6991
- args,
6992
- rows: result,
6993
- context,
6994
- info,
6995
- tx: executor
6996
- });
6997
- if (single && !result[0]) {
6998
- return void 0;
6999
- }
7000
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7001
- return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
7002
- },
7003
- !!hooks
7004
- );
7005
- } catch (e) {
7006
- throw withErrorContext(toGraphQLError(e), errorCtx);
6840
+ return writeResolver({
6841
+ db,
6842
+ tableName,
6843
+ operation: "upsert",
6844
+ single,
6845
+ fieldName,
6846
+ txCtx,
6847
+ policies,
6848
+ args: queryArgs,
6849
+ run: async ({ executor, args, context, info, before, after }) => {
6850
+ const supplied = single ? [args.values] : args.values;
6851
+ if (!supplied.length) {
6852
+ throw drizzleError("No values were provided!", { code: "DRIZZLE_NO_VALUES" });
7007
6853
  }
7008
- },
7009
- args: queryArgs
7010
- };
6854
+ await before();
6855
+ const entries = nested?.enabled(tableName) ? supplied.map((values) => nested.split(tableName, values)) : void 0;
6856
+ const nestedEntries = entries?.some((entry) => nested.hasOps(entry.ops)) ? entries : void 0;
6857
+ const contextColumns = policies?.contextValues?.(tableName);
6858
+ const scope = policies?.scope?.(context);
6859
+ const input = nestedEntries ? [] : applyContextValuesAll(
6860
+ remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : supplied, table),
6861
+ contextColumns,
6862
+ context
6863
+ );
6864
+ const parsedInfo = parseResolveInfo3(info, { deep: true });
6865
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6866
+ relationMap,
6867
+ tables,
6868
+ tableName,
6869
+ typeName,
6870
+ typeNameMapper,
6871
+ resolveName,
6872
+ table,
6873
+ pkNames,
6874
+ parsedInfo,
6875
+ limits,
6876
+ scope,
6877
+ defaultOrderBy: policies?.defaultOrderBy
6878
+ });
6879
+ const returning = nestedEntries ? nested.withJoinColumns(tableName, mergedOps(nestedEntries), { ...columns }, table) : columns;
6880
+ const runUpsert = async (target, values) => {
6881
+ const plan = resolveConflictPlan({
6882
+ table,
6883
+ values,
6884
+ onConflict: args.onConflict,
6885
+ pkNames,
6886
+ uniqueSets,
6887
+ excludedRef: excludedColumnRef,
6888
+ withTarget: true,
6889
+ buildWhere: (where) => extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName))
6890
+ });
6891
+ let query = target.insert(table).values(values).returning(returning);
6892
+ const setWhere = withScope(scope, tableName, table, plan.setWhere);
6893
+ query = plan.action === "NOTHING" ? query.onConflictDoNothing(plan.target ? { target: plan.target } : void 0) : query.onConflictDoUpdate({ target: plan.target, set: plan.set, setWhere });
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) => runUpsert(tx, [values]),
6903
+ context
6904
+ }) : await runUpsert(executor, input);
6905
+ await after(result);
6906
+ if (single && !result[0]) {
6907
+ return void 0;
6908
+ }
6909
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
6910
+ return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
6911
+ }
6912
+ });
7011
6913
  };
7012
6914
  const generateUpdate2 = (db, tableName, table, tables, relationMap, setArgs, filterArgs, fieldName, typeName, single, requireWhere, typeNameMapper, filterCtx, txCtx, nested, limits, policies, resolveName) => {
7013
6915
  const queryArgs = {
7014
6916
  set: {
7015
- type: new GraphQLNonNull15(setArgs)
6917
+ type: new GraphQLNonNull16(setArgs)
7016
6918
  },
7017
6919
  where: {
7018
- type: single || requireWhere ? new GraphQLNonNull15(filterArgs) : filterArgs
6920
+ type: single || requireWhere ? new GraphQLNonNull16(filterArgs) : filterArgs
7019
6921
  }
7020
6922
  };
7021
6923
  const pkNames = primaryKeyPropNames(table);
7022
- const hooks = policies?.onWrite?.(tableName, "update");
7023
- const errorCtx = { table: tableName, operation: "update", field: fieldName };
7024
- return {
7025
- name: fieldName,
7026
- resolver: async (_source, args, context, info) => {
7027
- try {
7028
- return await runMutation(
7029
- db,
7030
- context,
7031
- info,
7032
- txCtx,
7033
- async (executor) => {
7034
- const { where, set } = args;
7035
- const scope = policies?.scope?.(context);
7036
- await runWriteHook(hooks, "before", {
7037
- table: tableName,
7038
- operation: "update",
7039
- single,
7040
- args,
7041
- context,
7042
- info,
7043
- tx: executor
7044
- });
7045
- const parsedInfo = parseResolveInfo3(info, {
7046
- deep: true
7047
- });
7048
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7049
- relationMap,
7050
- tables,
7051
- tableName,
7052
- typeName,
7053
- typeNameMapper,
7054
- resolveName,
7055
- table,
7056
- pkNames,
7057
- parsedInfo,
7058
- limits,
7059
- scope,
7060
- defaultOrderBy: policies?.defaultOrderBy
7061
- });
7062
- const entry = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
7063
- const nestedOps = entry && nested.hasOps(entry.ops) ? entry.ops : void 0;
7064
- const input = stripContextValues(
7065
- remapUpdateInput(entry ? entry.columns : set, table, tableName),
7066
- policies?.contextValues?.(tableName)
7067
- );
7068
- if (!Object.keys(input).length && !nestedOps) {
7069
- throw drizzleError("Unable to update with no values specified!", { code: "DRIZZLE_NO_VALUES" });
7070
- }
7071
- const relationCtx = relationFilterCtx(filterCtx, tableName);
7072
- const filters = withScope(
7073
- scope,
7074
- tableName,
7075
- table,
7076
- single || requireWhere ? extractRequiredFilters(table, tableName, where, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
7077
- );
7078
- if (single) {
7079
- await assertSingleMatch(executor, table, filters);
7080
- }
7081
- const returning = nestedOps ? nested.withJoinColumns(tableName, nestedOps, { ...columns }, table) : columns;
7082
- const runUpdate = async (target, values) => {
7083
- const writes = Object.keys(values).length > 0;
7084
- let query = writes ? target.update(table).set(values) : target.select(returning).from(table);
7085
- if (filters) {
7086
- query = query.where(filters);
7087
- }
7088
- return await (writes ? query.returning(returning) : query);
7089
- };
7090
- const result = nestedOps ? await updateWithNestedOps({
7091
- executor,
7092
- runtime: nested,
7093
- tableName,
7094
- columns: input,
7095
- ops: nestedOps,
7096
- remapValues: (values) => values,
7097
- write: runUpdate,
7098
- context
7099
- }) : await runUpdate(executor, input);
7100
- await runWriteHook(hooks, "after", {
7101
- table: tableName,
7102
- operation: "update",
7103
- single,
7104
- args,
7105
- rows: result,
7106
- context,
7107
- info,
7108
- tx: executor
7109
- });
7110
- if (single && result.length > 1) {
7111
- throw drizzleError("'where' matched more than one row!", { code: "DRIZZLE_MULTI_ROW_MATCH" });
7112
- }
7113
- if (single && !result[0]) {
7114
- return void 0;
7115
- }
7116
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7117
- return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
7118
- },
7119
- !!hooks
7120
- );
7121
- } catch (e) {
7122
- throw withErrorContext(toGraphQLError(e), errorCtx);
6924
+ return writeResolver({
6925
+ db,
6926
+ tableName,
6927
+ operation: "update",
6928
+ single,
6929
+ fieldName,
6930
+ txCtx,
6931
+ policies,
6932
+ args: queryArgs,
6933
+ run: async ({ executor, args, context, info, before, after }) => {
6934
+ const { where, set } = args;
6935
+ const scope = policies?.scope?.(context);
6936
+ await before();
6937
+ const parsedInfo = parseResolveInfo3(info, {
6938
+ deep: true
6939
+ });
6940
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
6941
+ relationMap,
6942
+ tables,
6943
+ tableName,
6944
+ typeName,
6945
+ typeNameMapper,
6946
+ resolveName,
6947
+ table,
6948
+ pkNames,
6949
+ parsedInfo,
6950
+ limits,
6951
+ scope,
6952
+ defaultOrderBy: policies?.defaultOrderBy
6953
+ });
6954
+ const entry = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
6955
+ const nestedOps = entry && nested.hasOps(entry.ops) ? entry.ops : void 0;
6956
+ const input = stripContextValues(
6957
+ remapUpdateInput(entry ? entry.columns : set, table, tableName),
6958
+ policies?.contextValues?.(tableName)
6959
+ );
6960
+ if (!Object.keys(input).length && !nestedOps) {
6961
+ throw drizzleError("Unable to update with no values specified!", { code: "DRIZZLE_NO_VALUES" });
6962
+ }
6963
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
6964
+ const filters = withScope(
6965
+ scope,
6966
+ tableName,
6967
+ table,
6968
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0
6969
+ );
6970
+ if (single) {
6971
+ await assertSingleMatch(executor, table, filters);
6972
+ }
6973
+ const returning = nestedOps ? nested.withJoinColumns(tableName, nestedOps, { ...columns }, table) : columns;
6974
+ const runUpdate = async (target, values) => {
6975
+ const writes = Object.keys(values).length > 0;
6976
+ let query = writes ? target.update(table).set(values) : target.select(returning).from(table);
6977
+ if (filters) {
6978
+ query = query.where(filters);
6979
+ }
6980
+ return await (writes ? query.returning(returning) : query);
6981
+ };
6982
+ const result = nestedOps ? await updateWithNestedOps({
6983
+ executor,
6984
+ runtime: nested,
6985
+ tableName,
6986
+ columns: input,
6987
+ ops: nestedOps,
6988
+ remapValues: (values) => values,
6989
+ write: runUpdate,
6990
+ context
6991
+ }) : await runUpdate(executor, input);
6992
+ await after(result);
6993
+ if (single && result.length > 1) {
6994
+ throw drizzleError("'where' matched more than one row!", { code: "DRIZZLE_MULTI_ROW_MATCH" });
6995
+ }
6996
+ if (single && !result[0]) {
6997
+ return void 0;
7123
6998
  }
7124
- },
7125
- args: queryArgs
7126
- };
6999
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, result, pkNames, withParams) : result;
7000
+ return single ? remapToGraphQLSingleOutput(enriched[0], tableName, table, relationMap) : remapToGraphQLArrayOutput(enriched, tableName, table, relationMap);
7001
+ }
7002
+ });
7127
7003
  };
7128
7004
  const generateDelete2 = (db, tableName, table, filterArgs, fieldName, typeName, single, requireWhere, filterCtx, selectionCtx, txCtx, policies, restore = false, resolveName) => {
7129
7005
  const softDelete = policies?.softDelete?.(tableName);
7130
7006
  const operation = restore ? "restore" : "delete";
7131
- const hooks = policies?.onWrite?.(tableName, operation);
7132
- const errorCtx = { table: tableName, operation, field: fieldName };
7133
7007
  const canHardDelete = !restore && softDelete?.hardDelete === true;
7134
7008
  const queryArgs = {
7135
7009
  where: {
7136
- type: single || requireWhere ? new GraphQLNonNull15(filterArgs) : filterArgs
7010
+ type: single || requireWhere ? new GraphQLNonNull16(filterArgs) : filterArgs
7137
7011
  },
7138
7012
  ...canHardDelete ? { hard: hardDeleteArg } : {}
7139
7013
  };
7140
- return {
7141
- name: fieldName,
7142
- resolver: async (_source, args, context, info) => {
7143
- try {
7144
- return await runMutation(
7145
- db,
7146
- context,
7147
- info,
7148
- txCtx,
7149
- async (executor) => {
7150
- const { where } = args;
7151
- const hard = canHardDelete && args.hard === true;
7152
- const scope = policies?.scope?.(context);
7153
- await runWriteHook(hooks, "before", {
7154
- table: tableName,
7155
- operation,
7156
- single,
7157
- args,
7158
- context,
7159
- info,
7160
- tx: executor
7161
- });
7162
- const parsedInfo = parseResolveInfo3(info, {
7163
- deep: true
7164
- });
7165
- const columns = extractSelectedColumnsFromTreeSQLFormat(
7166
- parsedInfo.fieldsByTypeName[applyObjectTypeName(typeName, tableName, resolveName)],
7167
- table,
7168
- selectionCtx
7169
- );
7170
- const relationCtx = relationFilterCtx(filterCtx, tableName);
7171
- const filters = withScope(
7172
- scope,
7173
- tableName,
7174
- table,
7175
- single || requireWhere ? extractRequiredFilters(table, tableName, where, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
7176
- // A hard delete reads at INCLUDE: the rows it mostly exists to remove are the
7177
- // ones already marked, which the default EXCLUDE could not reach at all.
7178
- restore ? "ONLY" : hard ? "INCLUDE" : void 0
7179
- );
7180
- if (single) {
7181
- await assertSingleMatch(executor, table, filters);
7182
- }
7183
- let query = softDelete && !hard ? executor.update(table).set({
7184
- [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted()
7185
- }) : executor.delete(table);
7186
- if (filters) {
7187
- query = query.where(filters);
7188
- }
7189
- query = query.returning(columns);
7190
- const result = await query;
7191
- await runWriteHook(hooks, "after", {
7192
- table: tableName,
7193
- operation,
7194
- single,
7195
- args,
7196
- rows: result,
7197
- context,
7198
- info,
7199
- tx: executor
7200
- });
7201
- if (single && result.length > 1) {
7202
- throw drizzleError("'where' matched more than one row!", { code: "DRIZZLE_MULTI_ROW_MATCH" });
7203
- }
7204
- if (single) {
7205
- return result[0] ? remapToGraphQLSingleOutput(result[0], tableName, table) : void 0;
7206
- }
7207
- return remapToGraphQLArrayOutput(result, tableName, table);
7208
- },
7209
- !!hooks
7210
- );
7211
- } catch (e) {
7212
- throw withErrorContext(toGraphQLError(e), errorCtx);
7014
+ return writeResolver({
7015
+ db,
7016
+ tableName,
7017
+ operation,
7018
+ single,
7019
+ fieldName,
7020
+ txCtx,
7021
+ policies,
7022
+ args: queryArgs,
7023
+ run: async ({ executor, args, context, info, before, after }) => {
7024
+ const { where } = args;
7025
+ const hard = canHardDelete && args.hard === true;
7026
+ const scope = policies?.scope?.(context);
7027
+ await before();
7028
+ const parsedInfo = parseResolveInfo3(info, {
7029
+ deep: true
7030
+ });
7031
+ const columns = extractSelectedColumnsFromTreeSQLFormat(
7032
+ parsedInfo.fieldsByTypeName[applyObjectTypeName(typeName, tableName, resolveName)],
7033
+ table,
7034
+ selectionCtx
7035
+ );
7036
+ const relationCtx = relationFilterCtx(filterCtx, tableName);
7037
+ const filters = withScope(
7038
+ scope,
7039
+ tableName,
7040
+ table,
7041
+ single || requireWhere ? extractRequiredFilters(table, tableName, where, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0,
7042
+ // A hard delete reads at INCLUDE: the rows it mostly exists to remove are the
7043
+ // ones already marked, which the default EXCLUDE could not reach at all.
7044
+ restore ? "ONLY" : hard ? "INCLUDE" : void 0
7045
+ );
7046
+ if (single) {
7047
+ await assertSingleMatch(executor, table, filters);
7213
7048
  }
7214
- },
7215
- args: queryArgs
7216
- };
7049
+ let query = softDelete && !hard ? executor.update(table).set({
7050
+ [softDelete.columnName]: restore ? softDelete.writeRestored : softDelete.writeDeleted()
7051
+ }) : executor.delete(table);
7052
+ if (filters) {
7053
+ query = query.where(filters);
7054
+ }
7055
+ query = query.returning(columns);
7056
+ const result = await query;
7057
+ await after(result);
7058
+ if (single && result.length > 1) {
7059
+ throw drizzleError("'where' matched more than one row!", { code: "DRIZZLE_MULTI_ROW_MATCH" });
7060
+ }
7061
+ if (single) {
7062
+ return result[0] ? remapToGraphQLSingleOutput(result[0], tableName, table) : void 0;
7063
+ }
7064
+ return remapToGraphQLArrayOutput(result, tableName, table);
7065
+ }
7066
+ });
7217
7067
  };
7218
7068
  return { generateInsertArray: generateInsertArray2, generateInsertSingle: generateInsertSingle2, generateUpsert: generateUpsert2, generateUpdate: generateUpdate2, generateDelete: generateDelete2 };
7219
7069
  };
@@ -7223,141 +7073,34 @@ var createSchemaDataGenerator = (adapter) => {
7223
7073
  const primaryKeyPropNames = adapter.primaryKeyPropNames;
7224
7074
  const uniqueColumnSets = (table) => getUniqueColumnSets(table, adapter.getTableConfig);
7225
7075
  const { generateInsertArray: generateInsertArray2, generateInsertSingle: generateInsertSingle2, generateUpsert: generateUpsert2, generateUpdate: generateUpdate2, generateDelete: generateDelete2 } = buildWriteResolvers(primaryKeyPropNames);
7226
- const { generateSelectArray: generateSelectArray2, generateSelectSingle: generateSelectSingle2 } = createSelectGenerators(
7227
- primaryKeyPropNames,
7228
- adapter.nullOrdering
7229
- );
7076
+ const { prepareBuild: prepareBuild2, addReadFields: addReadFields2, finalizeBuild: finalizeBuild2 } = createSchemaBuilder(adapter);
7230
7077
  return (db, schema, relations, options) => {
7078
+ const { prefixes, suffixes, conflictDoNothing, typeNameMapper, limits } = options;
7079
+ const ctx = prepareBuild2(db, schema, relations, options);
7231
7080
  const {
7232
- relationsDepthLimit,
7233
- prefixes,
7234
- suffixes,
7235
- conflictDoNothing,
7236
- typeNameMapper,
7237
- shouldEagerLoad,
7238
- features,
7239
- complexity,
7240
- limits
7241
- } = options;
7242
- const schemaEntries = Object.entries(schema);
7243
- const excludedTables = new Set(options.exclude?.tables ?? []);
7244
- const tableEntries = schemaEntries.filter(
7245
- ([key, value]) => is12(value, adapter.tableClass) && !excludedTables.has(key)
7246
- );
7247
- const tables = Object.fromEntries(tableEntries);
7248
- const featureOf = resolveTableFeatures(features);
7249
- const anyTable = (feature) => tableEntries.some(([name]) => featureOf(name)[feature]);
7250
- if (!tableEntries.length) {
7251
- throw new Error(
7252
- "Drizzle-GraphQL Error: No tables detected in Drizzle-ORM's database instance. Did you forget to pass schema to drizzle constructor?"
7253
- );
7254
- }
7255
- registerScalarOverrides(tables, options);
7256
- registerEnumConfig(options);
7257
- registerColumnExclusions(tables, options.exclude);
7258
- const namedRelations = buildNamedRelations(relations ?? {}, tableEntries);
7259
- for (const excluded of excludedTables) {
7260
- delete namedRelations[excluded];
7261
- }
7262
- attachTargetPrimaryKeys(namedRelations, tables, (table) => primaryKeyPropNames(table));
7263
- const eagerRelations = pruneNonEagerRelations(namedRelations, shouldEagerLoad);
7264
- const uniqueKeys = {};
7265
- for (const [tableName, table] of tableEntries) {
7266
- if (!featureOf(tableName).uniqueKeyFilters) {
7267
- continue;
7268
- }
7269
- const taken = /* @__PURE__ */ new Set([...Object.keys(visibleColumns(table)), ...Object.keys(namedRelations[tableName] ?? {})]);
7270
- const map = buildUniqueKeyMap(uniqueColumnSets(table), taken);
7271
- if (Object.keys(map).length) {
7272
- uniqueKeys[tableName] = map;
7273
- }
7274
- }
7275
- const filterCtx = { tables, relationMap: namedRelations, uniqueKeys };
7276
- const tablePolicies = options.policies;
7277
- const contextValuesOf = tablePolicies?.contextValues;
7278
- const softDeleteOf = tablePolicies?.softDelete;
7279
- const policies = bindPolicies(tablePolicies, filterCtx);
7280
- const resolverFactory = createRelationResolverFactory(
7281
- db,
7282
7081
  tables,
7283
- adapter.nullOrdering,
7082
+ featureOf,
7083
+ eagerRelations,
7284
7084
  filterCtx,
7285
- limits,
7286
- tablePolicies
7287
- );
7288
- const cacheCtx = {
7289
- typeName: options.typeName ?? ((info) => info.defaultName),
7290
- genericFilterCache: /* @__PURE__ */ new Map(),
7291
- objectTypeCache: /* @__PURE__ */ new Map(),
7292
- relationFieldContainers: /* @__PURE__ */ new Map(),
7293
- fullyBuiltTables: /* @__PURE__ */ new Set(),
7294
- relationTypeCache: /* @__PURE__ */ new Map(),
7295
- selectFieldCache: /* @__PURE__ */ new WeakMap(),
7296
- filterFieldCache: /* @__PURE__ */ new WeakMap(),
7297
- orderTypeCache: /* @__PURE__ */ new WeakMap(),
7298
- filterTypeCache: /* @__PURE__ */ new WeakMap(),
7299
- listRelationFilterCache: /* @__PURE__ */ new Map(),
7300
- aggregateTypeCache: /* @__PURE__ */ new Map(),
7301
- complexity,
7302
- limits,
7303
- docs: options.docs ?? {},
7304
- primaryKeyOf: (name) => tables[name] ? primaryKeyPropNames(tables[name]) : [],
7305
- contextValuesOf,
7085
+ policies,
7306
7086
  softDeleteOf,
7307
- featureOf,
7308
- uniqueKeysOf: (tableName) => uniqueKeys[tableName]
7309
- };
7310
- adapter.preflight?.(db, options);
7311
- const nestedPlans = features.nestedWrites ? buildNestedWritePlans(
7312
- tables,
7313
7087
  namedRelations,
7314
- (target) => uniqueColumnSets(target),
7315
- (target) => primaryKeyPropNames(target),
7316
- extractRelationJoinColumns
7317
- ) : void 0;
7318
- const nestedTypes = nestedPlans ? createNestedWriteTypes({ plans: nestedPlans, cacheCtx, typeNameMapper }) : void 0;
7319
- const nestedRuntime = nestedPlans ? createNestedWriteRuntime({
7320
- plans: nestedPlans,
7321
- filterCtx,
7322
- policies: tablePolicies,
7323
- contextValues: contextValuesOf
7324
- }) : void 0;
7325
- const relationAggregateFactory = anyTable("relationAggregates") ? createRelationAggregateFactory(db, tables, cacheCtx, typeNameMapper, filterCtx, tablePolicies) : void 0;
7326
- const queries = {};
7327
- const mutations = {};
7328
- const mutationTxCtx = createMutationTxCtx(options.transactions);
7329
- const gqlSchemaTypes = Object.fromEntries(
7330
- Object.entries(tables).map(([tableName, _table]) => [
7331
- tableName,
7332
- generateTableTypes(
7333
- tableName,
7334
- tables,
7335
- namedRelations,
7336
- true,
7337
- relationsDepthLimit,
7338
- cacheCtx,
7339
- typeNameMapper,
7340
- prefixes.insert,
7341
- prefixes.update,
7342
- resolverFactory,
7343
- featureOf(tableName).relationAggregates ? relationAggregateFactory : void 0,
7344
- nestedTypes
7345
- )
7346
- ])
7347
- );
7348
- const inputs = {};
7349
- const outputs = {};
7088
+ cacheCtx,
7089
+ nestedRuntime,
7090
+ mutationTxCtx,
7091
+ gqlSchemaTypes,
7092
+ mutations,
7093
+ inputs,
7094
+ outputs
7095
+ } = ctx;
7350
7096
  for (const [tableName, tableTypes] of Object.entries(gqlSchemaTypes)) {
7351
7097
  const tableFeatures = featureOf(tableName);
7352
7098
  const drizzleMeta = tableFieldExtensions(tableName, primaryKeyPropNames(schema[tableName]));
7353
7099
  const { insertInput, updateInput, tableFilters, tableOrder } = tableTypes.inputs;
7354
- const { selectSingleOutput, selectArrOutput, singleTableItemOutput, arrTableItemOutput } = tableTypes.outputs;
7100
+ const { selectSingleOutput, singleTableItemOutput, arrTableItemOutput } = tableTypes.outputs;
7101
+ const names = computeResolverFieldNames(tableName, typeNameMapper, prefixes, suffixes);
7355
7102
  const {
7356
7103
  typeName,
7357
- listFieldName,
7358
- singleFieldName,
7359
- aggregateFieldName,
7360
- groupByFieldName,
7361
7104
  createArrayFieldName,
7362
7105
  createSingleFieldName,
7363
7106
  upsertArrayFieldName,
@@ -7371,39 +7114,9 @@ var createSchemaDataGenerator = (adapter) => {
7371
7114
  restoreFieldName,
7372
7115
  restoreSingleFieldName,
7373
7116
  deleteCountFieldName
7374
- } = computeResolverFieldNames(tableName, typeNameMapper, prefixes, suffixes);
7117
+ } = names;
7375
7118
  const softDeleteInfo = softDeleteOf?.(tableName);
7376
- const selectArrGenerated = generateSelectArray2(
7377
- db,
7378
- tableName,
7379
- tables,
7380
- eagerRelations,
7381
- tableOrder,
7382
- tableFilters,
7383
- listFieldName,
7384
- typeName,
7385
- typeNameMapper,
7386
- filterCtx,
7387
- tableFeatures.distinct,
7388
- limits,
7389
- policies,
7390
- cacheCtx.typeName
7391
- );
7392
- const selectSingleGenerated = generateSelectSingle2(
7393
- db,
7394
- tableName,
7395
- tables,
7396
- eagerRelations,
7397
- tableOrder,
7398
- tableFilters,
7399
- singleFieldName,
7400
- typeName,
7401
- typeNameMapper,
7402
- filterCtx,
7403
- limits,
7404
- policies,
7405
- cacheCtx.typeName
7406
- );
7119
+ const { aggregateType, groupByType, havingInput } = addReadFields2(ctx, tableName, names, tableTypes, drizzleMeta);
7407
7120
  const insertArrGenerated = tableFeatures.insert ? generateInsertArray2(
7408
7121
  db,
7409
7122
  tableName,
@@ -7641,73 +7354,6 @@ var createSchemaDataGenerator = (adapter) => {
7641
7354
  filterCtx,
7642
7355
  txCtx: mutationTxCtx
7643
7356
  }) : void 0;
7644
- const aggregateType = tableFeatures.aggregates ? generateAggregateTypes(schema[tableName], tableName, typeName, cacheCtx) : void 0;
7645
- const aggregateGenerated = tableFeatures.aggregates ? generateAggregate(
7646
- db,
7647
- tableName,
7648
- schema[tableName],
7649
- typeName,
7650
- aggregateFieldName,
7651
- tableFilters,
7652
- filterCtx,
7653
- tablePolicies,
7654
- cacheCtx.typeName
7655
- ) : void 0;
7656
- const groupByType = tableFeatures.aggregates && tableFeatures.groupBy ? generateGroupByType(schema[tableName], tableName, typeName, cacheCtx) : void 0;
7657
- const groupByEnum = groupByType ? generateGroupByEnum(schema[tableName], tableName, typeName, cacheCtx) : void 0;
7658
- const havingInput = groupByEnum ? generateHavingInput(schema[tableName], tableName, typeName, cacheCtx) : void 0;
7659
- const groupByGenerated = groupByType && groupByEnum && havingInput ? generateGroupBy(
7660
- db,
7661
- tableName,
7662
- schema[tableName],
7663
- typeName,
7664
- groupByFieldName,
7665
- tableFilters,
7666
- groupByEnum,
7667
- havingInput,
7668
- filterCtx,
7669
- tablePolicies,
7670
- cacheCtx.typeName
7671
- ) : void 0;
7672
- queries[selectArrGenerated.name] = {
7673
- type: selectArrOutput,
7674
- args: selectArrGenerated.args,
7675
- resolve: selectArrGenerated.resolver,
7676
- extensions: {
7677
- drizzle: drizzleMeta({ kind: "query", operation: "select", single: false, targetArg: "where" }),
7678
- ...complexity ? { complexity: listFieldComplexity(complexity, limits?.(tableName)) } : {}
7679
- }
7680
- };
7681
- queries[selectSingleGenerated.name] = {
7682
- type: selectSingleOutput,
7683
- args: selectSingleGenerated.args,
7684
- resolve: selectSingleGenerated.resolver,
7685
- extensions: {
7686
- drizzle: drizzleMeta({ kind: "query", operation: "select", single: true, targetArg: "where" })
7687
- }
7688
- };
7689
- if (aggregateGenerated && aggregateType) {
7690
- queries[aggregateGenerated.name] = {
7691
- type: new GraphQLNonNull16(aggregateType),
7692
- args: aggregateGenerated.args,
7693
- resolve: aggregateGenerated.resolver,
7694
- extensions: {
7695
- drizzle: drizzleMeta({ kind: "aggregate", operation: "aggregate", single: true, targetArg: "where" }),
7696
- ...complexity ? { complexity: aggregateFieldComplexity(complexity) } : {}
7697
- }
7698
- };
7699
- }
7700
- if (groupByGenerated && groupByType) {
7701
- queries[groupByGenerated.name] = {
7702
- type: new GraphQLNonNull16(new GraphQLList12(new GraphQLNonNull16(groupByType))),
7703
- args: groupByGenerated.args,
7704
- resolve: groupByGenerated.resolver,
7705
- extensions: {
7706
- drizzle: drizzleMeta({ kind: "aggregate", operation: "groupBy", single: false, targetArg: "where" }),
7707
- ...complexity ? { complexity: aggregateFieldComplexity(complexity) } : {}
7708
- }
7709
- };
7710
- }
7711
7357
  if (insertArrGenerated) {
7712
7358
  mutations[insertArrGenerated.name] = {
7713
7359
  type: arrTableItemOutput,
@@ -7722,7 +7368,7 @@ var createSchemaDataGenerator = (adapter) => {
7722
7368
  mutations[insertSingleGenerated.name] = {
7723
7369
  // An insert either returns the row it inserted or throws — the one path to `null` is
7724
7370
  // `conflictDoNothing` swallowing the insert, so the field is nullable only there.
7725
- type: conflictDoNothing ? singleTableItemOutput : new GraphQLNonNull16(singleTableItemOutput),
7371
+ type: conflictDoNothing ? singleTableItemOutput : new GraphQLNonNull17(singleTableItemOutput),
7726
7372
  args: insertSingleGenerated.args,
7727
7373
  resolve: insertSingleGenerated.resolver,
7728
7374
  extensions: {
@@ -7762,7 +7408,7 @@ var createSchemaDataGenerator = (adapter) => {
7762
7408
  }
7763
7409
  if (updateManyGenerated) {
7764
7410
  mutations[updateManyGenerated.name] = {
7765
- type: new GraphQLNonNull16(new GraphQLList12(singleTableItemOutput)),
7411
+ type: new GraphQLNonNull17(new GraphQLList13(singleTableItemOutput)),
7766
7412
  args: updateManyGenerated.args,
7767
7413
  resolve: updateManyGenerated.resolver,
7768
7414
  extensions: {
@@ -7838,7 +7484,7 @@ var createSchemaDataGenerator = (adapter) => {
7838
7484
  }
7839
7485
  if (updateCountGenerated) {
7840
7486
  mutations[updateCountGenerated.name] = {
7841
- type: new GraphQLNonNull16(GraphQLInt9),
7487
+ type: new GraphQLNonNull17(GraphQLInt9),
7842
7488
  args: updateCountGenerated.args,
7843
7489
  resolve: updateCountGenerated.resolver,
7844
7490
  description: "How many rows the update touched. The rows themselves are not read back, which is the point of this mutation."
@@ -7846,7 +7492,7 @@ var createSchemaDataGenerator = (adapter) => {
7846
7492
  }
7847
7493
  if (deleteCountGenerated) {
7848
7494
  mutations[deleteCountGenerated.name] = {
7849
- type: new GraphQLNonNull16(GraphQLInt9),
7495
+ type: new GraphQLNonNull17(GraphQLInt9),
7850
7496
  args: deleteCountGenerated.args,
7851
7497
  resolve: deleteCountGenerated.resolver,
7852
7498
  description: "How many rows the delete removed. The rows themselves are not read back, which is the point of this mutation."
@@ -7874,31 +7520,12 @@ var createSchemaDataGenerator = (adapter) => {
7874
7520
  inputs[havingInput.name] = havingInput;
7875
7521
  }
7876
7522
  }
7877
- if (mutationTxCtx) {
7878
- for (const name of Object.keys(mutations)) {
7879
- mutationTxCtx.fieldNames.add(name);
7880
- }
7881
- }
7882
- const fieldResolvers = {};
7883
- for (const [tableName, tableRelations] of Object.entries(namedRelations)) {
7884
- const relResolvers = {};
7885
- for (const [relName, relEntry] of Object.entries(tableRelations)) {
7886
- const isOne = is12(relEntry.relation ?? relEntry, One9);
7887
- const resolver = resolverFactory({ tableName, relationName: relName, relEntry, isOne });
7888
- if (resolver) {
7889
- relResolvers[relName] = resolver;
7890
- }
7891
- }
7892
- if (Object.keys(relResolvers).length > 0) {
7893
- fieldResolvers[tableName] = relResolvers;
7894
- }
7895
- }
7896
- return { queries, mutations, inputs, types: outputs, fieldResolvers };
7523
+ return finalizeBuild2(ctx);
7897
7524
  };
7898
7525
  };
7899
7526
 
7900
7527
  // src/util/builders/update-many.ts
7901
- import { GraphQLList as GraphQLList13, GraphQLNonNull as GraphQLNonNull17 } from "graphql";
7528
+ import { GraphQLList as GraphQLList14, GraphQLNonNull as GraphQLNonNull18 } from "graphql";
7902
7529
  import { parseResolveInfo as parseResolveInfo4 } from "graphql-parse-resolve-info";
7903
7530
  var runUpdateManyBatch = ({
7904
7531
  executor,
@@ -7929,126 +7556,100 @@ var createUpdateManyGenerator = (primaryKeyPropNames, runBatch = runUpdateManyBa
7929
7556
  return (db, tableName, table, tables, relationMap, updateManyInput, fieldName, typeName, typeNameMapper, filterCtx, txCtx, nested, limits, policies, resolveName) => {
7930
7557
  const queryArgs = {
7931
7558
  updates: {
7932
- type: new GraphQLNonNull17(new GraphQLList13(new GraphQLNonNull17(updateManyInput)))
7559
+ type: new GraphQLNonNull18(new GraphQLList14(new GraphQLNonNull18(updateManyInput)))
7933
7560
  }
7934
7561
  };
7935
7562
  const pkNames = primaryKeyPropNames(table);
7936
- const hooks = policies?.onWrite?.(tableName, "updateMany");
7937
- const errorCtx = { table: tableName, operation: "updateMany", field: fieldName };
7938
- return {
7939
- name: fieldName,
7940
- resolver: async (_source, args, context, info) => {
7941
- try {
7942
- return await runMutation(
7943
- db,
7944
- context,
7945
- info,
7946
- txCtx,
7947
- async (executor) => {
7948
- const { updates } = args;
7949
- if (!updates.length) {
7950
- throw drizzleError("No updates were provided!", { code: "DRIZZLE_NO_VALUES" });
7951
- }
7952
- await runWriteHook(hooks, "before", {
7953
- table: tableName,
7954
- operation: "updateMany",
7955
- single: false,
7956
- args,
7957
- context,
7958
- info,
7959
- tx: executor
7960
- });
7961
- const scope = policies?.scope?.(context);
7962
- const contextColumns = policies?.contextValues?.(tableName);
7963
- const parsedInfo = parseResolveInfo4(info, {
7964
- deep: true
7965
- });
7966
- const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7967
- relationMap,
7968
- tables,
7969
- tableName,
7970
- typeName,
7971
- typeNameMapper,
7972
- resolveName,
7973
- table,
7974
- pkNames,
7975
- parsedInfo,
7976
- limits,
7977
- scope,
7978
- defaultOrderBy: policies?.defaultOrderBy
7979
- });
7980
- const entries = updates.map(({ where, set }) => {
7981
- const split = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
7982
- const ops = split && nested.hasOps(split.ops) ? split.ops : void 0;
7983
- const input = stripContextValues(
7984
- remapUpdateInput(split ? split.columns : set, table, tableName),
7985
- contextColumns
7986
- );
7987
- if (!Object.keys(input).length && !ops) {
7988
- throw drizzleError("Unable to update with no values specified!", { code: "DRIZZLE_NO_VALUES" });
7989
- }
7990
- return {
7991
- set: input,
7992
- ops,
7993
- filters: withScope(
7994
- scope,
7995
- tableName,
7996
- table,
7997
- where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
7998
- )
7999
- };
8000
- });
8001
- const anyNested = entries.some((entry) => entry.ops);
8002
- const returning = anyNested ? nested.withJoinColumns(
8003
- tableName,
8004
- mergedOps(entries.map((entry) => ({ ops: entry.ops ?? {} }))),
8005
- { ...columns },
8006
- table
8007
- ) : columns;
8008
- const perEntry = await runBatch({
8009
- executor,
8010
- entries,
8011
- table,
8012
- returning,
8013
- anyNested,
8014
- nested,
8015
- tableName,
8016
- context
8017
- });
8018
- const flatRows = perEntry.flat();
8019
- await runWriteHook(hooks, "after", {
8020
- table: tableName,
8021
- operation: "updateMany",
8022
- single: false,
8023
- args,
8024
- rows: flatRows,
8025
- context,
8026
- info,
8027
- tx: executor
8028
- });
8029
- const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, flatRows, pkNames, withParams) : flatRows;
8030
- const output = [];
8031
- let offset = 0;
8032
- for (const rows of perEntry) {
8033
- if (!rows.length) {
8034
- output.push(null);
8035
- continue;
8036
- }
8037
- for (let i = 0; i < rows.length; i++) {
8038
- output.push(remapToGraphQLSingleOutput(enriched[offset + i], tableName, table, relationMap));
8039
- }
8040
- offset += rows.length;
8041
- }
8042
- return output;
8043
- },
8044
- !!hooks
7563
+ return writeResolver({
7564
+ db,
7565
+ tableName,
7566
+ operation: "updateMany",
7567
+ single: false,
7568
+ fieldName,
7569
+ txCtx,
7570
+ policies,
7571
+ args: queryArgs,
7572
+ run: async ({ executor, args, context, info, before, after }) => {
7573
+ const { updates } = args;
7574
+ if (!updates.length) {
7575
+ throw drizzleError("No updates were provided!", { code: "DRIZZLE_NO_VALUES" });
7576
+ }
7577
+ await before();
7578
+ const scope = policies?.scope?.(context);
7579
+ const contextColumns = policies?.contextValues?.(tableName);
7580
+ const parsedInfo = parseResolveInfo4(info, {
7581
+ deep: true
7582
+ });
7583
+ const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
7584
+ relationMap,
7585
+ tables,
7586
+ tableName,
7587
+ typeName,
7588
+ typeNameMapper,
7589
+ resolveName,
7590
+ table,
7591
+ pkNames,
7592
+ parsedInfo,
7593
+ limits,
7594
+ scope,
7595
+ defaultOrderBy: policies?.defaultOrderBy
7596
+ });
7597
+ const entries = updates.map(({ where, set }) => {
7598
+ const split = nested?.enabled(tableName) ? nested.split(tableName, set) : void 0;
7599
+ const ops = split && nested.hasOps(split.ops) ? split.ops : void 0;
7600
+ const input = stripContextValues(
7601
+ remapUpdateInput(split ? split.columns : set, table, tableName),
7602
+ contextColumns
8045
7603
  );
8046
- } catch (e) {
8047
- throw withErrorContext(toGraphQLError(e), errorCtx);
7604
+ if (!Object.keys(input).length && !ops) {
7605
+ throw drizzleError("Unable to update with no values specified!", { code: "DRIZZLE_NO_VALUES" });
7606
+ }
7607
+ return {
7608
+ set: input,
7609
+ ops,
7610
+ filters: withScope(
7611
+ scope,
7612
+ tableName,
7613
+ table,
7614
+ where ? extractFilters(table, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0
7615
+ )
7616
+ };
7617
+ });
7618
+ const anyNested = entries.some((entry) => entry.ops);
7619
+ const returning = anyNested ? nested.withJoinColumns(
7620
+ tableName,
7621
+ mergedOps(entries.map((entry) => ({ ops: entry.ops ?? {} }))),
7622
+ { ...columns },
7623
+ table
7624
+ ) : columns;
7625
+ const perEntry = await runBatch({
7626
+ executor,
7627
+ entries,
7628
+ table,
7629
+ returning,
7630
+ anyNested,
7631
+ nested,
7632
+ tableName,
7633
+ context
7634
+ });
7635
+ const flatRows = perEntry.flat();
7636
+ await after(flatRows);
7637
+ const enriched = hasRelations ? await eagerLoadMutationRelations(executor, tableName, flatRows, pkNames, withParams) : flatRows;
7638
+ const output = [];
7639
+ let offset = 0;
7640
+ for (const rows of perEntry) {
7641
+ if (!rows.length) {
7642
+ output.push(null);
7643
+ continue;
7644
+ }
7645
+ for (let i = 0; i < rows.length; i++) {
7646
+ output.push(remapToGraphQLSingleOutput(enriched[offset + i], tableName, table, relationMap));
7647
+ }
7648
+ offset += rows.length;
8048
7649
  }
8049
- },
8050
- args: queryArgs
8051
- };
7650
+ return output;
7651
+ }
7652
+ });
8052
7653
  };
8053
7654
  };
8054
7655
 
@@ -8061,6 +7662,8 @@ var pgSchemaData = createSchemaDataGenerator({
8061
7662
  primaryKeyPropNames: pgPrimaryKeyPropNames,
8062
7663
  // PostgreSQL sorts NULLs as the largest values (last in ASC).
8063
7664
  nullOrdering: "nulls-largest",
7665
+ // Writes come back with their rows, so the table types carry the `${Table}Item` outputs.
7666
+ returnsRows: true,
8064
7667
  generateUpdateMany: generateUpdateMany2
8065
7668
  });
8066
7669
  var generateSchemaData2 = (db, schema, relations, options) => pgSchemaData(db, schema, relations, options);
@@ -8132,6 +7735,8 @@ var sqliteSchemaData = createSchemaDataGenerator({
8132
7735
  primaryKeyPropNames: sqlitePrimaryKeyPropNames,
8133
7736
  // SQLite sorts NULLs as the smallest values (first in ASC).
8134
7737
  nullOrdering: "nulls-smallest",
7738
+ // Writes come back with their rows, so the table types carry the `${Table}Item` outputs.
7739
+ returnsRows: true,
8135
7740
  // A synchronous driver (e.g. better-sqlite3) commits the moment its transaction callback
8136
7741
  // returns, so it can neither interleave awaited statements inside one transaction nor hold
8137
7742
  // one open across resolver calls — which is what both of these features require.
@@ -8152,20 +7757,20 @@ var sqliteSchemaData = createSchemaDataGenerator({
8152
7757
  var generateSchemaData3 = (db, schema, relations, options) => sqliteSchemaData(db, schema, relations, options);
8153
7758
 
8154
7759
  // src/util/selection.ts
8155
- import { is as is13, Table as Table2 } from "drizzle-orm";
7760
+ import { is as is12, Table as Table2 } from "drizzle-orm";
8156
7761
  import { getTableConfig as getMySqlTableConfig, MySqlDatabase } from "drizzle-orm/mysql-core";
8157
7762
  import { getTableConfig as getPgTableConfig, PgAsyncDatabase } from "drizzle-orm/pg-core";
8158
7763
  import { BaseSQLiteDatabase, getTableConfig as getSQLiteTableConfig } from "drizzle-orm/sqlite-core";
8159
7764
  import { parseResolveInfo as parseResolveInfo5 } from "graphql-parse-resolve-info";
8160
7765
  var contextCache = /* @__PURE__ */ new WeakMap();
8161
7766
  var tableConfigFor = (db) => {
8162
- if (is13(db, MySqlDatabase)) {
7767
+ if (is12(db, MySqlDatabase)) {
8163
7768
  return getMySqlTableConfig;
8164
7769
  }
8165
- if (is13(db, PgAsyncDatabase)) {
7770
+ if (is12(db, PgAsyncDatabase)) {
8166
7771
  return getPgTableConfig;
8167
7772
  }
8168
- if (is13(db, BaseSQLiteDatabase)) {
7773
+ if (is12(db, BaseSQLiteDatabase)) {
8169
7774
  return getSQLiteTableConfig;
8170
7775
  }
8171
7776
  throw new Error("Drizzle-GraphQL Error: unsupported database instance \u2014 expected a PostgreSQL, MySQL or SQLite one.");
@@ -8179,7 +7784,7 @@ var contextFor = (db) => {
8179
7784
  const schema = db._.fullSchema ?? Object.fromEntries(
8180
7785
  Object.entries(relations).filter(([, config]) => config?.table != null).map(([key, config]) => [key, config.table])
8181
7786
  );
8182
- const tableEntries = Object.entries(schema).filter(([, value]) => is13(value, Table2));
7787
+ const tableEntries = Object.entries(schema).filter(([, value]) => is12(value, Table2));
8183
7788
  if (!tableEntries.length) {
8184
7789
  throw new Error(
8185
7790
  "Drizzle-GraphQL Error: Schema not found in drizzle instance. Pass relations (from buildRelations/defineRelations) to the drizzle constructor so drizzle-graphql can read your tables."
@@ -8311,11 +7916,11 @@ var buildSchema = (db, config) => {
8311
7916
  }
8312
7917
  const generatorOptions = resolveBuildConfig(config, schema);
8313
7918
  let generatorOutput;
8314
- if (is14(db, MySqlDatabase2)) {
7919
+ if (is13(db, MySqlDatabase2)) {
8315
7920
  generatorOutput = generateSchemaData(db, schema, relations, generatorOptions);
8316
- } else if (is14(db, PgAsyncDatabase2)) {
7921
+ } else if (is13(db, PgAsyncDatabase2)) {
8317
7922
  generatorOutput = generateSchemaData2(db, schema, relations, generatorOptions);
8318
- } else if (is14(db, BaseSQLiteDatabase2)) {
7923
+ } else if (is13(db, BaseSQLiteDatabase2)) {
8319
7924
  generatorOutput = generateSchemaData3(db, schema, relations, generatorOptions);
8320
7925
  } else {
8321
7926
  throw new Error("Drizzle-GraphQL Error: Unknown database instance type");