@vantreeseba/drizzle-graphql 7.5.0 → 7.6.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
@@ -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, scopes?: ScopeFor) => 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,20 @@ 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;
310
324
  /**
311
325
  * Where a dialect's default sort places NULLs relative to non-NULL values:
312
326
  * - `nulls-largest` — PostgreSQL: NULLs sort as the largest values (last in ASC, first in DESC).
@@ -821,6 +835,34 @@ type LimitsConfig = TableLimitPolicy & {
821
835
  /** Per-table overrides, keyed by the table's key in the Drizzle schema. */
822
836
  tables?: Record<string, TableLimitPolicy>;
823
837
  };
838
+ /**
839
+ * What a {@link RowScope} may return: a Drizzle `SQL` expression, a filter object in the same
840
+ * shape as the generated `where` argument, or `undefined`/`null` for "no restriction".
841
+ *
842
+ * The filter-object form is compiled with the same code that compiles a client `where`, so it
843
+ * supports relation filters — `{ author: { orgId: { eq: 1 } } }` scopes a table through a join
844
+ * rather than a column it owns.
845
+ */
846
+ type RowScopeFilter = Record<string, any> | undefined | null;
847
+ /**
848
+ * A per-table row scope: given the GraphQL context, the predicate every read and write of that
849
+ * table is confined to.
850
+ *
851
+ * `table` is the table instance the current statement runs against. For a relational read that
852
+ * is Drizzle's *aliased* copy of the table, so build the predicate from this argument rather
853
+ * than from the imported table object — `eq(table.orgId, ctx.orgId)` is always correct, while
854
+ * `eq(users.orgId, ctx.orgId)` refers to the wrong alias inside a nested read.
855
+ *
856
+ * See {@link BuildSchemaConfig.scope}.
857
+ */
858
+ type RowScope<TContext = any> = (context: TContext, table: any) => RowScopeFilter | object;
859
+ /** {@link BuildSchemaConfig.scope} — a row scope per table, keyed by the Drizzle schema key. */
860
+ type ScopeConfig<TContext = any> = Record<string, RowScope<TContext>>;
861
+ /**
862
+ * {@link BuildSchemaConfig.contextValues} — columns whose value the server derives from the
863
+ * request context, keyed by Drizzle schema key and then by column property name.
864
+ */
865
+ type ContextValuesConfig<TContext = any> = Record<string, Record<string, (context: TContext) => any>>;
824
866
  /**
825
867
  * {@link BuildSchemaConfig.exclude} — tables and columns to keep out of the generated schema.
826
868
  *
@@ -1049,6 +1091,66 @@ type BuildSchemaConfig = {
1049
1091
  * agree.
1050
1092
  */
1051
1093
  limits?: LimitsConfig;
