@loradb/lora-graphql 0.23.0 → 0.24.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.
Files changed (85) hide show
  1. package/README.md +42 -10
  2. package/dist/analyze/access-lint.d.ts +7 -0
  3. package/dist/analyze/access.d.ts +2 -30
  4. package/dist/analyze/assert-schema.d.ts +19 -0
  5. package/dist/analyze/diff.d.ts +1 -1
  6. package/dist/analyze/plans.d.ts +1 -1
  7. package/dist/analyze/principals.d.ts +25 -0
  8. package/dist/analyze/verdicts.d.ts +45 -0
  9. package/dist/cli.js +2 -2
  10. package/dist/cli.js.map +1 -1
  11. package/dist/compile/cache.d.ts +1 -1
  12. package/dist/compile/read/abstract.d.ts +19 -0
  13. package/dist/compile/read/aggregates.d.ts +34 -0
  14. package/dist/compile/read/by-keys.d.ts +10 -0
  15. package/dist/compile/read/common.d.ts +30 -0
  16. package/dist/compile/read/connection.d.ts +26 -0
  17. package/dist/compile/read/cypher-field.d.ts +21 -0
  18. package/dist/compile/read/match.d.ts +11 -0
  19. package/dist/compile/read/project.d.ts +15 -0
  20. package/dist/compile/read/root.d.ts +5 -0
  21. package/dist/compile/read/search.d.ts +16 -0
  22. package/dist/compile/read/sort.d.ts +42 -0
  23. package/dist/compile/read/types.d.ts +61 -0
  24. package/dist/{diff-B9iDdELF.js → diff-aDivqYqr.js} +2 -2
  25. package/dist/diff-aDivqYqr.js.map +1 -0
  26. package/dist/{driver-C5dSoSD8.js → driver-DSnytFsU.js} +11092 -10674
  27. package/dist/driver-DSnytFsU.js.map +1 -0
  28. package/dist/execute/cypher-mutation.d.ts +1 -1
  29. package/dist/execute/mutate/adjust.d.ts +5 -0
  30. package/dist/execute/mutate/checks.d.ts +21 -0
  31. package/dist/execute/mutate/delete.d.ts +7 -0
  32. package/dist/execute/mutate/env.d.ts +73 -0
  33. package/dist/execute/mutate/errors.d.ts +7 -0
  34. package/dist/execute/mutate/fragments.d.ts +37 -0
  35. package/dist/execute/mutate/plan.d.ts +95 -0
  36. package/dist/execute/mutate/runner.d.ts +129 -0
  37. package/dist/execute/mutate/unique-together.d.ts +18 -0
  38. package/dist/execute/mutate.d.ts +2 -79
  39. package/dist/index.d.ts +10 -6
  40. package/dist/index.js +2 -2
  41. package/dist/lora-graphql.d.ts +12 -326
  42. package/dist/model/build/authorization.d.ts +31 -0
  43. package/dist/model/build/cypher-field.d.ts +11 -0
  44. package/dist/model/build/directive-args.d.ts +16 -0
  45. package/dist/model/build/limits.d.ts +18 -0
  46. package/dist/model/build/relationship-field.d.ts +11 -0
  47. package/dist/model/build/rule-checks.d.ts +23 -0
  48. package/dist/model/build/rule-references.d.ts +28 -0
  49. package/dist/model/build/scalar-field.d.ts +7 -0
  50. package/dist/model/build/search.d.ts +4 -0
  51. package/dist/model/build/shapes.d.ts +18 -0
  52. package/dist/model/build/unique-together.d.ts +5 -0
  53. package/dist/model/build.d.ts +3 -20
  54. package/dist/model/directives.d.ts +1 -1
  55. package/dist/model/types.d.ts +12 -2
  56. package/dist/options.d.ts +255 -0
  57. package/dist/results.d.ts +70 -0
  58. package/dist/runtime/custom-requires.d.ts +7 -0
  59. package/dist/runtime/database-error.d.ts +10 -0
  60. package/dist/runtime/documents.d.ts +35 -0
  61. package/dist/runtime/limits.d.ts +37 -0
  62. package/dist/runtime/request.d.ts +33 -0
  63. package/dist/runtime/timing.d.ts +13 -0
  64. package/dist/schema/aggregates.d.ts +17 -0
  65. package/dist/schema/base.d.ts +17 -0
  66. package/dist/schema/build.d.ts +3 -42
  67. package/dist/schema/filters.d.ts +10 -0
  68. package/dist/schema/hooks.d.ts +42 -0
  69. package/dist/schema/objects.d.ts +36 -0
  70. package/dist/schema/query.d.ts +8 -0
  71. package/dist/schema/resolvers.d.ts +13 -0
  72. package/dist/schema/sorts.d.ts +5 -0
  73. package/dist/schema/subscriptions.d.ts +7 -0
  74. package/dist/subscriptions/change-hub.d.ts +50 -0
  75. package/dist/subscriptions/compiles.d.ts +23 -0
  76. package/dist/subscriptions/events.d.ts +9 -0
  77. package/dist/subscriptions/filter-cost.d.ts +15 -0
  78. package/dist/subscriptions/subscriptions.d.ts +73 -0
  79. package/dist/testing.d.ts +4 -1
  80. package/dist/testing.js +34 -29
  81. package/dist/testing.js.map +1 -1
  82. package/package.json +2 -2
  83. package/dist/compile/read.d.ts +0 -102
  84. package/dist/diff-B9iDdELF.js.map +0 -1
  85. package/dist/driver-C5dSoSD8.js.map +0 -1
