@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.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { Column, One, SQL, Table, aliasedTable, and, arrayContains, arrayOverlaps, asc, avg, count, countDistinct, desc, eq, extractExtendedColumnType, getColumns, getTableAsAliasSQL,
|
|
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
|
-
import { GraphQLBoolean, GraphQLEnumType, GraphQLError, GraphQLFloat, GraphQLInputObjectType, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLString, Kind } from "graphql";
|
|
6
|
-
import pluralize from "pluralize";
|
|
5
|
+
import { GraphQLBoolean, GraphQLEnumType, GraphQLError, GraphQLFloat, GraphQLInputObjectType, GraphQLInt, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLScalarType, GraphQLSchema, GraphQLString, Kind, getArgumentValues } from "graphql";
|
|
7
6
|
import { GraphQLDate, GraphQLDateTime, GraphQLJSON, GraphQLUUID } from "graphql-scalars";
|
|
8
|
-
import
|
|
7
|
+
import pluralize from "pluralize";
|
|
9
8
|
//#region src/util/builders/common/errors.ts
|
|
10
9
|
/**
|
|
11
10
|
* A `GraphQLError` carrying its context as data. The message says what went wrong, in prose
|
|
@@ -92,28 +91,6 @@ const applyErrorMapper = (entities, mapError) => {
|
|
|
92
91
|
for (const tableResolvers of Object.values(entities.fieldResolvers ?? {})) for (const [relationName, resolve] of Object.entries(tableResolvers)) tableResolvers[relationName] = wrap(resolve);
|
|
93
92
|
};
|
|
94
93
|
//#endregion
|
|
95
|
-
//#region src/util/case-ops/index.ts
|
|
96
|
-
const uncapitalize = (input) => input?.length ? `${input[0].toLocaleLowerCase()}${input.length > 1 ? input.slice(1, input.length) : ""}` : input;
|
|
97
|
-
const capitalize = (input) => input?.length ? `${input[0].toLocaleUpperCase()}${input.length > 1 ? input.slice(1, input.length) : ""}` : input;
|
|
98
|
-
/**
|
|
99
|
-
* The `typeNameMapper` preset behind `typeNameMapper: 'singularize'`.
|
|
100
|
-
*
|
|
101
|
-
* Derives the singular and plural forms of a table key with the library's own `pluralize`,
|
|
102
|
-
* which is what nearly every consumer with plural table keys (`export const tasks =
|
|
103
|
-
* pgTable('tasks', …)`) was writing by hand — and adding `pluralize` to their own
|
|
104
|
-
* dependencies to write.
|
|
105
|
-
*
|
|
106
|
-
* `tasks` becomes type `Task`, queries `tasks` / `task`, mutations `createTasks` /
|
|
107
|
-
* `createTask`. A key that is already singular is pluralized for the list side, so `task`
|
|
108
|
-
* yields the same names, and a capitalized key (`Tasks`) yields them too — the field forms
|
|
109
|
-
* are uncapitalized so the generated names follow GraphQL's camelCase convention whatever
|
|
110
|
-
* the schema key looks like. The type name is capitalized by the generator either way.
|
|
111
|
-
*/
|
|
112
|
-
const singularizeMapper = (tableName) => ({
|
|
113
|
-
singular: uncapitalize(pluralize.singular(tableName)),
|
|
114
|
-
plural: uncapitalize(pluralize.plural(tableName))
|
|
115
|
-
});
|
|
116
|
-
//#endregion
|
|
117
94
|
//#region src/util/scalars/index.ts
|
|
118
95
|
const INVALID_INPUT = "DRIZZLE_INVALID_INPUT_VALUE";
|
|
119
96
|
const UNREPRESENTABLE = "DRIZZLE_UNREPRESENTABLE_VALUE";
|
|
@@ -184,6 +161,28 @@ const GraphQLDecimalString = new GraphQLScalarType({
|
|
|
184
161
|
}
|
|
185
162
|
});
|
|
186
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
|
|
187
186
|
//#region src/util/type-converter/index.ts
|
|
188
187
|
const allowedNameChars = /^[a-zA-Z0-9_]+$/;
|
|
189
188
|
/**
|
|
@@ -413,7 +412,7 @@ const normalizeScalarOverride = (override, tableName, columnName) => {
|
|
|
413
412
|
* leaves the column on built-in detection.
|
|
414
413
|
*/
|
|
415
414
|
const registerScalarOverrides = (tables, config) => {
|
|
416
|
-
for (const [tableName, table] of Object.entries(tables)) for (const [columnName, column] of Object.entries(
|
|
415
|
+
for (const [tableName, table] of Object.entries(tables)) for (const [columnName, column] of Object.entries(getColumns(table))) {
|
|
417
416
|
const declared = config.scalars?.[tableName]?.[columnName];
|
|
418
417
|
let resolved;
|
|
419
418
|
if (declared !== void 0) resolved = normalizeScalarOverride(declared, tableName, columnName);
|
|
@@ -452,136 +451,6 @@ const drizzleColumnToGraphQLType = (column, columnName, tableName, forceNullable
|
|
|
452
451
|
return typeDesc;
|
|
453
452
|
};
|
|
454
453
|
//#endregion
|
|
455
|
-
//#region src/util/data-mappers/index.ts
|
|
456
|
-
const isJsonColumn$1 = (column) => (column.dataType ?? "").includes("json") && column.columnType !== "PgGeometryObject";
|
|
457
|
-
const remapToGraphQLCore = (key, value, tableName, column, relationMap) => {
|
|
458
|
-
if (Array.isArray(value)) {
|
|
459
|
-
const relations = relationMap?.[tableName];
|
|
460
|
-
if (relations?.[key]) {
|
|
461
|
-
const rel = relations[key];
|
|
462
|
-
return remapToGraphQLArrayOutput(value, rel.targetTableName, rel.relation?.targetTable ?? rel.relation?.referencedTable, relationMap);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
if (typeof value === "object" && value !== null) {
|
|
466
|
-
const relations = relationMap?.[tableName];
|
|
467
|
-
if (relations?.[key]) {
|
|
468
|
-
const rel = relations[key];
|
|
469
|
-
return remapToGraphQLSingleOutput(value, rel.targetTableName, rel.relation?.targetTable ?? rel.relation?.referencedTable, relationMap);
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
if (!column) return value;
|
|
473
|
-
if (getColumnScalarOverride(column, false)) return value;
|
|
474
|
-
if (isJsonColumn$1(column)) return value;
|
|
475
|
-
if (value instanceof Date) return value.toISOString();
|
|
476
|
-
if (value instanceof Buffer) return Array.from(value);
|
|
477
|
-
if (typeof value === "bigint") return value.toString();
|
|
478
|
-
if (Array.isArray(value)) {
|
|
479
|
-
if (column.columnType === "PgGeometry" || column.columnType === "PgVector") return value;
|
|
480
|
-
return value.map((arrVal) => remapToGraphQLCore(key, arrVal, tableName, column, relationMap));
|
|
481
|
-
}
|
|
482
|
-
if (typeof value === "object" && value !== null) {
|
|
483
|
-
if (column.columnType === "PgGeometryObject") return value;
|
|
484
|
-
return JSON.stringify(value);
|
|
485
|
-
}
|
|
486
|
-
return value;
|
|
487
|
-
};
|
|
488
|
-
const remapToGraphQLSingleOutput = (queryOutput, tableName, table, relationMap) => {
|
|
489
|
-
const columns = getTableColumns(table);
|
|
490
|
-
for (const [key, value] of Object.entries(queryOutput)) {
|
|
491
|
-
if (value === void 0 || value === null) {
|
|
492
|
-
const relEntry = value === null ? relationMap?.[tableName]?.[key] : void 0;
|
|
493
|
-
if (relEntry && is(relEntry.relation, One)) {
|
|
494
|
-
queryOutput[key] = null;
|
|
495
|
-
continue;
|
|
496
|
-
}
|
|
497
|
-
delete queryOutput[key];
|
|
498
|
-
continue;
|
|
499
|
-
}
|
|
500
|
-
const column = columns[key];
|
|
501
|
-
if (value === 0n && column && column.columnType === "SQLiteBigInt" && !column.notNull) {
|
|
502
|
-
delete queryOutput[key];
|
|
503
|
-
continue;
|
|
504
|
-
}
|
|
505
|
-
queryOutput[key] = remapToGraphQLCore(key, value, tableName, column, relationMap);
|
|
506
|
-
}
|
|
507
|
-
return queryOutput;
|
|
508
|
-
};
|
|
509
|
-
const remapToGraphQLArrayOutput = (queryOutput, tableName, table, relationMap) => {
|
|
510
|
-
for (const entry of queryOutput) remapToGraphQLSingleOutput(entry, tableName, table, relationMap);
|
|
511
|
-
return queryOutput;
|
|
512
|
-
};
|
|
513
|
-
const remapFromGraphQLCore = (value, column, columnName) => {
|
|
514
|
-
if (getColumnScalarOverride(column, true)) {
|
|
515
|
-
if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === null) return Object.assign({}, value);
|
|
516
|
-
return value;
|
|
517
|
-
}
|
|
518
|
-
const dataType = column.dataType ?? "";
|
|
519
|
-
const columnType = column.columnType ?? "";
|
|
520
|
-
if (columnType === "SQLiteTimestamp" || columnType === "SQLiteTimestampMs" || columnType === "MySqlTimestamp" || columnType === "MySqlDateTime" || columnType === "PgTimestamp" || columnType === "PgTimestampString") {
|
|
521
|
-
const formatted = new Date(value);
|
|
522
|
-
if (Number.isNaN(formatted.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
523
|
-
return formatted;
|
|
524
|
-
}
|
|
525
|
-
if ((columnType === "MySqlDate" || columnType === "PgDate") && typeof value === "string") {
|
|
526
|
-
const dateOnly = value.includes("T") ? value.split("T")[0] : value;
|
|
527
|
-
const check = new Date(dateOnly);
|
|
528
|
-
if (Number.isNaN(check.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
529
|
-
return dateOnly;
|
|
530
|
-
}
|
|
531
|
-
if (dataType.includes("bigint")) try {
|
|
532
|
-
return BigInt(value);
|
|
533
|
-
} catch {
|
|
534
|
-
throw drizzleError(`Field '${columnName}' is not a BigInt!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
535
|
-
}
|
|
536
|
-
if (dataType.includes("json") && column.columnType !== "PgGeometryObject") return value;
|
|
537
|
-
switch (dataType) {
|
|
538
|
-
case "date": {
|
|
539
|
-
const formatted = new Date(value);
|
|
540
|
-
if (Number.isNaN(formatted.getTime())) throw drizzleError(`Field '${columnName}' is not a valid date!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
541
|
-
return formatted;
|
|
542
|
-
}
|
|
543
|
-
case "buffer":
|
|
544
|
-
if (!Array.isArray(value)) throw drizzleError(`Field '${columnName}' is not an array!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
545
|
-
return Buffer.from(value);
|
|
546
|
-
case "json":
|
|
547
|
-
if (column.columnType === "PgGeometryObject") return value;
|
|
548
|
-
try {
|
|
549
|
-
return JSON.parse(value);
|
|
550
|
-
} catch (e) {
|
|
551
|
-
throw drizzleError(`Invalid JSON in field '${columnName}':\n${e instanceof Error ? e.message : "Unknown error"}`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
552
|
-
}
|
|
553
|
-
case "array":
|
|
554
|
-
if (!Array.isArray(value)) throw drizzleError(`Field '${columnName}' is not an array!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
555
|
-
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" });
|
|
556
|
-
return value;
|
|
557
|
-
case "bigint": try {
|
|
558
|
-
return BigInt(value);
|
|
559
|
-
} catch (_error) {
|
|
560
|
-
throw drizzleError(`Field '${columnName}' is not a BigInt!`, { code: "DRIZZLE_INVALID_INPUT_VALUE" });
|
|
561
|
-
}
|
|
562
|
-
default:
|
|
563
|
-
if (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === null) return Object.assign({}, value);
|
|
564
|
-
return value;
|
|
565
|
-
}
|
|
566
|
-
};
|
|
567
|
-
const remapFromGraphQLSingleInput = (queryInput, table) => {
|
|
568
|
-
for (const [key, value] of Object.entries(queryInput)) if (value === void 0) delete queryInput[key];
|
|
569
|
-
else {
|
|
570
|
-
const column = getTableColumns(table)[key];
|
|
571
|
-
if (!column) throw drizzleError(`Unknown column: ${key}`, { code: "DRIZZLE_UNKNOWN_COLUMN" });
|
|
572
|
-
if (value === null && column.notNull) {
|
|
573
|
-
delete queryInput[key];
|
|
574
|
-
continue;
|
|
575
|
-
}
|
|
576
|
-
queryInput[key] = remapFromGraphQLCore(value, column, key);
|
|
577
|
-
}
|
|
578
|
-
return queryInput;
|
|
579
|
-
};
|
|
580
|
-
const remapFromGraphQLArrayInput = (queryInput, table) => {
|
|
581
|
-
for (const entry of queryInput) remapFromGraphQLSingleInput(entry, table);
|
|
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)).
|
|
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
|
-
*
|
|
2335
|
-
*
|
|
2336
|
-
*
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
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
|
-
|
|
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
|
|
@@ -2980,10 +3023,14 @@ const splitFieldUpdateOperations = (values, table, tableName) => {
|
|
|
2980
3023
|
*
|
|
2981
3024
|
* Safe to call on every update path regardless of `features.fieldUpdateOperations` — see the
|
|
2982
3025
|
* shape check in {@link splitFieldUpdateOperations}.
|
|
3026
|
+
*
|
|
3027
|
+
* This is the single funnel every update goes through — the plural and `Single` mutations,
|
|
3028
|
+
* `updateMany`, the `Count` mutations and the MySQL builder's own — which is why it is the
|
|
3029
|
+
* one place that has to tell the remapper it is serving an update rather than an insert.
|
|
2983
3030
|
*/
|
|
2984
3031
|
const remapUpdateInput = (values, table, tableName) => {
|
|
2985
3032
|
const { columns, expressions } = splitFieldUpdateOperations(values, table, tableName);
|
|
2986
|
-
const remapped = remapFromGraphQLSingleInput(columns, table);
|
|
3033
|
+
const remapped = remapFromGraphQLSingleInput(columns, table, "update");
|
|
2987
3034
|
return Object.keys(expressions).length ? {
|
|
2988
3035
|
...remapped,
|
|
2989
3036
|
...expressions
|
|
@@ -3026,48 +3073,55 @@ const relationJoinColumns = (tree, table, selectionCtx) => {
|
|
|
3026
3073
|
}
|
|
3027
3074
|
return needed;
|
|
3028
3075
|
};
|
|
3029
|
-
|
|
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) => {
|
|
3030
3091
|
const tableColumns = getColumns(table);
|
|
3031
|
-
const
|
|
3032
|
-
const
|
|
3033
|
-
for (const [_fieldName, fieldData] of treeEntries) {
|
|
3092
|
+
const names = [];
|
|
3093
|
+
for (const fieldData of Object.values(tree)) {
|
|
3034
3094
|
if (!tableColumns[fieldData.name]) continue;
|
|
3035
|
-
|
|
3036
|
-
}
|
|
3037
|
-
for (const columnName of relationJoinColumns(tree, table, selectionCtx)) selectedColumns.push([columnName, true]);
|
|
3038
|
-
if (!selectedColumns.length) {
|
|
3039
|
-
const columnKeys = Object.entries(tableColumns);
|
|
3040
|
-
const columnName = columnKeys.find((e) => rqbCrashTypes.find((haram) => e[1].columnType !== haram))?.[0] ?? columnKeys[0][0];
|
|
3041
|
-
selectedColumns.push([columnName, true]);
|
|
3095
|
+
names.push(fieldData.name);
|
|
3042
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]);
|
|
3043
3104
|
return Object.fromEntries(selectedColumns);
|
|
3044
3105
|
};
|
|
3045
3106
|
/**
|
|
3107
|
+
* The same columns as a SQL select list.
|
|
3108
|
+
*
|
|
3046
3109
|
* Can't automatically determine column type on type level
|
|
3047
3110
|
* Since drizzle table types extend eachother
|
|
3048
3111
|
*/
|
|
3049
3112
|
const extractSelectedColumnsFromTreeSQLFormat = (tree, table, selectionCtx) => {
|
|
3050
3113
|
const tableColumns = getColumns(table);
|
|
3051
|
-
const
|
|
3052
|
-
const selectedColumns = [];
|
|
3053
|
-
for (const [_fieldName, fieldData] of treeEntries) {
|
|
3054
|
-
if (!tableColumns[fieldData.name]) continue;
|
|
3055
|
-
selectedColumns.push([fieldData.name, tableColumns[fieldData.name]]);
|
|
3056
|
-
}
|
|
3057
|
-
for (const columnName of relationJoinColumns(tree, table, selectionCtx)) selectedColumns.push([columnName, tableColumns[columnName]]);
|
|
3058
|
-
if (!selectedColumns.length) {
|
|
3059
|
-
const columnKeys = Object.entries(tableColumns);
|
|
3060
|
-
const columnName = columnKeys.find((e) => rqbCrashTypes.find((haram) => e[1].columnType !== haram))?.[0] ?? columnKeys[0][0];
|
|
3061
|
-
selectedColumns.push([columnName, tableColumns[columnName]]);
|
|
3062
|
-
}
|
|
3114
|
+
const selectedColumns = selectedColumnNames(tree, table, selectionCtx).map((columnName) => [columnName, tableColumns[columnName]]);
|
|
3063
3115
|
return Object.fromEntries(selectedColumns);
|
|
3064
3116
|
};
|
|
3065
3117
|
//#endregion
|
|
3066
3118
|
//#region src/util/builders/common/relation-params.ts
|
|
3067
|
-
const
|
|
3119
|
+
const extractRelationsParams = (relationMap, tables, tableName, info, typeName, options = {}) => {
|
|
3120
|
+
const { typeNameMapper, filterCtx, limits, scope, defaultOrderBy, resolveName } = options;
|
|
3121
|
+
if (!info) return;
|
|
3068
3122
|
const relationsForTable = relationMap[tableName];
|
|
3069
3123
|
if (!relationsForTable) return;
|
|
3070
|
-
const baseField = Object.entries(
|
|
3124
|
+
const baseField = Object.entries(info.fieldsByTypeName).find(([key, _value]) => key === typeName)?.[1];
|
|
3071
3125
|
if (!baseField) return;
|
|
3072
3126
|
const args = {};
|
|
3073
3127
|
for (const [relName, relEntry] of Object.entries(relationsForTable)) {
|
|
@@ -3104,15 +3158,11 @@ const extractRelationsParamsInner = (relationMap, tables, tableName, typeName, o
|
|
|
3104
3158
|
thisRecord.orderBy = relationArgs?.orderBy ? (aliasedTable) => extractOrderBy(aliasedTable, relationArgs.orderBy, relationFilterCtx(filterCtx, targetTableName), relWhere) : hasPagination && pkNames.length ? (aliasedTable) => primaryKeyOrderExprs(aliasedTable, pkNames) : void 0;
|
|
3105
3159
|
thisRecord.offset = offset;
|
|
3106
3160
|
thisRecord.limit = limit;
|
|
3107
|
-
thisRecord.with =
|
|
3161
|
+
thisRecord.with = extractRelationsParams(relationMap, tables, targetTableName, relationField, relTypeName, options);
|
|
3108
3162
|
args[relName] = thisRecord;
|
|
3109
3163
|
}
|
|
3110
3164
|
return args;
|
|
3111
3165
|
};
|
|
3112
|
-
const extractRelationsParams = (relationMap, tables, tableName, info, typeName, typeNameMapper, filterCtx, limits, scope, defaultOrderBy, resolveName) => {
|
|
3113
|
-
if (!info) return;
|
|
3114
|
-
return extractRelationsParamsInner(relationMap, tables, tableName, typeName, info, typeNameMapper, true, filterCtx, limits, scope, defaultOrderBy, resolveName);
|
|
3115
|
-
};
|
|
3116
3166
|
/**
|
|
3117
3167
|
* Returns a copy of `relationMap` containing only the relations that should be eagerly
|
|
3118
3168
|
* pre-fetched (per the `shouldEagerLoad` predicate). Pass the result wherever a query or
|
|
@@ -3313,7 +3363,13 @@ const hardDeleteArg = {
|
|
|
3313
3363
|
const prepareMutationRelationColumns = (params) => {
|
|
3314
3364
|
const { relationMap, tables, tableName, typeNameMapper, table, pkNames, parsedInfo, resolveName } = params;
|
|
3315
3365
|
const typeName = resolveObjectTypeName(tableName, typeNameMapper, resolveName);
|
|
3316
|
-
const withParams = relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName,
|
|
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;
|
|
3317
3373
|
const hasRelations = !!(withParams && Object.keys(withParams).length);
|
|
3318
3374
|
const baseColumns = extractSelectedColumnsFromTreeSQLFormat(parsedInfo.fieldsByTypeName[typeName], table, {
|
|
3319
3375
|
tableName,
|
|
@@ -3892,7 +3948,14 @@ const runRelationalSelect = async (opts) => {
|
|
|
3892
3948
|
offset: distinctKeys ? void 0 : offset,
|
|
3893
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,
|
|
3894
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,
|
|
3895
|
-
with: relationMap[tableName] ? extractRelationsParams(relationMap, tables, tableName, parsedInfo, typeName,
|
|
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
|
|
3896
3959
|
};
|
|
3897
3960
|
if (single) {
|
|
3898
3961
|
const result = await queryBase.findFirst(params);
|
|
@@ -4740,6 +4803,154 @@ const resolveBuildConfig = (config, schema) => {
|
|
|
4740
4803
|
};
|
|
4741
4804
|
};
|
|
4742
4805
|
//#endregion
|
|
4806
|
+
//#region src/util/parse-resolve-info.ts
|
|
4807
|
+
/** Unwraps `[T]!`-style wrappers down to the named type. `getNamedType` without the realm tie. */
|
|
4808
|
+
const namedTypeOf = (type) => {
|
|
4809
|
+
let current = type;
|
|
4810
|
+
while (current?.ofType) current = current.ofType;
|
|
4811
|
+
return current;
|
|
4812
|
+
};
|
|
4813
|
+
/**
|
|
4814
|
+
* Whether a field's named output type has sub-selections. Object types and interfaces expose
|
|
4815
|
+
* `getFields`, unions expose `getTypes`; scalars and enums expose neither. Input object types
|
|
4816
|
+
* also expose `getFields`, but an input type can never be a field's output type, so there is
|
|
4817
|
+
* nothing here for that to collide with.
|
|
4818
|
+
*/
|
|
4819
|
+
const isCompositeLike = (type) => !!type && (typeof type.getFields === "function" || typeof type.getTypes === "function");
|
|
4820
|
+
/**
|
|
4821
|
+
* The fields declared on a type, or `undefined` when it has none to declare. A union is the
|
|
4822
|
+
* case that matters: it has no fields of its own, so a selection directly against one resolves
|
|
4823
|
+
* to nothing and is dropped — only the inline fragments underneath contribute.
|
|
4824
|
+
*/
|
|
4825
|
+
const fieldsOf = (type) => typeof type?.getFields === "function" ? type.getFields() : void 0;
|
|
4826
|
+
/**
|
|
4827
|
+
* The runtime variable values, in the plain-map form the directive check wants. graphql 17
|
|
4828
|
+
* wraps them in `{ sources, coerced }`; graphql 16 hands over the map itself.
|
|
4829
|
+
*/
|
|
4830
|
+
const coercedVariables = (info) => {
|
|
4831
|
+
const values = info.variableValues;
|
|
4832
|
+
if (values && typeof values === "object" && "coerced" in values) return values.coerced ?? {};
|
|
4833
|
+
return values ?? {};
|
|
4834
|
+
};
|
|
4835
|
+
/** The value of a `@skip` / `@include` `if:` argument — a literal or a variable reference. */
|
|
4836
|
+
const directiveIfValue = (info, value) => {
|
|
4837
|
+
if (value.kind === Kind.VARIABLE) return coercedVariables(info)[value.name.value];
|
|
4838
|
+
if (value.kind === Kind.BOOLEAN) return value.value;
|
|
4839
|
+
};
|
|
4840
|
+
/**
|
|
4841
|
+
* Whether `@skip` / `@include` on this selection exclude it. Applies to fields, fragment
|
|
4842
|
+
* spreads and inline fragments alike, which is where graphql puts them.
|
|
4843
|
+
*/
|
|
4844
|
+
const isExcluded = (info, node) => {
|
|
4845
|
+
for (const directive of node.directives ?? []) {
|
|
4846
|
+
const directiveName = directive.name.value;
|
|
4847
|
+
if (directiveName !== "skip" && directiveName !== "include") continue;
|
|
4848
|
+
const ifArgument = directive.arguments?.find((argument) => argument.name.value === "if");
|
|
4849
|
+
if (!ifArgument) continue;
|
|
4850
|
+
const value = directiveIfValue(info, ifArgument.value);
|
|
4851
|
+
if (directiveName === "skip" ? !!value : !value) return true;
|
|
4852
|
+
}
|
|
4853
|
+
return false;
|
|
4854
|
+
};
|
|
4855
|
+
/** The type a fragment's `on Type` condition names, looked up in the executing schema. */
|
|
4856
|
+
const typeFromCondition = (info, condition) => info.schema.getType(condition.name.value);
|
|
4857
|
+
/**
|
|
4858
|
+
* Introspection meta-fields are not schema fields and never reach the database. `__typename` is
|
|
4859
|
+
* the one that turns up in practice; `__id` is excluded from the rule because a schema is free
|
|
4860
|
+
* to declare a field by that name.
|
|
4861
|
+
*/
|
|
4862
|
+
const isMetaField = (name) => name.startsWith("__") && name !== "__id";
|
|
4863
|
+
/**
|
|
4864
|
+
* Merges one selection set into `tree`, which is a `fieldsByTypeName` map — the caller owns the
|
|
4865
|
+
* level, this owns the entries under `parentType`'s name.
|
|
4866
|
+
*
|
|
4867
|
+
* `activeFragments` is the set of fragment names on the current spread path. A document that
|
|
4868
|
+
* passed validation cannot contain a fragment cycle, but this parser also runs on trees a
|
|
4869
|
+
* caller assembled by hand, and an unbounded walk would hang rather than fail.
|
|
4870
|
+
*/
|
|
4871
|
+
const collectSelections = (selections, info, tree, parentType, deep, activeFragments) => {
|
|
4872
|
+
const parentTypeName = parentType?.name;
|
|
4873
|
+
if (!parentTypeName) return tree;
|
|
4874
|
+
let fields = tree[parentTypeName];
|
|
4875
|
+
if (!fields) {
|
|
4876
|
+
fields = {};
|
|
4877
|
+
tree[parentTypeName] = fields;
|
|
4878
|
+
}
|
|
4879
|
+
const parentFields = fieldsOf(parentType);
|
|
4880
|
+
for (const selection of selections) {
|
|
4881
|
+
if (isExcluded(info, selection)) continue;
|
|
4882
|
+
if (selection.kind === Kind.FIELD) {
|
|
4883
|
+
const name = selection.name.value;
|
|
4884
|
+
if (isMetaField(name)) continue;
|
|
4885
|
+
const fieldDef = parentFields?.[name];
|
|
4886
|
+
if (!fieldDef) continue;
|
|
4887
|
+
const fieldType = namedTypeOf(fieldDef.type);
|
|
4888
|
+
if (!fieldType) continue;
|
|
4889
|
+
const composite = isCompositeLike(fieldType);
|
|
4890
|
+
const alias = selection.alias?.value || name;
|
|
4891
|
+
let node = fields[alias];
|
|
4892
|
+
if (!node) {
|
|
4893
|
+
node = {
|
|
4894
|
+
name,
|
|
4895
|
+
alias,
|
|
4896
|
+
args: { ...getArgumentValues(fieldDef, selection, info.variableValues) },
|
|
4897
|
+
fieldsByTypeName: composite && fieldType.name ? { [fieldType.name]: {} } : {}
|
|
4898
|
+
};
|
|
4899
|
+
fields[alias] = node;
|
|
4900
|
+
}
|
|
4901
|
+
if (selection.selectionSet && deep && composite) collectSelections(selection.selectionSet.selections, info, node.fieldsByTypeName, fieldType, deep, activeFragments);
|
|
4902
|
+
continue;
|
|
4903
|
+
}
|
|
4904
|
+
if (!deep) continue;
|
|
4905
|
+
if (selection.kind === Kind.FRAGMENT_SPREAD) {
|
|
4906
|
+
const fragmentName = selection.name.value;
|
|
4907
|
+
const fragment = info.fragments?.[fragmentName];
|
|
4908
|
+
if (!fragment) throw new Error(`Drizzle-GraphQL Error: unknown fragment '${fragmentName}' — it is spread in the query but not defined in the document.`);
|
|
4909
|
+
if (activeFragments.has(fragmentName)) continue;
|
|
4910
|
+
const fragmentType = fragment.typeCondition ? typeFromCondition(info, fragment.typeCondition) : parentType;
|
|
4911
|
+
if (!isCompositeLike(fragmentType)) continue;
|
|
4912
|
+
activeFragments.add(fragmentName);
|
|
4913
|
+
try {
|
|
4914
|
+
collectSelections(fragment.selectionSet.selections, info, tree, fragmentType, deep, activeFragments);
|
|
4915
|
+
} finally {
|
|
4916
|
+
activeFragments.delete(fragmentName);
|
|
4917
|
+
}
|
|
4918
|
+
continue;
|
|
4919
|
+
}
|
|
4920
|
+
if (selection.kind === Kind.INLINE_FRAGMENT) {
|
|
4921
|
+
const fragmentType = selection.typeCondition ? typeFromCondition(info, selection.typeCondition) : parentType;
|
|
4922
|
+
if (!isCompositeLike(fragmentType)) continue;
|
|
4923
|
+
collectSelections(selection.selectionSet.selections, info, tree, fragmentType, deep, activeFragments);
|
|
4924
|
+
}
|
|
4925
|
+
}
|
|
4926
|
+
return tree;
|
|
4927
|
+
};
|
|
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
|
+
};
|
|
4932
|
+
/**
|
|
4933
|
+
* Reads the selection under a resolver's own field out of its `info`, as a tree of
|
|
4934
|
+
* {@link ResolveTree} nodes.
|
|
4935
|
+
*
|
|
4936
|
+
* ```ts
|
|
4937
|
+
* const parsed = parseResolveInfo(info, { deep: true })!;
|
|
4938
|
+
* const selected = parsed.fieldsByTypeName['Users']; // keyed by response key
|
|
4939
|
+
* ```
|
|
4940
|
+
*
|
|
4941
|
+
* Returns `undefined` when the resolver's field produced no node at all, which in practice
|
|
4942
|
+
* means `info` carried no field nodes.
|
|
4943
|
+
*/
|
|
4944
|
+
const parseResolveInfo = (info, options = {}) => {
|
|
4945
|
+
const fieldNodes = info.fieldNodes;
|
|
4946
|
+
if (!fieldNodes) throw new Error("Drizzle-GraphQL Error: resolve info carries no fieldNodes, so no selection could be read from it.");
|
|
4947
|
+
const tree = collectSelections(fieldNodes, info, {}, info.parentType, options.deep ?? true, /* @__PURE__ */ new Set());
|
|
4948
|
+
const typeKey = firstKey(tree);
|
|
4949
|
+
const fields = typeKey === void 0 ? void 0 : tree[typeKey];
|
|
4950
|
+
const fieldKey = fields && firstKey(fields);
|
|
4951
|
+
return fieldKey === void 0 ? void 0 : fields?.[fieldKey];
|
|
4952
|
+
};
|
|
4953
|
+
//#endregion
|
|
4743
4954
|
//#region src/util/builders/aggregates.ts
|
|
4744
4955
|
/** Operations that aggregate over a set of column values. `count` is handled separately (whole rows). */
|
|
4745
4956
|
const AGGREGATE_OPS = [
|
|
@@ -4768,7 +4979,30 @@ const SEP = "__";
|
|
|
4768
4979
|
* arrays (including array-typed number columns), JSON, buffers, and object-shaped columns
|
|
4769
4980
|
* (e.g. geometry) are excluded entirely.
|
|
4770
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
|
+
};
|
|
4771
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;
|
|
4772
5006
|
const numeric = {};
|
|
4773
5007
|
const orderable = {};
|
|
4774
5008
|
const all = {};
|
|
@@ -4786,11 +5020,13 @@ const classifyAggregateColumns = (table, tableName) => {
|
|
|
4786
5020
|
};
|
|
4787
5021
|
if (dataType === "number") numeric[columnName] = column;
|
|
4788
5022
|
}
|
|
4789
|
-
|
|
5023
|
+
const sets = {
|
|
4790
5024
|
numeric,
|
|
4791
5025
|
orderable,
|
|
4792
5026
|
all
|
|
4793
5027
|
};
|
|
5028
|
+
byName.set(tableName, sets);
|
|
5029
|
+
return sets;
|
|
4794
5030
|
};
|
|
4795
5031
|
/**
|
|
4796
5032
|
* Builds the `${typeName}Aggregate` output type for a table:
|
|
@@ -5914,6 +6150,7 @@ const createSchemaBuilder = (adapter) => {
|
|
|
5914
6150
|
registerScalarOverrides(tables, options);
|
|
5915
6151
|
registerEnumConfig(options);
|
|
5916
6152
|
registerColumnExclusions(tables, options.exclude);
|
|
6153
|
+
resetAggregateColumnCache();
|
|
5917
6154
|
const namedRelations = buildNamedRelations(relations ?? {}, tableEntries);
|
|
5918
6155
|
for (const excluded of excludedTables) delete namedRelations[excluded];
|
|
5919
6156
|
attachTargetPrimaryKeys(namedRelations, tables, (table) => primaryKeyPropNames(table));
|
|
@@ -6303,11 +6540,13 @@ const generateDelete = (db, tableName, table, filterArgs, fieldName, single, req
|
|
|
6303
6540
|
}
|
|
6304
6541
|
});
|
|
6305
6542
|
};
|
|
6543
|
+
/** The dialect's table config, cached per table — see {@link memoizeTableConfig}. */
|
|
6544
|
+
const getTableConfig$5 = memoizeTableConfig(getTableConfig);
|
|
6306
6545
|
/** Primary-key property names for a MySQL table, including table-level composite keys. */
|
|
6307
|
-
const mysqlPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig);
|
|
6546
|
+
const mysqlPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig$5);
|
|
6308
6547
|
const { prepareBuild, addReadFields, finalizeBuild } = createSchemaBuilder({
|
|
6309
6548
|
tableClass: MySqlTable,
|
|
6310
|
-
getTableConfig,
|
|
6549
|
+
getTableConfig: getTableConfig$5,
|
|
6311
6550
|
primaryKeyPropNames: mysqlPrimaryKeyPropNames,
|
|
6312
6551
|
nullOrdering: "nulls-smallest",
|
|
6313
6552
|
returnsRows: false,
|
|
@@ -7188,12 +7427,14 @@ const createUpdateManyGenerator = (primaryKeyPropNames, runBatch = runUpdateMany
|
|
|
7188
7427
|
};
|
|
7189
7428
|
//#endregion
|
|
7190
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);
|
|
7191
7432
|
/** Primary-key property names for a PG table, including table-level composite keys. */
|
|
7192
|
-
const pgPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig$
|
|
7433
|
+
const pgPrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig$4);
|
|
7193
7434
|
const generateUpdateMany$1 = createUpdateManyGenerator(pgPrimaryKeyPropNames);
|
|
7194
7435
|
const pgSchemaData = createSchemaDataGenerator({
|
|
7195
7436
|
tableClass: PgTable,
|
|
7196
|
-
getTableConfig: getTableConfig$
|
|
7437
|
+
getTableConfig: getTableConfig$4,
|
|
7197
7438
|
primaryKeyPropNames: pgPrimaryKeyPropNames,
|
|
7198
7439
|
nullOrdering: "nulls-largest",
|
|
7199
7440
|
returnsRows: true,
|
|
@@ -7202,8 +7443,10 @@ const pgSchemaData = createSchemaDataGenerator({
|
|
|
7202
7443
|
const generateSchemaData$1 = (db, schema, relations, options) => pgSchemaData(db, schema, relations, options);
|
|
7203
7444
|
//#endregion
|
|
7204
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);
|
|
7205
7448
|
/** Primary-key property names for a SQLite table, including table-level composite keys. */
|
|
7206
|
-
const sqlitePrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig$
|
|
7449
|
+
const sqlitePrimaryKeyPropNames = (table) => getPrimaryKeyPropNamesFromConfig(table, getTableConfig$3);
|
|
7207
7450
|
/**
|
|
7208
7451
|
* SQLite's batch runner. A synchronous driver (better-sqlite3) commits the moment its
|
|
7209
7452
|
* transaction callback returns, so that callback must not be async — an awaited statement
|
|
@@ -7248,7 +7491,7 @@ const runSqliteUpdateManyBatch = ({ executor, entries, table, returning, anyNest
|
|
|
7248
7491
|
const generateUpdateMany = createUpdateManyGenerator(sqlitePrimaryKeyPropNames, runSqliteUpdateManyBatch);
|
|
7249
7492
|
const sqliteSchemaData = createSchemaDataGenerator({
|
|
7250
7493
|
tableClass: SQLiteTable,
|
|
7251
|
-
getTableConfig: getTableConfig$
|
|
7494
|
+
getTableConfig: getTableConfig$3,
|
|
7252
7495
|
primaryKeyPropNames: sqlitePrimaryKeyPropNames,
|
|
7253
7496
|
nullOrdering: "nulls-smallest",
|
|
7254
7497
|
returnsRows: true,
|
|
@@ -7262,11 +7505,14 @@ const generateSchemaData = (db, schema, relations, options) => sqliteSchemaData(
|
|
|
7262
7505
|
//#endregion
|
|
7263
7506
|
//#region src/util/selection.ts
|
|
7264
7507
|
const contextCache = /* @__PURE__ */ new WeakMap();
|
|
7508
|
+
const getMySqlTableConfig = memoizeTableConfig(getTableConfig);
|
|
7509
|
+
const getPgTableConfig = memoizeTableConfig(getTableConfig$1);
|
|
7510
|
+
const getSQLiteTableConfig = memoizeTableConfig(getTableConfig$2);
|
|
7265
7511
|
/** The dialect's `getTableConfig`, which is the only place a composite primary key shows up. */
|
|
7266
7512
|
const tableConfigFor = (db) => {
|
|
7267
|
-
if (is(db, MySqlAsyncDatabase)) return
|
|
7268
|
-
if (is(db, PgAsyncDatabase)) return
|
|
7269
|
-
if (is(db, SQLiteAsyncDatabase)) return
|
|
7513
|
+
if (is(db, MySqlAsyncDatabase)) return getMySqlTableConfig;
|
|
7514
|
+
if (is(db, PgAsyncDatabase)) return getPgTableConfig;
|
|
7515
|
+
if (is(db, SQLiteAsyncDatabase)) return getSQLiteTableConfig;
|
|
7270
7516
|
throw new Error("Drizzle-GraphQL Error: unsupported database instance — expected a PostgreSQL, MySQL or SQLite one.");
|
|
7271
7517
|
};
|
|
7272
7518
|
const contextFor = (db) => {
|
|
@@ -7347,7 +7593,11 @@ const selectionToWith = (info, options) => {
|
|
|
7347
7593
|
if (!tables[table]) throw new Error(`Drizzle-GraphQL Error: '${table}' is not a table in the Drizzle schema.`);
|
|
7348
7594
|
if (!relationMap[table]) return;
|
|
7349
7595
|
const parsed = parseInfo(info);
|
|
7350
|
-
const params = extractRelationsParams(relationMap, tables, table, parsed, resolveObjectTypeName(table, typeNameMapper, resolveName),
|
|
7596
|
+
const params = extractRelationsParams(relationMap, tables, table, parsed, resolveObjectTypeName(table, typeNameMapper, resolveName), {
|
|
7597
|
+
typeNameMapper,
|
|
7598
|
+
filterCtx,
|
|
7599
|
+
resolveName
|
|
7600
|
+
});
|
|
7351
7601
|
return params && Object.keys(params).length ? params : void 0;
|
|
7352
7602
|
};
|
|
7353
7603
|
/**
|
|
@@ -7428,6 +7678,6 @@ const buildSchema = (db, config) => {
|
|
|
7428
7678
|
};
|
|
7429
7679
|
};
|
|
7430
7680
|
//#endregion
|
|
7431
|
-
export { GraphQLBigIntString, GraphQLDate, GraphQLDateTime, GraphQLDecimalString, GraphQLJSON, GraphQLUUID, buildSchema, createRelationResolverFactory, defaultErrorMapper, drizzleError, drizzleExecutorKey, drizzleExtension, extractFilters, extractOrderBy, extractRelationJoinColumns, identifyRows, isDrizzleFieldExtension, resolveSelection, selectionToWith, singularizeMapper };
|
|
7681
|
+
export { GraphQLBigIntString, GraphQLDate, GraphQLDateTime, GraphQLDecimalString, GraphQLJSON, GraphQLUUID, buildSchema, createRelationResolverFactory, defaultErrorMapper, drizzleError, drizzleExecutorKey, drizzleExtension, extractFilters, extractOrderBy, extractRelationJoinColumns, identifyRows, isDrizzleFieldExtension, parseResolveInfo, resolveSelection, selectionToWith, singularizeMapper };
|
|
7432
7682
|
|
|
7433
7683
|
//# sourceMappingURL=index.js.map
|