@simtlix/simfinity-core 3.12.0 → 3.14.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 +15 -3
- package/package.json +2 -1
- package/src/const/QLQuantifier.js +21 -0
- package/src/index.js +2 -0
- package/src/metadata.js +24 -0
- package/src/query-emptiness.js +2 -2
- package/src/query-frames.js +510 -0
- package/src/query-limits.js +9 -2
- package/src/query-operators.js +23 -9
- package/src/query-plan.js +236 -155
- package/src/record-version.js +235 -0
- package/src/runtime.js +664 -168
- package/types/index.d.ts +181 -23
package/types/index.d.ts
CHANGED
|
@@ -12,9 +12,25 @@ import type {
|
|
|
12
12
|
|
|
13
13
|
/** The filter operator enum; its values are the {@link QueryOperator} names. */
|
|
14
14
|
export const QLOperator: GraphQLEnumType;
|
|
15
|
+
/** The collection and reference quantifier enum. */
|
|
16
|
+
export const QLQuantifier: GraphQLEnumType;
|
|
15
17
|
export const QLSort: GraphQLInputObjectType;
|
|
16
18
|
export const QLValue: GraphQLScalarType<unknown, unknown>;
|
|
17
19
|
|
|
20
|
+
/**
|
|
21
|
+
* The scalar of the `version` field that Simfinity adds to a type that declares optimistic
|
|
22
|
+
* concurrency (see {@link ConcurrencyDeclaration}). It holds safe integers from 1 to
|
|
23
|
+
* {@link MAX_RECORD_VERSION}, a JSON number on the wire: a string, a float, 0, a negative number and an
|
|
24
|
+
* unsafe integer fail GraphQL coercion. A client sends the version it read back unchanged in updates
|
|
25
|
+
* and deletes, and Simfinity advances it. Only the managed field may use it in a type, which
|
|
26
|
+
* `createSchema()` and `describeModels()` enforce with `INVALID_MODEL` (400); a registered mutation or
|
|
27
|
+
* custom query may use it in its own input and output types. Import it from the facade the application
|
|
28
|
+
* uses: the protection depends on one copy of core per process.
|
|
29
|
+
*/
|
|
30
|
+
export const RecordVersion: GraphQLScalarType;
|
|
31
|
+
/** The highest version, `Number.MAX_SAFE_INTEGER`. The version of a record never goes past it. */
|
|
32
|
+
export const MAX_RECORD_VERSION: number;
|
|
33
|
+
|
|
18
34
|
/**
|
|
19
35
|
* A `QLOperator` value. The operators of 3.7.0 are `EQ`, `NE`, `LT`, `LTE`, `GT`, `GTE`, `BTW`, `IN`,
|
|
20
36
|
* `NIN` and `LIKE`. The literal text operators take a non-null string without U+0000 on a `String`
|
|
@@ -31,19 +47,57 @@ export const QLValue: GraphQLScalarType<unknown, unknown>;
|
|
|
31
47
|
* embedded object or one whose stored members are all empty by these rules; the record identity is
|
|
32
48
|
* never empty. The target's `id` right after a reference is empty exactly when the reference is,
|
|
33
49
|
* including when the target is missing or hidden by its `find` scope. A path that continues inside an
|
|
34
|
-
* embedded list
|
|
50
|
+
* embedded list fails with `INVALID_FILTER_PATH`; shorthand through a collection excludes emptiness
|
|
51
|
+
* on a leaf, so use an explicit group. With an adapter that declares
|
|
35
52
|
* `queryFeatures.referenceEmptiness: true`, a path may also cross single references and end at a
|
|
36
53
|
* reference or a collection, and an embedded object may have reference and collection members: a
|
|
37
54
|
* reference is empty when no record it points to exists that the target's `find` scope admits for
|
|
38
55
|
* the caller, a collection when no such child exists, and a hidden record on the way reads as
|
|
39
56
|
* missing; constructs that middleware and scopes add read stored data. With any other adapter they
|
|
40
|
-
* fail with `UNSUPPORTED_QUERY`. A term or group condition without a path tests the field itself
|
|
57
|
+
* fail with `UNSUPPORTED_QUERY`. A term or group condition without a path tests the field itself, except that every term
|
|
58
|
+
* of a quantified relation filter needs a non-empty element-relative path.
|
|
41
59
|
*/
|
|
42
60
|
export type QueryOperator =
|
|
43
61
|
| 'EQ' | 'NE' | 'LT' | 'LTE' | 'GT' | 'GTE' | 'BTW' | 'IN' | 'NIN' | 'LIKE'
|
|
44
62
|
| 'ILIKE' | 'STARTS_WITH' | 'ISTARTS_WITH' | 'ENDS_WITH' | 'IENDS_WITH' | 'IEQ'
|
|
45
63
|
| 'IS_EMPTY' | 'IS_NOT_EMPTY';
|
|
46
64
|
|
|
65
|
+
/** The quantifier applied to the elements visible in a collection or reference frame. */
|
|
66
|
+
export type QueryQuantifier = 'ANY' | 'ALL' | 'NONE';
|
|
67
|
+
|
|
68
|
+
/** A condition inside a filter group, with paths relative to the current frame. */
|
|
69
|
+
export interface QLFilterCondition {
|
|
70
|
+
field: string;
|
|
71
|
+
operator?: QueryOperator | null;
|
|
72
|
+
value?: any;
|
|
73
|
+
path?: string | null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** Recursive Boolean groups and quantified frames. */
|
|
77
|
+
export interface QLFilterGroup {
|
|
78
|
+
conditions?: Array<QLFilterCondition | null> | null;
|
|
79
|
+
AND?: Array<QLFilterGroup | null> | null;
|
|
80
|
+
OR?: Array<QLFilterGroup | null> | null;
|
|
81
|
+
ANY?: Array<QLQuantifiedGroup | null> | null;
|
|
82
|
+
ALL?: Array<QLQuantifiedGroup | null> | null;
|
|
83
|
+
NONE?: Array<QLQuantifiedGroup | null> | null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** A frame path ends at a collection or single reference without crossing a list; inner paths are element-relative. */
|
|
87
|
+
export interface QLQuantifiedGroup extends QLFilterGroup {
|
|
88
|
+
path: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** A quantified field filter may omit terms; every supplied term needs a non-empty element-relative path. */
|
|
92
|
+
export interface QLTypeFilterExpression {
|
|
93
|
+
quantifier?: QueryQuantifier | null;
|
|
94
|
+
terms?: Array<{
|
|
95
|
+
operator?: QueryOperator | null;
|
|
96
|
+
value?: any;
|
|
97
|
+
path?: string | null;
|
|
98
|
+
} | null> | null;
|
|
99
|
+
}
|
|
100
|
+
|
|
47
101
|
/**
|
|
48
102
|
* A condition of a {@link FilterGroup}, as the `QLFilterCondition` input takes it: the field it
|
|
49
103
|
* tests, its {@link QueryOperator} (`EQ` when omitted) and its value. On an object field, `path`
|
|
@@ -57,8 +111,11 @@ export interface FilterCondition {
|
|
|
57
111
|
path?: string;
|
|
58
112
|
}
|
|
59
113
|
|
|
60
|
-
/** A `QLFilterGroup` value: flat conditions
|
|
114
|
+
/** A `QLFilterGroup` value: flat conditions, Boolean groups and element-relative quantified groups. */
|
|
61
115
|
export interface FilterGroup {
|
|
116
|
+
ANY?: QLQuantifiedGroup[];
|
|
117
|
+
ALL?: QLQuantifiedGroup[];
|
|
118
|
+
NONE?: QLQuantifiedGroup[];
|
|
62
119
|
AND?: FilterGroup[];
|
|
63
120
|
OR?: FilterGroup[];
|
|
64
121
|
conditions?: FilterCondition[];
|
|
@@ -83,6 +140,15 @@ export interface QueryFeatures {
|
|
|
83
140
|
* must apply each target scope in `scopes`; constructs without a marker read stored data.
|
|
84
141
|
*/
|
|
85
142
|
referenceEmptiness?: boolean | null | undefined;
|
|
143
|
+
/**
|
|
144
|
+
* Whether the adapter compiles quantified frames and their scoped joins. Requires
|
|
145
|
+
* `referenceEmptiness: true`; undefined or null means false. Invalid declarations fail with
|
|
146
|
+
* `INVALID_QUERY_FEATURES` (500). Client markers have frame-relative scope keys; compilers must
|
|
147
|
+
* apply frame scopes before quantification and honour scoped joins/aggregate anchors. Without
|
|
148
|
+
* this flag explicit quantified forms fail with `UNSUPPORTED_QUERY`; collection filters keep
|
|
149
|
+
* legacy joins. All adapters reject list sorts through collections, including count mode.
|
|
150
|
+
*/
|
|
151
|
+
quantifiers?: boolean | null | undefined;
|
|
86
152
|
}
|
|
87
153
|
|
|
88
154
|
export interface ModelRegistration {
|
|
@@ -99,7 +165,8 @@ export interface FieldDescription {
|
|
|
99
165
|
itemRequired: boolean;
|
|
100
166
|
unique: boolean;
|
|
101
167
|
readOnly: boolean;
|
|
102
|
-
|
|
168
|
+
/** `'Version'` is the managed version field of a type that declares optimistic concurrency (`version: true`). */
|
|
169
|
+
scalar?: 'ID' | 'String' | 'Int' | 'Float' | 'Boolean' | 'DateTime' | 'Enum' | 'Version';
|
|
103
170
|
values?: string[];
|
|
104
171
|
enumValues?: { name: string; value: unknown }[];
|
|
105
172
|
target?: string;
|
|
@@ -107,6 +174,12 @@ export interface FieldDescription {
|
|
|
107
174
|
fields?: FieldDescription[];
|
|
108
175
|
private?: boolean;
|
|
109
176
|
inferred?: boolean;
|
|
177
|
+
/**
|
|
178
|
+
* Set on the managed version field of a type that declares optimistic concurrency, which
|
|
179
|
+
* `describeModels()` appends after the type's own fields: `{ name: 'version', scalar: 'Version',
|
|
180
|
+
* required: true, readOnly: true, version: true }`.
|
|
181
|
+
*/
|
|
182
|
+
version?: true;
|
|
110
183
|
}
|
|
111
184
|
export interface ModelDescription {
|
|
112
185
|
entities: Array<{
|
|
@@ -121,6 +194,13 @@ export interface ModelDescription {
|
|
|
121
194
|
* fields are left out of every entity and embedded type, and the types only they reach are not
|
|
122
195
|
* described. Throws `INVALID_MODEL` (400) for an invalid `extensions.virtual` declaration, as
|
|
123
196
|
* `createSchema()` does (see {@link VirtualFieldOptions}).
|
|
197
|
+
*
|
|
198
|
+
* A type that declares optimistic concurrency (see {@link ConcurrencyDeclaration}) is described with
|
|
199
|
+
* its version field last, before `createSchema()` has added it and after, and the call throws
|
|
200
|
+
* `INVALID_MODEL` (400) for an invalid declaration, for a field named `version` that Simfinity did not
|
|
201
|
+
* add, for a reference stored under `version` (`connectionField: 'version'`), for a collection of
|
|
202
|
+
* such items that links through `version`, for such a type used as an embedded value, and for any
|
|
203
|
+
* other field typed {@link RecordVersion}.
|
|
124
204
|
*/
|
|
125
205
|
export function describeModels(registrations: ModelRegistration[]): ModelDescription;
|
|
126
206
|
/**
|
|
@@ -312,6 +392,19 @@ export type ScopeFunction<Model = any, Session = any> = (params: ScopeParams<Mod
|
|
|
312
392
|
* was changed.
|
|
313
393
|
*/
|
|
314
394
|
export type TypeScopes<Model = any, Session = any> = Partial<Record<ScopeOperation, ScopeFunction<Model, Session>>>;
|
|
395
|
+
/**
|
|
396
|
+
* Value of a type's `extensions.concurrency`: the entity is protected by optimistic concurrency.
|
|
397
|
+
* Simfinity adds a read-only `version: RecordVersion!` field to the type, which starts at 1 and grows
|
|
398
|
+
* by 1 with each accepted write; a client sends the version it read back in updates and deletes, and a
|
|
399
|
+
* write at another version fails with `VERSION_CONFLICT` (409). The only valid value is
|
|
400
|
+
* `{ mode: 'optimistic' }`: `null`, an array, another mode or an extra key throws `INVALID_MODEL`
|
|
401
|
+
* (400). So does a type that is not an entity, one used as an embedded value, one that already has a
|
|
402
|
+
* field named `version` (or a field stored under that name), and an adapter that does not declare
|
|
403
|
+
* `writeFeatures.optimisticConcurrency`.
|
|
404
|
+
*/
|
|
405
|
+
export interface ConcurrencyDeclaration {
|
|
406
|
+
mode: 'optimistic';
|
|
407
|
+
}
|
|
315
408
|
|
|
316
409
|
/**
|
|
317
410
|
* Process-wide limits for generated add, update and state-action mutations. Any other option,
|
|
@@ -342,11 +435,17 @@ export interface QueryLimitsOptions {
|
|
|
342
435
|
/** Positive safe integer; defaults to 1000. Unpaged lists use min(100, maxPageSize). */
|
|
343
436
|
maxPageSize?: number;
|
|
344
437
|
/**
|
|
345
|
-
* Positive safe integer; defaults to 10. The most
|
|
346
|
-
* client's
|
|
347
|
-
*
|
|
438
|
+
* Positive safe integer; defaults to 10. The most compiled frames and scoped joins that the
|
|
439
|
+
* client's conditions may need in one list, aggregate or collection-field call; more fail with
|
|
440
|
+
* `FILTER_DEPTH_EXCEEDED` (400), after every client 400 check and before middleware. Units count
|
|
441
|
+
* independently of markers: shorthand per group/prefix, explicit frames separately, scoped joins
|
|
442
|
+
* per containing frame/path/scope chain and emptiness frames per path/shape. Trusted units do
|
|
443
|
+
* not count toward this total. Named views check client arguments and their `where` groups
|
|
444
|
+
* against separate budgets of the same size; the `where` budget runs after middleware.
|
|
348
445
|
*/
|
|
349
446
|
maxReferenceFrames?: number;
|
|
447
|
+
/** Positive safe integer; defaults to 3. Maximum client/trusted collection or reference frames on one chain. */
|
|
448
|
+
maxFrameNesting?: number;
|
|
350
449
|
}
|
|
351
450
|
|
|
352
451
|
/**
|
|
@@ -501,6 +600,15 @@ export interface DatabaseAdapter<Model = any, Session = any> {
|
|
|
501
600
|
* collections also needs `referenceEmptiness: true`, and fails with `UNSUPPORTED_QUERY` without it.
|
|
502
601
|
*/
|
|
503
602
|
queryFeatures?: QueryFeatures | null | undefined;
|
|
603
|
+
/**
|
|
604
|
+
* Optional. Declares the write features this adapter implements. `createRuntime` reads it once and
|
|
605
|
+
* throws `INVALID_WRITE_FEATURES` (500) unless it is undefined, null or an object whose
|
|
606
|
+
* `optimisticConcurrency`, if present, is a boolean. A schema with a type that declares
|
|
607
|
+
* `extensions.concurrency` (see {@link ConcurrencyDeclaration}) throws `INVALID_MODEL` (400) unless
|
|
608
|
+
* the adapter declares `optimisticConcurrency: true`, which commits it to the `options.expectedVersion`
|
|
609
|
+
* contract of `update` and `delete` and to the requirements on `find` below.
|
|
610
|
+
*/
|
|
611
|
+
writeFeatures?: { optimisticConcurrency?: boolean } | null | undefined;
|
|
504
612
|
bind?(runtime: Pick<Runtime<Model, Session>, 'getModel' | 'getType' | 'getRegistrations'>): void;
|
|
505
613
|
validateRegistration?(registration: RuntimeRegistration<Model, Session>): void;
|
|
506
614
|
/**
|
|
@@ -509,10 +617,16 @@ export interface DatabaseAdapter<Model = any, Session = any> {
|
|
|
509
617
|
* must never be stored: an adapter that builds storage from a type's fields skips each field for
|
|
510
618
|
* which {@link isVirtualField} returns true, on the types its embedded fields reach as well, or
|
|
511
619
|
* builds it from `describeModels(registrations)`, which leaves them out. Generated writes, filters,
|
|
512
|
-
* sorts and aggregations never name a virtual field; a controller hook can still assign one.
|
|
620
|
+
* sorts and aggregations never name a virtual field; a controller hook can still assign one. The
|
|
621
|
+
* version field of a type that declares optimistic concurrency is injected after `prepare()`, so a
|
|
622
|
+
* type here may not have it yet; `describeModels(registrations)` describes it either way.
|
|
513
623
|
*/
|
|
514
624
|
prepare?(registrations: RuntimeRegistration<Model, Session>[], options: { createCollection: boolean }): void;
|
|
515
|
-
/**
|
|
625
|
+
/**
|
|
626
|
+
* Creates the model of a registered type. Its fields include virtual fields; see `prepare()`. A type
|
|
627
|
+
* that declares optimistic concurrency already has its injected version field here, which
|
|
628
|
+
* `describeModels(registrations)` describes as well.
|
|
629
|
+
*/
|
|
516
630
|
createModel(type: GraphQLObjectType, callback: ((model: Model) => void) | null | undefined, options: { createCollection: boolean }): Model;
|
|
517
631
|
/**
|
|
518
632
|
* Casts a reference or batch key to the stored identifier type. Throw a `SimfinityError` with
|
|
@@ -574,8 +688,31 @@ export interface DatabaseAdapter<Model = any, Session = any> {
|
|
|
574
688
|
*/
|
|
575
689
|
readByIdIsInert?(model: Model): boolean;
|
|
576
690
|
prepareUpdate(set: Record<string, any>, unset: Record<string, string>): any;
|
|
577
|
-
|
|
578
|
-
|
|
691
|
+
/**
|
|
692
|
+
* With `options.expectedVersion`, one atomic write that matches the ID and a stored version equal to
|
|
693
|
+
* it (on MongoDB a missing or null stored version counts as 1), applies `changes`, sets the version
|
|
694
|
+
* to `expectedVersion + 1` and returns the updated record. When nothing matches, or when
|
|
695
|
+
* `expectedVersion >= MAX_RECORD_VERSION` and the write is skipped, it reads the record by ID in the
|
|
696
|
+
* same session: it returns null for a missing one, throws `VERSION_CONFLICT` (409) when the stored
|
|
697
|
+
* version differs, `VERSION_EXHAUSTED` (409) when stored and expected are `MAX_RECORD_VERSION`, and
|
|
698
|
+
* returns null otherwise. Without `options.expectedVersion` it behaves as before. A wrapper must
|
|
699
|
+
* forward every argument, `options` included.
|
|
700
|
+
*/
|
|
701
|
+
update(model: Model, id: any, changes: any, session?: Session, options?: { expectedVersion?: number }): any;
|
|
702
|
+
/**
|
|
703
|
+
* With `options.expectedVersion`, one atomic delete that matches the ID and the version, and returns
|
|
704
|
+
* the deleted record. When nothing matches, it decides as `update` does, without the exhausted case:
|
|
705
|
+
* a delete does not advance the version, so a record at `MAX_RECORD_VERSION` is deleted like any
|
|
706
|
+
* other. Without it, it behaves as before. A wrapper must forward every argument, `options`
|
|
707
|
+
* included.
|
|
708
|
+
*/
|
|
709
|
+
delete(model: Model, id: any, session?: Session, options?: { expectedVersion?: number }): any;
|
|
710
|
+
/**
|
|
711
|
+
* An adapter that declares `writeFeatures.optimisticConcurrency` must run `find` inside the given
|
|
712
|
+
* `session`, honor `options.requiredId` and accept `options.context`: the runtime reads through
|
|
713
|
+
* `find` with the caller's session to check, before a hook runs, whether the caller can read a
|
|
714
|
+
* record whose version is stale.
|
|
715
|
+
*/
|
|
579
716
|
find(model: Model, type: GraphQLObjectType, args: any, session?: Session | null, options?: { requiredId?: any; context?: any }): any;
|
|
580
717
|
count(model: Model, type: GraphQLObjectType, args: any, session?: Session | null): Promise<number> | number;
|
|
581
718
|
aggregate(model: Model, type: GraphQLObjectType, args: any, session?: Session | null): any;
|
|
@@ -618,6 +755,9 @@ export interface DatabaseAdapter<Model = any, Session = any> {
|
|
|
618
755
|
}
|
|
619
756
|
export function createRuntime<Model = any, Session = any>(adapter: DatabaseAdapter<Model, Session>): Runtime<Model, Session>;
|
|
620
757
|
|
|
758
|
+
/** Scoped single-reference joins, keyed by a dotted prefix relative to the containing frame. */
|
|
759
|
+
export type QueryJoins = Record<string, QueryPredicate | null>;
|
|
760
|
+
|
|
621
761
|
/**
|
|
622
762
|
* `operator` is a {@link QueryOperator}; the value of a text operator is a validated string. For
|
|
623
763
|
* `IS_EMPTY` and `IS_NOT_EMPTY` the value is null, and `path` may end at an embedded object, an
|
|
@@ -626,17 +766,31 @@ export function createRuntime<Model = any, Session = any>(adapter: DatabaseAdapt
|
|
|
626
766
|
* references and end at a reference or a collection.
|
|
627
767
|
*
|
|
628
768
|
* `scopes` exists only on such an emptiness predicate from a client, and only for a compiler that
|
|
629
|
-
* declares `referenceEmptiness: true`. It has one key per dotted path
|
|
769
|
+
* declares `referenceEmptiness: true`. It has one key per dotted path relative to its frame: each
|
|
630
770
|
* single reference the path crosses (a scoped join, which admits the target only where the scope
|
|
631
771
|
* admits it), the end when it is a reference or a collection, and each reference and collection
|
|
632
772
|
* member of an embedded object (frames, which keep only the records the scope admits). Each value is
|
|
633
773
|
* the target's `find` scope as a predicate in the target's own frame, or null when the scope added
|
|
634
774
|
* nothing; after a scoped crossing, a null hop still correlates through that scoped join. Without
|
|
635
|
-
* `scopes` the predicate reads stored data, through plain joins.
|
|
775
|
+
* `scopes` the predicate reads stored data, through plain joins. `joins` carries the scopes of
|
|
776
|
+
* single references crossed inside a client frame, with keys relative to the containing frame.
|
|
777
|
+
* A `quantified` node selects elements with `ANY`, `ALL` or `NONE`, applying `scope` before `where`;
|
|
778
|
+
* both predicates use paths relative to the element, and null means no restriction. Empty elements
|
|
779
|
+
* give ANY false, ALL/NONE true; scope is never negated, and frames never multiply roots. `anchor` is
|
|
780
|
+
* an aggregate's legacy join chain; when present, `path` is relative to it and `joins` is absent.
|
|
636
781
|
*/
|
|
637
782
|
export type QueryPredicate =
|
|
638
|
-
| { kind: 'predicate'; path: string[]; operator: string; value: any; scopes?: Record<string, QueryPredicate | null
|
|
639
|
-
| { kind: 'and' | 'or'; terms: QueryPredicate[] }
|
|
783
|
+
| { kind: 'predicate'; path: string[]; operator: string; value: any; scopes?: Record<string, QueryPredicate | null>; joins?: QueryJoins }
|
|
784
|
+
| { kind: 'and' | 'or'; terms: QueryPredicate[] }
|
|
785
|
+
| {
|
|
786
|
+
kind: 'quantified';
|
|
787
|
+
quantifier: QueryQuantifier;
|
|
788
|
+
path: string[];
|
|
789
|
+
where: QueryPredicate | null;
|
|
790
|
+
scope: QueryPredicate | null;
|
|
791
|
+
joins?: QueryJoins;
|
|
792
|
+
anchor?: string[];
|
|
793
|
+
};
|
|
640
794
|
export interface QueryPlan {
|
|
641
795
|
entity: string;
|
|
642
796
|
where: QueryPredicate | null;
|
|
@@ -659,8 +813,8 @@ export interface QueryPlan {
|
|
|
659
813
|
* value inside an embedded list or a collection, `INVALID_FILTER_OPERATOR` for an embedded type that
|
|
660
814
|
* reaches itself through single embedded members, `INVALID_FILTER_VALUE` for a value that is not
|
|
661
815
|
* omitted or null, and `UNSUPPORTED_QUERY` for a reference or collection on the path or among the
|
|
662
|
-
* members. A term without a path (omitted, null or `""`) and a group
|
|
663
|
-
* the field itself. For other operators, a filter path of more than one segment that ends at an
|
|
816
|
+
* members. A nonquantified emptiness term without a path (omitted, null or `""`) and a group
|
|
817
|
+
* condition without a path test the field itself; quantified filter terms always need a path. For other operators, a filter path of more than one segment that ends at an
|
|
664
818
|
* object fails with `INVALID_FILTER_PATH`, as on MongoDB; a bare object field keeps
|
|
665
819
|
* `MISSING_FILTER_PATH`.
|
|
666
820
|
*
|
|
@@ -669,18 +823,22 @@ export interface QueryPlan {
|
|
|
669
823
|
* reads a reference or collection member, fails with `UNSUPPORTED_QUERY` where the order above has
|
|
670
824
|
* `UNSUPPORTED_QUERY` for references; when it is true, such a condition plans with stored semantics,
|
|
671
825
|
* unless its term or group condition carries a client scope marker that the runtime filled, which
|
|
672
|
-
* becomes the predicate's `scopes`.
|
|
826
|
+
* becomes the predicate's `scopes`. `quantifiers` has the same default rule and requires reference
|
|
827
|
+
* emptiness; enabled collection filters emit quantified nodes, with per-group/prefix correlation,
|
|
828
|
+
* element-relative scopes/joins and aggregate anchors beyond legacy J joins. `__scope`, `__implicit`
|
|
829
|
+
* and `__anchor` are reserved internal input metadata. A marker not filled for every path fails
|
|
673
830
|
* with `DETACHED_CLIENT_FILTER` (500).
|
|
674
831
|
*/
|
|
675
|
-
export function createQueryPlan(models: ModelDescription, entityName: string, input?: Record<string, any>, options?: { mode?: QueryPlan['mode']; operators?: Iterable<string>; referenceEmptiness?: boolean }): QueryPlan;
|
|
832
|
+
export function createQueryPlan(models: ModelDescription, entityName: string, input?: Record<string, any>, options?: { mode?: QueryPlan['mode']; operators?: Iterable<string>; referenceEmptiness?: boolean; quantifiers?: boolean }): QueryPlan;
|
|
676
833
|
export function resolveModelPath(models: ModelDescription, entityName: string, path: string | string[]): FieldDescription[];
|
|
677
834
|
|
|
678
835
|
/**
|
|
679
836
|
* Process-wide. `maxPageSize` (default 1000) caps page sizes. `maxReferenceFrames` (default 10) caps,
|
|
680
|
-
* per list, aggregate or collection-field call, the
|
|
681
|
-
*
|
|
682
|
-
*
|
|
683
|
-
*
|
|
837
|
+
* per list, aggregate or collection-field call, the compiled frames and scoped joins a client's
|
|
838
|
+
* conditions need. Named views check client arguments and `where` groups separately. `maxFrameNesting` (default 3) caps nested frames along one chain in client and
|
|
839
|
+
* trusted constructs. Exceeding either frame limit fails with `FILTER_DEPTH_EXCEEDED` (400). Each
|
|
840
|
+
* option must be a positive safe integer, or the call throws `INVALID_QUERY_LIMITS` (400) and keeps
|
|
841
|
+
* every current limit; an omitted option takes its default again.
|
|
684
842
|
*/
|
|
685
843
|
export function configureQueryLimits(options?: QueryLimitsOptions): void;
|
|
686
844
|
/**
|