@@ -204,16 +204,26 @@ export declare const RULE_REFERENCES: Set<string>;
204
204
  export type AuthorizationWhere = Record<string, unknown>;
205
205
  export interface AuthorizationFilterRule {
206
206
  operations: ReadonlySet<AuthOperation>;
207
+ /**
208
+ * Without a token the rule denies: the schema's
209
+ * `@authorizationDefaults(requireAuthentication:)`, and always true for
210
+ * a rule no anonymous request could pass.
211
+ */
207
212
  requireAuthentication: boolean;
208
- /** `requireAuthentication` was left to its default (true). */
213
+ /** The schema left `requireAuthentication` to its default (true). */
209
214
  requireAuthenticationDefaulted?: boolean;
210
215
  where: AuthorizationWhere;
211
216
  }
212
217
  export interface AuthorizationValidateRule {
213
218
  operations: ReadonlySet<AuthOperation>;
214
219
  when: ReadonlySet<"BEFORE" | "AFTER">;
220
+ /**
221
+ * Without a token the rule denies: the schema's
222
+ * `@authorizationDefaults(requireAuthentication:)`, and always true for
223
+ * a rule no anonymous request could pass.
224
+ */
215
225
  requireAuthentication: boolean;
216
- /** `requireAuthentication` was left to its default (true). */
226
+ /** The schema left `requireAuthentication` to its default (true). */
217
227
  requireAuthenticationDefaulted?: boolean;
218
228
  where: AuthorizationWhere;
219
229
  }
