@vantreeseba/drizzle-graphql 1.0.3 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -1,9 +1,20 @@
1
- import { Table, Column, SQL, Relation, One, Many } from 'drizzle-orm';
1
+ import { Table, Column, Relation, SQL, One, Many } from 'drizzle-orm';
2
2
  import { MySqlDatabase } from 'drizzle-orm/mysql-core';
3
3
  import { PgAsyncDatabase } from 'drizzle-orm/pg-core';
4
4
  import { BaseSQLiteDatabase } from 'drizzle-orm/sqlite-core';
5
- import { GraphQLResolveInfo, GraphQLSchema, GraphQLInputObjectType, GraphQLObjectType, GraphQLNonNull, GraphQLList, GraphQLScalarType } from 'graphql';
5
+ import { GraphQLFieldResolver, GraphQLResolveInfo, GraphQLSchema, GraphQLInputObjectType, GraphQLObjectType, GraphQLNonNull, GraphQLList, GraphQLScalarType, GraphQLEnumType } from 'graphql';
6
+ export { GraphQLDate, GraphQLDateTime, GraphQLJSON, GraphQLUUID } from 'graphql-scalars';
6
7
 
8
+ type TableNamedRelations = {
9
+ relation: Relation;
10
+ targetTableName: string;
11
+ /**
12
+ * Property names of the target table's primary key, resolved at build time (composite
13
+ * keys included, via the dialect's getTableConfig). Used to default paginated relations
14
+ * to a deterministic PK order. Empty when the target has no detectable primary key.
15
+ */
16
+ targetPkNames?: readonly string[];
17
+ };
7
18
  type ColTypeIsNull<TColumn extends Column, TColType> = TColumn['_']['notNull'] extends true ? TColType : TColType | null;
8
19
  type ColTypeIsNullOrUndefinedWithDefault<TColumn extends Column, TColType> = TColumn['_']['notNull'] extends true ? TColumn['_']['hasDefault'] extends true ? TColType | null | undefined : TColumn['defaultFn'] extends undefined ? TColType : TColType | null | undefined : TColType | null | undefined;
9
20
  type GetColumnGqlDataType<TColumn extends Column> = TColumn['dataType'] extends 'boolean' ? ColTypeIsNull<TColumn, boolean> : TColumn['dataType'] extends 'json' ? TColumn['_']['columnType'] extends 'PgGeometryObject' ? ColTypeIsNull<TColumn, {
@@ -62,8 +73,83 @@ type OrderByArgs<TTable extends Table> = {
62
73
  };
63
74
  };
64
75
 
76
+ /**
77
+ * Extracts the join column info from a drizzle-orm v1 Relation object.
78
+ * Returns the JS property name of the local column on the parent table and the
79
+ * Column object for the foreign column on the target table, or undefined if the
80
+ * relation internals are not accessible.
81
+ */
82
+ declare const extractRelationJoinColumns: (relEntry: TableNamedRelations, parentTable: Table, targetTable: Table) => {
83
+ localColPropName: string;
84
+ foreignCol: Column;
85
+ foreignColPropName: string;
86
+ } | undefined;
87
+ type RelationResolverFactory = (params: {
88
+ tableName: string;
89
+ relationName: string;
90
+ relEntry: TableNamedRelations;
91
+ isOne: boolean;
92
+ }) => GraphQLFieldResolver<any, any> | undefined;
93
+ /**
94
+ * Key on the GraphQL context object under which a caller can place a Drizzle transaction
95
+ * (or any other executor: a pooled connection, a logging proxy). Every generated resolver
96
+ * reads it at resolve time and runs its statements there instead of on the database the
97
+ * schema was built from, which is what lets several mutations in one request share a
98
+ * transaction and lets a query see that transaction's uncommitted rows:
99
+ *
100
+ * ```ts
101
+ * await db.transaction(async (tx) => {
102
+ * await graphql({ schema, source, contextValue: { [drizzleExecutorKey]: tx } });
103
+ * });
104
+ * ```
105
+ *
106
+ * Registered with `Symbol.for` so the ESM and CJS builds of this package agree on it when
107
+ * both end up loaded in one process.
108
+ */
109
+ declare const drizzleExecutorKey: unique symbol;
110
+ /**
111
+ * Creates a RelationResolverFactory that generates field-level resolvers for each relation.
112
+ * Each resolver:
113
+ * 1. Returns pre-fetched data if the parent resolver already included it (eager path, zero cost).
114
+ * 2. When limit/offset args are present, falls back to a direct per-item query.
115
+ * 3. Otherwise batches all sibling resolver calls within the same GraphQL execution tick
116
+ * into a single IN-clause query, eliminating N+1 database round-trips.
117
+ */
118
+ declare const createRelationResolverFactory: (db: any, tables: Record<string, Table>, filterCtx?: RelationFilterBase) => RelationResolverFactory;
65
119
  declare const extractOrderBy: <TTable extends Table, TArgs extends OrderByArgs<any> = OrderByArgs<TTable>>(table: TTable, orderArgs: TArgs) => SQL[];
