@vantreeseba/drizzle-graphql 10.0.0 → 10.0.1

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,10 +1,10 @@
1
- import { Column, One, SQL, Table, aliasedTable, and, arrayContains, arrayOverlaps, asc, avg, count, countDistinct, desc, eq, extractExtendedColumnType, getColumns, getTableAsAliasSQL, getTableColumns, gt, gte, ilike, inArray, is, isNotNull, isNull, like, lt, lte, max, min, ne, not, notIlike, notInArray, notLike, or, relationsFilterToSQL, sql, sum } from "drizzle-orm";
1
+ import { Column, One, SQL, Table, aliasedTable, and, arrayContains, arrayOverlaps, asc, avg, count, countDistinct, desc, eq, extractExtendedColumnType, getColumns, getTableAsAliasSQL, gt, gte, ilike, inArray, is, isNotNull, isNull, like, lt, lte, max, min, ne, not, notIlike, notInArray, notLike, or, relationsFilterToSQL, sql, sum } from "drizzle-orm";
2
2
  import { MySqlAsyncDatabase, MySqlInt, MySqlSerial, MySqlTable, getTableConfig } from "drizzle-orm/mysql-core";
3
3
  import { PgAsyncDatabase, PgDate, PgDateString, PgInteger, PgSerial, PgTable, PgTimestamp, PgTimestampString, PgUUID, getTableConfig as getTableConfig$1 } from "drizzle-orm/pg-core";
4
4
  import { SQLiteAsyncDatabase, SQLiteInteger, SQLiteTable, getTableConfig as getTableConfig$2 } from "drizzle-orm/sqlite-core";
5
5
  import { GraphQLBoolean, GraphQLEnumType, GraphQLError, GraphQLFloat, GraphQLInputObjectType, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLString, Kind, getArgumentValues } from "graphql";
6
- import pluralize from "pluralize";
7
6
  import { GraphQLDate, GraphQLDateTime, GraphQLJSON, GraphQLUUID } from "graphql-scalars";
7
+ import pluralize from "pluralize";
8
8
  //#region src/util/builders/common/errors.ts
9
9
  /**
10
10
  * A `GraphQLError` carrying its context as data. The message says what went wrong, in prose
@@ -91,28 +91,6 @@ const applyErrorMapper = (entities, mapError) => {
91
91
  for (const tableResolvers of Object.values(entities.fieldResolvers ?? {})) for (const [relationName, resolve] of Object.entries(tableResolvers)) tableResolvers[relationName] = wrap(resolve);
92
92
  };
93
93
  //#endregion
94
- //#region src/util/case-ops/index.ts
95
- const uncapitalize = (input) => input?.length ? `${input[0].toLocaleLowerCase()}${input.length > 1 ? input.slice(1, input.length) : ""}` : input;
96
- const capitalize = (input) => input?.length ? `${input[0].toLocaleUpperCase()}${input.length > 1 ? input.slice(1, input.length) : ""}` : input;
97
- /**
98
- * The `typeNameMapper` preset behind `typeNameMapper: 'singularize'`.
99
- *
100
- * Derives the singular and plural forms of a table key with the library's own `pluralize`,
101
- * which is what nearly every consumer with plural table keys (`export const tasks =
102
- * pgTable('tasks', …)`) was writing by hand — and adding `pluralize` to their own
103
- * dependencies to write.
104
- *
105
- * `tasks` becomes type `Task`, queries `tasks` / `task`, mutations `createTasks` /
106
- * `createTask`. A key that is already singular is pluralized for the list side, so `task`
107
- * yields the same names, and a capitalized key (`Tasks`) yields them too — the field forms
108
- * are uncapitalized so the generated names follow GraphQL's camelCase convention whatever
109
- * the schema key looks like. The type name is capitalized by the generator either way.
110
- */
111
- const singularizeMapper = (tableName) => ({
112
- singular: uncapitalize(pluralize.singular(tableName)),
113
- plural: uncapitalize(pluralize.plural(tableName))
114
- });
115
- //#endregion
116
94
  //#region src/util/scalars/index.ts
117
95
  const INVALID_INPUT = "DRIZZLE_INVALID_INPUT_VALUE";
118
96
  const UNREPRESENTABLE = "DRIZZLE_UNREPRESENTABLE_VALUE";
@@ -183,6 +161,28 @@ const GraphQLDecimalString = new GraphQLScalarType({
183
161
  }
184
162
  });
185
163
  //#endregion
164
+ //#region src/util/case-ops/index.ts
165
+ const uncapitalize = (input) => input?.length ? `${input[0].toLocaleLowerCase()}${input.length > 1 ? input.slice(1, input.length) : ""}` : input;
166
+ const capitalize = (input) => input?.length ? `${input[0].toLocaleUpperCase()}${input.length > 1 ? input.slice(1, input.length) : ""}` : input;
167
+ /**
168
+ * The `typeNameMapper` preset behind `typeNameMapper: 'singularize'`.
169
+ *
170
+ * Derives the singular and plural forms of a table key with the library's own `pluralize`,
171
+ * which is what nearly every consumer with plural table keys (`export const tasks =
172
+ * pgTable('tasks', …)`) was writing by hand — and adding `pluralize` to their own
173
+ * dependencies to write.
174
+ *
175
+ * `tasks` becomes type `Task`, queries `tasks` / `task`, mutations `createTasks` /
176
+ * `createTask`. A key that is already singular is pluralized for the list side, so `task`
177
+ * yields the same names, and a capitalized key (`Tasks`) yields them too — the field forms
178
+ * are uncapitalized so the generated names follow GraphQL's camelCase convention whatever
179
+ * the schema key looks like. The type name is capitalized by the generator either way.
180
+ */
181
+ const singularizeMapper = (tableName) => ({
182
+ singular: uncapitalize(pluralize.singular(tableName)),
183
+ plural: uncapitalize(pluralize.plural(tableName))
184
+ });
185
+ //#endregion
186
186
  //#region src/util/type-converter/index.ts
187
187
  const allowedNameChars = /^[a-zA-Z0-9_]+$/;
188
188
  /**
@@ -412,7 +412,7 @@ const normalizeScalarOverride = (override, tableName, columnName) => {
412
412
  * leaves the column on built-in detection.
413
413
  */