@@ -0,0 +1,255 @@
1
+ import { DocumentNode, GraphQLFieldResolver, GraphQLScalarType } from 'graphql';
2
+ import { LoraDriver, Statement } from './driver.js';
3
+ import { PopulatedByCallback } from './execute/mutate/env.js';
4
+ import { LoraTransaction } from './execute/transaction.js';
5
+ import { DocumentGuards } from './guards.js';
6
+ import { ModelOptions } from './model/build/limits.js';
7
+ import { ObservabilityOptions } from './observe.js';
8
+ export interface LoraGraphQLOptions extends ModelOptions, ObservabilityOptions {
9
+ /** Annotated SDL: the graph model and the API in one document. */
10
+ typeDefs: string | DocumentNode;
11
+ driver: LoraDriver;
12
+ /** Timeout for every statement, in milliseconds. Default 10 000; 0 disables. */
13
+ timeoutMs?: number;
14
+ /**
15
+ * Time budget for all root fields of one query, in milliseconds: past
16
+ * it, the operation's statements are aborted and its unfinished fields
17
+ * fail with TIMEOUT. Default twice `timeoutMs` (20 000); 0 disables.
18
+ * Subscriptions are not bounded by it; mutations keep `timeoutMs` per
19
+ * statement.
20
+ */
21
+ operationTimeoutMs?: number;
22
+ /**
23
+ * Statements one operation runs at once: aliased root fields queue for
24
+ * a slot instead of taking every libuv worker, so one request cannot
25
+ * starve the others. Default 2.
26
+ */
27
+ maxConcurrentStatements?: number;
28
+ /**
29
+ * Approximate bytes the compile cache may hold, and again the parsed
30
+ * document cache: entries are evicted oldest first past it, besides the
31
+ * entry caps. Requests with more than 16 KiB of variables a field uses
32
+ * (long `in:` lists, embedding vectors) are compiled but not cached.
33
+ * Default 64 MiB.
34
+ */
35
+ compileCacheBytes?: number;
36
+ /**
37
+ * Reject a root field whose estimated rows touched exceed this, before
38
+ * it runs. The estimate multiplies page sizes through nested lists,
39
+ * capped by relationship degrees from `analyze()` or `@cardinality`,
40
+ * and charges each filter the rows it examines: a label scan when no
41
+ * index answers it, the related nodes of every relationship it follows.
42
+ * Default 50 000; `Infinity` disables.
43
+ */
44
+ maxCost?: number;
45
+ /**
46
+ * The cost limit for one request, from its context (for example by
47
+ * user or plan). Undefined falls back to `maxCost`.
48
+ */
49
+ budget?: (context: unknown) => number | undefined;
50
+ /** Called with every root field's cost estimate, before it runs. */
51
+ onCost?: (event: CostEvent) => void;
52
+ /**
53
+ * The request's verified claims, from the GraphQL context. Default:
54
+ * `context.jwt`. The library never verifies tokens: do that in the
55
+ * server and put the claims in the context.
56
+ */
57
+ jwt?: (context: unknown) => Record<string, unknown> | undefined;
58
+ /**
59
+ * Most nodes one mutation may create, update or delete, nested ones
60
+ * included (and ten times as many relationships written). Default 1000: larger imports belong in a Cypher load, not a GraphQL
61
+ * request. Also the default `limit` of bulk updates and deletes.
62
+ */
63
+ maxBatch?: number;
64
+ /**
65
+ * Most items a list argument of a `@cypher` field takes, unless its
66
+ * `@size(max:)` says otherwise. More is BAD_USER_INPUT before the
67
+ * statement runs. Default 1000.
68
+ */
69
+ maxListArgument?: number;
70
+ /**
71
+ * Relationship levels one `where` may nest: quantifiers (`some`,
72
+ * `none`, `all`, `single`, `count`, `aggregate`), connection filters,
73
+ * `<field>Exists` and filters through a single relationship each count
74
+ * one. Deeper is BAD_USER_INPUT before anything runs: each level
75
+ * multiplies the work by the relationship's degree. Default 2.
76
+ */
77
+ maxFilterDepth?: number;
78
+ /**
79
+ * Items an `in` filter operand may hold. More is BAD_USER_INPUT before
80
+ * anything runs. Default 1000.
81
+ */
82
+ maxListFilter?: number;
83
+ /**
84
+ * Characters a string filter operand (`eq`, `contains`, an `in` item, …)
85
+ * may hold. More is BAD_USER_INPUT before anything runs. Default 10 000.
86
+ */
87
+ maxStringFilter?: number;
88
+ /**
89
+ * Changes a `changes()` consumer or subscriber may fall behind before it
90
+ * is ended with an error. Default 1000.
91
+ */
92
+ maxQueuedChanges?: number;
93
+ /**
94
+ * Live subscriptions one scope (see `subscriptionScope`) may hold; one
95
+ * more is LIMIT_EXCEEDED. Default 100.
96
+ */
97
+ maxSubscriptions?: number;
98
+ /**
99
+ * What `maxSubscriptions` counts per: by default the context object, so
100
+ * a server that reuses one context per connection (graphql-ws) limits
101
+ * each connection. Return the connection (or user) otherwise.
102
+ */
103
+ subscriptionScope?: (context: unknown) => object | undefined;
104
+ /**
105
+ * How deep relationship filters may nest in a subscription's `where`,
106
+ * which runs on every change. Deeper is LIMIT_EXCEEDED. Default 1.
107
+ */
108
+ maxSubscriptionFilterDepth?: number;
109
+ /**
110
+ * Per statement a subscription runs to check a change (visibility,
111
+ * `where`, related nodes). Default 2000, or `timeoutMs` when lower.
112
+ */
113
+ subscriptionTimeoutMs?: number;
114
+ /** Named callbacks for `@populatedBy(callback:)`. */
115
+ callbacks?: Record<string, PopulatedByCallback>;
116
+ /**
117
+ * Implementations of custom scalars declared with `@storedAs`, e.g. one
118
+ * that validates e-mail addresses. Without one a scalar passes through.
119
+ */
120
+ scalars?: Record<string, GraphQLScalarType>;
121
+ /**
122
+ * Feed subscriptions and `changes()` from the engine's committed change
123
+ * feed (lora-node `db.changes()`): every write to the database, from
124
+ * any path in the process that owns it, in commit order. `onWrite`
125
+ * still reports this instance's mutations, and `previousState` needs
126
+ * them. Default false.
127
+ */
128
+ changeFeed?: boolean;
129
+ /**
130
+ * Resolvers of `@customResolver` fields, by type and field name. The
131
+ * source holds the node's selected fields plus the field's `requires`.
132
+ */
133
+ resolvers?: Record<string, Record<string, GraphQLFieldResolver<Record<string, unknown>, unknown>>>;
134
+ /** Called with every statement before it runs; for logging and tests. */
135
+ onStatement?: (event: StatementEvent) => void;
136
+ /**
137
+ * Hide database error details from clients: they get
138
+ * `extensions.code` `DATABASE_ERROR` and an `id`, and `onError` gets the
139
+ * engine's message. Default: on when `NODE_ENV` is `production`.
140
+ */
141
+ maskErrors?: boolean;
142
+ /** Called with every database error, masked or not. */
143
+ onError?: (event: DatabaseErrorEvent) => void;
144
+ /**
145
+ * Limits on the documents `execute()`, `subscribe()` and `persist()`
146
+ * accept: depth,
147
+ * aliases, root fields, tokens, introspection. `false` turns them off.
148
+ * For other servers use `validationRules()` or `envelopPlugin()`.
149
+ */
150
+ guards?: DocumentGuards | false;
151
+ /**
152
+ * Make `execute()` and `subscribe()` refuse `source` and run only
153
+ * persisted operations by `id`. Default false.
154
+ */
155
+ persistedOnly?: boolean;
156
+ /**
157
+ * How `execute()` commits a mutation with several root fields.
158
+ * `"field"` (the default): each root field in its own transaction, so a
159
+ * later failure leaves the earlier ones committed. `"operation"`: every
160
+ * root field in one transaction, committed only when the operation
161
+ * reports no error, rolled back (with `data: null`) otherwise. A
162
+ * `transaction` in the context takes precedence. Envelop / Yoga servers
163
+ * on `getSchema()` get the same with `lora.envelopPlugin()`; other
164
+ * servers calling graphql-js directly put a `lora.begin()` transaction
165
+ * in the context (without one, a one-time warning says each root field
166
+ * committed on its own).
167
+ */
168
+ mutationTransaction?: "field" | "operation";
169
+ /**
170
+ * Add `extensions.timing` to `execute()` results: the request's total
171
+ * time, the time spent in LoraDB, and both per root field, in
172
+ * milliseconds. `true` for every request, or a function deciding per
173
+ * request from the GraphQL context (for example only for admins or in
174
+ * development). Default off: timings sent to clients can act as a
175
+ * timing side channel.
176
+ */
177
+ timing?: boolean | ((context: unknown) => boolean);
178
+ }
179
+ export interface CostEvent {
180
+ field: string;
181
+ /** Estimated rows this root field touches. */
182
+ cost: number;
183
+ /** Estimated rows of the operation so far, this field included. */
184
+ total: number;
185
+ /** The limit that applies: `budget(context)` or `maxCost`. */
186
+ limit: number;
187
+ context: unknown;
188
+ }
189
+ export interface DatabaseErrorEvent {
190
+ /** Correlation id, also in the client error's `extensions.id`. */
191
+ id: string;
192
+ /**
193
+ * The root field that failed, or `changeFeed` for a failure of the
194
+ * change feed (it reopens from where it stopped after a backoff).
195
+ */
196
+ field: string;
197
+ /** The engine's message, which may name labels, properties and Cypher. */
198
+ message: string;
199
+ /** The error as thrown by the driver. */
200
+ error: unknown;
201
+ }
202
+ export interface StatementEvent {
203
+ field: string;
204
+ statement: Statement;
205
+ }
206
+ /** Per-request options read from the GraphQL context, when present. */
207
+ export interface LoraGraphQLContext {
208
+ /** Verified claims; enables @authentication and @authorization. */
209
+ jwt?: Record<string, unknown>;
210
+ /** Cancels the request's statements when aborted. */
211
+ signal?: AbortSignal;
212
+ /**
213
+ * Run in this transaction (from `lora.begin()`) instead of one per
214
+ * field: the caller commits, together with its own Cypher.
215
+ */
216
+ transaction?: LoraTransaction;
217
+ }
218
+ export interface AssertSchemaOptions {
219
+ /** Create what is missing instead of only reporting it. */
220
+ create?: boolean;
221
+ }
222
+ export interface CheckOptions {
223
+ /**
224
+ * Flag statements whose largest engine row estimate (from graph
225
+ * statistics) exceeds this. Off by default: estimates ignore a LIMIT
226
+ * that stops an index-ordered scan early.
227
+ */
228
+ rowBudget?: number;
229
+ /**
230
+ * Operations to compile and plan-check (S2), with example variables and
231
+ * the GraphQL context to compile them under (e.g. `{ jwt }`, so rules
232
+ * compile as they do for a signed-in caller). Without one, an operation
233
+ * compiles as an anonymous request would.
234
+ */
235
+ operations?: Array<{
236
+ name?: string;
237
+ document: string | DocumentNode;
238
+ variables?: Record<string, unknown>;
239
+ context?: unknown;
240
+ }>;
241
+ }
242
+ export interface ExecuteArgs {
243
+ /** The document, or `id` of a persisted operation. */
244
+ source?: string;
245
+ id?: string;
246
+ variables?: Record<string, unknown>;
247
+ operationName?: string;
248
+ context?: unknown;
249
+ /**
250
+ * Attach the operation's read-set to the result as a non-enumerable
251
+ * `readSet` property (never serialized to the client), for a response
252
+ * cache to invalidate with `lora.affects(result.readSet, change)`.
253
+ */
254
+ readSet?: boolean;
255
+ }
@@ -0,0 +1,70 @@
1
+ import { ExecutionResult } from 'graphql';
2
+ import { CypherFinding } from './analyze/cypher-check.js';
3
+ import { SchemaRequirement } from './analyze/indexes.js';
4
+ import { PlanReport } from './analyze/plans.js';
5
+ import { ReadSet } from './compile/read/types.js';
6
+ import { ModelWarning } from './model/types.js';
7
+ /** `extensions.timing` of an `execute()` result (see the `timing` option). */
8
+ export interface ExecutionTiming {
9
+ /** The whole `execute()` call: parse, validation, execution. */
10
+ totalMs: number;
11
+ /** Time spent running statements in LoraDB. */
12
+ databaseMs: number;
13
+ /** Per root field, by response key (alias or name). */
14
+ fields: Record<string, {
15
+ totalMs: number;
16
+ databaseMs: number;
17
+ }>;
18
+ }
19
+ /** `execute()`'s result; `readSet` is there when `ExecuteArgs.readSet` asked. */
20
+ export type LoraExecutionResult = ExecutionResult & {
21
+ readonly readSet?: ReadSet;
22
+ };
23
+ export interface SchemaAssertion {
24
+ required: SchemaRequirement[];
25
+ missing: SchemaRequirement[];
26
+ created: SchemaRequirement[];
27
+ /**
28
+ * Full-text and vector indexes present under their name but defined
29
+ * differently (labels, properties, kind): search would keep using the
30
+ * old definition. Without `create`; with it they are re-created.
31
+ */
32
+ mismatched: SchemaRequirement[];
33
+ /** Indexes `create` dropped and created again with the model's definition. */
34
+ recreated: SchemaRequirement[];
35
+ }
36
+ export interface CheckReport {
37
+ /** True when nothing below is a failure. */
38
+ ok: boolean;
39
+ /** Model warnings, e.g. an unused @cypher argument. */
40
+ warnings: readonly ModelWarning[];
41
+ /** @cypher statements the engine rejects or that write from a query. */
42
+ cypher: CypherFinding[];
43
+ /** Constraints and indexes the database lacks. */
44
+ missing: SchemaRequirement[];
45
+ /** Indexes the database has that no part of the API needs. */
46
+ unused: Array<{
47
+ name: string;
48
+ type: string;
49
+ labels: string[];
50
+ properties: string[];
51
+ }>;
52
+ /** Schema lint: valid but costly or risky choices (not failures). */
53
+ lint: readonly ModelWarning[];
54
+ /**
55
+ * `@mutation` types with writes no rule guards (failures): declare them
56
+ * with `@authorization(public: [...])` when that is intended.
57
+ */
58
+ security: readonly ModelWarning[];
59
+ /** Plan findings per operation and root field. */
60
+ plans: Array<{
61
+ operation: string;
62
+ field: string;
63
+ reports: PlanReport[];
64
+ }>;
65
+ /** Operations that failed to compile. */
66
+ errors: Array<{
67
+ operation: string;
68
+ message: string;
69
+ }>;
70
+ }
@@ -0,0 +1,7 @@
1
+ import { GraphQLSchema } from 'graphql';
2
+ import { GraphModel } from '../model/types.js';
3
+ /**
4
+ * Every `@customResolver(requires:)` is a valid selection on its type and
5
+ * does not require custom fields (they are computed after the read).
6
+ */
7
+ export declare function checkCustomRequires(model: GraphModel, schema: GraphQLSchema): void;
@@ -0,0 +1,10 @@
1
+ import { GraphModel } from '../model/types.js';
2
+ import { DatabaseErrorEvent } from '../options.js';
3
+ export interface DatabaseErrorEnv {
4
+ model: GraphModel;
5
+ /** Hide database error details from clients (the `maskErrors` option). */
6
+ maskErrors: boolean;
7
+ onError: ((event: DatabaseErrorEvent) => void) | undefined;
8
+ }
9
+ /** The error to throw for `err`, raised while `field` ran. */
10
+ export declare function databaseError(env: DatabaseErrorEnv, field: string, err: unknown): unknown;
@@ -0,0 +1,35 @@
1
+ import { DocumentNode, ExecutionResult, GraphQLSchema, OperationDefinitionNode, ValidationRule } from 'graphql';
2
+ import { OperationManifest } from '../codegen.js';
3
+ import { DocumentGuards } from '../guards.js';
4
+ import { ExecuteArgs } from '../options.js';
5
+ export interface DocumentsOptions {
6
+ guards: DocumentGuards | false;
7
+ persistedOnly: boolean;
8
+ /** Approximate bytes the parsed document cache may hold. */
9
+ bytesMax: number;
10
+ /** The executable schema, built on first use. */
11
+ schema: () => GraphQLSchema;
12
+ /** The configured document guards as validation rules. */
13
+ rules: () => ValidationRule[];
14
+ }
15
+ export declare class Documents {
16
+ #private;
17
+ constructor(options: DocumentsOptions);
18
+ /**
19
+ * Register persisted operations by id. Every document is parsed and
20
+ * validated now, so a broken one fails at startup; at request time an
21
+ * id is looked up and executed without parsing or validating.
22
+ */
23
+ persist(operations: Record<string, string>): void;
24
+ /** Register a manifest's operations, without parsing or validating. */
25
+ load(manifest: OperationManifest): void;
26
+ /** A persisted operation's document, by id. */
27
+ persisted(id: string): DocumentNode | undefined;
28
+ /** The persisted id an operation node was registered under. */
29
+ persistedId(operation: OperationDefinitionNode): string | undefined;
30
+ /**
31
+ * The document `args` names: a persisted one by id, or `source` parsed
32
+ * and validated through the cache. An error result when there is none.
33
+ */
34
+ document(args: ExecuteArgs): DocumentNode | ExecutionResult;
35
+ }
@@ -0,0 +1,37 @@
1
+ import { GraphQLResolveInfo } from 'graphql';
2
+ import { OperationBudget } from '../execute/budget.js';
3
+ import { LoraGraphQLOptions } from '../options.js';
4
+ export interface OperationLimitsOptions {
5
+ operationTimeoutMs: number;
6
+ maxConcurrentStatements: number;
7
+ maxCost: number;
8
+ budget: LoraGraphQLOptions["budget"];
9
+ onCost: LoraGraphQLOptions["onCost"];
10
+ }
11
+ export declare class OperationLimits {
12
+ #private;
13
+ constructor(options: OperationLimitsOptions);
14
+ /** Mark `execution` as a root value `execute()` made. */
15
+ track(execution: object): void;
16
+ /** The estimated cost charged to an execution so far. */
17
+ spent(execution: object): number | undefined;
18
+ /**
19
+ * Charge `cost` to the operation: the limit holds per operation, so
20
+ * aliasing a root field many times does not multiply it. A
21
+ * subscription is charged per event.
22
+ */
23
+ charge(field: string, cost: number, context: unknown, info?: GraphQLResolveInfo): void;
24
+ /**
25
+ * The deadline and statement slots of the query `info` belongs to,
26
+ * started by its first root field. Subscriptions run indefinitely and
27
+ * are bounded per statement only.
28
+ */
29
+ operationBudget(context: unknown, info: GraphQLResolveInfo | undefined): OperationBudget | undefined;
30
+ /**
31
+ * A root field is done. When none is left in flight after the current
32
+ * turn (graphql-js starts a query's root fields together, and the next
33
+ * root field of a mutation in a microtask), the operation is over: a
34
+ * context reused for another request starts a fresh budget.
35
+ */
36
+ leaveOperation(context: object, info: GraphQLResolveInfo, budget: OperationBudget): void;
37
+ }
@@ -0,0 +1,33 @@
1
+ import { GraphQLError, DocumentNode, ExecutionResult, GraphQLResolveInfo, OperationDefinitionNode } from 'graphql';
2
+ import { RootKind } from '../compile/read/types.js';
3
+ import { SelectionContext } from '../compile/selection.js';
4
+ import { QueryResult, Statement } from '../driver.js';
5
+ import { LoraTransaction } from '../execute/transaction.js';
6
+ import { GraphModel, NodeType, SearchIndex } from '../model/types.js';
7
+ /** The read root field of a node type that `fieldName` names, if any. */
8
+ export declare function rootOf(model: GraphModel, fieldName: string): {
9
+ kind: RootKind;
10
+ node: NodeType;
11
+ } | undefined;
12
+ export declare function searchOf(model: GraphModel, fieldName: string): {
13
+ node: NodeType;
14
+ index: SearchIndex;
15
+ connection: boolean;
16
+ } | undefined;
17
+ /**
18
+ * A mutation with several root fields; a fragment at the root counts as
19
+ * several, since it may hold more than one.
20
+ */
21
+ export declare function multiRoot(operation: OperationDefinitionNode): boolean;
22
+ export declare function isDocument(value: DocumentNode | ExecutionResult): value is DocumentNode;
23
+ /**
24
+ * The type of the operation `operationName` selects; undefined when it
25
+ * selects none, which graphql then reports.
26
+ */
27
+ export declare function operationType(document: DocumentNode, operationName: string | null | undefined): "query" | "mutation" | "subscription" | undefined;
28
+ /** A variable graphql-js could not coerce: a request error with no code. */
29
+ export declare function isVariableError(e: GraphQLError): boolean;
30
+ export declare function findOperation(doc: DocumentNode, operationName: string | undefined): OperationDefinitionNode;
31
+ export declare function infoContext(info: GraphQLResolveInfo): SelectionContext;
32
+ /** Run statements one after the other in a caller-owned transaction. */
33
+ export declare function runInOrder(tx: LoraTransaction, statements: Statement[]): Promise<QueryResult[]>;
@@ -0,0 +1,13 @@
1
+ import { GraphQLResolveInfo } from 'graphql';
2
+ /** A request's timing entry for a root field, created on first use. */
3
+ export declare function timingEntry(timing: Map<string, {
4
+ totalMs: number;
5
+ databaseMs: number;
6
+ }>, key: string): {
7
+ totalMs: number;
8
+ databaseMs: number;
9
+ };
10
+ /** The response key of the root field `info` belongs to. */
11
+ export declare function rootKey(info: GraphQLResolveInfo | undefined): string | undefined;
12
+ /** Milliseconds, to a hundredth. */
13
+ export declare const ms: (value: number) => number;
@@ -0,0 +1,17 @@
1
+ import { GraphQLEnumType, GraphQLObjectType } from 'graphql';
2
+ import { GraphModel, ScalarField } from '../model/types.js';
3
+ import { BaseTypes } from './base.js';
4
+ /** Fields whose values can be aggregated: ordered scalars, not lists. */
5
+ export declare const aggregatable: (f: ScalarField) => boolean;
6
+ export declare const isNumeric: (f: ScalarField) => boolean;
7
+ /** The memoized `<Scalar>Aggregate` type of a field, shared by every aggregate. */
8
+ export declare function buildAggregateFieldType(base: BaseTypes): (f: ScalarField) => GraphQLObjectType<any, any>;
9
+ export type AggregateFieldType = ReturnType<typeof buildAggregateFieldType>;
10
+ export declare function buildAggregates(model: GraphModel, base: BaseTypes, aggregateFieldType: AggregateFieldType): {
11
+ aggregates: Map<string, GraphQLObjectType<any, any>>;
12
+ groups: Map<string, {
13
+ field: GraphQLEnumType;
14
+ group: GraphQLObjectType;
15
+ }>;
16
+ };
17
+ export type AggregateTypes = ReturnType<typeof buildAggregates>;
@@ -0,0 +1,17 @@
1
+ import { GraphQLEnumType, GraphQLInputObjectType, GraphQLInterfaceType, GraphQLList, GraphQLNonNull, GraphQLObjectType, GraphQLInputType, GraphQLOutputType, GraphQLScalarType } from 'graphql';
2
+ import { GraphModel, ScalarField, ScalarType } from '../model/types.js';
3
+ import { SchemaHooks } from './hooks.js';
4
+ export declare const nonNull: <T extends GraphQLOutputType | GraphQLInputType>(t: T) => GraphQLNonNull<T>;
5
+ export declare const listOf: <T extends GraphQLOutputType | GraphQLInputType>(t: T) => GraphQLList<T>;
6
+ export declare function buildBaseTypes(model: GraphModel, hooks: SchemaHooks): {
7
+ sortDirection: GraphQLEnumType;
8
+ pageInfo: GraphQLObjectType<any, any>;
9
+ countFilter: GraphQLInputObjectType;
10
+ enums: Map<string, GraphQLEnumType>;
11
+ nodeInterface: GraphQLInterfaceType | undefined;
12
+ customScalar: (name: string) => GraphQLScalarType | undefined;
13
+ scalarType: (f: ScalarField) => GraphQLScalarType | GraphQLEnumType | GraphQLObjectType;
14
+ baseType: (type: ScalarType, enumName: string | undefined) => GraphQLScalarType | GraphQLEnumType | GraphQLObjectType;
15
+ scalarOutput: (f: ScalarField) => GraphQLOutputType;
16
+ };
17
+ export type BaseTypes = ReturnType<typeof buildBaseTypes>;
@@ -1,43 +1,4 @@
1
- import { GraphQLSchema, GraphQLFieldResolver, GraphQLResolveInfo, GraphQLScalarType } from 'graphql';
2
- import { RootKind } from '../compile/read.js';
3
- import { AbstractType, CustomField, CypherField, GraphModel, NodeType, ScalarField, SearchIndex } from '../model/types.js';
4
- import { MutationResolver } from './mutations.js';
5
- /** One event of a generated subscription. */
6
- export interface ChangeEvent {
7
- operation: "CREATE" | "UPDATE" | "DELETE" | "CONNECT" | "DISCONNECT";
8
- key: unknown;
9
- /** When the write was committed, ISO-8601. */
10
- timestamp?: string | undefined;
11
- /** For CONNECT / DISCONNECT: the relationship and its other end. */
12
- relationship?: {
13
- field: string;
14
- type: string;
15
- relatedType: string;
16
- relatedKey: unknown;
17
- } | undefined;
18
- /** Stored properties before the write (`previousState: true`). */
19
- previous?: Record<string, unknown> | undefined;
20
- }
21
- export interface SchemaHooks {
22
- resolveAbstract: (abstract: AbstractType, info: GraphQLResolveInfo, context: unknown) => Promise<unknown>;
23
- subscribe: (node: NodeType, args: Record<string, unknown>, context: unknown) => AsyncIterable<ChangeEvent>;
24
- resolveChangedNode: (node: NodeType, event: ChangeEvent, info: GraphQLResolveInfo, context: unknown) => Promise<unknown>;
25
- /**
26
- * A `previousState` value as the subscriber may see it: throws when
27
- * field-level @authentication refuses it, applies masks by the claims.
28
- */
29
- previousValue: (node: NodeType, field: ScalarField, value: unknown, context: unknown) => unknown;
30
- /** Implementations of custom scalars, by name (the scalars option). */
31
- scalars?: Readonly<Record<string, GraphQLScalarType>> | undefined;
32
- /** The resolver of a `@customResolver` field (from the resolvers option). */
33
- customResolver: (node: NodeType, field: CustomField) => GraphQLFieldResolver<Record<string, unknown>, unknown>;
34
- resolveSearch: (node: NodeType, index: SearchIndex, info: GraphQLResolveInfo, context: unknown, connection: boolean) => Promise<unknown>;
35
- resolveRoot: RootResolver;
36
- resolveNode: NodeResolver;
37
- resolveCypher: CypherRootResolver;
38
- resolveMutation: MutationResolver;
39
- }
40
- export type CypherRootResolver = (field: CypherField, info: GraphQLResolveInfo, context: unknown) => Promise<unknown>;
41
- export type RootResolver = (kind: RootKind, node: NodeType, info: GraphQLResolveInfo, context: unknown) => Promise<unknown>;
42
- export type NodeResolver = (id: string, info: GraphQLResolveInfo, context: unknown) => Promise<unknown>;
1
+ import { GraphQLSchema } from 'graphql';
2
+ import { GraphModel } from '../model/types.js';
3
+ import { SchemaHooks } from './hooks.js';
43
4
  export declare function buildSchema(model: GraphModel, hooks: SchemaHooks): GraphQLSchema;
