@vantreeseba/drizzle-graphql 9.1.1 → 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/README.md +22 -1
- package/dist/index.cjs +502 -251
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -2
- package/dist/index.d.ts +50 -2
- package/dist/index.js +494 -244
- package/dist/index.js.map +1 -1
- package/package.json +3 -4
package/dist/index.cjs
CHANGED
|
@@ -26,10 +26,9 @@ let drizzle_orm_mysql_core = require("drizzle-orm/mysql-core");
|
|
|
26
26
|
let drizzle_orm_pg_core = require("drizzle-orm/pg-core");
|
|
27
27
|
let drizzle_orm_sqlite_core = require("drizzle-orm/sqlite-core");
|
|
28
28
|
let graphql = require("graphql");
|
|
29
|
+
let graphql_scalars = require("graphql-scalars");
|
|
29
30
|
let pluralize = require("pluralize");
|
|
30
31
|
pluralize = __toESM(pluralize, 1);
|
|
31
|
-
let graphql_scalars = require("graphql-scalars");
|
|
32
|
-
let graphql_parse_resolve_info = require("graphql-parse-resolve-info");
|
|
33
32
|
//#region src/util/builders/common/errors.ts
|
|
34
33
|
/**
|
|
35
34
|
* A `GraphQLError` carrying its context as data. The message says what went wrong, in prose
|
|
@@ -116,28 +115,6 @@ const applyErrorMapper = (entities, mapError) => {
|
|
|
116
115
|
for (const tableResolvers of Object.values(entities.fieldResolvers ?? {})) for (const [relationName, resolve] of Object.entries(tableResolvers)) tableResolvers[relationName] = wrap(resolve);
|
|
117
116
|
};
|
|
118
117
|
//#endregion
|
|
119
|
-
//#region src/util/case-ops/index.ts
|
|
120
|
-
const uncapitalize = (input) => input?.length ? `${input[0].toLocaleLowerCase()}${input.length > 1 ? input.slice(1, input.length) : ""}` : input;
|
|
121
|
-
const capitalize = (input) => input?.length ? `${input[0].toLocaleUpperCase()}${input.length > 1 ? input.slice(1, input.length) : ""}` : input;
|
|
122
|
-
/**
|
|
123
|
-
* The `typeNameMapper` preset behind `typeNameMapper: 'singularize'`.
|
|
124
|
-
*
|
|
125
|
-
* Derives the singular and plural forms of a table key with the library's own `pluralize`,
|
|
126
|
-
* which is what nearly every consumer with plural table keys (`export const tasks =
|
|
127
|
-
* pgTable('tasks', …)`) was writing by hand — and adding `pluralize` to their own
|
|
128
|
-
* dependencies to write.
|
|
129
|
-
*
|
|
130
|
-
* `tasks` becomes type `Task`, queries `tasks` / `task`, mutations `createTasks` /
|
|
131
|
-
* `createTask`. A key that is already singular is pluralized for the list side, so `task`
|
|
132
|
-
* yields the same names, and a capitalized key (`Tasks`) yields them too — the field forms
|
|
133
|
-
* are uncapitalized so the generated names follow GraphQL's camelCase convention whatever
|
|
134
|
-
* the schema key looks like. The type name is capitalized by the generator either way.
|
|
135
|
-
*/
|
|
136
|
-
const singularizeMapper = (tableName) => ({
|
|
137
|
-
singular: uncapitalize(pluralize.default.singular(tableName)),
|
|
138
|
-
plural: uncapitalize(pluralize.default.plural(tableName))
|
|
139
|
-
});
|
|
140
|
-
//#endregion
|
|
141
118
|
//#region src/util/scalars/index.ts
|
|
142
119
|
const INVALID_INPUT = "DRIZZLE_INVALID_INPUT_VALUE";
|
|
143
120
|
const UNREPRESENTABLE = "DRIZZLE_UNREPRESENTABLE_VALUE";
|
|
@@ -208,6 +185,28 @@ const GraphQLDecimalString = new graphql.GraphQLScalarType({
|
|
|
208
185
|
}
|
|
209
186
|
});
|
|
210
187
|
//#endregion
|
|
188
|
+
//#region src/util/case-ops/index.ts
|
|
189
|
+
const uncapitalize = (input) => input?.length ? `${input[0].toLocaleLowerCase()}${input.length > 1 ? input.slice(1, input.length) : ""}` : input;
|
|
190
|
+
const capitalize = (input) => input?.length ? `${input[0].toLocaleUpperCase()}${input.length > 1 ? input.slice(1, input.length) : ""}` : input;
|
|
191
|
+
/**
|
|
192
|
+
* The `typeNameMapper` preset behind `typeNameMapper: 'singularize'`.
|
|
193
|
+
*
|
|
194
|
+
* Derives the singular and plural forms of a table key with the library's own `pluralize`,
|
|
195
|
+
* which is what nearly every consumer with plural table keys (`export const tasks =
|
|
196
|
+
* pgTable('tasks', …)`) was writing by hand — and adding `pluralize` to their own
|
|
197
|
+
* dependencies to write.
|
|
198
|
+
*
|
|
199
|
+
* `tasks` becomes type `Task`, queries `tasks` / `task`, mutations `createTasks` /
|
|
200
|
+
* `createTask`. A key that is already singular is pluralized for the list side, so `task`
|
|
201
|
+
* yields the same names, and a capitalized key (`Tasks`) yields them too — the field forms
|
|
202
|
+
* are uncapitalized so the generated names follow GraphQL's camelCase convention whatever
|
|
203
|
+
* the schema key looks like. The type name is capitalized by the generator either way.
|
|
204
|
+
*/
|
|
205
|
+
const singularizeMapper = (tableName) => ({
|
|
206
|
+
singular: uncapitalize(pluralize.default.singular(tableName)),
|
|
207
|
+
plural: uncapitalize(pluralize.default.plural(tableName))
|
|
208
|
+
});
|
|
209
|
+
//#endregion
|
|
211
210
|
//#region src/util/type-converter/index.ts
|
|
212
211
|
const allowedNameChars = /^[a-zA-Z0-9_]+$/;
|
|
213
212
|
/**
|
|
@@ -437,7 +436,7 @@ const normalizeScalarOverride = (override, tableName, columnName) => {
|
|
|
437
436
|
* leaves the column on built-in detection.
|
|
438
437
|
*/
|
|
439
438
|
const registerScalarOverrides = (tables, config) => {
|
|
440
|
-
for (const [tableName, table] of Object.entries(tables)) for (const [columnName, column] of Object.entries((0, drizzle_orm.
|
|
439
|
+
for (const [tableName, table] of Object.entries(tables)) for (const [columnName, column] of Object.entries((0, drizzle_orm.getColumns)(table))) {
|
|
441
440
|
const declared = config.scalars?.[tableName]?.[columnName];
|
|
442
441
|
let resolved;
|
|
443
442
|
if (declared !== void 0) resolved = normalizeScalarOverride(declared, tableName, columnName);
|
|
@@ -476,136 +475,6 @@ const drizzleColumnToGraphQLType = (column, columnName, tableName, forceNullable
|
|
|
476
475
|
return typeDesc;
|
|
477
476
|
};
|
|
478
477
|
//#endregion
|
|
479
|
-
//#region src/util/data-mappers/index.ts
|
|
480
|
-
const isJsonColumn$1 = (column) => (column.dataType ?? "").includes("json") && column.columnType !== "PgGeometryObject";
|
|
481
|
-
const remapToGraphQLCore = (key, value, tableName, column, relationMap) => {
|
|
482
|
-
if (Array.isArray(value)) {
|
|
483
|
-
const relations = relationMap?.[tableName];
|
|
484
|
-
if (relations?.[key]) {
|
|
485
|
-
const rel = relations[key];
|
|
486
|
-
return remapToGraphQLArrayOutput(value, rel.targetTableName, rel.relation?.targetTable ?? rel.relation?.referencedTable, relationMap);
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
if (typeof value === "object" && value !== null) {
|
|
490
|
-
const relations = relationMap?.[tableName];
|
|
491
|
-
if (relations?.[key]) {
|
|
492
|
-
const rel = relations[key];
|
|
493
|
-
return remapToGraphQLSingleOutput(value, rel.targetTableName, rel.relation?.targetTable ?? rel.relation?.referencedTable, relationMap);
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
if (!column) return value;
|
|
497
|
-
if (getColumnScalarOverride(column, false)) return value;
|
|
498
|
-
if (isJsonColumn$1(column)) return value;
|
|
499
|
-
if (value instanceof Date) return value.toISOString();
|
|
500
|
-
if (value instanceof Buffer) return Array.from(value);
|
|
501
|
-
if (typeof value === "bigint") return value.toString();
|
|
502
|
-
if (Array.isArray(value)) {
|
|
503
|
-
if (column.columnType === "PgGeometry" || column.columnType === "PgVector") return value;
|
|
504
|
-
return value.map((arrVal) => remapToGraphQLCore(key, arrVal, tableName, column, relationMap));
|
|
505
|
-
}
|
|
506
|
-
if (typeof value === "object" && value !== null) {
|
|
507
|
-
if (column.columnType === "PgGeometryObject") return value;
|
|
508
|
-
return JSON.stringify(value);
|
|
509
|
-
}
|
|
510
|
-
return value;
|
|
511
|
-
};
|
|
512
|
-
const remapToGraphQLSingleOutput = (queryOutput, tableName, table, relationMap) => {
|
|
513
|
-
const columns = (0, drizzle_orm.getTableColumns)(table);
|
|
514
|
-
for (const [key, value] of Object.entries(queryOutput)) {
|
|
515
|
-
if (value === void 0 || value === null) {
|
|
516
|
-
const relEntry = value === null ? relationMap?.[tableName]?.[key] : void 0;
|
|
517
|
-
if (relEntry && (0, drizzle_orm.is)(relEntry.relation, drizzle_orm.One)) {
|
|
518
|
-
queryOutput[key] = null;
|
|
519
|
-
continue;
|
|
520
|
-
}
|
|
521
|
-
delete queryOutput[key];
|
|
522
|
-
continue;
|
|
523
|
-
}
|
|
524
|
-
const column = columns[key];
|
|
525
|
-
if (value === 0n && column && column.columnType === "SQLiteBigInt" && !column.notNull) {
|
|
526
|
-
delete queryOutput[key];
|
|
527
|
-
continue;
|
|
528
|
-
}
|
|
529
|
-
queryOutput[key] = remapToGraphQLCore(key, value, tableName, column, relationMap);
|
|
530
|
-
}
|
|
531
|
-
return queryOutput;
|
|
532
|
-
};
|
|
533
|
-
const remapToGraphQLArrayOutput = (queryOutput, tableName, table, relationMap) => {
|
|
534
|
-
for (const entry of queryOutput) remapToGraphQLSingleOutput(entry, tableName, table, relationMap);
|
|
535
|
-
return queryOutput;
|
|
536
|
-
};
|
|
537
|
-
const remapFromGraphQLCore = (value, column, columnName) => {
|
|
538
|
-
if (getColumnScalarOverride(column, true)) {
|
|
539
|
-
if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === null) return Object.assign({}, value);
|
|
540
|
-
return value;
|
|
541
|
-
}
|
|
542
|
-
const dataType = column.dataType ?? "";
|
|
543
|
-
const columnType = column.columnType ?? "";
|
|
544
|
-
if (columnType === "SQLiteTimestamp" || columnType === "SQLiteTimestampMs" || columnType === "MySqlTimestamp" || columnType === "MySqlDateTime" || columnType === "PgTimestamp" || columnType === "PgTimestampString") {
|
|
545
|
-
const formatted = new Date(value);
|
|
546
|
-
if (Number.isNaN(formatted.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
547
|
-
return formatted;
|
|
548
|
-
}
|
|
549
|
-
if ((columnType === "MySqlDate" || columnType === "PgDate") && typeof value === "string") {
|
|
550
|
-
const dateOnly = value.includes("T") ? value.split("T")[0] : value;
|
|
551
|
-
const check = new Date(dateOnly);
|
|
552
|
-
if (Number.isNaN(check.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
553
|
-
return dateOnly;
|
|
554
|
-
}
|
|
555
|
-
if (dataType.includes("bigint")) try {
|
|
556
|
-
return BigInt(value);
|
|
557
|
-
} catch {
|
|
558
|
-
throw drizzleError(`Field '${columnName}' is not a BigInt!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
559
|
-
}
|
|
560
|
-
if (dataType.includes("json") && column.columnType !== "PgGeometryObject") return value;
|
|
561
|
-
switch (dataType) {
|
|
562
|
-
case "date": {
|
|
563
|
-
const formatted = new Date(value);
|
|
564
|
-
if (Number.isNaN(formatted.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
565
|
-
return formatted;
|
|
566
|
-
}
|
|
567
|
-
case "buffer":
|
|
568
|
-
if (!Array.isArray(value)) throw drizzleError(`Field '${columnName}' is not an array!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
569
|
-
return Buffer.from(value);
|
|
570
|
-
case "json":
|
|
571
|
-
if (column.columnType === "PgGeometryObject") return value;
|
|
572
|
-
try {
|
|
573
|
-
return JSON.parse(value);
|
|
574
|
-
} catch (e) {
|
|
575
|
-
throw drizzleError(`Invalid JSON in field '${columnName}':\n${e instanceof Error ? e.message : "Unknown error"}`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
576
|
-
}
|
|
577
|
-
case "array":
|
|
578
|
-
if (!Array.isArray(value)) throw drizzleError(`Field '${columnName}' is not an array!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
579
|
-
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" });
|
|
580
|
-
return value;
|
|
581
|
-
case "bigint": try {
|
|
582
|
-
return BigInt(value);
|
|
583
|
-
} catch (_error) {
|
|
584
|
-
throw drizzleError(`Field '${columnName}' is not a BigInt!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
585
|
-
}
|
|
586
|
-
default:
|
|
587
|
-
if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === null) return Object.assign({}, value);
|
|
588
|
-
return value;
|
|
589
|
-
}
|
|
590
|
-
};
|
|
591
|
-
const remapFromGraphQLSingleInput = (queryInput, table) => {
|
|
592
|
-
for (const [key, value] of Object.entries(queryInput)) if (value === void 0) delete queryInput[key];
|
|
593
|
-
else {
|
|
594
|
-
const column = (0, drizzle_orm.getTableColumns)(table)[key];
|
|
595
|
-
if (!column) throw drizzleError(`Unknown column: ${key}`, { code: "DRIZZLE_UNKNOWN_COLUMN" });
|
|
596
|
-
if (value === null && column.notNull) {
|
|
597
|
-
delete queryInput[key];
|
|
598
|
-
continue;
|
|
599
|
-
}
|
|
600
|
-
queryInput[key] = remapFromGraphQLCore(value, column, key);
|
|
601
|
-
}
|
|
602
|
-
return queryInput;
|
|
603
|
-
};
|
|
604
|
-
const remapFromGraphQLArrayInput = (queryInput, table) => {
|
|
605
|
-
for (const entry of queryInput) remapFromGraphQLSingleInput(entry, table);
|
|
606
|
-
return queryInput;
|
|
607
|
-
};
|
|
608
|
-
//#endregion
|
|
609
478
|
//#region src/util/builders/common/type-names.ts
|
|
610
479
|
/**
|
|
611
480
|
* The build's naming rule: the mapper's answer where it has one, otherwise the default name
|
|
@@ -648,6 +517,23 @@ const columnDialect = (column) => {
|
|
|
648
517
|
if (ct.startsWith("SQLite")) return "sqlite";
|
|
649
518
|
};
|
|
650
519
|
/**
|
|
520
|
+
* Whether the column stores JSON.
|
|
521
|
+
*
|
|
522
|
+
* Decided on drizzle's `dataType`, its semantic marker, rather than on `columnType`, which
|
|
523
|
+
* names the implementing class. drizzle-orm v1 uses compound dataType strings (`"object
|
|
524
|
+
* json"` for every json/jsonb column across the three dialects), hence the inclusion test.
|
|
525
|
+
*
|
|
526
|
+
* `PgGeometryObject` is excluded explicitly. That is currently redundant — it reports
|
|
527
|
+
* `"object geometry"` — but it is stored as json, has its own object type in the generated
|
|
528
|
+
* schema, and must not be reclassified if drizzle ever spells its dataType differently.
|
|
529
|
+
*
|
|
530
|
+
* One predicate for two callers that must agree: the filter builder, whose `path` and
|
|
531
|
+
* `contains` operators mean structural JSON containment rather than the string operators,
|
|
532
|
+
* and the data mappers, which transport a JSON value as-is instead of remapping it. They
|
|
533
|
+
* previously had a copy each, asking different questions of the column.
|
|
534
|
+
*/
|
|
535
|
+
const isJsonColumn = (column) => (column.dataType ?? "").includes("json") && column.columnType !== "PgGeometryObject";
|
|
536
|
+
/**
|
|
651
537
|
* Maps a Drizzle column to the generic filter type to use.
|
|
652
538
|
*
|
|
653
539
|
* Selection is keyed on the column's data type, never its name: a text column named
|
|
@@ -1078,6 +964,137 @@ const generateColumnFilterValues = (column, tableName, columnName, cacheCtx) =>
|
|
|
1078
964
|
return mainType;
|
|
1079
965
|
};
|
|
1080
966
|
//#endregion
|
|
967
|
+
//#region src/util/data-mappers/index.ts
|
|
968
|
+
const remapToGraphQLCore = (key, value, tableName, column, relationMap) => {
|
|
969
|
+
if (Array.isArray(value)) {
|
|
970
|
+
const relations = relationMap?.[tableName];
|
|
971
|
+
if (relations?.[key]) {
|
|
972
|
+
const rel = relations[key];
|
|
973
|
+
return remapToGraphQLArrayOutput(value, rel.targetTableName, rel.relation?.targetTable ?? rel.relation?.referencedTable, relationMap);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
if (typeof value === "object" && value !== null) {
|
|
977
|
+
const relations = relationMap?.[tableName];
|
|
978
|
+
if (relations?.[key]) {
|
|
979
|
+
const rel = relations[key];
|
|
980
|
+
return remapToGraphQLSingleOutput(value, rel.targetTableName, rel.relation?.targetTable ?? rel.relation?.referencedTable, relationMap);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
if (!column) return value;
|
|
984
|
+
if (getColumnScalarOverride(column, false)) return value;
|
|
985
|
+
if (isJsonColumn(column)) return value;
|
|
986
|
+
if (value instanceof Date) return value.toISOString();
|
|
987
|
+
if (value instanceof Buffer) return Array.from(value);
|
|
988
|
+
if (typeof value === "bigint") return value.toString();
|
|
989
|
+
if (Array.isArray(value)) {
|
|
990
|
+
if (column.columnType === "PgGeometry" || column.columnType === "PgVector") return value;
|
|
991
|
+
return value.map((arrVal) => remapToGraphQLCore(key, arrVal, tableName, column, relationMap));
|
|
992
|
+
}
|
|
993
|
+
if (typeof value === "object" && value !== null) {
|
|
994
|
+
if (column.columnType === "PgGeometryObject") return value;
|
|
995
|
+
return JSON.stringify(value);
|
|
996
|
+
}
|
|
997
|
+
return value;
|
|
998
|
+
};
|
|
999
|
+
const remapToGraphQLSingleOutput = (queryOutput, tableName, table, relationMap) => {
|
|
1000
|
+
const columns = (0, drizzle_orm.getColumns)(table);
|
|
1001
|
+
for (const [key, value] of Object.entries(queryOutput)) {
|
|
1002
|
+
if (value === void 0 || value === null) {
|
|
1003
|
+
const relEntry = value === null ? relationMap?.[tableName]?.[key] : void 0;
|
|
1004
|
+
if (relEntry && (0, drizzle_orm.is)(relEntry.relation, drizzle_orm.One)) {
|
|
1005
|
+
queryOutput[key] = null;
|
|
1006
|
+
continue;
|
|
1007
|
+
}
|
|
1008
|
+
delete queryOutput[key];
|
|
1009
|
+
continue;
|
|
1010
|
+
}
|
|
1011
|
+
const column = columns[key];
|
|
1012
|
+
if (value === 0n && column && column.columnType === "SQLiteBigInt" && !column.notNull) {
|
|
1013
|
+
delete queryOutput[key];
|
|
1014
|
+
continue;
|
|
1015
|
+
}
|
|
1016
|
+
queryOutput[key] = remapToGraphQLCore(key, value, tableName, column, relationMap);
|
|
1017
|
+
}
|
|
1018
|
+
return queryOutput;
|
|
1019
|
+
};
|
|
1020
|
+
const remapToGraphQLArrayOutput = (queryOutput, tableName, table, relationMap) => {
|
|
1021
|
+
for (const entry of queryOutput) remapToGraphQLSingleOutput(entry, tableName, table, relationMap);
|
|
1022
|
+
return queryOutput;
|
|
1023
|
+
};
|
|
1024
|
+
const remapFromGraphQLCore = (value, column, columnName) => {
|
|
1025
|
+
if (getColumnScalarOverride(column, true)) {
|
|
1026
|
+
if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === null) return Object.assign({}, value);
|
|
1027
|
+
return value;
|
|
1028
|
+
}
|
|
1029
|
+
const dataType = column.dataType ?? "";
|
|
1030
|
+
const columnType = column.columnType ?? "";
|
|
1031
|
+
if (columnType === "SQLiteTimestamp" || columnType === "SQLiteTimestampMs" || columnType === "MySqlTimestamp" || columnType === "MySqlDateTime" || columnType === "PgTimestamp" || columnType === "PgTimestampString") {
|
|
1032
|
+
const formatted = new Date(value);
|
|
1033
|
+
if (Number.isNaN(formatted.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
1034
|
+
return formatted;
|
|
1035
|
+
}
|
|
1036
|
+
if ((columnType === "MySqlDate" || columnType === "PgDate") && typeof value === "string") {
|
|
1037
|
+
const dateOnly = value.includes("T") ? value.split("T")[0] : value;
|
|
1038
|
+
const check = new Date(dateOnly);
|
|
1039
|
+
if (Number.isNaN(check.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
1040
|
+
return dateOnly;
|
|
1041
|
+
}
|
|
1042
|
+
if (dataType.includes("bigint")) try {
|
|
1043
|
+
return BigInt(value);
|
|
1044
|
+
} catch {
|
|
1045
|
+
throw drizzleError(`Field '${columnName}' is not a BigInt!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
1046
|
+
}
|
|
1047
|
+
if (dataType.includes("json") && column.columnType !== "PgGeometryObject") return value;
|
|
1048
|
+
switch (dataType) {
|
|
1049
|
+
case "date": {
|
|
1050
|
+
const formatted = new Date(value);
|
|
1051
|
+
if (Number.isNaN(formatted.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
1052
|
+
return formatted;
|
|
1053
|
+
}
|
|
1054
|
+
case "buffer":
|
|
1055
|
+
if (!Array.isArray(value)) throw drizzleError(`Field '${columnName}' is not an array!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
1056
|
+
return Buffer.from(value);
|
|
1057
|
+
case "json":
|
|
1058
|
+
if (column.columnType === "PgGeometryObject") return value;
|
|
1059
|
+
try {
|
|
1060
|
+
return JSON.parse(value);
|
|
1061
|
+
} catch (e) {
|
|
1062
|
+
throw drizzleError(`Invalid JSON in field '${columnName}':\n${e instanceof Error ? e.message : "Unknown error"}`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
1063
|
+
}
|
|
1064
|
+
case "array":
|
|
1065
|
+
if (!Array.isArray(value)) throw drizzleError(`Field '${columnName}' is not an array!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
1066
|
+
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" });
|
|
1067
|
+
return value;
|
|
1068
|
+
case "bigint": try {
|
|
1069
|
+
return BigInt(value);
|
|
1070
|
+
} catch (_error) {
|
|
1071
|
+
throw drizzleError(`Field '${columnName}' is not a BigInt!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
1072
|
+
}
|
|
1073
|
+
default:
|
|
1074
|
+
if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === null) return Object.assign({}, value);
|
|
1075
|
+
return value;
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
const remapFromGraphQLSingleInput = (queryInput, table, operation = "insert") => {
|
|
1079
|
+
const columns = (0, drizzle_orm.getColumns)(table);
|
|
1080
|
+
for (const [key, value] of Object.entries(queryInput)) if (value === void 0) delete queryInput[key];
|
|
1081
|
+
else {
|
|
1082
|
+
const column = columns[key];
|
|
1083
|
+
if (!column) throw drizzleError(`Unknown column: ${key}`, { code: "DRIZZLE_UNKNOWN_COLUMN" });
|
|
1084
|
+
if (value === null && column.notNull) {
|
|
1085
|
+
if (operation === "update") throw drizzleError(`Column '${key}' cannot be set to null.`, { code: "DRIZZLE_NOT_NULL" });
|
|
1086
|
+
delete queryInput[key];
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
queryInput[key] = remapFromGraphQLCore(value, column, key);
|
|
1090
|
+
}
|
|
1091
|
+
return queryInput;
|
|
1092
|
+
};
|
|
1093
|
+
const remapFromGraphQLArrayInput = (queryInput, table, operation = "insert") => {
|
|
1094
|
+
for (const entry of queryInput) remapFromGraphQLSingleInput(entry, table, operation);
|
|
1095
|
+
return queryInput;
|
|
1096
|
+
};
|
|
1097
|
+
//#endregion
|
|
1081
1098
|
//#region src/util/builders/common/filters.ts
|
|
1082
1099
|
/**
|
|
1083
1100
|
* Escape character pinned via `ESCAPE` on every generated safe-LIKE predicate. Bound as a
|
|
@@ -1166,11 +1183,6 @@ const lowerMembership = (column, values, negated) => {
|
|
|
1166
1183
|
return negated ? drizzle_orm.sql`lower(${column}) not in (${lowered})` : drizzle_orm.sql`lower(${column}) in (${lowered})`;
|
|
1167
1184
|
};
|
|
1168
1185
|
/**
|
|
1169
|
-
* Whether the column stores JSON — its `contains` operator is structural containment,
|
|
1170
|
-
* not the safe substring operator string columns get.
|
|
1171
|
-
*/
|
|
1172
|
-
const isJsonColumn = (column) => (column.columnType ?? "").includes("Json");
|
|
1173
|
-
/**
|
|
1174
1186
|
* Structural JSON containment for the `contains` operator on json/jsonb columns.
|
|
1175
1187
|
* The value is serialized and bound as a parameter (never interpolated into the SQL text):
|
|
1176
1188
|
* - Postgres: `col @> $1::jsonb` (a plain `json` column is cast through jsonb — `json` has
|
|
@@ -1309,36 +1321,37 @@ const jsonPathCondition = (column, columnName, filter) => {
|
|
|
1309
1321
|
}
|
|
1310
1322
|
return variants.length ? variants.length > 1 ? (0, drizzle_orm.and)(...variants) : variants[0] : void 0;
|
|
1311
1323
|
};
|
|
1324
|
+
const singleValueOps = {
|
|
1325
|
+
eq: drizzle_orm.eq,
|
|
1326
|
+
ne: drizzle_orm.ne,
|
|
1327
|
+
gt: drizzle_orm.gt,
|
|
1328
|
+
gte: drizzle_orm.gte,
|
|
1329
|
+
lt: drizzle_orm.lt,
|
|
1330
|
+
lte: drizzle_orm.lte
|
|
1331
|
+
};
|
|
1332
|
+
const stringValueOps = {
|
|
1333
|
+
like: drizzle_orm.like,
|
|
1334
|
+
notLike: drizzle_orm.notLike,
|
|
1335
|
+
ilike: drizzle_orm.ilike,
|
|
1336
|
+
notIlike: drizzle_orm.notIlike
|
|
1337
|
+
};
|
|
1338
|
+
const arrayValueOps = {
|
|
1339
|
+
inArray: drizzle_orm.inArray,
|
|
1340
|
+
notInArray: drizzle_orm.notInArray
|
|
1341
|
+
};
|
|
1342
|
+
/** Membership operators for array columns: element list → SQL. Empty lists are rejected below. */
|
|
1343
|
+
const arrayMembershipOps = {
|
|
1344
|
+
hasSome: drizzle_orm.arrayOverlaps,
|
|
1345
|
+
hasEvery: drizzle_orm.arrayContains
|
|
1346
|
+
};
|
|
1347
|
+
const nullableOps = {
|
|
1348
|
+
isNull: drizzle_orm.isNull,
|
|
1349
|
+
isNotNull: drizzle_orm.isNotNull
|
|
1350
|
+
};
|
|
1312
1351
|
const extractFiltersColumn = (column, columnName, operators) => {
|
|
1313
1352
|
const { OR, AND, NOT, insensitive, ...restOperators } = operators;
|
|
1314
1353
|
const foldCase = insensitive === true;
|
|
1315
1354
|
const entries = Object.entries(restOperators);
|
|
1316
|
-
const singleValueOps = {
|
|
1317
|
-
eq: drizzle_orm.eq,
|
|
1318
|
-
ne: drizzle_orm.ne,
|
|
1319
|
-
gt: drizzle_orm.gt,
|
|
1320
|
-
gte: drizzle_orm.gte,
|
|
1321
|
-
lt: drizzle_orm.lt,
|
|
1322
|
-
lte: drizzle_orm.lte
|
|
1323
|
-
};
|
|
1324
|
-
const stringValueOps = {
|
|
1325
|
-
like: drizzle_orm.like,
|
|
1326
|
-
notLike: drizzle_orm.notLike,
|
|
1327
|
-
ilike: drizzle_orm.ilike,
|
|
1328
|
-
notIlike: drizzle_orm.notIlike
|
|
1329
|
-
};
|
|
1330
|
-
const arrayValueOps = {
|
|
1331
|
-
inArray: drizzle_orm.inArray,
|
|
1332
|
-
notInArray: drizzle_orm.notInArray
|
|
1333
|
-
};
|
|
1334
|
-
const arrayMembershipOps = {
|
|
1335
|
-
hasSome: drizzle_orm.arrayOverlaps,
|
|
1336
|
-
hasEvery: drizzle_orm.arrayContains
|
|
1337
|
-
};
|
|
1338
|
-
const nullableOps = {
|
|
1339
|
-
isNull: drizzle_orm.isNull,
|
|
1340
|
-
isNotNull: drizzle_orm.isNotNull
|
|
1341
|
-
};
|
|
1342
1355
|
const variants = [];
|
|
1343
1356
|
for (const [operatorName, operatorValue] of entries) {
|
|
1344
1357
|
if (operatorValue === null || operatorValue === false) continue;
|
|
@@ -2169,7 +2182,7 @@ const isFilterableRelation = (relation) => !relation.through;
|
|
|
2169
2182
|
* (an object without a `direction`) is rejected with a clear error instead of being
|
|
2170
2183
|
* silently dropped.
|
|
2171
2184
|
*/
|
|
2172
|
-
const orderByEntries = (orderArgs) => Object.entries(orderArgs).sort((a, b) => (b[1]?.priority ?? 0) - (a[1]?.priority ?? 0)).
|
|
2185
|
+
const orderByEntries = (orderArgs) => Object.entries(orderArgs).filter(([, config]) => config).sort((a, b) => (b[1]?.priority ?? 0) - (a[1]?.priority ?? 0)).map(([column, config]) => {
|
|
2173
2186
|
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" });
|
|
2174
2187
|
if (config.matchFilterOrder) throw drizzleError(`ORDER BY ${column}: 'matchFilterOrder' is not supported in this query`, { code: "DRIZZLE_INVALID_ORDER_BY" });
|
|
2175
2188
|
return [
|
|
@@ -2355,16 +2368,20 @@ const decodeCursorValue = (value) => {
|
|
|
2355
2368
|
return value;
|
|
2356
2369
|
};
|
|
2357
2370
|
/**
|
|
2358
|
-
*
|
|
2359
|
-
*
|
|
2360
|
-
*
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2371
|
+
* `encodeCursor` bound to one ordering, for encoding a whole page.
|
|
2372
|
+
*
|
|
2373
|
+
* The ordering spec is the same for every row of a page, so it is serialized once here and
|
|
2374
|
+
* spliced into each row's payload rather than re-serialized per row. The bytes are identical
|
|
2375
|
+
* to what building the payload object and stringifying it produces — same keys, same order —
|
|
2376
|
+
* so cursors stay interchangeable with ones issued before this was split out.
|
|
2377
|
+
*/
|
|
2378
|
+
const cursorEncoder = (entries) => {
|
|
2379
|
+
const spec = JSON.stringify(entries);
|
|
2380
|
+
const columns = entries.map(([column]) => column);
|
|
2381
|
+
return (row) => {
|
|
2382
|
+
const values = JSON.stringify(columns.map((column) => encodeCursorValue(row[column] ?? null)));
|
|
2383
|
+
return Buffer.from(`{"o":${spec},"v":${values}}`, "utf8").toString("base64url");
|
|
2366
2384
|
};
|
|
2367
|
-
return Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
|
|
2368
2385
|
};
|
|
2369
2386
|
/**
|
|
2370
2387
|
* Decodes an `after` cursor and validates it against the ordering the current request pages
|
|
@@ -2454,7 +2471,8 @@ const selectsCursorField = (info, table) => {
|
|
|
2454
2471
|
* dates and bigints into their transport forms.
|
|
2455
2472
|
*/
|
|
2456
2473
|
const attachRowCursors = (rows, entries) => {
|
|
2457
|
-
|
|
2474
|
+
const encode = cursorEncoder(entries);
|
|
2475
|
+
for (const row of rows) row[ROW_CURSOR_PROP] = encode(row);
|
|
2458
2476
|
};
|
|
2459
2477
|
/** Resolver for the `cursor` meta field: reads the value a list resolver attached, if any. */
|
|
2460
2478
|
const rowCursorResolver = (source) => source?.[ROW_CURSOR_PROP] ?? null;
|
|
@@ -2498,6 +2516,31 @@ const withPrimaryKeyColumns = (columns, table, pkNames) => {
|
|
|
2498
2516
|
return columns;
|
|
2499
2517
|
};
|
|
2500
2518
|
/**
|
|
2519
|
+
* Wraps a dialect's `getTableConfig` in a per-table cache.
|
|
2520
|
+
*
|
|
2521
|
+
* The dialect implementations are not lookups: each call re-runs the table's
|
|
2522
|
+
* `extraConfigBuilder` and rebuilds every index, check, unique constraint, primary key and
|
|
2523
|
+
* foreign key it declares. Nothing about a table changes after it is defined, so the result
|
|
2524
|
+
* is the same every time — but a build asks for it many times per table (primary-key names,
|
|
2525
|
+
* unique column sets, conflict targets, one per relation that keys off the target's PK), and
|
|
2526
|
+
* an overriding resolver asks again at request time.
|
|
2527
|
+
*
|
|
2528
|
+
* The cache is a `WeakMap` on the table object, so it costs nothing once the table is gone.
|
|
2529
|
+
* Bind it once per dialect module, at module scope, so the cache outlives a single
|
|
2530
|
+
* `buildSchema` call.
|
|
2531
|
+
*/
|
|
2532
|
+
const memoizeTableConfig = (getTableConfig) => {
|
|
2533
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
2534
|
+
return (table) => {
|
|
2535
|
+
let config = cache.get(table);
|
|
2536
|
+
if (config === void 0) {
|
|
2537
|
+
config = getTableConfig(table);
|
|
2538
|
+
cache.set(table, config);
|
|
2539
|
+
}
|
|
2540
|
+
return config;
|
|
2541
|
+
};
|
|
2542
|
+
};
|
|
2543
|
+
/**
|
|
2501
2544
|
* Resolves a table's primary-key property names using a dialect's `getTableConfig` to
|
|
2502
2545
|
* surface table-level composite keys (whose member columns aren't flagged `.primary`).
|
|
2503
2546
|
* Each dialect builder binds this with its own getTableConfig and reuses the binding for
|
|
@@ -3004,10 +3047,14 @@ const splitFieldUpdateOperations = (values, table, tableName) => {
|
|
|
3004
3047
|
*
|
|
3005
3048
|
* Safe to call on every update path regardless of `features.fieldUpdateOperations` — see the
|
|
3006
3049
|
* shape check in {@link splitFieldUpdateOperations}.
|
|
3050
|
+
*
|
|
3051
|
+
* This is the single funnel every update goes through — the plural and `Single` mutations,
|
|
3052
|
+
* `updateMany`, the `Count` mutations and the MySQL builder's own — which is why it is the
|
|
3053
|
+
* one place that has to tell the remapper it is serving an update rather than an insert.
|
|
3007
3054
|
*/
|
|
3008
3055
|
const remapUpdateInput = (values, table, tableName) => {
|
|
3009
3056
|
const { columns, expressions } = splitFieldUpdateOperations(values, table, tableName);
|
|
3010
|
-
const remapped = remapFromGraphQLSingleInput(columns, table);
|
|
3057
|
+
const remapped = remapFromGraphQLSingleInput(columns, table, "update");
|
|
3011
3058
|
return Object.keys(expressions).length ? {
|
|
3012
3059
|
...remapped,
|
|
3013
3060
|
...expressions
|
|
@@ -3050,48 +3097,55 @@ const relationJoinColumns = (tree, table, selectionCtx) => {
|
|
|
3050
3097
|
}
|
|
3051
3098
|
return needed;
|
|
3052
3099
|
};
|
|
3053
|
-
|
|
3100
|
+
/**
|
|
3101
|
+
* The column the extractors fall back to when a selection names none of its own — a query that
|
|
3102
|
+
* asked only for `__typename`, or only for relation fields. The relational query builder still
|
|
3103
|
+
* needs at least one column, and some SQLite column types crash it when they are the only one
|
|
3104
|
+
* selected, so a column of any other type is preferred and the first column is the last resort.
|
|
3105
|
+
*/
|
|
3106
|
+
const fallbackColumnName = (tableColumns) => {
|
|
3107
|
+
const columnKeys = Object.entries(tableColumns);
|
|
3108
|
+
return columnKeys.find(([, column]) => !rqbCrashTypes.includes(column.columnType))?.[0] ?? columnKeys[0][0];
|
|
3109
|
+
};
|
|
3110
|
+
/**
|
|
3111
|
+
* Property names of the columns a selection reads: the ones it names itself, plus the join
|
|
3112
|
+
* columns its relation fields correlate on, plus the fallback when that leaves nothing.
|
|
3113
|
+
*/
|
|
3114
|
+
const selectedColumnNames = (tree, table, selectionCtx) => {
|
|
3054
3115
|
const tableColumns = (0, drizzle_orm.getColumns)(table);
|
|
3055
|
-
const
|
|
3056
|
-
const
|
|
3057
|
-
for (const [_fieldName, fieldData] of treeEntries) {
|
|
3116
|
+
const names = [];
|
|
3117
|
+
for (const fieldData of Object.values(tree)) {
|
|
3058
3118
|
if (!tableColumns[fieldData.name]) continue;
|
|
3059
|
-
|
|
3060
|
-
}
|
|
3061
|
-
for (const columnName of relationJoinColumns(tree, table, selectionCtx)) selectedColumns.push([columnName, true]);
|
|
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, true]);
|
|
3119
|
+
names.push(fieldData.name);
|
|
3066
3120
|
}
|
|
3121
|
+
names.push(...relationJoinColumns(tree, table, selectionCtx));
|
|
3122
|
+
if (!names.length) names.push(fallbackColumnName(tableColumns));
|
|
3123
|
+
return names;
|
|
3124
|
+
};
|
|
3125
|
+
/** The requested columns as the relational query builder's `columns` map. */
|
|
3126
|
+
const extractSelectedColumnsFromTree = (tree, table, selectionCtx) => {
|
|
3127
|
+
const selectedColumns = selectedColumnNames(tree, table, selectionCtx).map((columnName) => [columnName, true]);
|
|
3067
3128
|
return Object.fromEntries(selectedColumns);
|
|
3068
3129
|
};
|
|
3069
3130
|
/**
|
|
3131
|
+
* The same columns as a SQL select list.
|
|
3132
|
+
*
|
|
3070
3133
|
* Can't automatically determine column type on type level
|
|
3071
3134
|
* Since drizzle table types extend eachother
|
|
3072
3135
|
*/
|
|
3073
3136
|
const extractSelectedColumnsFromTreeSQLFormat = (tree, table, selectionCtx) => {
|
|
3074
3137
|
const tableColumns = (0, drizzle_orm.getColumns)(table);
|
|
3075
|
-
const
|
|
3076
|
-
const selectedColumns = [];
|
|
3077
|
-
for (const [_fieldName, fieldData] of treeEntries) {
|
|
3078
|
-
if (!tableColumns[fieldData.name]) continue;
|
|
3079
|
-
selectedColumns.push([fieldData.name, tableColumns[fieldData.name]]);
|
|
3080
|
-
}
|
|
3081
|
-
for (const columnName of relationJoinColumns(tree, table, selectionCtx)) selectedColumns.push([columnName, tableColumns[columnName]]);
|
|
3082
|
-
if (!selectedColumns.length) {
|
|
3083
|
-
const columnKeys = Object.entries(tableColumns);
|
|
3084
|
-
const columnName = columnKeys.find((e) => rqbCrashTypes.find((haram) => e[1].columnType !== haram))?.[0] ?? columnKeys[0][0];
|
|
3085
|
-
selectedColumns.push([columnName, tableColumns[columnName]]);
|
|
3086
|
-
}
|
|
3138
|
+
const selectedColumns = selectedColumnNames(tree, table, selectionCtx).map((columnName) => [columnName, tableColumns[columnName]]);
|
|
3087
3139
|
return Object.fromEntries(selectedColumns);
|
|
3088
3140
|
};
|
|
3089
3141
|
//#endregion
|
|
3090
3142
|
//#region src/util/builders/common/relation-params.ts
|
|
3091
|
-
const
|
|
3143
|
+
const extractRelationsParams = (relationMap, tables, tableName, info, typeName, options = {}) => {
|
|
3144
|
+
const { typeNameMapper, filterCtx, limits, scope, defaultOrderBy, resolveName } = options;
|
|
3145
|
+
if (!info) return;
|
|
3092
3146
|
const relationsForTable = relationMap[tableName];
|
|
3093
3147
|
if (!relationsForTable) return;
|
|
3094
|
-
const baseField = Object.entries(
|
|
3148
|
+
const baseField = Object.entries(info.fieldsByTypeName).find(([key, _value]) => key === typeName)?.[1];
|
|
3095
3149
|
if (!baseField) return;
|
|
3096
3150
|
const args = {};
|
|
3097
3151
|
for (const [relName, relEntry] of Object.entries(relationsForTable)) {
|
|
@@ -3128,15 +3182,11 @@ const extractRelationsParamsInner = (relationMap, tables, tableName, typeName, o
|
|
|
3128
3182
|
thisRecord.orderBy = relationArgs?.orderBy ? (aliasedTable) => extractOrderBy(aliasedTable, relationArgs.orderBy, relationFilterCtx(filterCtx, targetTableName), relWhere) : hasPagination && pkNames.length ? (aliasedTable) => primaryKeyOrderExprs(aliasedTable, pkNames) : void 0;
|
|
3129
3183
|
thisRecord.offset = offset;
|
|
3130
3184
|
thisRecord.limit = limit;
|
|
3131
|
-
thisRecord.with =
|
|
3185
|
+
thisRecord.with = extractRelationsParams(relationMap, tables, targetTableName, relationField, relTypeName, options);
|
|
3132
3186
|
args[relName] = thisRecord;
|
|
3133
3187
|
}
|
|
3134
3188
|
return args;
|
|
3135
3189
|
};
|
|
3136
|
-
const extractRelationsParams = (relationMap, tables, tableName, info, typeName, typeNameMapper, filterCtx, limits, scope, defaultOrderBy, resolveName) => {
|
|
3137
|
-
if (!info) return;
|
|
3138
|
-
return extractRelationsParamsInner(relationMap, tables, tableName, typeName, info, typeNameMapper, true, filterCtx, limits, scope, defaultOrderBy, resolveName);
|
|
3139
|
-
};
|
|
3140
3190
|
/**
|
|
3141
3191
|
* Returns a copy of `relationMap` containing only the relations that should be eagerly
|
|
3142
3192
|
* pre-fetched (per the `shouldEagerLoad` predicate). Pass the result wherever a query or
|
|
@@ -3337,7 +3387,13 @@ const hardDeleteArg = {
|
|
|
3337
3387
|
const prepareMutationRelationColumns = (params) => {
|
|
3338
3388
|
const { relationMap, tables, tableName, typeNameMapper, table, pkNames, parsedInfo, resolveName } = params;
|
|
3339
3389
|
const typeName = resolveObjectTypeName(tableName, typeNameMapper, resolveName);
|
|
3340
|
-
const withParams = relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName,
|
|
3390
|
+
const withParams = relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName, {
|
|
3391
|
+
typeNameMapper,
|
|
3392
|
+
limits: params.limits,
|
|
3393
|
+
scope: params.scope,
|
|
3394
|
+
defaultOrderBy: params.defaultOrderBy,
|
|
3395
|
+
resolveName
|
|
3396
|
+
}) : void 0;
|
|
3341
3397
|
const hasRelations = !!(withParams && Object.keys(withParams).length);
|
|
3342
3398
|
const baseColumns = extractSelectedColumnsFromTreeSQLFormat(parsedInfo.fieldsByTypeName[typeName], table, {
|
|
3343
3399
|
tableName,
|
|
@@ -3916,7 +3972,14 @@ const runRelationalSelect = async (opts) => {
|
|
|
3916
3972
|
offset: distinctKeys ? void 0 : offset,
|
|
3917
3973
|
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,
|
|
3918
3974
|
where: distinctKeys ? { RAW: (aliasedTable) => primaryKeyRestriction(aliasedTable, pkNames, distinctKeys) } : where || cursorValues || scope?.has(tableName, deleted) ? { RAW: (aliasedTable) => withScope(scope, tableName, aliasedTable, (0, drizzle_orm.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,
|
|
3919
|
-
with: relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName,
|
|
3975
|
+
with: relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName, {
|
|
3976
|
+
typeNameMapper,
|
|
3977
|
+
filterCtx,
|
|
3978
|
+
limits: opts.limits,
|
|
3979
|
+
scope,
|
|
3980
|
+
defaultOrderBy: opts.defaultOrderBy,
|
|
3981
|
+
resolveName: opts.resolveName
|
|
3982
|
+
}) : void 0
|
|
3920
3983
|
};
|
|
3921
3984
|
if (single) {
|
|
3922
3985
|
const result = await queryBase.findFirst(params);
|
|
@@ -4764,6 +4827,154 @@ const resolveBuildConfig = (config, schema) => {
|
|
|
4764
4827
|
};
|
|
4765
4828
|
};
|
|
4766
4829
|
//#endregion
|
|
4830
|
+
//#region src/util/parse-resolve-info.ts
|
|
4831
|
+
/** Unwraps `[T]!`-style wrappers down to the named type. `getNamedType` without the realm tie. */
|
|
4832
|
+
const namedTypeOf = (type) => {
|
|
4833
|
+
let current = type;
|
|
4834
|
+
while (current?.ofType) current = current.ofType;
|
|
4835
|
+
return current;
|
|
4836
|
+
};
|
|
4837
|
+
/**
|
|
4838
|
+
* Whether a field's named output type has sub-selections. Object types and interfaces expose
|
|
4839
|
+
* `getFields`, unions expose `getTypes`; scalars and enums expose neither. Input object types
|
|
4840
|
+
* also expose `getFields`, but an input type can never be a field's output type, so there is
|
|
4841
|
+
* nothing here for that to collide with.
|
|
4842
|
+
*/
|
|
4843
|
+
const isCompositeLike = (type) => !!type && (typeof type.getFields === "function" || typeof type.getTypes === "function");
|
|
4844
|
+
/**
|
|
4845
|
+
* The fields declared on a type, or `undefined` when it has none to declare. A union is the
|
|
4846
|
+
* case that matters: it has no fields of its own, so a selection directly against one resolves
|
|
4847
|
+
* to nothing and is dropped — only the inline fragments underneath contribute.
|
|
4848
|
+
*/
|
|
4849
|
+
const fieldsOf = (type) => typeof type?.getFields === "function" ? type.getFields() : void 0;
|
|
4850
|
+
/**
|
|
4851
|
+
* The runtime variable values, in the plain-map form the directive check wants. graphql 17
|
|
4852
|
+
* wraps them in `{ sources, coerced }`; graphql 16 hands over the map itself.
|
|
4853
|
+
*/
|
|
4854
|
+
const coercedVariables = (info) => {
|
|
4855
|
+
const values = info.variableValues;
|
|
4856
|
+
if (values && typeof values === "object" && "coerced" in values) return values.coerced ?? {};
|
|
4857
|
+
return values ?? {};
|
|
4858
|
+
};
|
|
4859
|
+
/** The value of a `@skip` / `@include` `if:` argument — a literal or a variable reference. */
|
|
4860
|
+
const directiveIfValue = (info, value) => {
|
|
4861
|
+
if (value.kind === graphql.Kind.VARIABLE) return coercedVariables(info)[value.name.value];
|
|
4862
|
+
if (value.kind === graphql.Kind.BOOLEAN) return value.value;
|
|
4863
|
+
};
|
|
4864
|
+
/**
|
|
4865
|
+
* Whether `@skip` / `@include` on this selection exclude it. Applies to fields, fragment
|
|
4866
|
+
* spreads and inline fragments alike, which is where graphql puts them.
|
|
4867
|
+
*/
|
|
4868
|
+
const isExcluded = (info, node) => {
|
|
4869
|
+
for (const directive of node.directives ?? []) {
|
|
4870
|
+
const directiveName = directive.name.value;
|
|
4871
|
+
if (directiveName !== "skip" && directiveName !== "include") continue;
|
|
4872
|
+
const ifArgument = directive.arguments?.find((argument) => argument.name.value === "if");
|
|
4873
|
+
if (!ifArgument) continue;
|
|
4874
|
+
const value = directiveIfValue(info, ifArgument.value);
|
|
4875
|
+
if (directiveName === "skip" ? !!value : !value) return true;
|
|
4876
|
+
}
|
|
4877
|
+
return false;
|
|
4878
|
+
};
|
|
4879
|
+
/** The type a fragment's `on Type` condition names, looked up in the executing schema. */
|
|
4880
|
+
const typeFromCondition = (info, condition) => info.schema.getType(condition.name.value);
|
|
4881
|
+
/**
|
|
4882
|
+
* Introspection meta-fields are not schema fields and never reach the database. `__typename` is
|
|
4883
|
+
* the one that turns up in practice; `__id` is excluded from the rule because a schema is free
|
|
4884
|
+
* to declare a field by that name.
|
|
4885
|
+
*/
|
|
4886
|
+
const isMetaField = (name) => name.startsWith("__") && name !== "__id";
|
|
4887
|
+
/**
|
|
4888
|
+
* Merges one selection set into `tree`, which is a `fieldsByTypeName` map — the caller owns the
|
|
4889
|
+
* level, this owns the entries under `parentType`'s name.
|
|
4890
|
+
*
|
|
4891
|
+
* `activeFragments` is the set of fragment names on the current spread path. A document that
|
|
4892
|
+
* passed validation cannot contain a fragment cycle, but this parser also runs on trees a
|
|
4893
|
+
* caller assembled by hand, and an unbounded walk would hang rather than fail.
|
|
4894
|
+
*/
|
|
4895
|
+
const collectSelections = (selections, info, tree, parentType, deep, activeFragments) => {
|
|
4896
|
+
const parentTypeName = parentType?.name;
|
|
4897
|
+
if (!parentTypeName) return tree;
|
|
4898
|
+
let fields = tree[parentTypeName];
|
|
4899
|
+
if (!fields) {
|
|
4900
|
+
fields = {};
|
|
4901
|
+
tree[parentTypeName] = fields;
|
|
4902
|
+
}
|
|
4903
|
+
const parentFields = fieldsOf(parentType);
|
|
4904
|
+
for (const selection of selections) {
|
|
4905
|
+
if (isExcluded(info, selection)) continue;
|
|
4906
|
+
if (selection.kind === graphql.Kind.FIELD) {
|
|
4907
|
+
const name = selection.name.value;
|
|
4908
|
+
if (isMetaField(name)) continue;
|
|
4909
|
+
const fieldDef = parentFields?.[name];
|
|
4910
|
+
if (!fieldDef) continue;
|
|
4911
|
+
const fieldType = namedTypeOf(fieldDef.type);
|
|
4912
|
+
if (!fieldType) continue;
|
|
4913
|
+
const composite = isCompositeLike(fieldType);
|
|
4914
|
+
const alias = selection.alias?.value || name;
|
|
4915
|
+
let node = fields[alias];
|
|
4916
|
+
if (!node) {
|
|
4917
|
+
node = {
|
|
4918
|
+
name,
|
|
4919
|
+
alias,
|
|
4920
|
+
args: { ...(0, graphql.getArgumentValues)(fieldDef, selection, info.variableValues) },
|
|
4921
|
+
fieldsByTypeName: composite && fieldType.name ? { [fieldType.name]: {} } : {}
|
|
4922
|
+
};
|
|
4923
|
+
fields[alias] = node;
|
|
4924
|
+
}
|
|
4925
|
+
if (selection.selectionSet && deep && composite) collectSelections(selection.selectionSet.selections, info, node.fieldsByTypeName, fieldType, deep, activeFragments);
|
|
4926
|
+
continue;
|
|
4927
|
+
}
|
|
4928
|
+
if (!deep) continue;
|
|
4929
|
+
if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
|
|
4930
|
+
const fragmentName = selection.name.value;
|
|
4931
|
+
const fragment = info.fragments?.[fragmentName];
|
|
4932
|
+
if (!fragment) throw new Error(`Drizzle-GraphQL Error: unknown fragment '${fragmentName}' — it is spread in the query but not defined in the document.`);
|
|
4933
|
+
if (activeFragments.has(fragmentName)) continue;
|
|
4934
|
+
const fragmentType = fragment.typeCondition ? typeFromCondition(info, fragment.typeCondition) : parentType;
|
|
4935
|
+
if (!isCompositeLike(fragmentType)) continue;
|
|
4936
|
+
activeFragments.add(fragmentName);
|
|
4937
|
+
try {
|
|
4938
|
+
collectSelections(fragment.selectionSet.selections, info, tree, fragmentType, deep, activeFragments);
|
|
4939
|
+
} finally {
|
|
4940
|
+
activeFragments.delete(fragmentName);
|
|
4941
|
+
}
|
|
4942
|
+
continue;
|
|
4943
|
+
}
|
|
4944
|
+
if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
|
|
4945
|
+
const fragmentType = selection.typeCondition ? typeFromCondition(info, selection.typeCondition) : parentType;
|
|
4946
|
+
if (!isCompositeLike(fragmentType)) continue;
|
|
4947
|
+
collectSelections(selection.selectionSet.selections, info, tree, fragmentType, deep, activeFragments);
|
|
4948
|
+
}
|
|
4949
|
+
}
|
|
4950
|
+
return tree;
|
|
4951
|
+
};
|
|
4952
|
+
/** The first key of an object, without materializing the whole key array to discard it. */
|
|
4953
|
+
const firstKey = (object) => {
|
|
4954
|
+
for (const key in object) return key;
|
|
4955
|
+
};
|
|
4956
|
+
/**
|
|
4957
|
+
* Reads the selection under a resolver's own field out of its `info`, as a tree of
|
|
4958
|
+
* {@link ResolveTree} nodes.
|
|
4959
|
+
*
|
|
4960
|
+
* ```ts
|
|
4961
|
+
* const parsed = parseResolveInfo(info, { deep: true })!;
|
|
4962
|
+
* const selected = parsed.fieldsByTypeName['Users']; // keyed by response key
|
|
4963
|
+
* ```
|
|
4964
|
+
*
|
|
4965
|
+
* Returns `undefined` when the resolver's field produced no node at all, which in practice
|
|
4966
|
+
* means `info` carried no field nodes.
|
|
4967
|
+
*/
|
|
4968
|
+
const parseResolveInfo = (info, options = {}) => {
|
|
4969
|
+
const fieldNodes = info.fieldNodes;
|
|
4970
|
+
if (!fieldNodes) throw new Error("Drizzle-GraphQL Error: resolve info carries no fieldNodes, so no selection could be read from it.");
|
|
4971
|
+
const tree = collectSelections(fieldNodes, info, {}, info.parentType, options.deep ?? true, /* @__PURE__ */ new Set());
|
|
4972
|
+
const typeKey = firstKey(tree);
|
|
4973
|
+
const fields = typeKey === void 0 ? void 0 : tree[typeKey];
|
|
4974
|
+
const fieldKey = fields && firstKey(fields);
|
|
4975
|
+
return fieldKey === void 0 ? void 0 : fields?.[fieldKey];
|
|
4976
|
+
};
|
|
4977
|
+
//#endregion
|
|
4767
4978
|
//#region src/util/builders/aggregates.ts
|
|
4768
4979
|
/** Operations that aggregate over a set of column values. `count` is handled separately (whole rows). */
|
|
4769
4980
|
const AGGREGATE_OPS = [
|
|
@@ -4792,7 +5003,30 @@ const SEP = "__";
|
|
|
4792
5003
|
* arrays (including array-typed number columns), JSON, buffers, and object-shaped columns
|
|
4793
5004
|
* (e.g. geometry) are excluded entirely.
|
|
4794
5005
|
*/
|
|
5006
|
+
/**
|
|
5007
|
+
* Cache for {@link classifyAggregateColumns}. Keyed on the table object, then on the name it
|
|
5008
|
+
* was classified under — the name only reaches `drizzleColumnToGraphQLType` for enum naming,
|
|
5009
|
+
* but a table registered under two names would name its enums differently, so it is part of
|
|
5010
|
+
* the key rather than assumed irrelevant.
|
|
5011
|
+
*
|
|
5012
|
+
* The entries hold this build's GraphQL types and this build's column exclusions, so the
|
|
5013
|
+
* cache lives exactly as long as a build: {@link resetAggregateColumnCache} runs at the start
|
|
5014
|
+
* of every one, alongside the other per-build registries. Kept across builds it would hand a
|
|
5015
|
+
* second build the first build's enum instances, which is a schema with two types of one name.
|
|
5016
|
+
*/
|
|
5017
|
+
let aggregateColumnSetsCache = /* @__PURE__ */ new WeakMap();
|
|
5018
|
+
/** Drops the classifications cached for the previous build. Called once per `generateSchemaData`. */
|
|
5019
|
+
const resetAggregateColumnCache = () => {
|
|
5020
|
+
aggregateColumnSetsCache = /* @__PURE__ */ new WeakMap();
|
|
5021
|
+
};
|
|
4795
5022
|
const classifyAggregateColumns = (table, tableName) => {
|
|
5023
|
+
let byName = aggregateColumnSetsCache.get(table);
|
|
5024
|
+
if (!byName) {
|
|
5025
|
+
byName = /* @__PURE__ */ new Map();
|
|
5026
|
+
aggregateColumnSetsCache.set(table, byName);
|
|
5027
|
+
}
|
|
5028
|
+
const cached = byName.get(tableName);
|
|
5029
|
+
if (cached) return cached;
|
|
4796
5030
|
const numeric = {};
|
|
4797
5031
|
const orderable = {};
|
|
4798
5032
|
const all = {};
|
|
@@ -4810,11 +5044,13 @@ const classifyAggregateColumns = (table, tableName) => {
|
|
|
4810
5044
|
};
|
|
4811
5045
|
if (dataType === "number") numeric[columnName] = column;
|
|
4812
5046
|
}
|
|
4813
|
-
|
|
5047
|
+
const sets = {
|
|
4814
5048
|
numeric,
|
|
4815
5049
|
orderable,
|
|
4816
5050
|
all
|
|
4817
5051
|
};
|
|
5052
|
+
byName.set(tableName, sets);
|
|
5053
|
+
return sets;
|
|
4818
5054
|
};
|
|
4819
5055
|
/**
|
|
4820
5056
|
* Builds the `${typeName}Aggregate` output type for a table:
|
|
@@ -4905,7 +5141,7 @@ const aggregateTarget = (table, tableName, typeName, resolveName) => {
|
|
|
4905
5141
|
* client asked for nothing runnable (`__typename` only, or empty sub-selections).
|
|
4906
5142
|
*/
|
|
4907
5143
|
const parseAggregateRequest = (info, target, rootTypeName = target.aggregateTypeName) => {
|
|
4908
|
-
const selectionTree =
|
|
5144
|
+
const selectionTree = parseResolveInfo(info, { deep: true }).fieldsByTypeName[rootTypeName] ?? {};
|
|
4909
5145
|
const request = {
|
|
4910
5146
|
count: false,
|
|
4911
5147
|
ops: {
|
|
@@ -5833,7 +6069,7 @@ const createSelectGenerators = (primaryKeyPropNames, nullOrdering) => {
|
|
|
5833
6069
|
resolver: async (_source, rawArgs, context, info) => {
|
|
5834
6070
|
const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
|
|
5835
6071
|
try {
|
|
5836
|
-
const parsedInfo =
|
|
6072
|
+
const parsedInfo = parseResolveInfo(info, { deep: true });
|
|
5837
6073
|
const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
|
|
5838
6074
|
return await runRelationalSelect({
|
|
5839
6075
|
queryBase: requestQueryBase,
|
|
@@ -5879,7 +6115,7 @@ const createSelectGenerators = (primaryKeyPropNames, nullOrdering) => {
|
|
|
5879
6115
|
resolver: async (_source, rawArgs, context, info) => {
|
|
5880
6116
|
const args = withDefaultOrderBy(rawArgs, tableName, policies?.defaultOrderBy);
|
|
5881
6117
|
try {
|
|
5882
|
-
const parsedInfo =
|
|
6118
|
+
const parsedInfo = parseResolveInfo(info, { deep: true });
|
|
5883
6119
|
const { executor, queryBase: requestQueryBase } = resolveQueryExecutor(db, context, tableName, queryBase);
|
|
5884
6120
|
return await runRelationalSelect({
|
|
5885
6121
|
queryBase: requestQueryBase,
|
|
@@ -5938,6 +6174,7 @@ const createSchemaBuilder = (adapter) => {
|
|
|
5938
6174
|
registerScalarOverrides(tables, options);
|
|
5939
6175
|
registerEnumConfig(options);
|
|
5940
6176
|
registerColumnExclusions(tables, options.exclude);
|
|
6177
|
+
resetAggregateColumnCache();
|
|
5941
6178
|
const namedRelations = buildNamedRelations(relations ?? {}, tableEntries);
|
|
5942
6179
|
for (const excluded of excludedTables) delete namedRelations[excluded];
|
|
5943
6180
|
attachTargetPrimaryKeys(namedRelations, tables, (table) => primaryKeyPropNames(table));
|
|
@@ -6327,11 +6564,13 @@ const generateDelete = (db, tableName, table, filterArgs, fieldName, single, req
|
|
|
6327
6564
|
}
|
|
6328
6565
|
});
|
|
6329
6566
|
};
|
|
6567
|
+
/** The dialect's table config, cached per table — see {@link memoizeTableConfig}. */
|
|
6568
|
+
const getTableConfig$2 = memoizeTableConfig(drizzle_orm_mysql_core.getTableConfig);
|
|
6330
6569
|
/** Primary-key property names for a MySQL table, including table-level composite keys. */
|
|
6331
|
-
const mysqlPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table,
|
|
6570
|
+
const mysqlPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig$2);
|
|
6332
6571
|
const { prepareBuild, addReadFields, finalizeBuild } = createSchemaBuilder({
|
|
6333
6572
|
tableClass: drizzle_orm_mysql_core.MySqlTable,
|
|
6334
|
-
getTableConfig:
|
|
6573
|
+
getTableConfig: getTableConfig$2,
|
|
6335
6574
|
primaryKeyPropNames: mysqlPrimaryKeyPropNames,
|
|
6336
6575
|
nullOrdering: "nulls-smallest",
|
|
6337
6576
|
returnsRows: false,
|
|
@@ -6543,7 +6782,7 @@ const buildWriteResolvers = (primaryKeyPropNames) => {
|
|
|
6543
6782
|
const contextColumns = policies?.contextValues?.(tableName);
|
|
6544
6783
|
const scope = policies?.scope?.(context);
|
|
6545
6784
|
const input = nestedEntries ? [] : applyContextValuesAll(remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : args.values, table), contextColumns, context);
|
|
6546
|
-
const parsedInfo =
|
|
6785
|
+
const parsedInfo = parseResolveInfo(info, { deep: true });
|
|
6547
6786
|
const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
|
|
6548
6787
|
relationMap,
|
|
6549
6788
|
tables,
|
|
@@ -6598,7 +6837,7 @@ const buildWriteResolvers = (primaryKeyPropNames) => {
|
|
|
6598
6837
|
const contextColumns = policies?.contextValues?.(tableName);
|
|
6599
6838
|
const scope = policies?.scope?.(context);
|
|
6600
6839
|
const input = nestedEntry ? {} : applyContextValues(remapFromGraphQLSingleInput(entry ? entry.columns : args.values, table), contextColumns, context);
|
|
6601
|
-
const parsedInfo =
|
|
6840
|
+
const parsedInfo = parseResolveInfo(info, { deep: true });
|
|
6602
6841
|
const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
|
|
6603
6842
|
relationMap,
|
|
6604
6843
|
tables,
|
|
@@ -6671,7 +6910,7 @@ const buildWriteResolvers = (primaryKeyPropNames) => {
|
|
|
6671
6910
|
const contextColumns = policies?.contextValues?.(tableName);
|
|
6672
6911
|
const scope = policies?.scope?.(context);
|
|
6673
6912
|
const input = nestedEntries ? [] : applyContextValuesAll(remapFromGraphQLArrayInput(entries ? entries.map((entry) => entry.columns) : supplied, table), contextColumns, context);
|
|
6674
|
-
const parsedInfo =
|
|
6913
|
+
const parsedInfo = parseResolveInfo(info, { deep: true });
|
|
6675
6914
|
const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
|
|
6676
6915
|
relationMap,
|
|
6677
6916
|
tables,
|
|
@@ -6742,7 +6981,7 @@ const buildWriteResolvers = (primaryKeyPropNames) => {
|
|
|
6742
6981
|
const { where, set } = args;
|
|
6743
6982
|
const scope = policies?.scope?.(context);
|
|
6744
6983
|
await before();
|
|
6745
|
-
const parsedInfo =
|
|
6984
|
+
const parsedInfo = parseResolveInfo(info, { deep: true });
|
|
6746
6985
|
const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
|
|
6747
6986
|
relationMap,
|
|
6748
6987
|
tables,
|
|
@@ -6823,7 +7062,7 @@ const buildWriteResolvers = (primaryKeyPropNames) => {
|
|
|
6823
7062
|
const hard = canHardDelete && args.hard === true;
|
|
6824
7063
|
const scope = policies?.scope?.(context);
|
|
6825
7064
|
await before();
|
|
6826
|
-
const parsedInfo =
|
|
7065
|
+
const parsedInfo = parseResolveInfo(info, { deep: true });
|
|
6827
7066
|
const columns = extractSelectedColumnsFromTreeSQLFormat(parsedInfo.fieldsByTypeName[applyObjectTypeName(typeName, tableName, resolveName)], table, selectionCtx);
|
|
6828
7067
|
const relationCtx = relationFilterCtx(filterCtx, tableName);
|
|
6829
7068
|
const filters = withScope(scope, tableName, table, single || requireWhere ? extractRequiredFilters(table, tableName, where, relationCtx) : where ? extractFilters(table, tableName, where, relationCtx) : void 0, restore ? "ONLY" : hard ? "INCLUDE" : void 0);
|
|
@@ -7155,7 +7394,7 @@ const createUpdateManyGenerator = (primaryKeyPropNames, runBatch = runUpdateMany
|
|
|
7155
7394
|
await before();
|
|
7156
7395
|
const scope = policies?.scope?.(context);
|
|
7157
7396
|
const contextColumns = policies?.contextValues?.(tableName);
|
|
7158
|
-
const parsedInfo =
|
|
7397
|
+
const parsedInfo = parseResolveInfo(info, { deep: true });
|
|
7159
7398
|
const { columns, hasRelations, withParams } = prepareMutationRelationColumns({
|
|
7160
7399
|
relationMap,
|
|
7161
7400
|
tables,
|
|
@@ -7212,12 +7451,14 @@ const createUpdateManyGenerator = (primaryKeyPropNames, runBatch = runUpdateMany
|
|
|
7212
7451
|
};
|
|
7213
7452
|
//#endregion
|
|
7214
7453
|
//#region src/util/builders/pg.ts
|
|
7454
|
+
/** The dialect's table config, cached per table — see {@link memoizeTableConfig}. */
|
|
7455
|
+
const getTableConfig$1 = memoizeTableConfig(drizzle_orm_pg_core.getTableConfig);
|
|
7215
7456
|
/** Primary-key property names for a PG table, including table-level composite keys. */
|
|
7216
|
-
const pgPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table,
|
|
7457
|
+
const pgPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig$1);
|
|
7217
7458
|
const generateUpdateMany$1 = createUpdateManyGenerator(pgPrimaryKeyPropNames);
|
|
7218
7459
|
const pgSchemaData = createSchemaDataGenerator({
|
|
7219
7460
|
tableClass: drizzle_orm_pg_core.PgTable,
|
|
7220
|
-
getTableConfig:
|
|
7461
|
+
getTableConfig: getTableConfig$1,
|
|
7221
7462
|
primaryKeyPropNames: pgPrimaryKeyPropNames,
|
|
7222
7463
|
nullOrdering: "nulls-largest",
|
|
7223
7464
|
returnsRows: true,
|
|
@@ -7226,8 +7467,10 @@ const pgSchemaData = createSchemaDataGenerator({
|
|
|
7226
7467
|
const generateSchemaData$1 = (db, schema, relations, options) => pgSchemaData(db, schema, relations, options);
|
|
7227
7468
|
//#endregion
|
|
7228
7469
|
//#region src/util/builders/sqlite.ts
|
|
7470
|
+
/** The dialect's table config, cached per table — see {@link memoizeTableConfig}. */
|
|
7471
|
+
const getTableConfig = memoizeTableConfig(drizzle_orm_sqlite_core.getTableConfig);
|
|
7229
7472
|
/** Primary-key property names for a SQLite table, including table-level composite keys. */
|
|
7230
|
-
const sqlitePrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table,
|
|
7473
|
+
const sqlitePrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig);
|
|
7231
7474
|
/**
|
|
7232
7475
|
* SQLite's batch runner. A synchronous driver (better-sqlite3) commits the moment its
|
|
7233
7476
|
* transaction callback returns, so that callback must not be async — an awaited statement
|
|
@@ -7272,7 +7515,7 @@ const runSqliteUpdateManyBatch = ({ executor, entries, table, returning, anyNest
|
|
|
7272
7515
|
const generateUpdateMany = createUpdateManyGenerator(sqlitePrimaryKeyPropNames, runSqliteUpdateManyBatch);
|
|
7273
7516
|
const sqliteSchemaData = createSchemaDataGenerator({
|
|
7274
7517
|
tableClass: drizzle_orm_sqlite_core.SQLiteTable,
|
|
7275
|
-
getTableConfig
|
|
7518
|
+
getTableConfig,
|
|
7276
7519
|
primaryKeyPropNames: sqlitePrimaryKeyPropNames,
|
|
7277
7520
|
nullOrdering: "nulls-smallest",
|
|
7278
7521
|
returnsRows: true,
|
|
@@ -7286,11 +7529,14 @@ const generateSchemaData = (db, schema, relations, options) => sqliteSchemaData(
|
|
|
7286
7529
|
//#endregion
|
|
7287
7530
|
//#region src/util/selection.ts
|
|
7288
7531
|
const contextCache = /* @__PURE__ */ new WeakMap();
|
|
7532
|
+
const getMySqlTableConfig = memoizeTableConfig(drizzle_orm_mysql_core.getTableConfig);
|
|
7533
|
+
const getPgTableConfig = memoizeTableConfig(drizzle_orm_pg_core.getTableConfig);
|
|
7534
|
+
const getSQLiteTableConfig = memoizeTableConfig(drizzle_orm_sqlite_core.getTableConfig);
|
|
7289
7535
|
/** The dialect's `getTableConfig`, which is the only place a composite primary key shows up. */
|
|
7290
7536
|
const tableConfigFor = (db) => {
|
|
7291
|
-
if ((0, drizzle_orm.is)(db, drizzle_orm_mysql_core.MySqlAsyncDatabase)) return
|
|
7292
|
-
if ((0, drizzle_orm.is)(db, drizzle_orm_pg_core.PgAsyncDatabase)) return
|
|
7293
|
-
if ((0, drizzle_orm.is)(db, drizzle_orm_sqlite_core.SQLiteAsyncDatabase)) return
|
|
7537
|
+
if ((0, drizzle_orm.is)(db, drizzle_orm_mysql_core.MySqlAsyncDatabase)) return getMySqlTableConfig;
|
|
7538
|
+
if ((0, drizzle_orm.is)(db, drizzle_orm_pg_core.PgAsyncDatabase)) return getPgTableConfig;
|
|
7539
|
+
if ((0, drizzle_orm.is)(db, drizzle_orm_sqlite_core.SQLiteAsyncDatabase)) return getSQLiteTableConfig;
|
|
7294
7540
|
throw new Error("Drizzle-GraphQL Error: unsupported database instance — expected a PostgreSQL, MySQL or SQLite one.");
|
|
7295
7541
|
};
|
|
7296
7542
|
const contextFor = (db) => {
|
|
@@ -7341,7 +7587,7 @@ const namingRuleOf = (options) => resolveGeneratedTypeNames({
|
|
|
7341
7587
|
*/
|
|
7342
7588
|
const parseInfo = (info) => {
|
|
7343
7589
|
if ("fieldsByTypeName" in info) return info;
|
|
7344
|
-
return
|
|
7590
|
+
return parseResolveInfo(info, { deep: true });
|
|
7345
7591
|
};
|
|
7346
7592
|
/**
|
|
7347
7593
|
* Translates a GraphQL selection set into the relational query builder's `with` tree — the
|
|
@@ -7371,7 +7617,11 @@ const selectionToWith = (info, options) => {
|
|
|
7371
7617
|
if (!tables[table]) throw new Error(`Drizzle-GraphQL Error: '${table}' is not a table in the Drizzle schema.`);
|
|
7372
7618
|
if (!relationMap[table]) return;
|
|
7373
7619
|
const parsed = parseInfo(info);
|
|
7374
|
-
const params = extractRelationsParams(relationMap, tables, table, parsed, resolveObjectTypeName(table, typeNameMapper, resolveName),
|
|
7620
|
+
const params = extractRelationsParams(relationMap, tables, table, parsed, resolveObjectTypeName(table, typeNameMapper, resolveName), {
|
|
7621
|
+
typeNameMapper,
|
|
7622
|
+
filterCtx,
|
|
7623
|
+
resolveName
|
|
7624
|
+
});
|
|
7375
7625
|
return params && Object.keys(params).length ? params : void 0;
|
|
7376
7626
|
};
|
|
7377
7627
|
/**
|
|
@@ -7469,6 +7719,7 @@ exports.extractOrderBy = extractOrderBy;
|
|
|
7469
7719
|
exports.extractRelationJoinColumns = extractRelationJoinColumns;
|
|
7470
7720
|
exports.identifyRows = identifyRows;
|
|
7471
7721
|
exports.isDrizzleFieldExtension = isDrizzleFieldExtension;
|
|
7722
|
+
exports.parseResolveInfo = parseResolveInfo;
|
|
7472
7723
|
exports.resolveSelection = resolveSelection;
|
|
7473
7724
|
exports.selectionToWith = selectionToWith;
|
|
7474
7725
|
exports.singularizeMapper = singularizeMapper;
|