1094
+ /**
1095
+ * Row-level scoping: a predicate, derived from the GraphQL context, that every read and
1096
+ * write of a table is confined to. This is the multi-tenancy / ownership knob — the one
1097
+ * rule a wrapper cannot enforce from outside, because a nested relation field never passes
1098
+ * through a root resolver.
1099
+ *
1100
+ * ```ts
1101
+ * import { and, eq } from 'drizzle-orm';
1102
+ *
1103
+ * buildSchema(db, {
1104
+ * scope: {
1105
+ * posts: (ctx, table) => eq(table.orgId, ctx.orgId),
1106
+ * // A filter object works too, and can scope through a relation:
1107
+ * comments: (ctx) => ({ post: { orgId: { eq: ctx.orgId } } }),
1108
+ * },
1109
+ * });
1110
+ * ```
1111
+ *
1112
+ * - The predicate is ANDed on **last**, after the client's `where`, so a client filter can
1113
+ * only ever narrow the scope, never widen it.
1114
+ * - It applies to every path that reads the table: list and single queries, aggregates and
1115
+ * `groupBy`, relation fields (batched and eager), relation aggregates, and cursor pages.
1116
+ * - It applies to every path that writes it: `update`, `updateMany`, `delete`, the
1117
+ * conflict-update half of an upsert (PostgreSQL and SQLite), and the rows a nested
1118
+ * `connect` / `disconnect` / `set` is allowed to reach. An out-of-scope row is simply not
1119
+ * matched — a scoped `delete` reports zero rows rather than refusing.
1120
+ * - It cannot apply to a plain `insert`: there is no existing row to filter. Use
1121
+ * {@link BuildSchemaConfig.contextValues} to stamp the owning column on the way in.
1122
+ * - `table` is the table the current statement runs against, which for a relational read is
1123
+ * Drizzle's aliased copy — always build the predicate from that argument.
1124
+ * - Returning `undefined` means "no restriction for this context", so a hook can let an
1125
+ * admin through. A table with no entry is unscoped.
1126
+ * - MySQL's `ON DUPLICATE KEY UPDATE` takes no predicate, so a MySQL upsert cannot be
1127
+ * scoped on the conflict path; scope the table's `update` and rely on `contextValues`
1128
+ * for the insert half.
1129
+ */
1130
+ scope?: ScopeConfig;
1131
+ /**
1132
+ * Columns whose value the server derives from the request context rather than accepting
1133
+ * from the client — the write-side half of {@link BuildSchemaConfig.scope}.
1134
+ *
1135
+ * ```ts
1136
+ * buildSchema(db, {
1137
+ * contextValues: {
1138
+ * posts: {
1139
+ * orgId: (ctx) => ctx.orgId,
1140
+ * authorId: (ctx) => ctx.userId,
1141
+ * },
1142
+ * },
1143
+ * });
1144
+ * ```
1145
+ *
1146
+ * - The column is removed from the generated insert and update inputs, so a client cannot
1147
+ * send it at all — the schema itself documents that it is server-owned.
1148
+ * - Every insert stamps it, including the rows created by a nested `create`.
1149
+ * - Updates never write it: an update cannot hand a row to another owner.
1150
+ * - Keyed by the Drizzle schema key, then by the column's property name (not its database
1151
+ * name), the same keying {@link BuildSchemaConfig.exclude} uses.
1152
+ */
1153
+ contextValues?: ContextValuesConfig;
1052
1154
  /**
1053
1155
  * Tables and columns to leave out of the generated schema entirely.
1054
1156
  *
@@ -1511,4 +1613,4 @@ declare const resolveSelection: (info: GraphQLResolveInfo | ResolveTree, options
1511
1613
 
1512
1614
  declare const buildSchema: <TDbClient extends AnyDrizzleDB<any>>(db: TDbClient, config?: BuildSchemaConfig) => GeneratedData<TDbClient>;
1513
1615
 
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 };
1616
+ 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 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, scopes?: ScopeFor) => 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,20 @@ 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;
310
324
  /**
311
325
  * Where a dialect's default sort places NULLs relative to non-NULL values:
312
326
  * - `nulls-largest` — PostgreSQL: NULLs sort as the largest values (last in ASC, first in DESC).
@@ -821,6 +835,34 @@ type LimitsConfig = TableLimitPolicy & {
821
835
  /** Per-table overrides, keyed by the table's key in the Drizzle schema. */
822
836
  tables?: Record<string, TableLimitPolicy>;
823
837
  };
838
+ /**
839
+ * What a {@link RowScope} may return: a Drizzle `SQL` expression, a filter object in the same
840
+ * shape as the generated `where` argument, or `undefined`/`null` for "no restriction".
841
+ *
842
+ * The filter-object form is compiled with the same code that compiles a client `where`, so it
843
+ * supports relation filters — `{ author: { orgId: { eq: 1 } } }` scopes a table through a join
844
+ * rather than a column it owns.
845
+ */
846
+ type RowScopeFilter = Record<string, any> | undefined | null;
847
+ /**
848
+ * A per-table row scope: given the GraphQL context, the predicate every read and write of that
849
+ * table is confined to.
850
+ *
851
+ * `table` is the table instance the current statement runs against. For a relational read that
852
+ * is Drizzle's *aliased* copy of the table, so build the predicate from this argument rather
853
+ * than from the imported table object — `eq(table.orgId, ctx.orgId)` is always correct, while
854
+ * `eq(users.orgId, ctx.orgId)` refers to the wrong alias inside a nested read.
855
+ *
856
+ * See {@link BuildSchemaConfig.scope}.
857
+ */
858
+ type RowScope<TContext = any> = (context: TContext, table: any) => RowScopeFilter | object;
859
+ /** {@link BuildSchemaConfig.scope} — a row scope per table, keyed by the Drizzle schema key. */
860
+ type ScopeConfig<TContext = any> = Record<string, RowScope<TContext>>;
861
+ /**
862
+ * {@link BuildSchemaConfig.contextValues} — columns whose value the server derives from the
863
+ * request context, keyed by Drizzle schema key and then by column property name.
864
+ */
865
+ type ContextValuesConfig<TContext = any> = Record<string, Record<string, (context: TContext) => any>>;
824
866
  /**
825
867
  * {@link BuildSchemaConfig.exclude} — tables and columns to keep out of the generated schema.
826
868
  *
@@ -1049,6 +1091,66 @@ type BuildSchemaConfig = {
1049
1091
  * agree.
1050
1092
  */