66
- declare const extractFilters: <TTable extends Table>(table: TTable, tableName: string, filters: Filters<TTable>) => SQL | undefined;
120
+ /**
121
+ * Everything `extractFilters` needs to turn a relation key in a `where` argument into a
122
+ * correlated subquery. Omitted by callers that don't generate relation filters, in which case
123
+ * relation keys can't appear in the input to begin with.
124
+ */
125
+ interface RelationFilterContext {
126
+ /** Every table in the schema, keyed by its schema key. */
127
+ tables: Record<string, Table>;
128
+ /** Relations keyed by table schema key, then relation name. */
129
+ relationMap: Record<string, Record<string, TableNamedRelations>>;
130
+ /**
131
+ * Schema key of the table being filtered. Not always the same as the `tableName` label
132
+ * used in error messages (relation `where` callbacks pass the relation name there).
133
+ */
134
+ tableKey: string;
135
+ /** Shared counter making every subquery alias unique within one extraction. */
136
+ aliases?: {
137
+ n: number;
138
+ };
139
+ }
140
+ /**
141
+ * The build-scoped half of {@link RelationFilterContext}. Created once per generated schema and
142
+ * handed to every resolver, which adds the table it is filtering.
143
+ */
144
+ type RelationFilterBase = Pick<RelationFilterContext, 'tables' | 'relationMap'>;
145
+ declare const extractFilters: <TTable extends Table>(table: TTable, tableName: string, filters: Filters<TTable>, relationCtx?: RelationFilterContext) => SQL | undefined;
146
+ /**
147
+ * Default for `config.onError`: keeps drizzle-graphql's own errors, which are written for
148
+ * the client, and replaces driver/database errors with a generic message. Their text names
149
+ * tables, columns, constraints and offending values, none of which belongs in a response.
150
+ * The original is preserved on `originalError` for server-side logging.
151
+ */
152
+ declare const defaultErrorMapper: (error: unknown) => unknown;
67
153
 