@@ -0,0 +1,10 @@
1
+ import { GraphQLInputObjectType, GraphQLInputType } from 'graphql';
2
+ import { GraphModel, NodeType, RelationshipField, ScalarField } from '../model/types.js';
3
+ import { BaseTypes } from './base.js';
4
+ export declare function buildFilters(model: GraphModel, base: BaseTypes): {
5
+ inputTypeOf: (f: ScalarField) => GraphQLInputType;
6
+ whereOf: (typeName: string) => GraphQLInputObjectType;
7
+ polymorphic: (rel: RelationshipField) => boolean;
8
+ connectionWhere: (node: NodeType, rel: RelationshipField) => GraphQLInputObjectType;
9
+ };
10
+ export type Filters = ReturnType<typeof buildFilters>;
@@ -0,0 +1,42 @@
1
+ import { GraphQLFieldResolver, GraphQLResolveInfo, GraphQLScalarType } from 'graphql';
2
+ import { RootKind } from '../compile/read/types.js';
3
+ import { AbstractType, CustomField, CypherField, NodeType, ScalarField, SearchIndex } from '../model/types.js';
4
+ import { MutationResolver } from './mutations.js';
5
+ /** One event of a generated subscription. */
6
+ export interface ChangeEvent {
7
+ operation: "CREATE" | "UPDATE" | "DELETE" | "CONNECT" | "DISCONNECT";
8
+ key: unknown;
9
+ /** When the write was committed, ISO-8601. */
10
+ timestamp?: string | undefined;
11
+ /** For CONNECT / DISCONNECT: the relationship and its other end. */
12
+ relationship?: {
13
+ field: string;
14
+ type: string;
15
+ relatedType: string;
16
+ relatedKey: unknown;
17
+ } | undefined;
18
+ /** Stored properties before the write (`previousState: true`). */
19
+ previous?: Record<string, unknown> | undefined;
20
+ }
21
+ export interface SchemaHooks {
22
+ resolveAbstract: (abstract: AbstractType, info: GraphQLResolveInfo, context: unknown) => Promise<unknown>;
23
+ subscribe: (node: NodeType, args: Record<string, unknown>, context: unknown) => AsyncIterable<ChangeEvent>;
24
+ resolveChangedNode: (node: NodeType, event: ChangeEvent, info: GraphQLResolveInfo, context: unknown) => Promise<unknown>;
25
+ /**
26
+ * A `previousState` value as the subscriber may see it: throws when
27
+ * field-level @authentication refuses it, applies masks by the claims.
28
+ */
29
+ previousValue: (node: NodeType, field: ScalarField, value: unknown, context: unknown) => unknown;
30
+ /** Implementations of custom scalars, by name (the scalars option). */
31
+ scalars?: Readonly<Record<string, GraphQLScalarType>> | undefined;
32
+ /** The resolver of a `@customResolver` field (from the resolvers option). */
33
+ customResolver: (node: NodeType, field: CustomField) => GraphQLFieldResolver<Record<string, unknown>, unknown>;
34
+ resolveSearch: (node: NodeType, index: SearchIndex, info: GraphQLResolveInfo, context: unknown, connection: boolean) => Promise<unknown>;
35
+ resolveRoot: RootResolver;
36
+ resolveNode: NodeResolver;
37
+ resolveCypher: CypherRootResolver;
38
+ resolveMutation: MutationResolver;
39
+ }
40
+ export type CypherRootResolver = (field: CypherField, info: GraphQLResolveInfo, context: unknown) => Promise<unknown>;
41
+ export type RootResolver = (kind: RootKind, node: NodeType, info: GraphQLResolveInfo, context: unknown) => Promise<unknown>;
42
+ export type NodeResolver = (id: string, info: GraphQLResolveInfo, context: unknown) => Promise<unknown>;