@vantreeseba/drizzle-graphql 15.1.1 → 15.1.3
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 +70 -7
- package/dist/index.cjs +334 -96
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +68 -7
- package/dist/index.d.ts +68 -7
- package/dist/index.js +335 -97
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -385,7 +385,9 @@ type IdentifiedRows = {
|
|
|
385
385
|
*
|
|
386
386
|
* `false` means the arguments do not pin the rows down — an insert whose key the
|
|
387
387
|
* database generates, a `where` that filters on something other than the primary key,
|
|
388
|
-
* a plural update with no filter at all,
|
|
388
|
+
* a plural update with no filter at all, a table with no primary key, or an upsert whose
|
|
389
|
+
* `onConflict` conflicts on another unique key (the row updated is the one holding that
|
|
390
|
+
* key) or can skip a conflicting row (`action: NOTHING`, a `where` guard). `rows` is then
|
|
389
391
|
* a best-effort subset-free superset: every entry in it is a row the key values name,
|
|
390
392
|
* but other filters may narrow the real set further, and it may be empty.
|
|
391
393
|
*/
|
|
@@ -805,6 +807,14 @@ interface RelationFilterContext {
|
|
|
805
807
|
* generate is an unknown filter key like any other.
|
|
806
808
|
*/
|
|
807
809
|
uniqueKeys?: Record<string, UniqueKeyMap>;
|
|
810
|
+
/**
|
|
811
|
+
* The row policies of the request being compiled. A relation filter (and an ordering through
|
|
812
|
+
* a relation) reads the target table in a subquery, so it applies the target's `scope` and
|
|
813
|
+
* `softDelete` here — with the mode the relation field itself would default to — or a filter
|
|
814
|
+
* could match, and a sort could rank by, a row the relation hides. Absent for a scope's own
|
|
815
|
+
* filter object, which is the server's predicate and is compiled unscoped.
|
|
816
|
+
*/
|
|
817
|
+
scope?: ScopeResolver;
|
|
808
818
|
}
|
|
809
819
|
/**
|
|
810
820
|
* The build-scoped half of {@link RelationFilterContext}. Created once per generated schema and
|
|
@@ -922,6 +932,8 @@ type WriteHookFor = (tableName: string, operation: WriteOperation) => ResolvedWr
|
|
|
922
932
|
type ScopeHook<TContext = any> = (context: TContext, table: any) => SQL | Record<string, any> | undefined | null;
|
|
923
933
|
/** Build-time lookup: the scope configured for a table, if any. */
|
|
924
934
|
type ScopeFor = (tableName: string) => ScopeHook | undefined;
|
|
935
|
+
/** What a read over a soft-deleting table does with rows that are marked deleted. */
|
|
936
|
+
type DeletedMode = 'EXCLUDE' | 'INCLUDE' | 'ONLY';
|
|
925
937
|
/**
|
|
926
938
|
* One table's soft-delete convention, resolved against the real column at build time.
|
|
927
939
|
*
|
|
@@ -959,6 +971,22 @@ type SoftDeleteInfo = {
|
|
|
959
971
|
};
|
|
960
972
|
/** Build-time lookup: the soft-delete convention of a table, if it declares one. */
|
|
961
973
|
type SoftDeleteFor = (tableName: string) => SoftDeleteInfo | undefined;
|
|
974
|
+
/**
|
|
975
|
+
* The row policies of one request, bound to its context: the table's scope and its
|
|
976
|
+
* soft-delete convention, which both narrow the same `where`. `has` answers "does this table
|
|
977
|
+
* restrict anything at all", cheaply and without evaluating a hook; `on` compiles the
|
|
978
|
+
* predicate against a given table.
|
|
979
|
+
*/
|
|
980
|
+
type ScopeResolver = {
|
|
981
|
+
has: (tableName: string, mode?: DeletedMode) => boolean;
|
|
982
|
+
on: (tableName: string, table: Table, mode?: DeletedMode) => SQL | undefined;
|
|
983
|
+
/**
|
|
984
|
+
* The mode a relation field reading `tableName` defaults to — see
|
|
985
|
+
* {@link relationDeletedDefault}. Carried here because the eager (`with:`) path has the
|
|
986
|
+
* resolver but not the build-time soft-delete lookup.
|
|
987
|
+
*/
|
|
988
|
+
relationDefault: (tableName: string, requiredToOne: boolean) => DeletedMode | undefined;
|
|
989
|
+
};
|
|
962
990
|
/** Produces one column's value from the GraphQL context. See `BuildSchemaConfig.contextValues`. */
|
|
963
991
|
type ContextValueHook<TContext = any> = (context: TContext) => any;
|
|
964
992
|
/** Build-time lookup: the context-derived columns of a table, keyed by column property name. */
|
|
@@ -1178,6 +1206,9 @@ type UpdateManyArgs<TTable extends Table> = {
|
|
|
1178
1206
|
* `target` and `where` exist on PostgreSQL and SQLite only: MySQL's
|
|
1179
1207
|
* `ON DUPLICATE KEY UPDATE` fires on whichever unique key was violated and takes no
|
|
1180
1208
|
* predicate, so neither field is generated there.
|
|
1209
|
+
*
|
|
1210
|
+
* `target` may name a partial unique index; its predicate is repeated in the statement's
|
|
1211
|
+
* `ON CONFLICT (…) WHERE …`, which is what lets the database match it.
|
|
1181
1212
|
*/
|
|
1182
1213
|
type UpsertConflictArgs<TTable extends Table> = {
|
|
1183
1214
|
action?: 'UPDATE' | 'NOTHING';
|
|
@@ -1604,7 +1635,9 @@ type SchemaFeatures = {
|
|
|
1604
1635
|
* have — the guarantee is in the input type.
|
|
1605
1636
|
*
|
|
1606
1637
|
* Single-column constraints get no field (`eq` on the column already says it), and a
|
|
1607
|
-
* constraint whose field name is taken by a column or a relation is skipped.
|
|
1638
|
+
* constraint whose field name is taken by a column or a relation is skipped. So is a partial
|
|
1639
|
+
* unique index (`uniqueIndex().on(…).where(…)`): it is unique only among the rows its
|
|
1640
|
+
* predicate matches, so its columns do not name one row of the table. The fields live
|
|
1608
1641
|
* on `<Type>Filters`, so they are accepted wherever a filter is: the `Single` reads and
|
|
1609
1642
|
* writes they are meant for, but also list queries, relation filters and `onConflict.where`.
|
|
1610
1643
|
*
|
|
@@ -2029,7 +2062,8 @@ type BuildSchemaConfig = {
|
|
|
2029
2062
|
* what an `after`-only page is ordered by. Changing a table's default changes what its
|
|
2030
2063
|
* existing cursors mean.
|
|
2031
2064
|
* - Entries name column property names of that table; a direction alone is shorthand for
|
|
2032
|
-
* `{ direction }`. Unknown table or column names throw at build time
|
|
2065
|
+
* `{ direction }`. Unknown table or column names throw at build time, and so does a
|
|
2066
|
+
* column hidden by `exclude.columns`: cursors carry the ordering values in readable form.
|
|
2033
2067
|
* - Aggregates and `groupBy` take their own ordering and are unaffected.
|
|
2034
2068
|
*
|
|
2035
2069
|
* Off by default: a table with no entry keeps returning rows in whatever order the database
|
|
@@ -2058,6 +2092,10 @@ type BuildSchemaConfig = {
|
|
|
2058
2092
|
* only ever narrow the scope, never widen it.
|
|
2059
2093
|
* - It applies to every path that reads the table: list and single queries, aggregates and
|
|
2060
2094
|
* `groupBy`, relation fields (batched and eager), relation aggregates, and cursor pages.
|
|
2095
|
+
* It also applies wherever another table's request reads this one in a subquery: a
|
|
2096
|
+
* relation filter (`some` / `none` / `every`, to-one, `.through()` — the junction's scope
|
|
2097
|
+
* included) can only match in-scope rows, and an `orderBy` through a to-one relation sorts
|
|
2098
|
+
* an out-of-scope target as `NULL`.
|
|
2061
2099
|
* - It applies to every path that writes it: `update`, `updateMany`, `delete`, the
|
|
2062
2100
|
* conflict-update half of an upsert (PostgreSQL and SQLite), and the rows a nested
|
|
2063
2101
|
* `connect` / `disconnect` / `set` is allowed to reach. An out-of-scope row is simply not
|
|
@@ -2091,7 +2129,8 @@ type BuildSchemaConfig = {
|
|
|
2091
2129
|
* - The column is removed from the generated insert and update inputs, so a client cannot
|
|
2092
2130
|
* send it at all — the schema itself documents that it is server-owned.
|
|
2093
2131
|
* - Every insert stamps it, including the rows created by a nested `create`.
|
|
2094
|
-
* - Updates never write it: an update cannot hand a row to another owner.
|
|
2132
|
+
* - Updates never write it: an update cannot hand a row to another owner. That includes
|
|
2133
|
+
* the conflict branch of an upsert, whose `onConflict.update` does not offer it.
|
|
2095
2134
|
* - Keyed by the Drizzle schema key, then by the column's property name (not its database
|
|
2096
2135
|
* name), the same keying {@link BuildSchemaConfig.exclude} uses.
|
|
2097
2136
|
*/
|
|
@@ -2121,7 +2160,8 @@ type BuildSchemaConfig = {
|
|
|
2121
2160
|
* - Every generated read hides marked rows: list and single queries, aggregates, `groupBy`,
|
|
2122
2161
|
* relation fields on both the eager and the batched path, and relation aggregates. Each
|
|
2123
2162
|
* of those fields takes a `deleted: EXCLUDE | INCLUDE | ONLY` argument (default
|
|
2124
|
-
* `EXCLUDE`); `ONLY` is a trash view.
|
|
2163
|
+
* `EXCLUDE`); `ONLY` is a trash view. Relation filters and an `orderBy` through a to-one
|
|
2164
|
+
* relation see the rows the relation field would show, with the same default mode.
|
|
2125
2165
|
* - Every generated write skips them too: an `update`, a `delete`, or a nested `connect`
|
|
2126
2166
|
* cannot reach a row that is already marked.
|
|
2127
2167
|
* - The marker column is removed from the create and update inputs, so the only ways to set
|
|
@@ -2214,6 +2254,11 @@ type BuildSchemaConfig = {
|
|
|
2214
2254
|
* deliberately all-or-nothing: a column you can filter on but not select is an oracle, since
|
|
2215
2255
|
* `where: { keyHash: { eq: '…' } }` confirms a value without ever returning it.
|
|
2216
2256
|
*
|
|
2257
|
+
* One value stays readable: a row's `cursor` is base64url JSON of its ordering values, and the
|
|
2258
|
+
* primary key is always among them, so excluding the primary key does not hide it from a
|
|
2259
|
+
* client that decodes a cursor. Wrap cursors in your own opaque token if it must stay secret.
|
|
2260
|
+
* A `defaults` ordering on an excluded column throws at build time for the same reason.
|
|
2261
|
+
*
|
|
2217
2262
|
* Excluding a `NOT NULL` column that has no default makes that table's inserts impossible to
|
|
2218
2263
|
* satisfy — `buildSchema` warns on the console when it sees this, and still builds, since a
|
|
2219
2264
|
* read-only table is a reasonable thing to want.
|
|
@@ -2620,6 +2665,11 @@ type SelectionOptions = {
|
|
|
2620
2665
|
derivedTypeNameMapper?: DerivedTypeNameMapper;
|
|
2621
2666
|
typeNamePrefix?: string;
|
|
2622
2667
|
typeNameSuffix?: string;
|
|
2668
|
+
/**
|
|
2669
|
+
* The resolver's GraphQL context. The build's `scope` hooks are called with it, so a build
|
|
2670
|
+
* that configures `scope` requires it — the helpers throw rather than read unscoped.
|
|
2671
|
+
*/
|
|
2672
|
+
context?: any;
|
|
2623
2673
|
};
|
|
2624
2674
|
/**
|
|
2625
2675
|
* Translates a GraphQL selection set into the relational query builder's `with` tree — the
|
|
@@ -2639,6 +2689,10 @@ type SelectionOptions = {
|
|
|
2639
2689
|
* const row = await tx.query.Users.findFirst({ where: { id: { eq } }, with: withTree });
|
|
2640
2690
|
* ```
|
|
2641
2691
|
*
|
|
2692
|
+
* Every nested entry carries the build's row policies — `scope`, `softDelete`, `limits` and
|
|
2693
|
+
* `defaults.orderBy` — exactly as the generated `with:` clause does. The build is found
|
|
2694
|
+
* through the resolve info; pass `context` when it configures `scope`.
|
|
2695
|
+
*
|
|
2642
2696
|
* Returns `undefined` when the selection asks for no relations, which is the value the
|
|
2643
2697
|
* query builder wants for "no `with` clause".
|
|
2644
2698
|
*/
|
|
@@ -2660,6 +2714,11 @@ type ResolveSelectionOptions = SelectionOptions & {
|
|
|
2660
2714
|
offset?: number;
|
|
2661
2715
|
/** The generated `after` cursor argument, for keyset pagination. */
|
|
2662
2716
|
after?: string;
|
|
2717
|
+
/**
|
|
2718
|
+
* The generated `deleted` argument, for a soft-deleting table. Defaults to `EXCLUDE`, as the
|
|
2719
|
+
* generated field does.
|
|
2720
|
+
*/
|
|
2721
|
+
deleted?: DeletedMode;
|
|
2663
2722
|
};
|
|
2664
2723
|
/**
|
|
2665
2724
|
* Runs the read a generated select resolver would have run, against whichever executor is
|
|
@@ -2669,11 +2728,13 @@ type ResolveSelectionOptions = SelectionOptions & {
|
|
|
2669
2728
|
* This is what an override usually wants after it has done its own work:
|
|
2670
2729
|
*
|
|
2671
2730
|
* ```ts
|
|
2672
|
-
* const rows = await resolveSelection(info, { db, table: 'Users', where, executor: tx });
|
|
2731
|
+
* const rows = await resolveSelection(info, { db, table: 'Users', context, where, executor: tx });
|
|
2673
2732
|
* ```
|
|
2674
2733
|
*
|
|
2675
2734
|
* Relation arguments and aggregate fields keep behaving as they do in the generated schema,
|
|
2676
|
-
* because it is the generated schema's own code path.
|
|
2735
|
+
* because it is the generated schema's own code path. So do the build's row policies: the
|
|
2736
|
+
* root table and every nested relation are scoped and soft-delete-filtered, and the limit
|
|
2737
|
+
* policy and default ordering apply. Pass `context` when the build configures `scope`.
|
|
2677
2738
|
*/
|
|
2678
2739
|
declare const resolveSelection: (info: GraphQLResolveInfo | ResolveTree, options: ResolveSelectionOptions) => Promise<any>;
|
|
2679
2740
|
//#endregion
|
package/dist/index.d.ts
CHANGED
|
@@ -385,7 +385,9 @@ type IdentifiedRows = {
|
|
|
385
385
|
*
|
|
386
386
|
* `false` means the arguments do not pin the rows down — an insert whose key the
|
|
387
387
|
* database generates, a `where` that filters on something other than the primary key,
|
|
388
|
-
* a plural update with no filter at all,
|
|
388
|
+
* a plural update with no filter at all, a table with no primary key, or an upsert whose
|
|
389
|
+
* `onConflict` conflicts on another unique key (the row updated is the one holding that
|
|
390
|
+
* key) or can skip a conflicting row (`action: NOTHING`, a `where` guard). `rows` is then
|
|
389
391
|
* a best-effort subset-free superset: every entry in it is a row the key values name,
|
|
390
392
|
* but other filters may narrow the real set further, and it may be empty.
|
|
391
393
|
*/
|
|
@@ -805,6 +807,14 @@ interface RelationFilterContext {
|
|
|
805
807
|
* generate is an unknown filter key like any other.
|
|
806
808
|
*/
|
|
807
809
|
uniqueKeys?: Record<string, UniqueKeyMap>;
|
|
810
|
+
/**
|
|
811
|
+
* The row policies of the request being compiled. A relation filter (and an ordering through
|
|
812
|
+
* a relation) reads the target table in a subquery, so it applies the target's `scope` and
|
|
813
|
+
* `softDelete` here — with the mode the relation field itself would default to — or a filter
|
|
814
|
+
* could match, and a sort could rank by, a row the relation hides. Absent for a scope's own
|
|
815
|
+
* filter object, which is the server's predicate and is compiled unscoped.
|
|
816
|
+
*/
|
|
817
|
+
scope?: ScopeResolver;
|
|
808
818
|
}
|
|
809
819
|
/**
|
|
810
820
|
* The build-scoped half of {@link RelationFilterContext}. Created once per generated schema and
|
|
@@ -922,6 +932,8 @@ type WriteHookFor = (tableName: string, operation: WriteOperation) => ResolvedWr
|
|
|
922
932
|
type ScopeHook<TContext = any> = (context: TContext, table: any) => SQL | Record<string, any> | undefined | null;
|
|
923
933
|
/** Build-time lookup: the scope configured for a table, if any. */
|
|
924
934
|
type ScopeFor = (tableName: string) => ScopeHook | undefined;
|
|
935
|
+
/** What a read over a soft-deleting table does with rows that are marked deleted. */
|
|
936
|
+
type DeletedMode = 'EXCLUDE' | 'INCLUDE' | 'ONLY';
|
|
925
937
|
/**
|
|
926
938
|
* One table's soft-delete convention, resolved against the real column at build time.
|
|
927
939
|
*
|
|
@@ -959,6 +971,22 @@ type SoftDeleteInfo = {
|
|
|
959
971
|
};
|
|
960
972
|
/** Build-time lookup: the soft-delete convention of a table, if it declares one. */
|
|
961
973
|
type SoftDeleteFor = (tableName: string) => SoftDeleteInfo | undefined;
|
|
974
|
+
/**
|
|
975
|
+
* The row policies of one request, bound to its context: the table's scope and its
|
|
976
|
+
* soft-delete convention, which both narrow the same `where`. `has` answers "does this table
|
|
977
|
+
* restrict anything at all", cheaply and without evaluating a hook; `on` compiles the
|
|
978
|
+
* predicate against a given table.
|
|
979
|
+
*/
|
|
980
|
+
type ScopeResolver = {
|
|
981
|
+
has: (tableName: string, mode?: DeletedMode) => boolean;
|
|
982
|
+
on: (tableName: string, table: Table, mode?: DeletedMode) => SQL | undefined;
|
|
983
|
+
/**
|
|
984
|
+
* The mode a relation field reading `tableName` defaults to — see
|
|
985
|
+
* {@link relationDeletedDefault}. Carried here because the eager (`with:`) path has the
|
|
986
|
+
* resolver but not the build-time soft-delete lookup.
|
|
987
|
+
*/
|
|
988
|
+
relationDefault: (tableName: string, requiredToOne: boolean) => DeletedMode | undefined;
|
|
989
|
+
};
|
|
962
990
|
/** Produces one column's value from the GraphQL context. See `BuildSchemaConfig.contextValues`. */
|
|
963
991
|
type ContextValueHook<TContext = any> = (context: TContext) => any;
|
|
964
992
|
/** Build-time lookup: the context-derived columns of a table, keyed by column property name. */
|
|
@@ -1178,6 +1206,9 @@ type UpdateManyArgs<TTable extends Table> = {
|
|
|
1178
1206
|
* `target` and `where` exist on PostgreSQL and SQLite only: MySQL's
|
|
1179
1207
|
* `ON DUPLICATE KEY UPDATE` fires on whichever unique key was violated and takes no
|
|
1180
1208
|
* predicate, so neither field is generated there.
|
|
1209
|
+
*
|
|
1210
|
+
* `target` may name a partial unique index; its predicate is repeated in the statement's
|
|
1211
|
+
* `ON CONFLICT (…) WHERE …`, which is what lets the database match it.
|
|
1181
1212
|
*/
|
|
1182
1213
|
type UpsertConflictArgs<TTable extends Table> = {
|
|
1183
1214
|
action?: 'UPDATE' | 'NOTHING';
|
|
@@ -1604,7 +1635,9 @@ type SchemaFeatures = {
|
|
|
1604
1635
|
* have — the guarantee is in the input type.
|
|
1605
1636
|
*
|
|
1606
1637
|
* Single-column constraints get no field (`eq` on the column already says it), and a
|
|
1607
|
-
* constraint whose field name is taken by a column or a relation is skipped.
|
|
1638
|
+
* constraint whose field name is taken by a column or a relation is skipped. So is a partial
|
|
1639
|
+
* unique index (`uniqueIndex().on(…).where(…)`): it is unique only among the rows its
|
|
1640
|
+
* predicate matches, so its columns do not name one row of the table. The fields live
|
|
1608
1641
|
* on `<Type>Filters`, so they are accepted wherever a filter is: the `Single` reads and
|
|
1609
1642
|
* writes they are meant for, but also list queries, relation filters and `onConflict.where`.
|
|
1610
1643
|
*
|
|
@@ -2029,7 +2062,8 @@ type BuildSchemaConfig = {
|
|
|
2029
2062
|
* what an `after`-only page is ordered by. Changing a table's default changes what its
|
|
2030
2063
|
* existing cursors mean.
|
|
2031
2064
|
* - Entries name column property names of that table; a direction alone is shorthand for
|
|
2032
|
-
* `{ direction }`. Unknown table or column names throw at build time
|
|
2065
|
+
* `{ direction }`. Unknown table or column names throw at build time, and so does a
|
|
2066
|
+
* column hidden by `exclude.columns`: cursors carry the ordering values in readable form.
|
|
2033
2067
|
* - Aggregates and `groupBy` take their own ordering and are unaffected.
|
|
2034
2068
|
*
|
|
2035
2069
|
* Off by default: a table with no entry keeps returning rows in whatever order the database
|
|
@@ -2058,6 +2092,10 @@ type BuildSchemaConfig = {
|
|
|
2058
2092
|
* only ever narrow the scope, never widen it.
|
|
2059
2093
|
* - It applies to every path that reads the table: list and single queries, aggregates and
|
|
2060
2094
|
* `groupBy`, relation fields (batched and eager), relation aggregates, and cursor pages.
|
|
2095
|
+
* It also applies wherever another table's request reads this one in a subquery: a
|
|
2096
|
+
* relation filter (`some` / `none` / `every`, to-one, `.through()` — the junction's scope
|
|
2097
|
+
* included) can only match in-scope rows, and an `orderBy` through a to-one relation sorts
|
|
2098
|
+
* an out-of-scope target as `NULL`.
|
|
2061
2099
|
* - It applies to every path that writes it: `update`, `updateMany`, `delete`, the
|
|
2062
2100
|
* conflict-update half of an upsert (PostgreSQL and SQLite), and the rows a nested
|
|
2063
2101
|
* `connect` / `disconnect` / `set` is allowed to reach. An out-of-scope row is simply not
|
|
@@ -2091,7 +2129,8 @@ type BuildSchemaConfig = {
|
|
|
2091
2129
|
* - The column is removed from the generated insert and update inputs, so a client cannot
|
|
2092
2130
|
* send it at all — the schema itself documents that it is server-owned.
|
|
2093
2131
|
* - Every insert stamps it, including the rows created by a nested `create`.
|
|
2094
|
-
* - Updates never write it: an update cannot hand a row to another owner.
|
|
2132
|
+
* - Updates never write it: an update cannot hand a row to another owner. That includes
|
|
2133
|
+
* the conflict branch of an upsert, whose `onConflict.update` does not offer it.
|
|
2095
2134
|
* - Keyed by the Drizzle schema key, then by the column's property name (not its database
|
|
2096
2135
|
* name), the same keying {@link BuildSchemaConfig.exclude} uses.
|
|
2097
2136
|
*/
|
|
@@ -2121,7 +2160,8 @@ type BuildSchemaConfig = {
|
|
|
2121
2160
|
* - Every generated read hides marked rows: list and single queries, aggregates, `groupBy`,
|
|
2122
2161
|
* relation fields on both the eager and the batched path, and relation aggregates. Each
|
|
2123
2162
|
* of those fields takes a `deleted: EXCLUDE | INCLUDE | ONLY` argument (default
|
|
2124
|
-
* `EXCLUDE`); `ONLY` is a trash view.
|
|
2163
|
+
* `EXCLUDE`); `ONLY` is a trash view. Relation filters and an `orderBy` through a to-one
|
|
2164
|
+
* relation see the rows the relation field would show, with the same default mode.
|
|
2125
2165
|
* - Every generated write skips them too: an `update`, a `delete`, or a nested `connect`
|
|
2126
2166
|
* cannot reach a row that is already marked.
|
|
2127
2167
|
* - The marker column is removed from the create and update inputs, so the only ways to set
|
|
@@ -2214,6 +2254,11 @@ type BuildSchemaConfig = {
|
|
|
2214
2254
|
* deliberately all-or-nothing: a column you can filter on but not select is an oracle, since
|
|
2215
2255
|
* `where: { keyHash: { eq: '…' } }` confirms a value without ever returning it.
|
|
2216
2256
|
*
|
|
2257
|
+
* One value stays readable: a row's `cursor` is base64url JSON of its ordering values, and the
|
|
2258
|
+
* primary key is always among them, so excluding the primary key does not hide it from a
|
|
2259
|
+
* client that decodes a cursor. Wrap cursors in your own opaque token if it must stay secret.
|
|
2260
|
+
* A `defaults` ordering on an excluded column throws at build time for the same reason.
|
|
2261
|
+
*
|
|
2217
2262
|
* Excluding a `NOT NULL` column that has no default makes that table's inserts impossible to
|
|
2218
2263
|
* satisfy — `buildSchema` warns on the console when it sees this, and still builds, since a
|
|
2219
2264
|
* read-only table is a reasonable thing to want.
|
|
@@ -2620,6 +2665,11 @@ type SelectionOptions = {
|
|
|
2620
2665
|
derivedTypeNameMapper?: DerivedTypeNameMapper;
|
|
2621
2666
|
typeNamePrefix?: string;
|
|
2622
2667
|
typeNameSuffix?: string;
|
|
2668
|
+
/**
|
|
2669
|
+
* The resolver's GraphQL context. The build's `scope` hooks are called with it, so a build
|
|
2670
|
+
* that configures `scope` requires it — the helpers throw rather than read unscoped.
|
|
2671
|
+
*/
|
|
2672
|
+
context?: any;
|
|
2623
2673
|
};
|
|
2624
2674
|
/**
|
|
2625
2675
|
* Translates a GraphQL selection set into the relational query builder's `with` tree — the
|
|
@@ -2639,6 +2689,10 @@ type SelectionOptions = {
|
|
|
2639
2689
|
* const row = await tx.query.Users.findFirst({ where: { id: { eq } }, with: withTree });
|
|
2640
2690
|
* ```
|
|
2641
2691
|
*
|
|
2692
|
+
* Every nested entry carries the build's row policies — `scope`, `softDelete`, `limits` and
|
|
2693
|
+
* `defaults.orderBy` — exactly as the generated `with:` clause does. The build is found
|
|
2694
|
+
* through the resolve info; pass `context` when it configures `scope`.
|
|
2695
|
+
*
|
|
2642
2696
|
* Returns `undefined` when the selection asks for no relations, which is the value the
|
|
2643
2697
|
* query builder wants for "no `with` clause".
|
|
2644
2698
|
*/
|
|
@@ -2660,6 +2714,11 @@ type ResolveSelectionOptions = SelectionOptions & {
|
|
|
2660
2714
|
offset?: number;
|
|
2661
2715
|
/** The generated `after` cursor argument, for keyset pagination. */
|
|
2662
2716
|
after?: string;
|
|
2717
|
+
/**
|
|
2718
|
+
* The generated `deleted` argument, for a soft-deleting table. Defaults to `EXCLUDE`, as the
|
|
2719
|
+
* generated field does.
|
|
2720
|
+
*/
|
|
2721
|
+
deleted?: DeletedMode;
|
|
2663
2722
|
};
|
|
2664
2723
|
/**
|
|
2665
2724
|
* Runs the read a generated select resolver would have run, against whichever executor is
|
|
@@ -2669,11 +2728,13 @@ type ResolveSelectionOptions = SelectionOptions & {
|
|
|
2669
2728
|
* This is what an override usually wants after it has done its own work:
|
|
2670
2729
|
*
|
|
2671
2730
|
* ```ts
|
|
2672
|
-
* const rows = await resolveSelection(info, { db, table: 'Users', where, executor: tx });
|
|
2731
|
+
* const rows = await resolveSelection(info, { db, table: 'Users', context, where, executor: tx });
|
|
2673
2732
|
* ```
|
|
2674
2733
|
*
|
|
2675
2734
|
* Relation arguments and aggregate fields keep behaving as they do in the generated schema,
|
|
2676
|
-
* because it is the generated schema's own code path.
|
|
2735
|
+
* because it is the generated schema's own code path. So do the build's row policies: the
|
|
2736
|
+
* root table and every nested relation are scoped and soft-delete-filtered, and the limit
|
|
2737
|
+
* policy and default ordering apply. Pass `context` when the build configures `scope`.
|
|
2677
2738
|
*/
|
|
2678
2739
|
declare const resolveSelection: (info: GraphQLResolveInfo | ResolveTree, options: ResolveSelectionOptions) => Promise<any>;
|
|
2679
2740
|
//#endregion
|