@vantreeseba/drizzle-graphql 7.7.0 → 7.9.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
@@ -237,6 +237,43 @@ type RelationResolverFactory = (params: {
237
237
  * both end up loaded in one process.
238
238
  */
239
239
  declare const drizzleExecutorKey: unique symbol;
240
+ /** The write a hook is attached to. `restore` only exists for a soft-deleting table. */
241
+ type WriteOperation = 'insert' | 'update' | 'updateMany' | 'upsert' | 'delete' | 'restore';
242
+ /** What a write hook is handed. See {@link BuildSchemaConfig.onWrite}. */
243
+ type WriteHookPayload = {
244
+ /** Drizzle schema key of the table being written. */
245
+ table: string;
246
+ operation: WriteOperation;
247
+ /** `'before'` runs ahead of the statement, `'after'` once it has returned. */
248
+ position: 'before' | 'after';
249
+ /** Whether the field writes a single row (`createUsersSingle`) or a list. */
250
+ single: boolean;
251
+ /** The field's GraphQL arguments, exactly as the resolver received them. */
252
+ args: any;
253
+ /**
254
+ * The rows the write produced, as the database returned them — before the output mapper,
255
+ * so values are database-shaped. Empty at the `before` position, and on MySQL, whose
256
+ * mutations return no rows.
257
+ */
258
+ rows: any[];
259
+ context: any;
260
+ info: any;
261
+ /** The executor the mutation itself ran on. Throwing from the hook rolls it back. */
262
+ tx: any;
263
+ };
264
+ type WriteHook = (payload: WriteHookPayload) => void | Promise<void>;
265
+ type WriteHookPositions = {
266
+ before?: WriteHook;
267
+ after?: WriteHook;
268
+ };
269
+ type WriteHooks = WriteHook | WriteHookPositions;
270
+ /** Resolved, per-field hooks: `undefined` when the table registered none. */
271
+ type ResolvedWriteHooks = {
272
+ before?: WriteHook;
273
+ after?: WriteHook;
274
+ };
275
+ /** Build-time lookup of a table's hooks, installed on {@link TablePolicies}. */
276
+ type WriteHookFor = (tableName: string, operation: WriteOperation) => ResolvedWriteHooks | undefined;
240
277
  /**
241
278
  * Creates a RelationResolverFactory that generates field-level resolvers for each relation.
242
279
  * Each resolver:
@@ -263,6 +300,13 @@ type ResolvedLimitPolicy = {
263
300
  * `buildSchema`; `undefined` for a table the caller left unbounded.
264
301
  */
265
302
  type LimitPolicyFor = (tableName: string) => ResolvedLimitPolicy | undefined;
303
+ /**
304
+ * {@link BuildSchemaConfig.defaults} resolved for one table: the `orderBy` a read falls back
305
+ * to when the request passes none, already in the shape the generated argument has.
306
+ * `undefined` means the table declares no default and keeps whatever order the database
307
+ * returns.
308
+ */
309
+ type DefaultOrderByFor = (tableName: string) => Record<string, any> | undefined;
266
310
  /**
267
311
  * Compiles an `orderBy` argument into ORDER BY expressions, highest priority first.
268
312
  *
@@ -360,6 +404,10 @@ type TablePolicies = {
360
404
  contextValues?: ContextValuesFor;
361
405
  /** See `BuildSchemaConfig.softDelete`. */
362
406
  softDelete?: SoftDeleteFor;
407
+ /** See `BuildSchemaConfig.onWrite`. */
408
+ onWrite?: WriteHookFor;
409
+ /** See `BuildSchemaConfig.defaults`. */
410
+ defaultOrderBy?: DefaultOrderByFor;
363
411
  };
364
412
  /**
365
413
  * Where a dialect's default sort places NULLs relative to non-NULL values:
@@ -759,8 +807,14 @@ type SchemaFeatures = {
759
807
  * Each relation field offers `create` and `connect`; the update input adds `disconnect`
760
808
  * and, for a to-many relation, `set` (replace the whole set). `disconnect` and `set` are
761
809
  * generated only when the foreign key is nullable — there is no way to detach a row whose
762
- * key is NOT NULL — and many-to-many (`.through()`) relations are not written through at
763
- * all. Nesting is one level deep: the row a nested `create` inserts takes columns only.
810
+ * key is NOT NULL. Nesting is one level deep: the row a nested `create` inserts takes
811
+ * columns only.
812
+ *
813
+ * A many-to-many (`.through()`) relation is written as junction rows: `connect` on the
814
+ * create input, and `connect` / `disconnect` / `set` on the update input, all
815
+ * unconditional, since unlinking deletes a junction row rather than nulling a column.
816
+ * It offers no `create` — inserting a row and linking it are two writes to two tables —
817
+ * and `set: []` clears the relation.
764
818
  *
765
819
  * The whole tree runs in one transaction (a savepoint when the request already carries
766
820
  * one), and a column a relation fills in (`authorId`, when `author: { create: … }` is
@@ -870,6 +924,25 @@ type TableLimitPolicy = {
870
924
  */
871
925
  clampToMax?: boolean;
872
926
  };