68
154
  type Relations<TTable extends string = string, TConfig extends Record<string, Relation> = Record<string, Relation>> = {
69
155
  table: {
@@ -108,6 +194,22 @@ type UpdateArgs<TTable extends Table> = Partial<{
108
194
  set: GetRemappedTableUpdateDataType<TTable>;
109
195
  where?: Filters<TTable>;
110
196
  }>;
197
+ /**
198
+ * The `onConflict` argument of the generated upsert mutations.
199
+ *
200
+ * `target` and `where` exist on PostgreSQL and SQLite only: MySQL's
201
+ * `ON DUPLICATE KEY UPDATE` fires on whichever unique key was violated and takes no
202
+ * predicate, so neither field is generated there.
203
+ */
204
+ type UpsertConflictArgs<TTable extends Table> = {
205
+ action?: 'UPDATE' | 'NOTHING';
206
+ target?: string[];
207
+ update?: string[];
208
+ where?: Filters<TTable>;
209
+ };
210
+ type UpsertArgs<TTable extends Table, isSingle extends boolean> = InsertArgs<TTable, isSingle> & {
211
+ onConflict?: UpsertConflictArgs<TTable>;
212
+ };
111
213
  type DeleteArgs<TTable extends Table> = {
112
214
  where?: Filters<TTable>;
113
215
  };
@@ -120,6 +222,18 @@ type SelectSingleResolver<TTable extends Table, TTables extends Record<string, T
120
222
  type InsertResolver<TTable extends Table, IsReturnless extends boolean> = (source: any, args: Partial<InsertArgs<TTable, false>>, context: any, info: GraphQLResolveInfo) => Promise<IsReturnless extends false ? Array<GetRemappedTableDataType<TTable>> : MutationReturnlessResult>;
121
223
  type InsertArrResolver<TTable extends Table, IsReturnless extends boolean> = (source: any, args: Partial<InsertArgs<TTable, true>>, context: any, info: GraphQLResolveInfo) => Promise<IsReturnless extends false ? GetRemappedTableDataType<TTable> | undefined : MutationReturnlessResult>;
122
224
  type UpdateResolver<TTable extends Table, IsReturnless extends boolean> = (source: any, args: UpdateArgs<TTable>, context: any, info: GraphQLResolveInfo) => Promise<IsReturnless extends false ? GetRemappedTableDataType<TTable> | undefined : MutationReturnlessResult>;
225
+ /** Resolver for `upsert<Table>Single`. */
226
+ type UpsertResolver<TTable extends Table, IsReturnless extends boolean> = (source: any, args: Partial<UpsertArgs<TTable, true>>, context: any, info: GraphQLResolveInfo) => Promise<IsReturnless extends false ? GetRemappedTableDataType<TTable> | undefined : MutationReturnlessResult>;
227
+ /** Resolver for `upsert<Table>`. */
228
+ type UpsertArrResolver<TTable extends Table, IsReturnless extends boolean> = (source: any, args: Partial<UpsertArgs<TTable, false>>, context: any, info: GraphQLResolveInfo) => Promise<IsReturnless extends false ? Array<GetRemappedTableDataType<TTable>> : MutationReturnlessResult>;
229
+ /**
230
+ * Resolver for a table's generated aggregate query (`<plural>Aggregate`).
231
+ * Returns only the requested aggregations: `count` plus per-column `avg` / `sum`
232
+ * (numeric columns, as Float) and `min` / `max` (orderable columns, as the column's type).
233
+ */
234
+ type AggregateResolver<TTable extends Table> = (source: any, args: {
235
+ where?: Filters<TTable>;
236
+ }, context: any, info: GraphQLResolveInfo) => Promise<Record<string, any>>;
123
237
  type DeleteResolver<TTable extends Table, IsReturnless extends boolean> = (source: any, args: DeleteArgs<TTable>, context: any, info: GraphQLResolveInfo) => Promise<IsReturnless extends false ? GetRemappedTableDataType<TTable> | undefined : MutationReturnlessResult>;
124
238
  type QueriesCore<TSchemaTables extends Record<string, Table>, TSchemaRelations extends Record<string, Relations>, TInputs extends Record<string, GraphQLInputObjectType>, TOutputs extends Record<string, GraphQLObjectType>> = {
125
239
  [TName in keyof TSchemaTables as TName extends string ? `${Uncapitalize<TName>}` : never]: TName extends string ? {
@@ -137,6 +251,9 @@ type QueriesCore<TSchemaTables extends Record<string, Table>, TSchemaRelations e
137
251
  where: {
138
252
  type: TInputs[`${Capitalize<TName>}Filters`] extends GraphQLInputObjectType ? TInputs[`${Capitalize<TName>}Filters`] : never;
139
253
  };
254
+ distinct: {
255
+ type: GraphQLList<GraphQLNonNull<GraphQLEnumType>>;
256
+ };
140
257
  };
141
258
  resolve: SelectResolver<TSchemaTables[TName], TSchemaTables, ExtractTableRelations<TSchemaTables[TName], TSchemaRelations> extends infer R ? R[keyof R] : never>;
142
259
  } : never;
@@ -156,9 +273,19 @@ type QueriesCore<TSchemaTables extends Record<string, Table>, TSchemaRelations e
156
273
  };
157
274
  resolve: SelectSingleResolver<TSchemaTables[TName], TSchemaTables, ExtractTableRelations<TSchemaTables[TName], TSchemaRelations> extends infer R ? R[keyof R] : never>;
158
275
  } : never;
