@vantreeseba/drizzle-graphql 7.5.0 → 7.7.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/README.md +167 -1
- package/dist/README.md +167 -1
- package/dist/index.cjs +877 -210
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +219 -3
- package/dist/index.d.ts +219 -3
- package/dist/index.js +878 -210
- package/dist/index.js.map +1 -1
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -251,7 +251,7 @@ declare const drizzleExecutorKey: unique symbol;
|
|
|
251
251
|
* each dialect builder states it: `'nulls-largest'` for PostgreSQL, `'nulls-smallest'` for
|
|
252
252
|
* MySQL and SQLite.
|
|
253
253
|
*/
|
|
254
|
-
declare const createRelationResolverFactory: (db: any, tables: Record<string, Table>, nullOrdering: NullOrdering, filterCtx?: RelationFilterBase, limits?: LimitPolicyFor) => RelationResolverFactory;
|
|
254
|
+
declare const createRelationResolverFactory: (db: any, tables: Record<string, Table>, nullOrdering: NullOrdering, filterCtx?: RelationFilterBase, limits?: LimitPolicyFor, policies?: TablePolicies) => RelationResolverFactory;
|
|
255
255
|
/** {@link BuildSchemaConfig.limits} resolved for one table. `undefined` means no policy. */
|
|
256
256
|
type ResolvedLimitPolicy = {
|
|
257
257
|
defaultLimit: number | undefined;
|
|
@@ -307,6 +307,60 @@ interface RelationFilterContext {
|
|
|
307
307
|
*/
|
|
308
308
|
type RelationFilterBase = Pick<RelationFilterContext, 'tables' | 'relationMap'>;
|
|
309
309
|
declare const extractFilters: <TTable extends Table>(table: TTable, tableName: string, filters: Filters<TTable>, relationCtx?: RelationFilterContext) => SQL | undefined;
|
|
310
|
+
/**
|
|
311
|
+
* A table's row-level scope: the predicate every generated read, update and delete on that
|
|
312
|
+
* table is narrowed by. See `BuildSchemaConfig.scope`.
|
|
313
|
+
*
|
|
314
|
+
* `table` is the table the predicate must be built against. On the relational-query path
|
|
315
|
+
* drizzle hands its callbacks an *aliased* proxy (`d0`, `d1`, …), so a predicate built from
|
|
316
|
+
* the imported schema table would reference a name that isn't in the query — always build
|
|
317
|
+
* from the argument. Returning a filter object instead (the same shape as the field's
|
|
318
|
+
* `where`) sidesteps aliasing entirely, and is the only form that can reach through a
|
|
319
|
+
* relation — which is what ownership through a join table needs.
|
|
320
|
+
*/
|
|
321
|
+
type ScopeHook<TContext = any> = (context: TContext, table: any) => SQL | Record<string, any> | undefined | null;
|
|
322
|
+
/** Build-time lookup: the scope configured for a table, if any. */
|
|
323
|
+
type ScopeFor = (tableName: string) => ScopeHook | undefined;
|
|
324
|
+
/**
|
|
325
|
+
* One table's soft-delete convention, resolved against the real column at build time.
|
|
326
|
+
*
|
|
327
|
+
* `nullable` picks the shape of the predicate. A nullable column marks a row deleted by
|
|
328
|
+
* holding a value at all (`deletedAt IS NOT NULL`), which is the common timestamp form; a
|
|
329
|
+
* non-nullable one marks it by holding `marker` (`isDeleted = true`), so the column has to
|
|
330
|
+
* have a constant that means "deleted" and another that means "not deleted".
|
|
331
|
+
*/
|
|
332
|
+
type SoftDeleteInfo = {
|
|
333
|
+
/** Property name of the column on the drizzle table — also the key on an aliased proxy. */
|
|
334
|
+
columnName: string;
|
|
335
|
+
column: Column;
|
|
336
|
+
nullable: boolean;
|
|
337
|
+
/** Evaluated per delete, so a timestamp form stamps the moment of the delete. */
|
|
338
|
+
writeDeleted: () => any;
|
|
339
|
+
/** Written by the restore mutation. */
|
|
340
|
+
writeRestored: any;
|
|
341
|
+
/** Non-nullable form only: the constant that means "this row is deleted". */
|
|
342
|
+
marker?: any;
|
|
343
|
+
};
|
|
344
|
+
/** Build-time lookup: the soft-delete convention of a table, if it declares one. */
|
|
345
|
+
type SoftDeleteFor = (tableName: string) => SoftDeleteInfo | undefined;
|
|
346
|
+
/** Produces one column's value from the GraphQL context. See `BuildSchemaConfig.contextValues`. */
|
|
347
|
+
type ContextValueHook<TContext = any> = (context: TContext) => any;
|
|
348
|
+
/** Build-time lookup: the context-derived columns of a table, keyed by column property name. */
|
|
349
|
+
type ContextValuesFor = (tableName: string) => Record<string, ContextValueHook> | undefined;
|
|
350
|
+
/**
|
|
351
|
+
* The two request-time policies a generated resolver applies, passed to the dialect
|
|
352
|
+
* generators as one value so a table's read scope and its server-owned columns travel
|
|
353
|
+
* together. Both stay `undefined` when nothing is configured, and every call site checks
|
|
354
|
+
* before doing any work — an unconfigured build generates exactly the SQL it did before.
|
|
355
|
+
*/
|
|
356
|
+
type TablePolicies = {
|
|
357
|
+
/** See `BuildSchemaConfig.scope`. */
|
|
358
|
+
scope?: ScopeFor;
|
|
359
|
+
/** See `BuildSchemaConfig.contextValues`. */
|
|
360
|
+
contextValues?: ContextValuesFor;
|
|
361
|
+
/** See `BuildSchemaConfig.softDelete`. */
|
|
362
|
+
softDelete?: SoftDeleteFor;
|
|
363
|
+
};
|
|
310
364
|
/**
|
|
311
365
|
* Where a dialect's default sort places NULLs relative to non-NULL values:
|
|
312
366
|
* - `nulls-largest` — PostgreSQL: NULLs sort as the largest values (last in ASC, first in DESC).
|
|
@@ -821,6 +875,59 @@ type LimitsConfig = TableLimitPolicy & {
|
|
|
821
875
|
/** Per-table overrides, keyed by the table's key in the Drizzle schema. */
|
|
822
876
|
tables?: Record<string, TableLimitPolicy>;
|
|
823
877
|
};
|
|
878
|
+
/**
|
|
879
|
+
* What a {@link RowScope} may return: a Drizzle `SQL` expression, a filter object in the same
|
|
880
|
+
* shape as the generated `where` argument, or `undefined`/`null` for "no restriction".
|
|
881
|
+
*
|
|
882
|
+
* The filter-object form is compiled with the same code that compiles a client `where`, so it
|
|
883
|
+
* supports relation filters — `{ author: { orgId: { eq: 1 } } }` scopes a table through a join
|
|
884
|
+
* rather than a column it owns.
|
|
885
|
+
*/
|
|
886
|
+
type RowScopeFilter = Record<string, any> | undefined | null;
|
|
887
|
+
/**
|
|
888
|
+
* A per-table row scope: given the GraphQL context, the predicate every read and write of that
|
|
889
|
+
* table is confined to.
|
|
890
|
+
*
|
|
891
|
+
* `table` is the table instance the current statement runs against. For a relational read that
|
|
892
|
+
* is Drizzle's *aliased* copy of the table, so build the predicate from this argument rather
|
|
893
|
+
* than from the imported table object — `eq(table.orgId, ctx.orgId)` is always correct, while
|
|
894
|
+
* `eq(users.orgId, ctx.orgId)` refers to the wrong alias inside a nested read.
|
|
895
|
+
*
|
|
896
|
+
* See {@link BuildSchemaConfig.scope}.
|
|
897
|
+
*/
|
|
898
|
+
type RowScope<TContext = any> = (context: TContext, table: any) => RowScopeFilter | object;
|
|
899
|
+
/** {@link BuildSchemaConfig.scope} — a row scope per table, keyed by the Drizzle schema key. */
|
|
900
|
+
type ScopeConfig<TContext = any> = Record<string, RowScope<TContext>>;
|
|
901
|
+
/**
|
|
902
|
+
* {@link BuildSchemaConfig.contextValues} — columns whose value the server derives from the
|
|
903
|
+
* request context, keyed by Drizzle schema key and then by column property name.
|
|
904
|
+
*/
|
|
905
|
+
type ContextValuesConfig<TContext = any> = Record<string, Record<string, (context: TContext) => any>>;
|
|
906
|
+
/**
|
|
907
|
+
* How one table marks a row deleted: the column's property name, or that name plus the values
|
|
908
|
+
* written on delete and on restore. See {@link BuildSchemaConfig.softDelete}.
|
|
909
|
+
*/
|
|
910
|
+
type SoftDeleteColumn = string | {
|
|
911
|
+
/** Property name of the column that marks a row deleted. */
|
|
912
|
+
column: string;
|
|
913
|
+
/**
|
|
914
|
+
* Written when a row is deleted. A function is evaluated per delete. Defaults by column
|
|
915
|
+
* type: `new Date()` for a timestamp, an ISO string for text, `Date.now()` for a number,
|
|
916
|
+
* `true` for a boolean. Required, as a constant, when the column is NOT NULL and not a
|
|
917
|
+
* boolean — the predicate that hides marked rows has to compare against it.
|
|
918
|
+
*/
|
|
919
|
+
deletedValue?: any;
|
|
920
|
+
/**
|
|
921
|
+
* Written when a row is restored. Defaults to `null` for a nullable column and `false`
|
|
922
|
+
* for a NOT NULL boolean; required for any other NOT NULL column.
|
|
923
|
+
*/
|
|
924
|
+
restoredValue?: any;
|
|
925
|
+
};
|
|
926
|
+
/**
|
|
927
|
+
* Per-table soft-delete declarations, either keyed by Drizzle schema key or as a rule applied
|
|
928
|
+
* to every table. See {@link BuildSchemaConfig.softDelete}.
|
|
929
|
+
*/
|
|
930
|
+
type SoftDeleteConfig = Record<string, SoftDeleteColumn> | ((table: any, tableName: string) => SoftDeleteColumn | undefined | null);
|
|
824
931
|
/**
|
|
825
932
|
* {@link BuildSchemaConfig.exclude} — tables and columns to keep out of the generated schema.
|
|
826
933
|
*
|
|
@@ -879,6 +986,11 @@ type BuildSchemaConfig = {
|
|
|
879
986
|
update?: string;
|
|
880
987
|
/** Prefix for upsert mutations (e.g., 'users' -> 'upsertUsers') */
|
|
881
988
|
upsert?: string;
|
|
989
|
+
/**
|
|
990
|
+
* Prefix for the restore mutations of a soft-deleting table (e.g., 'users' ->
|
|
991
|
+
* 'restoreUsers'). Only used when {@link BuildSchemaConfig.softDelete} names the table.
|
|
992
|
+
*/
|
|
993
|
+
restore?: string;
|
|
882
994
|
};
|
|
883
995
|
/**
|
|
884
996
|
* Customizes query name suffixes for generated GraphQL operations.
|
|
@@ -1049,6 +1161,110 @@ type BuildSchemaConfig = {
|
|
|
1049
1161
|
* agree.
|
|
1050
1162
|
*/
|
|
1051
1163
|
limits?: LimitsConfig;
|
|
1164
|
+
/**
|
|
1165
|
+
* Row-level scoping: a predicate, derived from the GraphQL context, that every read and
|
|
1166
|
+
* write of a table is confined to. This is the multi-tenancy / ownership knob — the one
|
|
1167
|
+
* rule a wrapper cannot enforce from outside, because a nested relation field never passes
|
|
1168
|
+
* through a root resolver.
|
|
1169
|
+
*
|
|
1170
|
+
* ```ts
|
|
1171
|
+
* import { and, eq } from 'drizzle-orm';
|
|
1172
|
+
*
|
|
1173
|
+
* buildSchema(db, {
|
|
1174
|
+
* scope: {
|
|
1175
|
+
* posts: (ctx, table) => eq(table.orgId, ctx.orgId),
|
|
1176
|
+
* // A filter object works too, and can scope through a relation:
|
|
1177
|
+
* comments: (ctx) => ({ post: { orgId: { eq: ctx.orgId } } }),
|
|
1178
|
+
* },
|
|
1179
|
+
* });
|
|
1180
|
+
* ```
|
|
1181
|
+
*
|
|
1182
|
+
* - The predicate is ANDed on **last**, after the client's `where`, so a client filter can
|
|
1183
|
+
* only ever narrow the scope, never widen it.
|
|
1184
|
+
* - It applies to every path that reads the table: list and single queries, aggregates and
|
|
1185
|
+
* `groupBy`, relation fields (batched and eager), relation aggregates, and cursor pages.
|
|
1186
|
+
* - It applies to every path that writes it: `update`, `updateMany`, `delete`, the
|
|
1187
|
+
* conflict-update half of an upsert (PostgreSQL and SQLite), and the rows a nested
|
|
1188
|
+
* `connect` / `disconnect` / `set` is allowed to reach. An out-of-scope row is simply not
|
|
1189
|
+
* matched — a scoped `delete` reports zero rows rather than refusing.
|
|
1190
|
+
* - It cannot apply to a plain `insert`: there is no existing row to filter. Use
|
|
1191
|
+
* {@link BuildSchemaConfig.contextValues} to stamp the owning column on the way in.
|
|
1192
|
+
* - `table` is the table the current statement runs against, which for a relational read is
|
|
1193
|
+
* Drizzle's aliased copy — always build the predicate from that argument.
|
|
1194
|
+
* - Returning `undefined` means "no restriction for this context", so a hook can let an
|
|
1195
|
+
* admin through. A table with no entry is unscoped.
|
|
1196
|
+
* - MySQL's `ON DUPLICATE KEY UPDATE` takes no predicate, so a MySQL upsert cannot be
|
|
1197
|
+
* scoped on the conflict path; scope the table's `update` and rely on `contextValues`
|
|
1198
|
+
* for the insert half.
|
|
1199
|
+
*/
|
|
1200
|
+
scope?: ScopeConfig;
|
|
1201
|
+
/**
|
|
1202
|
+
* Columns whose value the server derives from the request context rather than accepting
|
|
1203
|
+
* from the client — the write-side half of {@link BuildSchemaConfig.scope}.
|
|
1204
|
+
*
|
|
1205
|
+
* ```ts
|
|
1206
|
+
* buildSchema(db, {
|
|
1207
|
+
* contextValues: {
|
|
1208
|
+
* posts: {
|
|
1209
|
+
* orgId: (ctx) => ctx.orgId,
|
|
1210
|
+
* authorId: (ctx) => ctx.userId,
|
|
1211
|
+
* },
|
|
1212
|
+
* },
|
|
1213
|
+
* });
|
|
1214
|
+
* ```
|
|
1215
|
+
*
|
|
1216
|
+
* - The column is removed from the generated insert and update inputs, so a client cannot
|
|
1217
|
+
* send it at all — the schema itself documents that it is server-owned.
|
|
1218
|
+
* - Every insert stamps it, including the rows created by a nested `create`.
|
|
1219
|
+
* - Updates never write it: an update cannot hand a row to another owner.
|
|
1220
|
+
* - Keyed by the Drizzle schema key, then by the column's property name (not its database
|
|
1221
|
+
* name), the same keying {@link BuildSchemaConfig.exclude} uses.
|
|
1222
|
+
*/
|
|
1223
|
+
contextValues?: ContextValuesConfig;
|
|
1224
|
+
/**
|
|
1225
|
+
* Tables that mark rows deleted instead of removing them.
|
|
1226
|
+
*
|
|
1227
|
+
* ```ts
|
|
1228
|
+
* buildSchema(db, {
|
|
1229
|
+
* softDelete: {
|
|
1230
|
+
* users: 'deletedAt', // nullable timestamp: stamped on delete
|
|
1231
|
+
* posts: { column: 'isDeleted', deletedValue: true, restoredValue: false },
|
|
1232
|
+
* },
|
|
1233
|
+
* });
|
|
1234
|
+
*
|
|
1235
|
+
* // or as a convention across the whole schema:
|
|
1236
|
+
* buildSchema(db, { softDelete: (table) => ('deletedAt' in table ? 'deletedAt' : undefined) });
|
|
1237
|
+
* ```
|
|
1238
|
+
*
|
|
1239
|
+
* For a table that declares one:
|
|
1240
|
+
*
|
|
1241
|
+
* - `delete<Table>` and `delete<Table>Single` issue an `UPDATE` of the marker column
|
|
1242
|
+
* instead of a `DELETE`, and return the rows as they now stand.
|
|
1243
|
+
* - `restore<Table>` and `restore<Table>Single` are generated alongside them, matching only
|
|
1244
|
+
* marked rows and writing the restored value. The prefix is configurable through
|
|
1245
|
+
* {@link BuildSchemaConfig.prefixes}.
|
|
1246
|
+
* - Every generated read hides marked rows: list and single queries, aggregates, `groupBy`,
|
|
1247
|
+
* relation fields on both the eager and the batched path, and relation aggregates. Each
|
|
1248
|
+
* of those fields takes a `deleted: EXCLUDE | INCLUDE | ONLY` argument (default
|
|
1249
|
+
* `EXCLUDE`); `ONLY` is a trash view.
|
|
1250
|
+
* - Every generated write skips them too: an `update`, a `delete`, or a nested `connect`
|
|
1251
|
+
* cannot reach a row that is already marked.
|
|
1252
|
+
* - The marker column is removed from the create and update inputs, so the only ways to set
|
|
1253
|
+
* or clear it are the delete and restore mutations.
|
|
1254
|
+
* - The predicate is ANDed on before {@link BuildSchemaConfig.scope}, and both are ANDed
|
|
1255
|
+
* after the client's `where` — a request can only ever narrow them.
|
|
1256
|
+
*
|
|
1257
|
+
* Two consequences of the pattern itself, which this does not paper over:
|
|
1258
|
+
*
|
|
1259
|
+
* - A marked row still occupies its unique keys, so inserting a row that reuses the natural
|
|
1260
|
+
* key of a deleted one still fails on the constraint.
|
|
1261
|
+
* - An upsert whose conflict target hits a marked row updates nothing on PostgreSQL and
|
|
1262
|
+
* SQLite (the conflict predicate excludes it) but revives it on MySQL, whose
|
|
1263
|
+
* `ON DUPLICATE KEY UPDATE` takes no predicate.
|
|
1264
|
+
*
|
|
1265
|
+
* Marking a parent deleted does not mark its children — a cascade is a schema decision.
|
|
1266
|
+
*/
|
|
1267
|
+
softDelete?: SoftDeleteConfig;
|
|
1052
1268
|
/**
|
|
1053
1269
|
* Tables and columns to leave out of the generated schema entirely.
|
|
1054
1270
|
*
|
|
@@ -1337,7 +1553,7 @@ type DrizzleFieldKind = 'query' | 'mutation' | 'relation' | 'aggregate' | 'type'
|
|
|
1337
1553
|
* What the field does. Arity is carried separately by `single`, so `select` covers both
|
|
1338
1554
|
* the list query and its `…Single` sibling rather than being spelled twice.
|
|
1339
1555
|
*/
|
|
1340
|
-
type DrizzleFieldOperation = 'select' | 'insert' | 'update' | 'updateMany' | 'upsert' | 'delete' | 'aggregate' | 'groupBy' | 'relation' | 'relationAggregate';
|
|
1556
|
+
type DrizzleFieldOperation = 'select' | 'insert' | 'update' | 'updateMany' | 'upsert' | 'delete' | 'restore' | 'aggregate' | 'groupBy' | 'relation' | 'relationAggregate';
|
|
1341
1557
|
/** The argument holding the rows a field is about, when it has one. */
|
|
1342
1558
|
type DrizzleTargetArg = 'where' | 'values' | 'updates';
|
|
1343
1559
|
/** `extensions.drizzle` on a generated field. */
|
|
@@ -1511,4 +1727,4 @@ declare const resolveSelection: (info: GraphQLResolveInfo | ResolveTree, options
|
|
|
1511
1727
|
|
|
1512
1728
|
declare const buildSchema: <TDbClient extends AnyDrizzleDB<any>>(db: TDbClient, config?: BuildSchemaConfig) => GeneratedData<TDbClient>;
|
|
1513
1729
|
|
|
1514
|
-
export { type AggregateResolver, type AnyDrizzleDB, type BuildSchemaConfig, type ColumnDeprecator, type ColumnDescriber, type ColumnDocInfo, type ColumnTypeMapper, type ColumnTypeMapperInfo, type ComplexityConfig, 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 ScalarOverride, type ScalarOverridesConfig, type SchemaDocs, type SchemaExclusions, type SchemaFeatures, type SelectResolver, type SelectSingleResolver, type SelectionOptions, 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 };
|
|
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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -251,7 +251,7 @@ declare const drizzleExecutorKey: unique symbol;
|
|
|
251
251
|
* each dialect builder states it: `'nulls-largest'` for PostgreSQL, `'nulls-smallest'` for
|
|
252
252
|
* MySQL and SQLite.
|
|
253
253
|
*/
|
|
254
|
-
declare const createRelationResolverFactory: (db: any, tables: Record<string, Table>, nullOrdering: NullOrdering, filterCtx?: RelationFilterBase, limits?: LimitPolicyFor) => RelationResolverFactory;
|
|
254
|
+
declare const createRelationResolverFactory: (db: any, tables: Record<string, Table>, nullOrdering: NullOrdering, filterCtx?: RelationFilterBase, limits?: LimitPolicyFor, policies?: TablePolicies) => RelationResolverFactory;
|
|
255
255
|
/** {@link BuildSchemaConfig.limits} resolved for one table. `undefined` means no policy. */
|
|
256
256
|
type ResolvedLimitPolicy = {
|
|
257
257
|
defaultLimit: number | undefined;
|
|
@@ -307,6 +307,60 @@ interface RelationFilterContext {
|
|
|
307
307
|
*/
|
|
308
308
|
type RelationFilterBase = Pick<RelationFilterContext, 'tables' | 'relationMap'>;
|
|
309
309
|
declare const extractFilters: <TTable extends Table>(table: TTable, tableName: string, filters: Filters<TTable>, relationCtx?: RelationFilterContext) => SQL | undefined;
|
|
310
|
+
/**
|
|
311
|
+
* A table's row-level scope: the predicate every generated read, update and delete on that
|
|
312
|
+
* table is narrowed by. See `BuildSchemaConfig.scope`.
|
|
313
|
+
*
|
|
314
|
+
* `table` is the table the predicate must be built against. On the relational-query path
|
|
315
|
+
* drizzle hands its callbacks an *aliased* proxy (`d0`, `d1`, …), so a predicate built from
|
|
316
|
+
* the imported schema table would reference a name that isn't in the query — always build
|
|
317
|
+
* from the argument. Returning a filter object instead (the same shape as the field's
|
|
318
|
+
* `where`) sidesteps aliasing entirely, and is the only form that can reach through a
|
|
319
|
+
* relation — which is what ownership through a join table needs.
|
|
320
|
+
*/
|
|
321
|
+
type ScopeHook<TContext = any> = (context: TContext, table: any) => SQL | Record<string, any> | undefined | null;
|
|
322
|
+
/** Build-time lookup: the scope configured for a table, if any. */
|
|
323
|
+
type ScopeFor = (tableName: string) => ScopeHook | undefined;
|
|
324
|
+
/**
|
|
325
|
+
* One table's soft-delete convention, resolved against the real column at build time.
|
|
326
|
+
*
|
|
327
|
+
* `nullable` picks the shape of the predicate. A nullable column marks a row deleted by
|
|
328
|
+
* holding a value at all (`deletedAt IS NOT NULL`), which is the common timestamp form; a
|
|
329
|
+
* non-nullable one marks it by holding `marker` (`isDeleted = true`), so the column has to
|
|
330
|
+
* have a constant that means "deleted" and another that means "not deleted".
|
|
331
|
+
*/
|
|
332
|
+
type SoftDeleteInfo = {
|
|
333
|
+
/** Property name of the column on the drizzle table — also the key on an aliased proxy. */
|
|
334
|
+
columnName: string;
|
|
335
|
+
column: Column;
|
|
336
|
+
nullable: boolean;
|
|
337
|
+
/** Evaluated per delete, so a timestamp form stamps the moment of the delete. */
|
|
338
|
+
writeDeleted: () => any;
|
|
339
|
+
/** Written by the restore mutation. */
|
|
340
|
+
writeRestored: any;
|
|
341
|
+
/** Non-nullable form only: the constant that means "this row is deleted". */
|
|
342
|
+
marker?: any;
|
|
343
|
+
};
|
|
344
|
+
/** Build-time lookup: the soft-delete convention of a table, if it declares one. */
|
|
345
|
+
type SoftDeleteFor = (tableName: string) => SoftDeleteInfo | undefined;
|
|
346
|
+
/** Produces one column's value from the GraphQL context. See `BuildSchemaConfig.contextValues`. */
|
|
347
|
+
type ContextValueHook<TContext = any> = (context: TContext) => any;
|
|
348
|
+
/** Build-time lookup: the context-derived columns of a table, keyed by column property name. */
|
|
349
|
+
type ContextValuesFor = (tableName: string) => Record<string, ContextValueHook> | undefined;
|
|
350
|
+
/**
|
|
351
|
+
* The two request-time policies a generated resolver applies, passed to the dialect
|
|
352
|
+
* generators as one value so a table's read scope and its server-owned columns travel
|
|
353
|
+
* together. Both stay `undefined` when nothing is configured, and every call site checks
|
|
354
|
+
* before doing any work — an unconfigured build generates exactly the SQL it did before.
|
|
355
|
+
*/
|
|
356
|
+
type TablePolicies = {
|
|
357
|
+
/** See `BuildSchemaConfig.scope`. */
|
|
358
|
+
scope?: ScopeFor;
|
|
359
|
+
/** See `BuildSchemaConfig.contextValues`. */
|
|
360
|
+
contextValues?: ContextValuesFor;
|
|
361
|
+
/** See `BuildSchemaConfig.softDelete`. */
|
|
362
|
+
softDelete?: SoftDeleteFor;
|
|
363
|
+
};
|
|
310
364
|
/**
|
|
311
365
|
* Where a dialect's default sort places NULLs relative to non-NULL values:
|
|
312
366
|
* - `nulls-largest` — PostgreSQL: NULLs sort as the largest values (last in ASC, first in DESC).
|
|
@@ -821,6 +875,59 @@ type LimitsConfig = TableLimitPolicy & {
|
|
|
821
875
|
/** Per-table overrides, keyed by the table's key in the Drizzle schema. */
|
|
822
876
|
tables?: Record<string, TableLimitPolicy>;
|
|
823
877
|
};
|
|
878
|
+
/**
|
|
879
|
+
* What a {@link RowScope} may return: a Drizzle `SQL` expression, a filter object in the same
|
|
880
|
+
* shape as the generated `where` argument, or `undefined`/`null` for "no restriction".
|
|
881
|
+
*
|
|
882
|
+
* The filter-object form is compiled with the same code that compiles a client `where`, so it
|
|
883
|
+
* supports relation filters — `{ author: { orgId: { eq: 1 } } }` scopes a table through a join
|
|
884
|
+
* rather than a column it owns.
|
|
885
|
+
*/
|
|
886
|
+
type RowScopeFilter = Record<string, any> | undefined | null;
|
|
887
|
+
/**
|
|
888
|
+
* A per-table row scope: given the GraphQL context, the predicate every read and write of that
|
|
889
|
+
* table is confined to.
|
|
890
|
+
*
|
|
891
|
+
* `table` is the table instance the current statement runs against. For a relational read that
|
|
892
|
+
* is Drizzle's *aliased* copy of the table, so build the predicate from this argument rather
|
|
893
|
+
* than from the imported table object — `eq(table.orgId, ctx.orgId)` is always correct, while
|
|
894
|
+
* `eq(users.orgId, ctx.orgId)` refers to the wrong alias inside a nested read.
|
|
895
|
+
*
|
|
896
|
+
* See {@link BuildSchemaConfig.scope}.
|
|
897
|
+
*/
|
|
898
|
+
type RowScope<TContext = any> = (context: TContext, table: any) => RowScopeFilter | object;
|
|
899
|
+
/** {@link BuildSchemaConfig.scope} — a row scope per table, keyed by the Drizzle schema key. */
|
|
900
|
+
type ScopeConfig<TContext = any> = Record<string, RowScope<TContext>>;
|
|
901
|
+
/**
|
|
902
|
+
* {@link BuildSchemaConfig.contextValues} — columns whose value the server derives from the
|
|
903
|
+
* request context, keyed by Drizzle schema key and then by column property name.
|
|
904
|
+
*/
|
|
905
|
+
type ContextValuesConfig<TContext = any> = Record<string, Record<string, (context: TContext) => any>>;
|
|
906
|
+
/**
|
|
907
|
+
* How one table marks a row deleted: the column's property name, or that name plus the values
|
|
908
|
+
* written on delete and on restore. See {@link BuildSchemaConfig.softDelete}.
|
|
909
|
+
*/
|
|
910
|
+
type SoftDeleteColumn = string | {
|
|
911
|
+
/** Property name of the column that marks a row deleted. */
|
|
912
|
+
column: string;
|
|
913
|
+
/**
|
|
914
|
+
* Written when a row is deleted. A function is evaluated per delete. Defaults by column
|
|
915
|
+
* type: `new Date()` for a timestamp, an ISO string for text, `Date.now()` for a number,
|
|
916
|
+
* `true` for a boolean. Required, as a constant, when the column is NOT NULL and not a
|
|
917
|
+
* boolean — the predicate that hides marked rows has to compare against it.
|
|
918
|
+
*/
|
|
919
|
+
deletedValue?: any;
|
|
920
|
+
/**
|
|
921
|
+
* Written when a row is restored. Defaults to `null` for a nullable column and `false`
|
|
922
|
+
* for a NOT NULL boolean; required for any other NOT NULL column.
|
|
923
|
+
*/
|
|
924
|
+
restoredValue?: any;
|
|
925
|
+
};
|
|
926
|
+
/**
|
|
927
|
+
* Per-table soft-delete declarations, either keyed by Drizzle schema key or as a rule applied
|
|
928
|
+
* to every table. See {@link BuildSchemaConfig.softDelete}.
|
|
929
|
+
*/
|
|
930
|
+
type SoftDeleteConfig = Record<string, SoftDeleteColumn> | ((table: any, tableName: string) => SoftDeleteColumn | undefined | null);
|
|
824
931
|
/**
|
|
825
932
|
* {@link BuildSchemaConfig.exclude} — tables and columns to keep out of the generated schema.
|
|
826
933
|
*
|
|
@@ -879,6 +986,11 @@ type BuildSchemaConfig = {
|
|
|
879
986
|
update?: string;
|
|
880
987
|
/** Prefix for upsert mutations (e.g., 'users' -> 'upsertUsers') */
|
|
881
988
|
upsert?: string;
|
|
989
|
+
/**
|
|
990
|
+
* Prefix for the restore mutations of a soft-deleting table (e.g., 'users' ->
|
|
991
|
+
* 'restoreUsers'). Only used when {@link BuildSchemaConfig.softDelete} names the table.
|
|
992
|
+
*/
|
|
993
|
+
restore?: string;
|
|
882
994
|
};
|
|
883
995
|
/**
|
|
884
996
|
* Customizes query name suffixes for generated GraphQL operations.
|
|
@@ -1049,6 +1161,110 @@ type BuildSchemaConfig = {
|
|
|
1049
1161
|
* agree.
|
|
1050
1162
|
*/
|
|
1051
1163
|
limits?: LimitsConfig;
|
|
1164
|
+
/**
|
|
1165
|
+
* Row-level scoping: a predicate, derived from the GraphQL context, that every read and
|
|
1166
|
+
* write of a table is confined to. This is the multi-tenancy / ownership knob — the one
|
|
1167
|
+
* rule a wrapper cannot enforce from outside, because a nested relation field never passes
|
|
1168
|
+
* through a root resolver.
|
|
1169
|
+
*
|
|
1170
|
+
* ```ts
|
|
1171
|
+
* import { and, eq } from 'drizzle-orm';
|
|
1172
|
+
*
|
|
1173
|
+
* buildSchema(db, {
|
|
1174
|
+
* scope: {
|
|
1175
|
+
* posts: (ctx, table) => eq(table.orgId, ctx.orgId),
|
|
1176
|
+
* // A filter object works too, and can scope through a relation:
|
|
1177
|
+
* comments: (ctx) => ({ post: { orgId: { eq: ctx.orgId } } }),
|
|
1178
|
+
* },
|
|
1179
|
+
* });
|
|
1180
|
+
* ```
|
|
1181
|
+
*
|
|
1182
|
+
* - The predicate is ANDed on **last**, after the client's `where`, so a client filter can
|
|
1183
|
+
* only ever narrow the scope, never widen it.
|
|
1184
|
+
* - It applies to every path that reads the table: list and single queries, aggregates and
|
|
1185
|
+
* `groupBy`, relation fields (batched and eager), relation aggregates, and cursor pages.
|
|
1186
|
+
* - It applies to every path that writes it: `update`, `updateMany`, `delete`, the
|
|
1187
|
+
* conflict-update half of an upsert (PostgreSQL and SQLite), and the rows a nested
|
|
1188
|
+
* `connect` / `disconnect` / `set` is allowed to reach. An out-of-scope row is simply not
|
|
1189
|
+
* matched — a scoped `delete` reports zero rows rather than refusing.
|
|
1190
|
+
* - It cannot apply to a plain `insert`: there is no existing row to filter. Use
|
|
1191
|
+
* {@link BuildSchemaConfig.contextValues} to stamp the owning column on the way in.
|
|
1192
|
+
* - `table` is the table the current statement runs against, which for a relational read is
|
|
1193
|
+
* Drizzle's aliased copy — always build the predicate from that argument.
|
|
1194
|
+
* - Returning `undefined` means "no restriction for this context", so a hook can let an
|
|
1195
|
+
* admin through. A table with no entry is unscoped.
|
|
1196
|
+
* - MySQL's `ON DUPLICATE KEY UPDATE` takes no predicate, so a MySQL upsert cannot be
|
|
1197
|
+
* scoped on the conflict path; scope the table's `update` and rely on `contextValues`
|
|
1198
|
+
* for the insert half.
|
|
1199
|
+
*/
|
|
1200
|
+
scope?: ScopeConfig;
|
|
1201
|
+
/**
|
|
1202
|
+
* Columns whose value the server derives from the request context rather than accepting
|
|
1203
|
+
* from the client — the write-side half of {@link BuildSchemaConfig.scope}.
|
|
1204
|
+
*
|
|
1205
|
+
* ```ts
|
|
1206
|
+
* buildSchema(db, {
|
|
1207
|
+
* contextValues: {
|
|
1208
|
+
* posts: {
|
|
1209
|
+
* orgId: (ctx) => ctx.orgId,
|
|
1210
|
+
* authorId: (ctx) => ctx.userId,
|
|
1211
|
+
* },
|
|
1212
|
+
* },
|
|
1213
|
+
* });
|
|
1214
|
+
* ```
|
|
1215
|
+
*
|
|
1216
|
+
* - The column is removed from the generated insert and update inputs, so a client cannot
|
|
1217
|
+
* send it at all — the schema itself documents that it is server-owned.
|
|
1218
|
+
* - Every insert stamps it, including the rows created by a nested `create`.
|
|
1219
|
+
* - Updates never write it: an update cannot hand a row to another owner.
|
|
1220
|
+
* - Keyed by the Drizzle schema key, then by the column's property name (not its database
|
|
1221
|
+
* name), the same keying {@link BuildSchemaConfig.exclude} uses.
|
|
1222
|
+
*/
|
|
1223
|
+
contextValues?: ContextValuesConfig;
|
|
1224
|
+
/**
|
|
1225
|
+
* Tables that mark rows deleted instead of removing them.
|
|
1226
|
+
*
|
|
1227
|
+
* ```ts
|
|
1228
|
+
* buildSchema(db, {
|
|
1229
|
+
* softDelete: {
|
|
1230
|
+
* users: 'deletedAt', // nullable timestamp: stamped on delete
|
|
1231
|
+
* posts: { column: 'isDeleted', deletedValue: true, restoredValue: false },
|
|
1232
|
+
* },
|
|
1233
|
+
* });
|
|
1234
|
+
*
|
|
1235
|
+
* // or as a convention across the whole schema:
|
|
1236
|
+
* buildSchema(db, { softDelete: (table) => ('deletedAt' in table ? 'deletedAt' : undefined) });
|
|
1237
|
+
* ```
|
|
1238
|
+
*
|
|
1239
|
+
* For a table that declares one:
|
|
1240
|
+
*
|
|
1241
|
+
* - `delete<Table>` and `delete<Table>Single` issue an `UPDATE` of the marker column
|
|
1242
|
+
* instead of a `DELETE`, and return the rows as they now stand.
|
|
1243
|
+
* - `restore<Table>` and `restore<Table>Single` are generated alongside them, matching only
|
|
1244
|
+
* marked rows and writing the restored value. The prefix is configurable through
|
|
1245
|
+
* {@link BuildSchemaConfig.prefixes}.
|
|
1246
|
+
* - Every generated read hides marked rows: list and single queries, aggregates, `groupBy`,
|
|
1247
|
+
* relation fields on both the eager and the batched path, and relation aggregates. Each
|
|
1248
|
+
* of those fields takes a `deleted: EXCLUDE | INCLUDE | ONLY` argument (default
|
|
1249
|
+
* `EXCLUDE`); `ONLY` is a trash view.
|
|
1250
|
+
* - Every generated write skips them too: an `update`, a `delete`, or a nested `connect`
|
|
1251
|
+
* cannot reach a row that is already marked.
|
|
1252
|
+
* - The marker column is removed from the create and update inputs, so the only ways to set
|
|
1253
|
+
* or clear it are the delete and restore mutations.
|
|
1254
|
+
* - The predicate is ANDed on before {@link BuildSchemaConfig.scope}, and both are ANDed
|
|
1255
|
+
* after the client's `where` — a request can only ever narrow them.
|
|
1256
|
+
*
|
|
1257
|
+
* Two consequences of the pattern itself, which this does not paper over:
|
|
1258
|
+
*
|
|
1259
|
+
* - A marked row still occupies its unique keys, so inserting a row that reuses the natural
|
|
1260
|
+
* key of a deleted one still fails on the constraint.
|
|
1261
|
+
* - An upsert whose conflict target hits a marked row updates nothing on PostgreSQL and
|
|
1262
|
+
* SQLite (the conflict predicate excludes it) but revives it on MySQL, whose
|
|
1263
|
+
* `ON DUPLICATE KEY UPDATE` takes no predicate.
|
|
1264
|
+
*
|
|
1265
|
+
* Marking a parent deleted does not mark its children — a cascade is a schema decision.
|
|
1266
|
+
*/
|
|
1267
|
+
softDelete?: SoftDeleteConfig;
|
|
1052
1268
|
/**
|
|
1053
1269
|
* Tables and columns to leave out of the generated schema entirely.
|
|
1054
1270
|
*
|
|
@@ -1337,7 +1553,7 @@ type DrizzleFieldKind = 'query' | 'mutation' | 'relation' | 'aggregate' | 'type'
|
|
|
1337
1553
|
* What the field does. Arity is carried separately by `single`, so `select` covers both
|
|
1338
1554
|
* the list query and its `…Single` sibling rather than being spelled twice.
|
|
1339
1555
|
*/
|
|
1340
|
-
type DrizzleFieldOperation = 'select' | 'insert' | 'update' | 'updateMany' | 'upsert' | 'delete' | 'aggregate' | 'groupBy' | 'relation' | 'relationAggregate';
|
|
1556
|
+
type DrizzleFieldOperation = 'select' | 'insert' | 'update' | 'updateMany' | 'upsert' | 'delete' | 'restore' | 'aggregate' | 'groupBy' | 'relation' | 'relationAggregate';
|
|
1341
1557
|
/** The argument holding the rows a field is about, when it has one. */
|
|
1342
1558
|
type DrizzleTargetArg = 'where' | 'values' | 'updates';
|
|
1343
1559
|
/** `extensions.drizzle` on a generated field. */
|
|
@@ -1511,4 +1727,4 @@ declare const resolveSelection: (info: GraphQLResolveInfo | ResolveTree, options
|
|
|
1511
1727
|
|
|
1512
1728
|
declare const buildSchema: <TDbClient extends AnyDrizzleDB<any>>(db: TDbClient, config?: BuildSchemaConfig) => GeneratedData<TDbClient>;
|
|
1513
1729
|
|
|
1514
|
-
export { type AggregateResolver, type AnyDrizzleDB, type BuildSchemaConfig, type ColumnDeprecator, type ColumnDescriber, type ColumnDocInfo, type ColumnTypeMapper, type ColumnTypeMapperInfo, type ComplexityConfig, 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 ScalarOverride, type ScalarOverridesConfig, type SchemaDocs, type SchemaExclusions, type SchemaFeatures, type SelectResolver, type SelectSingleResolver, type SelectionOptions, 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 };
|
|
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 };
|