927
+ /**
928
+ * One entry of a {@link TableDefaults} ordering: a direction, or a direction with the
929
+ * priority that decides where it sits among the other entries (higher first, as in the
930
+ * generated `orderBy` argument).
931
+ */
932
+ type DefaultOrderByEntry = 'asc' | 'desc' | {
933
+ direction: 'asc' | 'desc';
934
+ priority?: number;
935
+ };
936
+ /** {@link DefaultsConfig} — what one table falls back to when the request does not say. */
937
+ type TableDefaults = {
938
+ /**
939
+ * The ordering a read of this table runs with when the request passes no `orderBy`, keyed
940
+ * by column property name.
941
+ */
942
+ orderBy?: Record<string, DefaultOrderByEntry>;
943
+ };
944
+ /** {@link BuildSchemaConfig.defaults} — per-table defaults, keyed by the Drizzle schema key. */
945
+ type DefaultsConfig = Record<string, TableDefaults>;
873
946
  /** {@link BuildSchemaConfig.limits} — a global policy plus per-table overrides. */
874
947
  type LimitsConfig = TableLimitPolicy & {
875
948
  /** Per-table overrides, keyed by the table's key in the Drizzle schema. */
@@ -923,6 +996,13 @@ type SoftDeleteColumn = string | {
923
996
  */
924
997
  restoredValue?: any;
925
998
  };
999
+
1000
+ /**
1001
+ * Write hooks, either applied to every table (a bare function, or an object naming the
1002
+ * positions) or registered per table by Drizzle schema key. See
1003
+ * {@link BuildSchemaConfig.onWrite}.
1004
+ */
1005
+ type OnWriteConfig = WriteHooks | Record<string, WriteHooks>;
926
1006
  /**
927
1007
  * Per-table soft-delete declarations, either keyed by Drizzle schema key or as a rule applied
928
1008
  * to every table. See {@link BuildSchemaConfig.softDelete}.
@@ -1161,6 +1241,38 @@ type BuildSchemaConfig = {
1161
1241
  * agree.
1162
1242
  */
1163
1243
  limits?: LimitsConfig;
1244
+ /**
1245
+ * Per-table defaults for arguments the request leaves out. Today that is `orderBy`: the
1246
+ * presentation order a table has, declared once on the server instead of repeated by every
1247
+ * client.
1248
+ *
1249
+ * ```ts
1250
+ * buildSchema(db, {
1251
+ * defaults: {
1252
+ * Todos: { orderBy: { priority: 'desc', createdAt: 'desc' } },
1253
+ * AuditLog: { orderBy: { createdAt: { direction: 'desc', priority: 10 } } },
1254
+ * },
1255
+ * });
1256
+ * ```
1257
+ *
1258
+ * - Applies to the table's list and single queries, and to every to-many relation field
1259
+ * that *targets* it — a relation is ordered by the default of the table it reads, so a
1260
+ * table presents the same way wherever it is reached from. Eagerly and lazily loaded
1261
+ * relations agree.
1262
+ * - Only a missing `orderBy` is replaced. `orderBy: {}` is a request for no ordering and
1263
+ * stays one, and any `orderBy` the client sends replaces the default outright rather than
1264
+ * merging with it.
1265
+ * - Cursor pagination is defined over the effective ordering, so a default `orderBy` is
1266
+ * what an `after`-only page is ordered by. Changing a table's default changes what its
1267
+ * existing cursors mean.
1268
+ * - Entries name column property names of that table; a direction alone is shorthand for
1269
+ * `{ direction }`. Unknown table or column names throw at build time.
1270
+ * - Aggregates and `groupBy` take their own ordering and are unaffected.
1271
+ *
1272
+ * Off by default: a table with no entry keeps returning rows in whatever order the database
1273
+ * gives them, tiebroken by primary key where an operation needs a total order.
1274
+ */
1275
+ defaults?: DefaultsConfig;
1164
1276
  /**
1165
1277
  * Row-level scoping: a predicate, derived from the GraphQL context, that every read and
1166
1278
  * write of a table is confined to. This is the multi-tenancy / ownership knob — the one
@@ -1265,6 +1377,39 @@ type BuildSchemaConfig = {
1265
1377
  * Marking a parent deleted does not mark its children — a cascade is a schema decision.
1266
1378
  */
1267
1379
  softDelete?: SoftDeleteConfig;
1380
+ /**
1381
+ * A hook that runs **inside the mutation's transaction**, so its writes commit or roll back
1382
+ * with the mutation itself — the position an audit row, an outbox row, or a denormalized
1383
+ * counter needs, and the one a `graphql-middleware` wrapper cannot occupy.
1384
+ *
1385
+ * ```ts
1386
+ * buildSchema(db, {
1387
+ * onWrite: {
1388
+ * posts: async ({ table, operation, rows, tx }) => {
1389
+ * await tx.insert(auditLog).values(rows.map((row) => ({ table, operation, rowId: row.id })));
1390
+ * },
1391
+ * },
1392
+ * });
1393
+ * ```
1394
+ *
1395
+ * A bare function is the **`after`** hook — the position that has rows. `{ before, after }`
1396
+ * names them explicitly; `before` receives the field's args ahead of the statement, for a
1397
+ * check that has to read inside the same snapshot. Registering a bare function (or a
1398
+ * positions object) at the top level applies it to every table; anything else is read as a
1399
+ * table map keyed by Drizzle schema key, and an unknown name fails the build.
1400
+ *
1401
+ * - **`tx` is the executor the mutation ran on** — a caller-supplied executor under
1402
+ * `drizzleExecutorKey`, the request's auto-transaction, or, for a field that would
1403
+ * otherwise have run unwrapped, a transaction opened for it because the hook is there.
1404
+ * - **Throwing rolls the mutation back.** That is the point of the position.
1405
+ * - **`rows` are the post-write rows as the database returned them**, before the output
1406
+ * mapper. Empty at the `before` position, and on MySQL, whose mutations return no rows.
1407
+ * - The hook fires for the **mutation field's own table**. Rows a nested write creates in
1408
+ * another table do not fire that table's hook.
1409
+ *
1410
+ * Off by default, and a build without it opens exactly the transactions it did before.
1411
+ */
1412
+ onWrite?: OnWriteConfig;
1268
1413
  /**
1269
1414
  * Tables and columns to leave out of the generated schema entirely.
1270
1415
  *
@@ -1727,4 +1872,4 @@ declare const resolveSelection: (info: GraphQLResolveInfo | ResolveTree, options
1727
1872
 
1728
1873
  declare const buildSchema: <TDbClient extends AnyDrizzleDB<any>>(db: TDbClient, config?: BuildSchemaConfig) => GeneratedData<TDbClient>;
1729
1874
 
1730
- export { type AggregateResolver, type AnyDrizzleDB, type BuildSchemaConfig, type ColumnDeprecator, type ColumnDescriber, type ColumnDocInfo, type ColumnTypeMapper, type ColumnTypeMapperInfo, type ComplexityConfig, type ContextValuesConfig, type DeleteResolver, type DeleteSingleResolver, type DrizzleExtension, type DrizzleFieldExtension, type DrizzleFieldKind, type DrizzleFieldOperation, type DrizzleTargetArg, type DrizzleTypeExtension, type EnumNameInfo, type EnumNameMapper, type ExtractRelations, type ExtractTableByName, type ExtractTableRelations, type ExtractTables, type FeatureSwitch, type GeneratedData, type GeneratedEntities, type GeneratedInputs, type GeneratedOutputs, GraphQLBigIntString, GraphQLDecimalString, type IdentifiedRows, type InsertArrResolver, type InsertResolver, type LimitsConfig, type MutationReturnlessResult, type MutationsCore, type QueriesCore, type RelationDescriber, type RelationResolverFactory, type ResolveSelectionOptions, type RowScope, type RowScopeFilter, type ScalarOverride, type ScalarOverridesConfig, type SchemaDocs, type SchemaExclusions, type SchemaFeatures, type ScopeConfig, type SelectResolver, type SelectSingleResolver, type SelectionOptions, type SoftDeleteColumn, type SoftDeleteConfig, type TableDescriber, type TableLimitPolicy, type TableNamedRelations, type UpdateManyArgs, type UpdateManyEntry, type UpdateManyResolver, type UpdateResolver, type UpdateSingleResolver, type UpsertArgs, type UpsertArrResolver, type UpsertConflictArgs, type UpsertResolver, buildSchema, createRelationResolverFactory, defaultErrorMapper, drizzleExecutorKey, drizzleExtension, extractFilters, extractOrderBy, extractRelationJoinColumns, identifyRows, isDrizzleFieldExtension, resolveSelection, selectionToWith, singularizeMapper };
1875
+ export { type AggregateResolver, type AnyDrizzleDB, type BuildSchemaConfig, type ColumnDeprecator, type ColumnDescriber, type ColumnDocInfo, type ColumnTypeMapper, type ColumnTypeMapperInfo, type ComplexityConfig, type ContextValuesConfig, type DefaultOrderByEntry, type DefaultsConfig, type DeleteResolver, type DeleteSingleResolver, type DrizzleExtension, type DrizzleFieldExtension, type DrizzleFieldKind, type DrizzleFieldOperation, type DrizzleTargetArg, type DrizzleTypeExtension, type EnumNameInfo, type EnumNameMapper, type ExtractRelations, type ExtractTableByName, type ExtractTableRelations, type ExtractTables, type FeatureSwitch, type GeneratedData, type GeneratedEntities, type GeneratedInputs, type GeneratedOutputs, GraphQLBigIntString, GraphQLDecimalString, type IdentifiedRows, type InsertArrResolver, type InsertResolver, type LimitsConfig, type MutationReturnlessResult, type MutationsCore, type OnWriteConfig, type QueriesCore, type RelationDescriber, type RelationResolverFactory, type ResolveSelectionOptions, type RowScope, type RowScopeFilter, type ScalarOverride, type ScalarOverridesConfig, type SchemaDocs, type SchemaExclusions, type SchemaFeatures, type ScopeConfig, type SelectResolver, type SelectSingleResolver, type SelectionOptions, type SoftDeleteColumn, type SoftDeleteConfig, type TableDefaults, type TableDescriber, type TableLimitPolicy, type TableNamedRelations, type UpdateManyArgs, type UpdateManyEntry, type UpdateManyResolver, type UpdateResolver, type UpdateSingleResolver, type UpsertArgs, type UpsertArrResolver, type UpsertConflictArgs, type UpsertResolver, type WriteHook, type WriteHookPayload, type WriteHookPositions, type WriteHooks, type WriteOperation, buildSchema, createRelationResolverFactory, defaultErrorMapper, drizzleExecutorKey, drizzleExtension, extractFilters, extractOrderBy, extractRelationJoinColumns, identifyRows, isDrizzleFieldExtension, resolveSelection, selectionToWith, singularizeMapper };
package/dist/index.d.ts CHANGED
@@ -237,6 +237,43 @@ type RelationResolverFactory = (params: {
237
237
  * both end up loaded in one process.
238
238
  */
239
239
  declare const drizzleExecutorKey: unique symbol;
240
+ /** The write a hook is attached to. `restore` only exists for a soft-deleting table. */
241
+ type WriteOperation = 'insert' | 'update' | 'updateMany' | 'upsert' | 'delete' | 'restore';
242
+ /** What a write hook is handed. See {@link BuildSchemaConfig.onWrite}. */
243
+ type WriteHookPayload = {
244
+ /** Drizzle schema key of the table being written. */
245
+ table: string;
246
+ operation: WriteOperation;
247
+ /** `'before'` runs ahead of the statement, `'after'` once it has returned. */
248
+ position: 'before' | 'after';
249
+ /** Whether the field writes a single row (`createUsersSingle`) or a list. */
250
+ single: boolean;
251
+ /** The field's GraphQL arguments, exactly as the resolver received them. */
252
+ args: any;
253
+ /**
254
+ * The rows the write produced, as the database returned them — before the output mapper,
255
+ * so values are database-shaped. Empty at the `before` position, and on MySQL, whose
256
+ * mutations return no rows.
257
+ */
258
+ rows: any[];
259
+ context: any;
260
+ info: any;
261
+ /** The executor the mutation itself ran on. Throwing from the hook rolls it back. */
262
+ tx: any;
263
+ };
264
+ type WriteHook = (payload: WriteHookPayload) => void | Promise<void>;
265
+ type WriteHookPositions = {
266
+ before?: WriteHook;
267
+ after?: WriteHook;
268
+ };
269
+ type WriteHooks = WriteHook | WriteHookPositions;
270
+ /** Resolved, per-field hooks: `undefined` when the table registered none. */
271
+ type ResolvedWriteHooks = {
272
+ before?: WriteHook;
273
+ after?: WriteHook;
274
+ };
275
+ /** Build-time lookup of a table's hooks, installed on {@link TablePolicies}. */
276
+ type WriteHookFor = (tableName: string, operation: WriteOperation) => ResolvedWriteHooks | undefined;
240
277
  /**
241
278
  * Creates a RelationResolverFactory that generates field-level resolvers for each relation.
242
279
  * Each resolver:
@@ -263,6 +300,13 @@ type ResolvedLimitPolicy = {
263
300
  * `buildSchema`; `undefined` for a table the caller left unbounded.
264
301
  */
265
302
  type LimitPolicyFor = (tableName: string) => ResolvedLimitPolicy | undefined;
303
+ /**
304
+ * {@link BuildSchemaConfig.defaults} resolved for one table: the `orderBy` a read falls back
305
+ * to when the request passes none, already in the shape the generated argument has.
306
+ * `undefined` means the table declares no default and keeps whatever order the database
307
+ * returns.
308
+ */
309
+ type DefaultOrderByFor = (tableName: string) => Record<string, any> | undefined;
266
310
  /**
267
311
  * Compiles an `orderBy` argument into ORDER BY expressions, highest priority first.
268
312
  *
@@ -360,6 +404,10 @@ type TablePolicies = {
360
404
  contextValues?: ContextValuesFor;
361
405
  /** See `BuildSchemaConfig.softDelete`. */
362
406
  softDelete?: SoftDeleteFor;
407
+ /** See `BuildSchemaConfig.onWrite`. */
408
+ onWrite?: WriteHookFor;
409
+ /** See `BuildSchemaConfig.defaults`. */
410
+ defaultOrderBy?: DefaultOrderByFor;
363
411
  };