276
+ } & {
277
+ [TName in keyof TSchemaTables as TName extends string ? `${Uncapitalize<TName>}Aggregate` : never]: TName extends string ? {
278
+ type: GraphQLNonNull<TOutputs[`${Capitalize<TName>}Aggregate`] extends GraphQLObjectType ? TOutputs[`${Capitalize<TName>}Aggregate`] : GraphQLObjectType>;
279
+ args: {
280
+ where: {
281
+ type: TInputs[`${Capitalize<TName>}Filters`] extends GraphQLInputObjectType ? TInputs[`${Capitalize<TName>}Filters`] : never;
282
+ };
283
+ };
284
+ resolve: AggregateResolver<TSchemaTables[TName]>;
285
+ } : never;
159
286
  };
160
287
  type MutationsCore<TSchemaTables extends Record<string, Table>, TInputs extends Record<string, GraphQLInputObjectType>, TOutputs extends Record<string, GraphQLObjectType>, IsReturnless extends boolean> = {
161
- [TName in keyof TSchemaTables as TName extends string ? `insertInto${Capitalize<TName>}` : never]: TName extends string ? {
288
+ [TName in keyof TSchemaTables as TName extends string ? `create${Capitalize<TName>}` : never]: TName extends string ? {
162
289
  type: IsReturnless extends true ? TOutputs['MutationReturn'] extends GraphQLObjectType ? TOutputs['MutationReturn'] : never : GraphQLNonNull<GraphQLList<GraphQLNonNull<TOutputs[`${Capitalize<TName>}Item`]>>>;
163
290
  args: {
164
291
  values: {
@@ -168,7 +295,7 @@ type MutationsCore<TSchemaTables extends Record<string, Table>, TInputs extends
168
295
  resolve: InsertArrResolver<TSchemaTables[TName], IsReturnless>;
169
296
  } : never;
170
297
  } & {
171
- [TName in keyof TSchemaTables as TName extends string ? `insertInto${Capitalize<TName>}Single` : never]: TName extends string ? {
298
+ [TName in keyof TSchemaTables as TName extends string ? `create${Capitalize<TName>}Single` : never]: TName extends string ? {
172
299
  type: IsReturnless extends true ? TOutputs['MutationReturn'] extends GraphQLObjectType ? TOutputs['MutationReturn'] : never : TOutputs[`${Capitalize<TName>}Item`];
173
300
  args: {
174
301
  values: {
@@ -177,6 +304,32 @@ type MutationsCore<TSchemaTables extends Record<string, Table>, TInputs extends
177
304
  };
178
305
  resolve: InsertResolver<TSchemaTables[TName], IsReturnless>;
179
306
  } : never;
307
+ } & {
308
+ [TName in keyof TSchemaTables as TName extends string ? `upsert${Capitalize<TName>}` : never]?: TName extends string ? {
309
+ type: IsReturnless extends true ? TOutputs['MutationReturn'] extends GraphQLObjectType ? TOutputs['MutationReturn'] : never : GraphQLNonNull<GraphQLList<GraphQLNonNull<TOutputs[`${Capitalize<TName>}Item`]>>>;
310
+ args: {
311
+ values: {
312
+ type: GraphQLNonNull<GraphQLList<GraphQLNonNull<TInputs[`${Capitalize<TName>}InsertInput`]>>>;
313
+ };
314
+ onConflict: {
315
+ type: GraphQLInputObjectType;
316
+ };
317
+ };
318
+ resolve: UpsertArrResolver<TSchemaTables[TName], IsReturnless>;
319
+ } : never;
320
+ } & {
321
+ [TName in keyof TSchemaTables as TName extends string ? `upsert${Capitalize<TName>}Single` : never]?: TName extends string ? {
322
+ type: IsReturnless extends true ? TOutputs['MutationReturn'] extends GraphQLObjectType ? TOutputs['MutationReturn'] : never : TOutputs[`${Capitalize<TName>}Item`];
323
+ args: {
324
+ values: {
325
+ type: GraphQLNonNull<TInputs[`${Capitalize<TName>}InsertInput`]>;
326
+ };
327
+ onConflict: {
328
+ type: GraphQLInputObjectType;
329
+ };
330
+ };
331
+ resolve: UpsertResolver<TSchemaTables[TName], IsReturnless>;
332
+ } : never;
180
333
  } & {
181
334
  [TName in keyof TSchemaTables as TName extends string ? `update${Capitalize<TName>}` : never]: TName extends string ? {
182
335
  type: IsReturnless extends true ? TOutputs['MutationReturn'] extends GraphQLObjectType ? TOutputs['MutationReturn'] : never : GraphQLNonNull<GraphQLList<GraphQLNonNull<TOutputs[`${Capitalize<TName>}Item`]>>>;
@@ -191,7 +344,7 @@ type MutationsCore<TSchemaTables extends Record<string, Table>, TInputs extends
191
344
  resolve: UpdateResolver<TSchemaTables[TName], IsReturnless>;
192
345
  } : never;
193
346
  } & {
194
- [TName in keyof TSchemaTables as TName extends string ? `deleteFrom${Capitalize<TName>}` : never]: TName extends string ? {
347
+ [TName in keyof TSchemaTables as TName extends string ? `delete${Capitalize<TName>}` : never]: TName extends string ? {
195
348
  type: IsReturnless extends true ? TOutputs['MutationReturn'] extends GraphQLObjectType ? TOutputs['MutationReturn'] : never : GraphQLNonNull<GraphQLList<GraphQLNonNull<TOutputs[`${Capitalize<TName>}Item`]>>>;
196
349
  args: {
197
350
  where: {
@@ -212,6 +365,8 @@ type GeneratedInputs<TSchema extends Record<string, Table>> = {
212
365
  };
213
366
  type GeneratedOutputs<TSchema extends Record<string, Table>, IsReturnless extends boolean> = {
214
367
  [TName in keyof TSchema as TName extends string ? `${Capitalize<TName>}SelectItem` : never]: GraphQLObjectType;
368
+ } & {
369
+ [TName in keyof TSchema as TName extends string ? `${Capitalize<TName>}Aggregate` : never]: GraphQLObjectType;
215
370
  } & (IsReturnless extends true ? {
216
371
  MutationReturn: GraphQLObjectType;
217
372
  } : {
@@ -222,11 +377,46 @@ type GeneratedEntities<TDatabase extends AnyDrizzleDB<TSchema>, TSchema extends
222
377
  mutations: MutationsCore<TSchemaTables, TInputs, TOutputs, TDatabase extends MySqlDatabase<any, any, any, any> ? true : false>;
223
378
  inputs: TInputs;
224
379
  types: TOutputs;
380
+ /**
381
+ * Field-level resolvers for each relation on each table.
382
+ * Each resolver handles both the eager path (data pre-fetched by the parent query)
383
+ * and the lazy path (data fetched on demand with N+1 protection via request-scoped batching).
384
+ * Keyed as `fieldResolvers[tableSchemaKey][relationName]`.
385
+ */
386
+ fieldResolvers: {
387
+ [TName in keyof TSchemaTables as TName extends string ? TName : never]?: Record<string, (source: any, args: any, context: any, info: GraphQLResolveInfo) => Promise<any>>;
388
+ };
225
389
  };
226
390
  type GeneratedData<TDatabase extends AnyDrizzleDB<any>> = {
227
391
  schema: GraphQLSchema;
228
392
  entities: GeneratedEntities<TDatabase>;
229
393
  };
394
+ /**
395
+ * Per-feature switches for what `buildSchema` generates. Every flag defaults to `true`.
396
+ * See {@link BuildSchemaConfig.features}.
397
+ */
398
+ type SchemaFeatures = {
399
+ /** `<plural>Aggregate` root queries and the aggregate output types. @default true */
400
+ aggregates?: boolean;
401
+ /** `<relation>Aggregate` fields on object types, for to-many relations. @default true */
402
+ relationAggregates?: boolean;
403
+ /** The `distinct` argument on list queries. @default true */
404
+ distinct?: boolean;
405
+ /** `create<Table>` / `create<Table>Single` mutations. @default true */
406
+ insert?: boolean;
407
+ /** `update<Table>` mutations. @default true */
408
+ update?: boolean;
409
+ /** `delete<Table>` mutations. @default true */
410
+ delete?: boolean;
411
+ /**
412
+ * `upsert<Table>` / `upsert<Table>Single` mutations — insert, or update the row that
413
+ * already holds the same unique key. Off unless asked for, so an existing schema does
414
+ * not grow new mutations on upgrade.
415
+ *
416
+ * @default false
417
+ */
418
+ upsert?: boolean;
419
+ };
230
420
  type BuildSchemaConfig = {
231
421
  /**
232
422
  * Determines whether generated mutations will be passed to returned schema.
@@ -237,29 +427,39 @@ type BuildSchemaConfig = {
237
427
  */
238
428
  mutations?: boolean;
239
429
  /**
240
- * Limits depth of generated relation fields on queries.
430
+ * Limits depth of relation-field generation.
241
431
  *
242
- * Expects non-negative integer or undefined.
432
+ * Expects a non-negative integer or `undefined`.
243
433
  *
244
- * Set value to `undefined` to not limit relation depth.
434
+ * `undefined` (default) no limit; all relations are generated recursively
435
+ * until a cycle is detected.
245
436
  *
246
- * Set value to `0` to omit relations altogether.
437
+ * `0` no relation fields are generated on any type. Useful for a flat,
438
+ * columns-only schema.
247
439
  *
248
- * Value is treated as if set to `undefined` by default.
440
+ * `N > 0` each table's own direct relations are still generated (every
441
+ * table's root type is processed at depth 0, which is always < N). The
442
+ * depth limit controls how deep the generation RECURSES when traversing
443
+ * related types; because all types share a single instance via the type
444
+ * cache, setting N > 0 currently behaves the same as `undefined` for the
445
+ * final schema shape. The principal useful values are `0` (no relations)
446
+ * and `undefined` (unlimited).
249
447
  */
250
448
  relationsDepthLimit?: number;
251
449
  /**
252
450
  * Customizes query name prefixes for generated GraphQL operations.
253
451
  *
254
- * @default { list: '', single: 'Single' }
452
+ * @default { insert: 'create', delete: 'delete', update: 'update', upsert: 'upsert' }
255
453
  */
256
454
  prefixes?: {
257
- /** Prefix for insert mutations (e.g., 'users' -> 'insertIntoUsers') */
455
+ /** Prefix for insert mutations (e.g., 'users' -> 'createUsers') */
258
456
  insert?: string;
259
- /** Prefix for delete mutations (e.g., 'users' -> 'deleteFromUsers') */
457
+ /** Prefix for delete mutations (e.g., 'users' -> 'deleteUsers') */
260
458
  delete?: string;
261
459
  /** Prefix for update mutations (e.g., 'users' -> 'updateUsers') */
262
460
  update?: string;
461
+ /** Prefix for upsert mutations (e.g., 'users' -> 'upsertUsers') */
462
+ upsert?: string;
263
463
  };
264
464
  /**
265
465
  * Customizes query name suffixes for generated GraphQL operations.
@@ -275,17 +475,121 @@ type BuildSchemaConfig = {
275
475
  /**
276
476
  * When true, insert mutations will use onConflictDoNothing() to silently
277
477
  * ignore duplicate key violations. Defaults to false (conflicts throw errors).
478
+ *
479
+ * PostgreSQL and SQLite only — MySQL's insert builder has no equivalent, so the flag is
480
+ * ignored there and conflicts keep throwing.
481
+ *
482
+ * @deprecated Build-wide and unconditional: a request cannot opt out of it, and a
483
+ * swallowed insert returns `null` with no indication why. Turn on `features.upsert` and
484
+ * pass `onConflict: { action: NOTHING }` per request instead. This flag keeps working
485
+ * until the next major.
278
486
  */
279
487
  conflictDoNothing?: boolean;
280
488
  /**
281
- * When true, all generated GraphQL object type names will use the singular form
282
- * of the table name (e.g. `users` table → `User` type instead of `Users`).
489
+ * Turns individual generated features off.
490
+ *
491
+ * Every flag defaults to `true` except `upsert`, which is opt-in: a build with no
492
+ * `features` block generates exactly what it generated before this option existed.
493
+ * Turning one off removes both the schema surface it adds and the work behind it.
494
+ *
495
+ * ```ts
496
+ * buildSchema(db, {
497
+ * features: {
498
+ * aggregates: false, // no `<plural>Aggregate` root queries
499
+ * relationAggregates: false, // no `<relation>Aggregate` fields on object types
500
+ * distinct: false, // no `distinct` argument on list queries
501
+ * delete: false, // no delete mutations
502
+ * upsert: true, // opt in to `upsert<Table>` mutations
503
+ * },
504
+ * });
505
+ * ```
506
+ *
507
+ * Turning off every mutation feature omits the `Mutation` type entirely, exactly as
508
+ * `mutations: false` does. Query-side features can all be off — the list and single
509
+ * queries are always generated, so `Query` is never empty.
510
+ */
511
+ features?: SchemaFeatures;
512
+ /**
513
+ * Optional mapper from table key to singular/plural name pair.
514
+ * When provided for a table, overrides the default (table key) naming for GraphQL type names,
515
+ * query field names, and mutation field names.
516
+ * Return `undefined` for tables that should use the default naming.
283
517
  *
284
- * Defaults to false.
518
+ * Example: `(name) => name === 'users' ? { singular: 'user', plural: 'users' } : undefined`
519
+ * produces type `User`, queries `users` / `user`, mutations `createUsers` / `createUser` for
520
+ * the `users` table, and leaves other tables with their default names.
285
521
  */
286
- singularTypes?: boolean;
522
+ typeNameMapper?: (tableName: string) => {
523
+ singular: string;
524
+ plural: string;
525
+ } | undefined;
526
+ /**
527
+ * Controls whether a relation is eagerly pre-fetched via Drizzle's `with:` clause
528
+ * when its parent is loaded through a generated query or mutation.
529
+ *
530
+ * `true` (default) — every selected relation is eager-loaded in the parent's query.
531
+ *
532
+ * `false` — no relation is ever eager-loaded; all relations resolve lazily through
533
+ * their (request-batched) field resolvers.
534
+ *
535
+ * `(tableName, relationName) => boolean` — decide per relation. Return `false` to
536
+ * exclude that relation from `with:` (and from the mutation eager re-fetch).
537
+ *
538
+ * Opting a relation out does NOT remove its field resolver — it still resolves
539
+ * lazily via the request-scoped batch loader. This is the hook for overriding a
540
+ * relation's resolver (e.g. via `@graphql-tools/schema`'s `addResolversToSchema`)
541
+ * without the eager `with:` query also fetching it from the database:
542
+ *
543
+ * ```ts
544
+ * const { schema } = buildSchema(db, {
545
+ * eagerLoadRelations: (t, r) => !(t === 'Users' && r === 'posts'),
546
+ * });
547
+ * const finalSchema = addResolversToSchema({
548
+ * schema,
549
+ * resolvers: { Users: { posts: (parent) => myLoader.load(parent.id) } },
550
+ * });
551
+ * ```
552
+ *
553
+ * Table and relation names are the Drizzle schema keys (e.g. `Users`, `posts`),
554
+ * matching the keys of `entities.fieldResolvers`.
555
+ *
556
+ * @default true
557
+ */
558
+ eagerLoadRelations?: boolean | ((tableName: string, relationName: string) => boolean);
559
+ /**
560
+ * Called for every error thrown by a generated resolver, before it reaches the client.
561
+ *
562
+ * Return an error to surface that one instead. Return nothing to fall through to the
563
+ * default handling, which makes this a pure logging hook:
564
+ *
565
+ * ```ts
566
+ * buildSchema(db, { onError: (error) => { logger.error(error) } })
567
+ * ```
568
+ *
569
+ * The default passes through errors drizzle-graphql raises itself (bad filter, missing
570
+ * values, invalid date, …) and replaces everything else — driver and database errors —
571
+ * with a generic `Internal server error`, keeping the original on `originalError` so it
572
+ * is still available to server-side logging. Database messages routinely name tables,
573
+ * columns, constraints and the values that violated them, which is not something a
574
+ * public API should hand back.
575
+ *
576
+ * To surface raw database errors instead (useful in development):
577
+ *
578
+ * ```ts
579
+ * buildSchema(db, { onError: (error) => error as Error })
580
+ * ```
581
+ */
582
+ onError?: (error: unknown) => unknown;
287
583
  };
288
584
 
585
+ /**
586
+ * A 64-bit integer. Always transported as a decimal string, in both directions, so no value
587
+ * is ever silently rounded by JSON's double-precision numbers. `graphql-scalars`' own
588
+ * `GraphQLBigInt` is deliberately not used: it emits numbers for safe integers and strings
589
+ * for everything else, so a client cannot know which it will get.
590
+ */
591
+ declare const GraphQLBigIntString: GraphQLScalarType<string, string>;
592
+
289
593
  declare const buildSchema: <TDbClient extends AnyDrizzleDB<any>>(db: TDbClient, config?: BuildSchemaConfig) => GeneratedData<TDbClient>;
290
594
 
291
- export { type AnyDrizzleDB, type BuildSchemaConfig, type DeleteResolver, type ExtractRelations, type ExtractTableByName, type ExtractTableRelations, type ExtractTables, type GeneratedData, type GeneratedEntities, type GeneratedInputs, type GeneratedOutputs, type InsertArrResolver, type InsertResolver, type MutationReturnlessResult, type MutationsCore, type QueriesCore, type SelectResolver, type SelectSingleResolver, type UpdateResolver, buildSchema, extractFilters, extractOrderBy };
595
+ export { type AggregateResolver, type AnyDrizzleDB, type BuildSchemaConfig, type DeleteResolver, type ExtractRelations, type ExtractTableByName, type ExtractTableRelations, type ExtractTables, type GeneratedData, type GeneratedEntities, type GeneratedInputs, type GeneratedOutputs, GraphQLBigIntString, type InsertArrResolver, type InsertResolver, type MutationReturnlessResult, type MutationsCore, type QueriesCore, type RelationResolverFactory, type SchemaFeatures, type SelectResolver, type SelectSingleResolver, type TableNamedRelations, type UpdateResolver, type UpsertArgs, type UpsertArrResolver, type UpsertConflictArgs, type UpsertResolver, buildSchema, createRelationResolverFactory, defaultErrorMapper, drizzleExecutorKey, extractFilters, extractOrderBy, extractRelationJoinColumns };