@simtlix/simfinity-core 3.13.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 +7 -3
- package/package.json +1 -1
- package/src/const/QLQuantifier.js +21 -0
- package/src/index.js +1 -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/runtime.js +241 -122
- package/types/index.d.ts +97 -18
package/types/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ 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
|
|
|
@@ -45,19 +47,57 @@ export const MAX_RECORD_VERSION: number;
|
|
|
45
47
|
* embedded object or one whose stored members are all empty by these rules; the record identity is
|
|
46
48
|
* never empty. The target's `id` right after a reference is empty exactly when the reference is,
|
|
47
49
|
* including when the target is missing or hidden by its `find` scope. A path that continues inside an
|
|
48
|
-
* 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
|
|
49
52
|
* `queryFeatures.referenceEmptiness: true`, a path may also cross single references and end at a
|
|
50
53
|
* reference or a collection, and an embedded object may have reference and collection members: a
|
|
51
54
|
* reference is empty when no record it points to exists that the target's `find` scope admits for
|
|
52
55
|
* the caller, a collection when no such child exists, and a hidden record on the way reads as
|
|
53
56
|
* missing; constructs that middleware and scopes add read stored data. With any other adapter they
|
|
54
|
-
* 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.
|
|
55
59
|
*/
|
|
56
60
|
export type QueryOperator =
|
|
57
61
|
| 'EQ' | 'NE' | 'LT' | 'LTE' | 'GT' | 'GTE' | 'BTW' | 'IN' | 'NIN' | 'LIKE'
|
|
58
62
|
| 'ILIKE' | 'STARTS_WITH' | 'ISTARTS_WITH' | 'ENDS_WITH' | 'IENDS_WITH' | 'IEQ'
|
|
59
63
|
| 'IS_EMPTY' | 'IS_NOT_EMPTY';
|
|
60
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
|
+
|
|
61
101
|
/**
|
|
62
102
|
* A condition of a {@link FilterGroup}, as the `QLFilterCondition` input takes it: the field it
|
|
63
103
|
* tests, its {@link QueryOperator} (`EQ` when omitted) and its value. On an object field, `path`
|
|
@@ -71,8 +111,11 @@ export interface FilterCondition {
|
|
|
71
111
|
path?: string;
|
|
72
112
|
}
|
|
73
113
|
|
|
74
|
-
/** A `QLFilterGroup` value: flat conditions
|
|
114
|
+
/** A `QLFilterGroup` value: flat conditions, Boolean groups and element-relative quantified groups. */
|
|
75
115
|
export interface FilterGroup {
|
|
116
|
+
ANY?: QLQuantifiedGroup[];
|
|
117
|
+
ALL?: QLQuantifiedGroup[];
|
|
118
|
+
NONE?: QLQuantifiedGroup[];
|
|
76
119
|
AND?: FilterGroup[];
|
|
77
120
|
OR?: FilterGroup[];
|
|
78
121
|
conditions?: FilterCondition[];
|
|
@@ -97,6 +140,15 @@ export interface QueryFeatures {
|
|
|
97
140
|
* must apply each target scope in `scopes`; constructs without a marker read stored data.
|
|
98
141
|
*/
|
|
99
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;
|
|
100
152
|
}
|
|
101
153
|
|
|
102
154
|
export interface ModelRegistration {
|
|
@@ -383,11 +435,17 @@ export interface QueryLimitsOptions {
|
|
|
383
435
|
/** Positive safe integer; defaults to 1000. Unpaged lists use min(100, maxPageSize). */
|
|
384
436
|
maxPageSize?: number;
|
|
385
437
|
/**
|
|
386
|
-
* Positive safe integer; defaults to 10. The most
|
|
387
|
-
* client's
|
|
388
|
-
*
|
|
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.
|
|
389
445
|
*/
|
|
390
446
|
maxReferenceFrames?: number;
|
|
447
|
+
/** Positive safe integer; defaults to 3. Maximum client/trusted collection or reference frames on one chain. */
|
|
448
|
+
maxFrameNesting?: number;
|
|
391
449
|
}
|
|
392
450
|
|
|
393
451
|
/**
|
|
@@ -697,6 +755,9 @@ export interface DatabaseAdapter<Model = any, Session = any> {
|
|
|
697
755
|
}
|
|
698
756
|
export function createRuntime<Model = any, Session = any>(adapter: DatabaseAdapter<Model, Session>): Runtime<Model, Session>;
|
|
699
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
|
+
|
|
700
761
|
/**
|
|
701
762
|
* `operator` is a {@link QueryOperator}; the value of a text operator is a validated string. For
|
|
702
763
|
* `IS_EMPTY` and `IS_NOT_EMPTY` the value is null, and `path` may end at an embedded object, an
|
|
@@ -705,17 +766,31 @@ export function createRuntime<Model = any, Session = any>(adapter: DatabaseAdapt
|
|
|
705
766
|
* references and end at a reference or a collection.
|
|
706
767
|
*
|
|
707
768
|
* `scopes` exists only on such an emptiness predicate from a client, and only for a compiler that
|
|
708
|
-
* 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
|
|
709
770
|
* single reference the path crosses (a scoped join, which admits the target only where the scope
|
|
710
771
|
* admits it), the end when it is a reference or a collection, and each reference and collection
|
|
711
772
|
* member of an embedded object (frames, which keep only the records the scope admits). Each value is
|
|
712
773
|
* the target's `find` scope as a predicate in the target's own frame, or null when the scope added
|
|
713
774
|
* nothing; after a scoped crossing, a null hop still correlates through that scoped join. Without
|
|
714
|
-
* `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.
|
|
715
781
|
*/
|
|
716
782
|
export type QueryPredicate =
|
|
717
|
-
| { kind: 'predicate'; path: string[]; operator: string; value: any; scopes?: Record<string, QueryPredicate | null
|
|
718
|
-
| { 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
|
+
};
|
|
719
794
|
export interface QueryPlan {
|
|
720
795
|
entity: string;
|
|
721
796
|
where: QueryPredicate | null;
|
|
@@ -738,8 +813,8 @@ export interface QueryPlan {
|
|
|
738
813
|
* value inside an embedded list or a collection, `INVALID_FILTER_OPERATOR` for an embedded type that
|
|
739
814
|
* reaches itself through single embedded members, `INVALID_FILTER_VALUE` for a value that is not
|
|
740
815
|
* omitted or null, and `UNSUPPORTED_QUERY` for a reference or collection on the path or among the
|
|
741
|
-
* members. A term without a path (omitted, null or `""`) and a group
|
|
742
|
-
* 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
|
|
743
818
|
* object fails with `INVALID_FILTER_PATH`, as on MongoDB; a bare object field keeps
|
|
744
819
|
* `MISSING_FILTER_PATH`.
|
|
745
820
|
*
|
|
@@ -748,18 +823,22 @@ export interface QueryPlan {
|
|
|
748
823
|
* reads a reference or collection member, fails with `UNSUPPORTED_QUERY` where the order above has
|
|
749
824
|
* `UNSUPPORTED_QUERY` for references; when it is true, such a condition plans with stored semantics,
|
|
750
825
|
* unless its term or group condition carries a client scope marker that the runtime filled, which
|
|
751
|
-
* 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
|
|
752
830
|
* with `DETACHED_CLIENT_FILTER` (500).
|
|
753
831
|
*/
|
|
754
|
-
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;
|
|
755
833
|
export function resolveModelPath(models: ModelDescription, entityName: string, path: string | string[]): FieldDescription[];
|
|
756
834
|
|
|
757
835
|
/**
|
|
758
836
|
* Process-wide. `maxPageSize` (default 1000) caps page sizes. `maxReferenceFrames` (default 10) caps,
|
|
759
|
-
* per list, aggregate or collection-field call, the
|
|
760
|
-
*
|
|
761
|
-
*
|
|
762
|
-
*
|
|
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.
|
|
763
842
|
*/
|
|
764
843
|
export function configureQueryLimits(options?: QueryLimitsOptions): void;
|
|
765
844
|
/**
|