364
412
  /**
365
413
  * Where a dialect's default sort places NULLs relative to non-NULL values:
@@ -759,8 +807,14 @@ type SchemaFeatures = {
759
807
  * Each relation field offers `create` and `connect`; the update input adds `disconnect`
760
808
  * and, for a to-many relation, `set` (replace the whole set). `disconnect` and `set` are
761
809
  * generated only when the foreign key is nullable — there is no way to detach a row whose
762
- * key is NOT NULL — and many-to-many (`.through()`) relations are not written through at
763
- * all. Nesting is one level deep: the row a nested `create` inserts takes columns only.
810
+ * key is NOT NULL. Nesting is one level deep: the row a nested `create` inserts takes
811
+ * columns only.
812
+ *
813
+ * A many-to-many (`.through()`) relation is written as junction rows: `connect` on the
814
+ * create input, and `connect` / `disconnect` / `set` on the update input, all
815
+ * unconditional, since unlinking deletes a junction row rather than nulling a column.
816
+ * It offers no `create` — inserting a row and linking it are two writes to two tables —
817
+ * and `set: []` clears the relation.
764
818
  *
765
819
  * The whole tree runs in one transaction (a savepoint when the request already carries
766
820
  * one), and a column a relation fills in (`authorId`, when `author: { create: … }` is
@@ -870,6 +924,25 @@ type TableLimitPolicy = {
870
924
  */