414
414
  const registerScalarOverrides = (tables, config) => {
415
- for (const [tableName, table] of Object.entries(tables)) for (const [columnName, column] of Object.entries(getTableColumns(table))) {
415
+ for (const [tableName, table] of Object.entries(tables)) for (const [columnName, column] of Object.entries(getColumns(table))) {
416
416
  const declared = config.scalars?.[tableName]?.[columnName];
417
417
  let resolved;
418
418
  if (declared !== void 0) resolved = normalizeScalarOverride(declared, tableName, columnName);
@@ -451,137 +451,6 @@ const drizzleColumnToGraphQLType = (column, columnName, tableName, forceNullable
451
451
  return typeDesc;
452
452
  };
453
453
  //#endregion
454
- //#region src/util/data-mappers/index.ts
455
- const isJsonColumn$1 = (column) => (column.dataType ?? "").includes("json") && column.columnType !== "PgGeometryObject";
456
- const remapToGraphQLCore = (key, value, tableName, column, relationMap) => {
457
- if (Array.isArray(value)) {
458
- const relations = relationMap?.[tableName];
459
- if (relations?.[key]) {
460
- const rel = relations[key];
461
- return remapToGraphQLArrayOutput(value, rel.targetTableName, rel.relation?.targetTable ?? rel.relation?.referencedTable, relationMap);
462
- }
463
- }
464
- if (typeof value === "object" && value !== null) {
465
- const relations = relationMap?.[tableName];
466
- if (relations?.[key]) {
467
- const rel = relations[key];
468
- return remapToGraphQLSingleOutput(value, rel.targetTableName, rel.relation?.targetTable ?? rel.relation?.referencedTable, relationMap);
469
- }
470
- }
471
- if (!column) return value;
472
- if (getColumnScalarOverride(column, false)) return value;
473
- if (isJsonColumn$1(column)) return value;
474
- if (value instanceof Date) return value.toISOString();
475
- if (value instanceof Buffer) return Array.from(value);
476
- if (typeof value === "bigint") return value.toString();
477
- if (Array.isArray(value)) {
478
- if (column.columnType === "PgGeometry" || column.columnType === "PgVector") return value;
479
- return value.map((arrVal) => remapToGraphQLCore(key, arrVal, tableName, column, relationMap));
480
- }
481
- if (typeof value === "object" && value !== null) {
482
- if (column.columnType === "PgGeometryObject") return value;
483
- return JSON.stringify(value);
484
- }
485
- return value;
486
- };
487
- const remapToGraphQLSingleOutput = (queryOutput, tableName, table, relationMap) => {
488
- const columns = getTableColumns(table);
489
- for (const [key, value] of Object.entries(queryOutput)) {
490
- if (value === void 0 || value === null) {
491
- const relEntry = value === null ? relationMap?.[tableName]?.[key] : void 0;
492
- if (relEntry && is(relEntry.relation, One)) {
493
- queryOutput[key] = null;
494
- continue;
495
- }
496
- delete queryOutput[key];
497
- continue;
498
- }
499
- const column = columns[key];
500
- if (value === 0n && column && column.columnType === "SQLiteBigInt" && !column.notNull) {
501
- delete queryOutput[key];
502
- continue;
503
- }
504
- queryOutput[key] = remapToGraphQLCore(key, value, tableName, column, relationMap);
505
- }
506
- return queryOutput;
507
- };
508
- const remapToGraphQLArrayOutput = (queryOutput, tableName, table, relationMap) => {
509
- for (const entry of queryOutput) remapToGraphQLSingleOutput(entry, tableName, table, relationMap);
510
- return queryOutput;
511
- };
512
- const remapFromGraphQLCore = (value, column, columnName) => {
513
- if (getColumnScalarOverride(column, true)) {
514
- if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === null) return Object.assign({}, value);
515
- return value;
516
- }
517
- const dataType = column.dataType ?? "";
518
- const columnType = column.columnType ?? "";
519
- if (columnType === "SQLiteTimestamp" || columnType === "SQLiteTimestampMs" || columnType === "MySqlTimestamp" || columnType === "MySqlDateTime" || columnType === "PgTimestamp" || columnType === "PgTimestampString") {
520
- const formatted = new Date(value);
521
- if (Number.isNaN(formatted.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
522
- return formatted;
523
- }
524
- if ((columnType === "MySqlDate" || columnType === "PgDate") && typeof value === "string") {
525
- const dateOnly = value.includes("T") ? value.split("T")[0] : value;
526
- const check = new Date(dateOnly);
527
- if (Number.isNaN(check.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
528
- return dateOnly;
529
- }
530
- if (dataType.includes("bigint")) try {
531
- return BigInt(value);
532
- } catch {
533
- throw drizzleError(`Field '${columnName}' is not a BigInt!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
534
- }
535
- if (dataType.includes("json") && column.columnType !== "PgGeometryObject") return value;
536
- switch (dataType) {
537
- case "date": {
538
- const formatted = new Date(value);
539
- if (Number.isNaN(formatted.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
540
- return formatted;
541
- }
542
- case "buffer":
543
- if (!Array.isArray(value)) throw drizzleError(`Field '${columnName}' is not an array!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
544
- return Buffer.from(value);
545
- case "json":
546
- if (column.columnType === "PgGeometryObject") return value;
547
- try {
548
- return JSON.parse(value);
549
- } catch (e) {
550
- throw drizzleError(`Invalid JSON in field '${columnName}':\n${e instanceof Error ? e.message : "Unknown error"}`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
551
- }
552
- case "array":
553
- if (!Array.isArray(value)) throw drizzleError(`Field '${columnName}' is not an array!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
554
- if (column.columnType === "PgGeometry" && value.length !== 2) throw drizzleError(`Invalid float tuple in field '${columnName}': expected array with length of 2, received ${value.length}`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
555
- return value;
556
- case "bigint": try {
557
- return BigInt(value);
558
- } catch (_error) {
559
- throw drizzleError(`Field '${columnName}' is not a BigInt!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
560
- }
561
- default:
562
- if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === null) return Object.assign({}, value);
563
- return value;
564
- }
565
- };
566
- const remapFromGraphQLSingleInput = (queryInput, table, operation = "insert") => {
567
- for (const [key, value] of Object.entries(queryInput)) if (value === void 0) delete queryInput[key];
568
- else {
569
- const column = getTableColumns(table)[key];
570
- if (!column) throw drizzleError(`Unknown column: ${key}`, { code: "DRIZZLE_UNKNOWN_COLUMN" });
571
- if (value === null && column.notNull) {
572
- if (operation === "update") throw drizzleError(`Column '${key}' cannot be set to null.`, { code: "DRIZZLE_NOT_NULL" });
573
- delete queryInput[key];
574
- continue;
575
- }
576
- queryInput[key] = remapFromGraphQLCore(value, column, key);
577
- }
578
- return queryInput;
579
- };
580
- const remapFromGraphQLArrayInput = (queryInput, table, operation = "insert") => {
581
- for (const entry of queryInput) remapFromGraphQLSingleInput(entry, table, operation);
582
- return queryInput;
583
- };
584
- //#endregion
585
454
  //#region src/util/builders/common/type-names.ts
586
455
  /**
587
456
  * The build's naming rule: the mapper's answer where it has one, otherwise the default name
@@ -624,6 +493,23 @@ const columnDialect = (column) => {
624
493
  if (ct.startsWith("SQLite")) return "sqlite";
625
494
  };
626
495
  /**
496
+ * Whether the column stores JSON.
497
+ *
498
+ * Decided on drizzle's `dataType`, its semantic marker, rather than on `columnType`, which
499
+ * names the implementing class. drizzle-orm v1 uses compound dataType strings (`"object
500
+ * json"` for every json/jsonb column across the three dialects), hence the inclusion test.
501
+ *
502
+ * `PgGeometryObject` is excluded explicitly. That is currently redundant — it reports
503
+ * `"object geometry"` — but it is stored as json, has its own object type in the generated
504
+ * schema, and must not be reclassified if drizzle ever spells its dataType differently.
505
+ *
506
+ * One predicate for two callers that must agree: the filter builder, whose `path` and
507
+ * `contains` operators mean structural JSON containment rather than the string operators,
508
+ * and the data mappers, which transport a JSON value as-is instead of remapping it. They
509
+ * previously had a copy each, asking different questions of the column.
510
+ */
511
+ const isJsonColumn = (column) => (column.dataType ?? "").includes("json") && column.columnType !== "PgGeometryObject";
512
+ /**
627
513
  * Maps a Drizzle column to the generic filter type to use.
628
514
  *
629
515
  * Selection is keyed on the column's data type, never its name: a text column named
@@ -1054,6 +940,137 @@ const generateColumnFilterValues = (column, tableName, columnName, cacheCtx) =>
1054
940
  return mainType;
1055
941
  };
1056
942
  //#endregion
943
+ //#region src/util/data-mappers/index.ts
944
+ const remapToGraphQLCore = (key, value, tableName, column, relationMap) => {
945
+ if (Array.isArray(value)) {
946
+ const relations = relationMap?.[tableName];
947
+ if (relations?.[key]) {
948
+ const rel = relations[key];
949
+ return remapToGraphQLArrayOutput(value, rel.targetTableName, rel.relation?.targetTable ?? rel.relation?.referencedTable, relationMap);
950
+ }
951
+ }
952
+ if (typeof value === "object" && value !== null) {
953
+ const relations = relationMap?.[tableName];
954
+ if (relations?.[key]) {
955
+ const rel = relations[key];
956
+ return remapToGraphQLSingleOutput(value, rel.targetTableName, rel.relation?.targetTable ?? rel.relation?.referencedTable, relationMap);
957
+ }
958
+ }
959
+ if (!column) return value;
960
+ if (getColumnScalarOverride(column, false)) return value;
961
+ if (isJsonColumn(column)) return value;
962
+ if (value instanceof Date) return value.toISOString();
963
+ if (value instanceof Buffer) return Array.from(value);
964
+ if (typeof value === "bigint") return value.toString();
965
+ if (Array.isArray(value)) {
966
+ if (column.columnType === "PgGeometry" || column.columnType === "PgVector") return value;
967
+ return value.map((arrVal) => remapToGraphQLCore(key, arrVal, tableName, column, relationMap));
968
+ }
969
+ if (typeof value === "object" && value !== null) {
970
+ if (column.columnType === "PgGeometryObject") return value;
971
+ return JSON.stringify(value);
972
+ }
973
+ return value;
974
+ };
975
+ const remapToGraphQLSingleOutput = (queryOutput, tableName, table, relationMap) => {
976
+ const columns = getColumns(table);
977
+ for (const [key, value] of Object.entries(queryOutput)) {
978
+ if (value === void 0 || value === null) {
979
+ const relEntry = value === null ? relationMap?.[tableName]?.[key] : void 0;
980
+ if (relEntry && is(relEntry.relation, One)) {
981
+ queryOutput[key] = null;
982
+ continue;
983
+ }
984
+ delete queryOutput[key];
985
+ continue;
986
+ }
987
+ const column = columns[key];
988
+ if (value === 0n && column && column.columnType === "SQLiteBigInt" && !column.notNull) {
989
+ delete queryOutput[key];
990
+ continue;
991
+ }
992
+ queryOutput[key] = remapToGraphQLCore(key, value, tableName, column, relationMap);
993
+ }
994
+ return queryOutput;
995
+ };
996
+ const remapToGraphQLArrayOutput = (queryOutput, tableName, table, relationMap) => {
997
+ for (const entry of queryOutput) remapToGraphQLSingleOutput(entry, tableName, table, relationMap);
998
+ return queryOutput;
999
+ };
1000
+ const remapFromGraphQLCore = (value, column, columnName) => {
1001
+ if (getColumnScalarOverride(column, true)) {
1002
+ if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === null) return Object.assign({}, value);
1003
+ return value;
1004
+ }
1005
+ const dataType = column.dataType ?? "";
1006
+ const columnType = column.columnType ?? "";
1007
+ if (columnType === "SQLiteTimestamp" || columnType === "SQLiteTimestampMs" || columnType === "MySqlTimestamp" || columnType === "MySqlDateTime" || columnType === "PgTimestamp" || columnType === "PgTimestampString") {
1008
+ const formatted = new Date(value);
1009
+ if (Number.isNaN(formatted.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
1010
+ return formatted;
1011
+ }
1012
+ if ((columnType === "MySqlDate" || columnType === "PgDate") && typeof value === "string") {
1013
+ const dateOnly = value.includes("T") ? value.split("T")[0] : value;
1014
+ const check = new Date(dateOnly);
1015
+ if (Number.isNaN(check.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
1016
+ return dateOnly;
1017
+ }
1018
+ if (dataType.includes("bigint")) try {
1019
+ return BigInt(value);
1020
+ } catch {
1021
+ throw drizzleError(`Field '${columnName}' is not a BigInt!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
1022
+ }
1023
+ if (dataType.includes("json") && column.columnType !== "PgGeometryObject") return value;
1024
+ switch (dataType) {
1025
+ case "date": {
1026
+ const formatted = new Date(value);
1027
+ if (Number.isNaN(formatted.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
1028
+ return formatted;
1029
+ }
1030
+ case "buffer":
1031
+ if (!Array.isArray(value)) throw drizzleError(`Field '${columnName}' is not an array!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
1032
+ return Buffer.from(value);
1033
+ case "json":
1034
+ if (column.columnType === "PgGeometryObject") return value;
1035
+ try {
1036
+ return JSON.parse(value);
1037
+ } catch (e) {
1038
+ throw drizzleError(`Invalid JSON in field '${columnName}':\n${e instanceof Error ? e.message : "Unknown error"}`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
1039
+ }
1040
+ case "array":
1041
+ if (!Array.isArray(value)) throw drizzleError(`Field '${columnName}' is not an array!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
1042
+ if (column.columnType === "PgGeometry" && value.length !== 2) throw drizzleError(`Invalid float tuple in field '${columnName}': expected array with length of 2, received ${value.length}`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
1043
+ return value;
1044
+ case "bigint": try {
1045
+ return BigInt(value);
1046
+ } catch (_error) {
1047
+ throw drizzleError(`Field '${columnName}' is not a BigInt!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
1048
+ }
1049
+ default:
1050
+ if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === null) return Object.assign({}, value);
1051
+ return value;
1052
+ }
1053
+ };
1054
+ const remapFromGraphQLSingleInput = (queryInput, table, operation = "insert") => {
1055
+ const columns = getColumns(table);
1056
+ for (const [key, value] of Object.entries(queryInput)) if (value === void 0) delete queryInput[key];
1057
+ else {
1058
+ const column = columns[key];
1059
+ if (!column) throw drizzleError(`Unknown column: ${key}`, { code: "DRIZZLE_UNKNOWN_COLUMN" });
1060
+ if (value === null && column.notNull) {
1061
+ if (operation === "update") throw drizzleError(`Column '${key}' cannot be set to null.`, { code: "DRIZZLE_NOT_NULL" });
1062
+ delete queryInput[key];
1063
+ continue;
1064
+ }
1065
+ queryInput[key] = remapFromGraphQLCore(value, column, key);
1066
+ }
1067
+ return queryInput;
1068
+ };
1069
+ const remapFromGraphQLArrayInput = (queryInput, table, operation = "insert") => {
1070
+ for (const entry of queryInput) remapFromGraphQLSingleInput(entry, table, operation);
1071
+ return queryInput;
1072
+ };
1073
+ //#endregion
1057
1074
  //#region src/util/builders/common/filters.ts
1058
1075
  /**
1059
1076
  * Escape character pinned via `ESCAPE` on every generated safe-LIKE predicate. Bound as a
@@ -1142,11 +1159,6 @@ const lowerMembership = (column, values, negated) => {
1142
1159
  return negated ? sql`lower(${column}) not in (${lowered})` : sql`lower(${column}) in (${lowered})`;
1143
1160
  };
1144
1161
  /**
1145
- * Whether the column stores JSON — its `contains` operator is structural containment,
1146
- * not the safe substring operator string columns get.
1147
- */
1148
- const isJsonColumn = (column) => (column.columnType ?? "").includes("Json");
1149
- /**
1150
1162
  * Structural JSON containment for the `contains` operator on json/jsonb columns.
1151
1163
  * The value is serialized and bound as a parameter (never interpolated into the SQL text):
1152
1164
  * - Postgres: `col @> $1::jsonb` (a plain `json` column is cast through jsonb — `json` has
@@ -1285,36 +1297,37 @@ const jsonPathCondition = (column, columnName, filter) => {
1285
1297
  }
1286
1298
  return variants.length ? variants.length > 1 ? and(...variants) : variants[0] : void 0;
1287
1299
  };
1300
+ const singleValueOps = {
1301
+ eq,
1302
+ ne,
1303
+ gt,
1304
+ gte,
1305
+ lt,
1306
+ lte
1307
+ };
1308
+ const stringValueOps = {
1309
+ like,
1310
+ notLike,
1311
+ ilike,
1312
+ notIlike
1313
+ };
1314
+ const arrayValueOps = {
1315
+ inArray,
1316
+ notInArray
1317
+ };
1318
+ /** Membership operators for array columns: element list → SQL. Empty lists are rejected below. */
1319
+ const arrayMembershipOps = {
1320
+ hasSome: arrayOverlaps,
1321
+ hasEvery: arrayContains
1322
+ };
1323
+ const nullableOps = {
1324
+ isNull,
1325
+ isNotNull
1326
+ };
1288
1327
  const extractFiltersColumn = (column, columnName, operators) => {
1289
1328
  const { OR, AND, NOT, insensitive, ...restOperators } = operators;
1290
1329
  const foldCase = insensitive === true;
1291
1330
  const entries = Object.entries(restOperators);
1292
- const singleValueOps = {
1293
- eq,
1294
- ne,
1295
- gt,
1296
- gte,
1297
- lt,
1298
- lte
1299
- };
1300
- const stringValueOps = {
1301
- like,
1302
- notLike,
1303
- ilike,
1304
- notIlike
1305
- };
1306
- const arrayValueOps = {
1307
- inArray,
1308
- notInArray
1309
- };
1310
- const arrayMembershipOps = {
1311
- hasSome: arrayOverlaps,
1312
- hasEvery: arrayContains
1313
- };
1314
- const nullableOps = {
1315
- isNull,
1316
- isNotNull
1317
- };
1318
1331
  const variants = [];
1319
1332
  for (const [operatorName, operatorValue] of entries) {
1320
1333
  if (operatorValue === null || operatorValue === false) continue;
@@ -2145,7 +2158,7 @@ const isFilterableRelation = (relation) => !relation.through;
2145
2158
  * (an object without a `direction`) is rejected with a clear error instead of being
2146
2159
  * silently dropped.
2147
2160
  */
2148
- const orderByEntries = (orderArgs) => Object.entries(orderArgs).sort((a, b) => (b[1]?.priority ?? 0) - (a[1]?.priority ?? 0)).filter(([, config]) => config).map(([column, config]) => {
2161
+ const orderByEntries = (orderArgs) => Object.entries(orderArgs).filter(([, config]) => config).sort((a, b) => (b[1]?.priority ?? 0) - (a[1]?.priority ?? 0)).map(([column, config]) => {
2149
2162
  if (typeof config === "object" && config.direction === void 0) throw drizzleError(`ORDER BY ${column}: ordering through a relation is not supported in this query`, { code: "DRIZZLE_INVALID_ORDER_BY" });
2150
2163
  if (config.matchFilterOrder) throw drizzleError(`ORDER BY ${column}: 'matchFilterOrder' is not supported in this query`, { code: "DRIZZLE_INVALID_ORDER_BY" });
2151
2164
  return [
@@ -2331,16 +2344,20 @@ const decodeCursorValue = (value) => {
2331
2344
  return value;
2332
2345
  };
2333
2346
  /**
2334
- * Encodes a row's position in the given total order as an opaque cursor: base64url of a JSON
2335
- * payload holding the ordering spec (`o`) and the row's values for it (`v`). The spec rides
2336
- * along so a later request can verify the cursor was issued for the same ordering it is using.
2337
- */
2338
- const encodeCursor = (entries, row) => {
2339
- const payload = {
2340
- o: entries,
2341
- v: entries.map(([column]) => encodeCursorValue(row[column] ?? null))
2347
+ * `encodeCursor` bound to one ordering, for encoding a whole page.
2348
+ *
2349
+ * The ordering spec is the same for every row of a page, so it is serialized once here and
2350
+ * spliced into each row's payload rather than re-serialized per row. The bytes are identical
2351
+ * to what building the payload object and stringifying it produces — same keys, same order —
2352
+ * so cursors stay interchangeable with ones issued before this was split out.
2353
+ */
2354
+ const cursorEncoder = (entries) => {
2355
+ const spec = JSON.stringify(entries);
2356
+ const columns = entries.map(([column]) => column);
2357
+ return (row) => {
2358
+ const values = JSON.stringify(columns.map((column) => encodeCursorValue(row[column] ?? null)));
2359
+ return Buffer.from(`{"o":${spec},"v":${values}}`, "utf8").toString("base64url");
2342
2360
  };
2343
- return Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
2344
2361
  };
2345
2362
  /**
2346
2363
  * Decodes an `after` cursor and validates it against the ordering the current request pages
@@ -2430,7 +2447,8 @@ const selectsCursorField = (info, table) => {
2430
2447
  * dates and bigints into their transport forms.
2431
2448
  */
2432
2449
  const attachRowCursors = (rows, entries) => {
2433
- for (const row of rows) row[ROW_CURSOR_PROP] = encodeCursor(entries, row);
2450
+ const encode = cursorEncoder(entries);
2451
+ for (const row of rows) row[ROW_CURSOR_PROP] = encode(row);
2434
2452
  };
2435
2453
  /** Resolver for the `cursor` meta field: reads the value a list resolver attached, if any. */
2436
2454
  const rowCursorResolver = (source) => source?.[ROW_CURSOR_PROP] ?? null;
@@ -2474,6 +2492,31 @@ const withPrimaryKeyColumns = (columns, table, pkNames) => {
2474
2492
  return columns;
2475
2493
  };
2476
2494
  /**
2495
+ * Wraps a dialect's `getTableConfig` in a per-table cache.
2496
+ *
2497
+ * The dialect implementations are not lookups: each call re-runs the table's
2498
+ * `extraConfigBuilder` and rebuilds every index, check, unique constraint, primary key and
2499
+ * foreign key it declares. Nothing about a table changes after it is defined, so the result
2500
+ * is the same every time — but a build asks for it many times per table (primary-key names,
2501
+ * unique column sets, conflict targets, one per relation that keys off the target's PK), and
2502
+ * an overriding resolver asks again at request time.
2503
+ *
2504
+ * The cache is a `WeakMap` on the table object, so it costs nothing once the table is gone.
2505
+ * Bind it once per dialect module, at module scope, so the cache outlives a single
2506
+ * `buildSchema` call.
2507
+ */
2508
+ const memoizeTableConfig = (getTableConfig) => {
2509
+ const cache = /* @__PURE__ */ new WeakMap();
2510
+ return (table) => {
2511
+ let config = cache.get(table);
2512
+ if (config === void 0) {
2513
+ config = getTableConfig(table);
2514
+ cache.set(table, config);
2515
+ }
2516
+ return config;
2517
+ };
2518
+ };
2519
+ /**
2477
2520
  * Resolves a table's primary-key property names using a dialect's `getTableConfig` to
2478
2521
  * surface table-level composite keys (whose member columns aren't flagged `.primary`).
2479
2522
  * Each dialect builder binds this with its own getTableConfig and reuses the binding for
@@ -3030,48 +3073,55 @@ const relationJoinColumns = (tree, table, selectionCtx) => {
3030
3073
  }
3031
3074
  return needed;
3032
3075
  };
3033
- const extractSelectedColumnsFromTree = (tree, table, selectionCtx) => {
3076
+ /**
3077
+ * The column the extractors fall back to when a selection names none of its own — a query that
3078
+ * asked only for `__typename`, or only for relation fields. The relational query builder still
3079
+ * needs at least one column, and some SQLite column types crash it when they are the only one
3080
+ * selected, so a column of any other type is preferred and the first column is the last resort.
3081
+ */
3082
+ const fallbackColumnName = (tableColumns) => {
3083
+ const columnKeys = Object.entries(tableColumns);
3084
+ return columnKeys.find(([, column]) => !rqbCrashTypes.includes(column.columnType))?.[0] ?? columnKeys[0][0];
3085
+ };
3086
+ /**
3087
+ * Property names of the columns a selection reads: the ones it names itself, plus the join
3088
+ * columns its relation fields correlate on, plus the fallback when that leaves nothing.
3089
+ */
3090
+ const selectedColumnNames = (tree, table, selectionCtx) => {
3034
3091
  const tableColumns = getColumns(table);
3035
- const treeEntries = Object.entries(tree);
3036
- const selectedColumns = [];
3037
- for (const [_fieldName, fieldData] of treeEntries) {
3092
+ const names = [];
3093
+ for (const fieldData of Object.values(tree)) {
3038
3094
  if (!tableColumns[fieldData.name]) continue;
3039
- selectedColumns.push([fieldData.name, true]);
3040
- }
3041
- for (const columnName of relationJoinColumns(tree, table, selectionCtx)) selectedColumns.push([columnName, true]);
3042
- if (!selectedColumns.length) {
3043
- const columnKeys = Object.entries(tableColumns);
3044
- const columnName = columnKeys.find((e) => rqbCrashTypes.find((haram) => e[1].columnType !== haram))?.[0] ?? columnKeys[0][0];
3045
- selectedColumns.push([columnName, true]);
3095
+ names.push(fieldData.name);
3046
3096
  }
3097
+ names.push(...relationJoinColumns(tree, table, selectionCtx));
3098
+ if (!names.length) names.push(fallbackColumnName(tableColumns));
3099
+ return names;
3100
+ };
3101
+ /** The requested columns as the relational query builder's `columns` map. */
3102
+ const extractSelectedColumnsFromTree = (tree, table, selectionCtx) => {
3103
+ const selectedColumns = selectedColumnNames(tree, table, selectionCtx).map((columnName) => [columnName, true]);
3047
3104
  return Object.fromEntries(selectedColumns);
3048
3105
  };
3049
3106
  /**
3107
+ * The same columns as a SQL select list.
3108
+ *
3050
3109
  * Can't automatically determine column type on type level
3051
3110
  * Since drizzle table types extend eachother
3052
3111
  */
3053
3112
  const extractSelectedColumnsFromTreeSQLFormat = (tree, table, selectionCtx) => {
3054
3113
  const tableColumns = getColumns(table);
3055
- const treeEntries = Object.entries(tree);
3056
- const selectedColumns = [];
3057
- for (const [_fieldName, fieldData] of treeEntries) {
3058
- if (!tableColumns[fieldData.name]) continue;
3059
- selectedColumns.push([fieldData.name, tableColumns[fieldData.name]]);
3060
- }
3061
- for (const columnName of relationJoinColumns(tree, table, selectionCtx)) selectedColumns.push([columnName, tableColumns[columnName]]);
3062
- if (!selectedColumns.length) {
3063
- const columnKeys = Object.entries(tableColumns);
3064
- const columnName = columnKeys.find((e) => rqbCrashTypes.find((haram) => e[1].columnType !== haram))?.[0] ?? columnKeys[0][0];
3065
- selectedColumns.push([columnName, tableColumns[columnName]]);
3066
- }
3114
+ const selectedColumns = selectedColumnNames(tree, table, selectionCtx).map((columnName) => [columnName, tableColumns[columnName]]);
3067
3115
  return Object.fromEntries(selectedColumns);
3068
3116
  };
3069
3117
  //#endregion
3070
3118
  //#region src/util/builders/common/relation-params.ts
3071
- const extractRelationsParamsInner = (relationMap, tables, tableName, typeName, originField, typeNameMapper, _isInitial = false, filterCtx, limits, scope, defaultOrderBy, resolveName) => {
3119
+ const extractRelationsParams = (relationMap, tables, tableName, info, typeName, options = {}) => {
3120
+ const { typeNameMapper, filterCtx, limits, scope, defaultOrderBy, resolveName } = options;
3121
+ if (!info) return;
3072
3122
  const relationsForTable = relationMap[tableName];
3073
3123
  if (!relationsForTable) return;
3074
- const baseField = Object.entries(originField.fieldsByTypeName).find(([key, _value]) => key === typeName)?.[1];
3124
+ const baseField = Object.entries(info.fieldsByTypeName).find(([key, _value]) => key === typeName)?.[1];
3075
3125
  if (!baseField) return;
3076
3126
  const args = {};
3077
3127
  for (const [relName, relEntry] of Object.entries(relationsForTable)) {
@@ -3108,15 +3158,11 @@ const extractRelationsParamsInner = (relationMap, tables, tableName, typeName, o
3108
3158
  thisRecord.orderBy = relationArgs?.orderBy ? (aliasedTable) => extractOrderBy(aliasedTable, relationArgs.orderBy, relationFilterCtx(filterCtx, targetTableName), relWhere) : hasPagination && pkNames.length ? (aliasedTable) => primaryKeyOrderExprs(aliasedTable, pkNames) : void 0;
3109
3159
  thisRecord.offset = offset;
3110
3160
  thisRecord.limit = limit;
3111
- thisRecord.with = relationField ? extractRelationsParamsInner(relationMap, tables, targetTableName, relTypeName, relationField, typeNameMapper, false, filterCtx, limits, scope, defaultOrderBy, resolveName) : void 0;
3161
+ thisRecord.with = extractRelationsParams(relationMap, tables, targetTableName, relationField, relTypeName, options);
3112
3162
  args[relName] = thisRecord;
3113
3163
  }
3114
3164
  return args;
3115
3165
  };
3116
- const extractRelationsParams = (relationMap, tables, tableName, info, typeName, typeNameMapper, filterCtx, limits, scope, defaultOrderBy, resolveName) => {
3117
- if (!info) return;
3118
- return extractRelationsParamsInner(relationMap, tables, tableName, typeName, info, typeNameMapper, true, filterCtx, limits, scope, defaultOrderBy, resolveName);
3119
- };
3120
3166
  /**
3121
3167
  * Returns a copy of `relationMap` containing only the relations that should be eagerly
3122
3168
  * pre-fetched (per the `shouldEagerLoad` predicate). Pass the result wherever a query or
@@ -3317,7 +3363,13 @@ const hardDeleteArg = {
3317
3363
  const prepareMutationRelationColumns = (params) => {
3318
3364
  const { relationMap, tables, tableName, typeNameMapper, table, pkNames, parsedInfo, resolveName } = params;
3319
3365
  const typeName = resolveObjectTypeName(tableName, typeNameMapper, resolveName);
3320
- const withParams = relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName, typeNameMapper, void 0, params.limits, params.scope, params.defaultOrderBy, resolveName) : void 0;
3366
+ const withParams = relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName, {
3367
+ typeNameMapper,
3368
+ limits: params.limits,
3369
+ scope: params.scope,
3370
+ defaultOrderBy: params.defaultOrderBy,
3371
+ resolveName
3372
+ }) : void 0;
3321
3373
  const hasRelations = !!(withParams && Object.keys(withParams).length);
3322
3374
  const baseColumns = extractSelectedColumnsFromTreeSQLFormat(parsedInfo.fieldsByTypeName[typeName], table, {
3323
3375
  tableName,
@@ -3896,7 +3948,14 @@ const runRelationalSelect = async (opts) => {
3896
3948
  offset: distinctKeys ? void 0 : offset,
3897
3949
  orderBy: distinctKeys ? (aliasedTable) => [...orderBy ? extractOrderBy(aliasedTable, orderBy, relationFilterCtx(filterCtx, tableName), where) : [], ...primaryKeyOrderExprs(aliasedTable, pkNames)] : cursorEntries ? (aliasedTable) => cursorOrderExprs(aliasedTable, cursorEntries) : orderBy ? (aliasedTable) => extractOrderBy(aliasedTable, orderBy, relationFilterCtx(filterCtx, tableName), where) : needsDefaultOrder && pkNames?.length ? (aliasedTable) => primaryKeyOrderExprs(aliasedTable, pkNames) : void 0,
3898
3950
  where: distinctKeys ? { RAW: (aliasedTable) => primaryKeyRestriction(aliasedTable, pkNames, distinctKeys) } : where || cursorValues || scope?.has(tableName, deleted) ? { RAW: (aliasedTable) => withScope(scope, tableName, aliasedTable, and(where ? extractFilters(aliasedTable, tableName, where, relationFilterCtx(filterCtx, tableName)) : void 0, cursorValues ? buildCursorCondition(aliasedTable, cursorEntries, cursorValues, opts.nullOrdering ?? "nulls-smallest") : void 0), deleted) } : void 0,
3899
- with: relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName, typeNameMapper, filterCtx, opts.limits, scope, opts.defaultOrderBy, opts.resolveName) : void 0
3951
+ with: relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName, {
3952
+ typeNameMapper,
3953
+ filterCtx,
3954
+ limits: opts.limits,
3955
+ scope,
3956
+ defaultOrderBy: opts.defaultOrderBy,
3957
+ resolveName: opts.resolveName
3958
+ }) : void 0
3900
3959
  };
3901
3960
  if (single) {
3902
3961
  const result = await queryBase.findFirst(params);
@@ -4817,12 +4876,13 @@ const collectSelections = (selections, info, tree, parentType, deep, activeFragm
4817
4876
  fields = {};
4818
4877
  tree[parentTypeName] = fields;
4819
4878
  }
4879
+ const parentFields = fieldsOf(parentType);
4820
4880
  for (const selection of selections) {
4821
4881
  if (isExcluded(info, selection)) continue;
4822
4882
  if (selection.kind === Kind.FIELD) {
4823
4883
  const name = selection.name.value;
4824
4884
  if (isMetaField(name)) continue;
4825
- const fieldDef = fieldsOf(parentType)?.[name];
4885
+ const fieldDef = parentFields?.[name];
4826
4886
  if (!fieldDef) continue;
4827
4887
  const fieldType = namedTypeOf(fieldDef.type);
4828
4888
  if (!fieldType) continue;
@@ -4865,7 +4925,10 @@ const collectSelections = (selections, info, tree, parentType, deep, activeFragm
4865
4925
  }
4866
4926
  return tree;
4867
4927
  };
4868
- const firstKey = (object) => Object.keys(object)[0];
4928
+ /** The first key of an object, without materializing the whole key array to discard it. */
4929
+ const firstKey = (object) => {
4930
+ for (const key in object) return key;
4931
+ };
4869
4932
  /**
4870
4933
  * Reads the selection under a resolver's own field out of its `info`, as a tree of
4871
4934
  * {@link ResolveTree} nodes.
@@ -4916,7 +4979,30 @@ const SEP = "__";
4916
4979
  * arrays (including array-typed number columns), JSON, buffers, and object-shaped columns
4917
4980
  * (e.g. geometry) are excluded entirely.
4918
4981
  */
4982
+ /**
4983
+ * Cache for {@link classifyAggregateColumns}. Keyed on the table object, then on the name it
4984
+ * was classified under — the name only reaches `drizzleColumnToGraphQLType` for enum naming,
4985
+ * but a table registered under two names would name its enums differently, so it is part of
4986
+ * the key rather than assumed irrelevant.
4987
+ *
4988
+ * The entries hold this build's GraphQL types and this build's column exclusions, so the
4989
+ * cache lives exactly as long as a build: {@link resetAggregateColumnCache} runs at the start
4990
+ * of every one, alongside the other per-build registries. Kept across builds it would hand a
4991
+ * second build the first build's enum instances, which is a schema with two types of one name.
4992
+ */
4993
+ let aggregateColumnSetsCache = /* @__PURE__ */ new WeakMap();
4994
+ /** Drops the classifications cached for the previous build. Called once per `generateSchemaData`. */
4995
+ const resetAggregateColumnCache = () => {
4996
+ aggregateColumnSetsCache = /* @__PURE__ */ new WeakMap();
4997
+ };
4919
4998
  const classifyAggregateColumns = (table, tableName) => {
4999
+ let byName = aggregateColumnSetsCache.get(table);
5000
+ if (!byName) {
5001
+ byName = /* @__PURE__ */ new Map();
5002
+ aggregateColumnSetsCache.set(table, byName);
5003
+ }
5004
+ const cached = byName.get(tableName);
5005
+ if (cached) return cached;
4920
5006
  const numeric = {};
4921
5007
  const orderable = {};
4922
5008
  const all = {};
@@ -4934,11 +5020,13 @@ const classifyAggregateColumns = (table, tableName) => {
4934
5020
  };
4935
5021
  if (dataType === "number") numeric[columnName] = column;
4936
5022
  }
4937
- return {
5023
+ const sets = {
4938
5024
  numeric,
4939
5025
  orderable,
4940
5026
  all
4941
5027
  };
5028
+ byName.set(tableName, sets);
5029
+ return sets;
4942
5030
  };
4943
5031
  /**
4944
5032
  * Builds the `${typeName}Aggregate` output type for a table:
@@ -6062,6 +6150,7 @@ const createSchemaBuilder = (adapter) => {
6062
6150
  registerScalarOverrides(tables, options);
6063
6151
  registerEnumConfig(options);
6064
6152
  registerColumnExclusions(tables, options.exclude);
6153
+ resetAggregateColumnCache();
6065
6154
  const namedRelations = buildNamedRelations(relations ?? {}, tableEntries);
6066
6155
  for (const excluded of excludedTables) delete namedRelations[excluded];
6067
6156
  attachTargetPrimaryKeys(namedRelations, tables, (table) => primaryKeyPropNames(table));
@@ -6451,11 +6540,13 @@ const generateDelete = (db, tableName, table, filterArgs, fieldName, single, req
6451
6540
  }
6452
6541
  });
6453
6542
  };
6543
+ /** The dialect's table config, cached per table — see {@link memoizeTableConfig}. */
6544
+ const getTableConfig$5 = memoizeTableConfig(getTableConfig);
6454
6545
  /** Primary-key property names for a MySQL table, including table-level composite keys. */
6455
- const mysqlPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig);
6546
+ const mysqlPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig$5);
6456
6547
  const { prepareBuild, addReadFields, finalizeBuild } = createSchemaBuilder({
6457
6548
  tableClass: MySqlTable,
6458
- getTableConfig,
6549
+ getTableConfig: getTableConfig$5,
6459
6550
  primaryKeyPropNames: mysqlPrimaryKeyPropNames,
6460
6551
  nullOrdering: "nulls-smallest",
6461
6552
  returnsRows: false,
@@ -7336,12 +7427,14 @@ const createUpdateManyGenerator = (primaryKeyPropNames, runBatch = runUpdateMany
7336
7427
  };
7337
7428
  //#endregion
7338
7429
  //#region src/util/builders/pg.ts
7430
+ /** The dialect's table config, cached per table — see {@link memoizeTableConfig}. */
7431
+ const getTableConfig$4 = memoizeTableConfig(getTableConfig$1);
7339
7432
  /** Primary-key property names for a PG table, including table-level composite keys. */
7340
- const pgPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig$1);
7433
+ const pgPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig$4);
7341
7434
  const generateUpdateMany$1 = createUpdateManyGenerator(pgPrimaryKeyPropNames);
7342
7435
  const pgSchemaData = createSchemaDataGenerator({
7343
7436
  tableClass: PgTable,
7344
- getTableConfig: getTableConfig$1,
7437
+ getTableConfig: getTableConfig$4,
7345
7438
  primaryKeyPropNames: pgPrimaryKeyPropNames,
7346
7439
  nullOrdering: "nulls-largest",
7347
7440
  returnsRows: true,
@@ -7350,8 +7443,10 @@ const pgSchemaData = createSchemaDataGenerator({
7350
7443
  const generateSchemaData$1 = (db, schema, relations, options) => pgSchemaData(db, schema, relations, options);
7351
7444
  //#endregion
7352
7445
  //#region src/util/builders/sqlite.ts
7446
+ /** The dialect's table config, cached per table — see {@link memoizeTableConfig}. */
7447
+ const getTableConfig$3 = memoizeTableConfig(getTableConfig$2);
7353
7448
  /** Primary-key property names for a SQLite table, including table-level composite keys. */
7354
- const sqlitePrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig$2);
7449
+ const sqlitePrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig$3);
7355
7450
  /**
7356
7451
  * SQLite's batch runner. A synchronous driver (better-sqlite3) commits the moment its
7357
7452
  * transaction callback returns, so that callback must not be async — an awaited statement
@@ -7396,7 +7491,7 @@ const runSqliteUpdateManyBatch = ({ executor, entries, table, returning, anyNest
7396
7491
  const generateUpdateMany = createUpdateManyGenerator(sqlitePrimaryKeyPropNames, runSqliteUpdateManyBatch);
7397
7492
  const sqliteSchemaData = createSchemaDataGenerator({
7398
7493
  tableClass: SQLiteTable,
7399
- getTableConfig: getTableConfig$2,
7494
+ getTableConfig: getTableConfig$3,
7400
7495
  primaryKeyPropNames: sqlitePrimaryKeyPropNames,
7401
7496
  nullOrdering: "nulls-smallest",
7402
7497
  returnsRows: true,
@@ -7410,11 +7505,14 @@ const generateSchemaData = (db, schema, relations, options) => sqliteSchemaData(
7410
7505
  //#endregion
7411
7506
  //#region src/util/selection.ts
7412
7507
  const contextCache = /* @__PURE__ */ new WeakMap();
7508
+ const getMySqlTableConfig = memoizeTableConfig(getTableConfig);
7509
+ const getPgTableConfig = memoizeTableConfig(getTableConfig$1);
7510
+ const getSQLiteTableConfig = memoizeTableConfig(getTableConfig$2);
7413
7511
  /** The dialect's `getTableConfig`, which is the only place a composite primary key shows up. */
7414
7512
  const tableConfigFor = (db) => {
7415
- if (is(db, MySqlAsyncDatabase)) return getTableConfig;
7416
- if (is(db, PgAsyncDatabase)) return getTableConfig$1;
7417
- if (is(db, SQLiteAsyncDatabase)) return getTableConfig$2;
7513
+ if (is(db, MySqlAsyncDatabase)) return getMySqlTableConfig;
7514
+ if (is(db, PgAsyncDatabase)) return getPgTableConfig;
7515
+ if (is(db, SQLiteAsyncDatabase)) return getSQLiteTableConfig;
7418
7516
  throw new Error("Drizzle-GraphQL Error: unsupported database instance — expected a PostgreSQL, MySQL or SQLite one.");
7419
7517
  };
7420
7518
  const contextFor = (db) => {
@@ -7495,7 +7593,11 @@ const selectionToWith = (info, options) => {
7495
7593
  if (!tables[table]) throw new Error(`Drizzle-GraphQL Error: '${table}' is not a table in the Drizzle schema.`);
7496
7594
  if (!relationMap[table]) return;
7497
7595
  const parsed = parseInfo(info);
7498
- const params = extractRelationsParams(relationMap, tables, table, parsed, resolveObjectTypeName(table, typeNameMapper, resolveName), typeNameMapper, filterCtx, void 0, void 0, void 0, resolveName);
7596
+ const params = extractRelationsParams(relationMap, tables, table, parsed, resolveObjectTypeName(table, typeNameMapper, resolveName), {
7597
+ typeNameMapper,
7598
+ filterCtx,
7599
+ resolveName
7600
+ });
7499
7601
  return params && Object.keys(params).length ? params : void 0;
7500
7602
  };
7501
7603
  /**