1051
1093
  limits?: LimitsConfig;
1094
+ /**
1095
+ * Row-level scoping: a predicate, derived from the GraphQL context, that every read and
1096
+ * write of a table is confined to. This is the multi-tenancy / ownership knob — the one
1097
+ * rule a wrapper cannot enforce from outside, because a nested relation field never passes
1098
+ * through a root resolver.
1099
+ *
1100
+ * ```ts
1101
+ * import { and, eq } from 'drizzle-orm';
1102
+ *
1103
+ * buildSchema(db, {
1104
+ * scope: {
1105
+ * posts: (ctx, table) => eq(table.orgId, ctx.orgId),
1106
+ * // A filter object works too, and can scope through a relation:
1107
+ * comments: (ctx) => ({ post: { orgId: { eq: ctx.orgId } } }),
1108
+ * },
1109
+ * });
1110
+ * ```
1111
+ *
1112
+ * - The predicate is ANDed on **last**, after the client's `where`, so a client filter can
1113
+ * only ever narrow the scope, never widen it.
1114
+ * - It applies to every path that reads the table: list and single queries, aggregates and
1115
+ * `groupBy`, relation fields (batched and eager), relation aggregates, and cursor pages.
1116
+ * - It applies to every path that writes it: `update`, `updateMany`, `delete`, the
1117
+ * conflict-update half of an upsert (PostgreSQL and SQLite), and the rows a nested
1118
+ * `connect` / `disconnect` / `set` is allowed to reach. An out-of-scope row is simply not
1119
+ * matched — a scoped `delete` reports zero rows rather than refusing.
1120
+ * - It cannot apply to a plain `insert`: there is no existing row to filter. Use
1121
+ * {@link BuildSchemaConfig.contextValues} to stamp the owning column on the way in.
1122
+ * - `table` is the table the current statement runs against, which for a relational read is
1123
+ * Drizzle's aliased copy — always build the predicate from that argument.
1124
+ * - Returning `undefined` means "no restriction for this context", so a hook can let an
1125
+ * admin through. A table with no entry is unscoped.
1126
+ * - MySQL's `ON DUPLICATE KEY UPDATE` takes no predicate, so a MySQL upsert cannot be
1127
+ * scoped on the conflict path; scope the table's `update` and rely on `contextValues`
1128
+ * for the insert half.
1129
+ */
1130
+ scope?: ScopeConfig;
1131
+ /**
1132
+ * Columns whose value the server derives from the request context rather than accepting
1133
+ * from the client — the write-side half of {@link BuildSchemaConfig.scope}.
1134
+ *
1135
+ * ```ts
1136
+ * buildSchema(db, {
1137
+ * contextValues: {
1138
+ * posts: {
1139
+ * orgId: (ctx) => ctx.orgId,
1140
+ * authorId: (ctx) => ctx.userId,
1141
+ * },
1142
+ * },
1143
+ * });
1144
+ * ```
1145
+ *
1146
+ * - The column is removed from the generated insert and update inputs, so a client cannot
1147
+ * send it at all — the schema itself documents that it is server-owned.
1148
+ * - Every insert stamps it, including the rows created by a nested `create`.
1149
+ * - Updates never write it: an update cannot hand a row to another owner.
1150
+ * - Keyed by the Drizzle schema key, then by the column's property name (not its database
1151
+ * name), the same keying {@link BuildSchemaConfig.exclude} uses.
1152
+ */
1153
+ contextValues?: ContextValuesConfig;
1052
1154
  /**
1053
1155
  * Tables and columns to leave out of the generated schema entirely.
1054
1156
  *
@@ -1511,4 +1613,4 @@ declare const resolveSelection: (info: GraphQLResolveInfo | ResolveTree, options
1511
1613
 
1512
1614
  declare const buildSchema: <TDbClient extends AnyDrizzleDB<any>>(db: TDbClient, config?: BuildSchemaConfig) => GeneratedData<TDbClient>;
1513
1615
 
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 };
1616
+ 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 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 };