871
925
  clampToMax?: boolean;
872
926
  };
927
+ /**
928
+ * One entry of a {@link TableDefaults} ordering: a direction, or a direction with the
929
+ * priority that decides where it sits among the other entries (higher first, as in the
930
+ * generated `orderBy` argument).
931
+ */
932
+ type DefaultOrderByEntry = 'asc' | 'desc' | {
933
+ direction: 'asc' | 'desc';
934
+ priority?: number;
935
+ };
936
+ /** {@link DefaultsConfig} — what one table falls back to when the request does not say. */
937
+ type TableDefaults = {
938
+ /**
939
+ * The ordering a read of this table runs with when the request passes no `orderBy`, keyed
940
+ * by column property name.
941
+ */
942
+ orderBy?: Record<string, DefaultOrderByEntry>;
943
+ };
944
+ /** {@link BuildSchemaConfig.defaults} — per-table defaults, keyed by the Drizzle schema key. */
945
+ type DefaultsConfig = Record<string, TableDefaults>;
873
946
  /** {@link BuildSchemaConfig.limits} — a global policy plus per-table overrides. */
874
947
  type LimitsConfig = TableLimitPolicy & {
875
948
  /** Per-table overrides, keyed by the table's key in the Drizzle schema. */
@@ -923,6 +996,13 @@ type SoftDeleteColumn = string | {
923
996
  */
924
997
  restoredValue?: any;
925
998
  };
999
+
1000
+ /**
1001
+ * Write hooks, either applied to every table (a bare function, or an object naming the
1002
+ * positions) or registered per table by Drizzle schema key. See
1003
+ * {@link BuildSchemaConfig.onWrite}.
1004
+ */
1005
+ type OnWriteConfig = WriteHooks | Record<string, WriteHooks>;
926
1006
  /**
927
1007
  * Per-table soft-delete declarations, either keyed by Drizzle schema key or as a rule applied
928
1008
  * to every table. See {@link BuildSchemaConfig.softDelete}.
@@ -1161,6 +1241,38 @@ type BuildSchemaConfig = {
1161
1241
  * agree.
1162
1242
  */
1163
1243
  limits?: LimitsConfig;
1244
+ /**
1245
+ * Per-table defaults for arguments the request leaves out. Today that is `orderBy`: the
1246
+ * presentation order a table has, declared once on the server instead of repeated by every
1247
+ * client.
1248
+ *
1249
+ * ```ts
1250
+ * buildSchema(db, {
1251
+ * defaults: {
1252
+ * Todos: { orderBy: { priority: 'desc', createdAt: 'desc' } },
1253
+ * AuditLog: { orderBy: { createdAt: { direction: 'desc', priority: 10 } } },
1254
+ * },
1255
+ * });
1256
+ * ```
1257
+ *
1258
+ * - Applies to the table's list and single queries, and to every to-many relation field
1259
+ * that *targets* it — a relation is ordered by the default of the table it reads, so a
1260
+ * table presents the same way wherever it is reached from. Eagerly and lazily loaded
1261
+ * relations agree.
1262
+ * - Only a missing `orderBy` is replaced. `orderBy: {}` is a request for no ordering and
1263
+ * stays one, and any `orderBy` the client sends replaces the default outright rather than
1264
+ * merging with it.
1265
+ * - Cursor pagination is defined over the effective ordering, so a default `orderBy` is
1266
+ * what an `after`-only page is ordered by. Changing a table's default changes what its
1267
+ * existing cursors mean.
1268
+ * - Entries name column property names of that table; a direction alone is shorthand for
1269
+ * `{ direction }`. Unknown table or column names throw at build time.
1270
+ * - Aggregates and `groupBy` take their own ordering and are unaffected.
1271
+ *
1272
+ * Off by default: a table with no entry keeps returning rows in whatever order the database
1273
+ * gives them, tiebroken by primary key where an operation needs a total order.
1274
+ */
1275
+ defaults?: DefaultsConfig;
1164
1276
  /**
1165
1277
  * Row-level scoping: a predicate, derived from the GraphQL context, that every read and
1166
1278
  * write of a table is confined to. This is the multi-tenancy / ownership knob — the one
@@ -1265,6 +1377,39 @@ type BuildSchemaConfig = {
1265
1377
  * Marking a parent deleted does not mark its children — a cascade is a schema decision.
1266
1378
  */
1267
1379
  softDelete?: SoftDeleteConfig;
1380
+ /**
1381
+ * A hook that runs **inside the mutation's transaction**, so its writes commit or roll back
1382
+ * with the mutation itself — the position an audit row, an outbox row, or a denormalized
1383
+ * counter needs, and the one a `graphql-middleware` wrapper cannot occupy.
1384
+ *
1385
+ * ```ts
1386
+ * buildSchema(db, {
1387
+ * onWrite: {
1388
+ * posts: async ({ table, operation, rows, tx }) => {
1389
+ * await tx.insert(auditLog).values(rows.map((row) => ({ table, operation, rowId: row.id })));
1390
+ * },
1391
+ * },
1392
+ * });
1393
+ * ```
1394
+ *
1395
+ * A bare function is the **`after`** hook — the position that has rows. `{ before, after }`
1396
+ * names them explicitly; `before` receives the field's args ahead of the statement, for a
1397
+ * check that has to read inside the same snapshot. Registering a bare function (or a
1398
+ * positions object) at the top level applies it to every table; anything else is read as a
1399
+ * table map keyed by Drizzle schema key, and an unknown name fails the build.
1400
+ *
1401
+ * - **`tx` is the executor the mutation ran on** — a caller-supplied executor under
1402
+ * `drizzleExecutorKey`, the request's auto-transaction, or, for a field that would
1403
+ * otherwise have run unwrapped, a transaction opened for it because the hook is there.
1404
+ * - **Throwing rolls the mutation back.** That is the point of the position.
1405
+ * - **`rows` are the post-write rows as the database returned them**, before the output
1406
+ * mapper. Empty at the `before` position, and on MySQL, whose mutations return no rows.
1407
+ * - The hook fires for the **mutation field's own table**. Rows a nested write creates in
1408
+ * another table do not fire that table's hook.
1409
+ *
1410
+ * Off by default, and a build without it opens exactly the transactions it did before.
1411
+ */
1412
+ onWrite?: OnWriteConfig;
1268
1413
  /**
1269
1414
  * Tables and columns to leave out of the generated schema entirely.
1270
1415
  *
@@ -1727,4 +1872,4 @@ declare const resolveSelection: (info: GraphQLResolveInfo | ResolveTree, options
1727
1872
 
1728
1873
  declare const buildSchema: <TDbClient extends AnyDrizzleDB<any>>(db: TDbClient, config?: BuildSchemaConfig) => GeneratedData<TDbClient>;
1729
1874
 
1730
- export { type AggregateResolver, type AnyDrizzleDB, type BuildSchemaConfig, type ColumnDeprecator, type ColumnDescriber, type ColumnDocInfo, type ColumnTypeMapper, type ColumnTypeMapperInfo, type ComplexityConfig, type ContextValuesConfig, type DeleteResolver, type DeleteSingleResolver, type DrizzleExtension, type DrizzleFieldExtension, type DrizzleFieldKind, type DrizzleFieldOperation, type DrizzleTargetArg, type DrizzleTypeExtension, type EnumNameInfo, type EnumNameMapper, type ExtractRelations, type ExtractTableByName, type ExtractTableRelations, type ExtractTables, type FeatureSwitch, type GeneratedData, type GeneratedEntities, type GeneratedInputs, type GeneratedOutputs, GraphQLBigIntString, GraphQLDecimalString, type IdentifiedRows, type InsertArrResolver, type InsertResolver, type LimitsConfig, type MutationReturnlessResult, type MutationsCore, type QueriesCore, type RelationDescriber, type RelationResolverFactory, type ResolveSelectionOptions, type RowScope, type RowScopeFilter, type ScalarOverride, type ScalarOverridesConfig, type SchemaDocs, type SchemaExclusions, type SchemaFeatures, type ScopeConfig, type SelectResolver, type SelectSingleResolver, type SelectionOptions, type SoftDeleteColumn, type SoftDeleteConfig, type TableDescriber, type TableLimitPolicy, type TableNamedRelations, type UpdateManyArgs, type UpdateManyEntry, type UpdateManyResolver, type UpdateResolver, type UpdateSingleResolver, type UpsertArgs, type UpsertArrResolver, type UpsertConflictArgs, type UpsertResolver, buildSchema, createRelationResolverFactory, defaultErrorMapper, drizzleExecutorKey, drizzleExtension, extractFilters, extractOrderBy, extractRelationJoinColumns, identifyRows, isDrizzleFieldExtension, resolveSelection, selectionToWith, singularizeMapper };
1875
+ export { type AggregateResolver, type AnyDrizzleDB, type BuildSchemaConfig, type ColumnDeprecator, type ColumnDescriber, type ColumnDocInfo, type ColumnTypeMapper, type ColumnTypeMapperInfo, type ComplexityConfig, type ContextValuesConfig, type DefaultOrderByEntry, type DefaultsConfig, type DeleteResolver, type DeleteSingleResolver, type DrizzleExtension, type DrizzleFieldExtension, type DrizzleFieldKind, type DrizzleFieldOperation, type DrizzleTargetArg, type DrizzleTypeExtension, type EnumNameInfo, type EnumNameMapper, type ExtractRelations, type ExtractTableByName, type ExtractTableRelations, type ExtractTables, type FeatureSwitch, type GeneratedData, type GeneratedEntities, type GeneratedInputs, type GeneratedOutputs, GraphQLBigIntString, GraphQLDecimalString, type IdentifiedRows, type InsertArrResolver, type InsertResolver, type LimitsConfig, type MutationReturnlessResult, type MutationsCore, type OnWriteConfig, type QueriesCore, type RelationDescriber, type RelationResolverFactory, type ResolveSelectionOptions, type RowScope, type RowScopeFilter, type ScalarOverride, type ScalarOverridesConfig, type SchemaDocs, type SchemaExclusions, type SchemaFeatures, type ScopeConfig, type SelectResolver, type SelectSingleResolver, type SelectionOptions, type SoftDeleteColumn, type SoftDeleteConfig, type TableDefaults, type TableDescriber, type TableLimitPolicy, type TableNamedRelations, type UpdateManyArgs, type UpdateManyEntry, type UpdateManyResolver, type UpdateResolver, type UpdateSingleResolver, type UpsertArgs, type UpsertArrResolver, type UpsertConflictArgs, type UpsertResolver, type WriteHook, type WriteHookPayload, type WriteHookPositions, type WriteHooks, type WriteOperation, buildSchema, createRelationResolverFactory, defaultErrorMapper, drizzleExecutorKey, drizzleExtension, extractFilters, extractOrderBy, extractRelationJoinColumns, identifyRows, isDrizzleFieldExtension, resolveSelection, selectionToWith, singularizeMapper };