@routier/core 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assertions/index.cjs +19 -8
- package/dist/assertions/index.cjs.map +1 -1
- package/dist/assertions/index.d.ts +5 -1
- package/dist/assertions/index.js +21 -9
- package/dist/assertions/index.js.map +1 -1
- package/dist/codegen/blocks.d.ts +17 -1
- package/dist/codegen/handlers/types.d.ts +13 -5
- package/dist/codegen/index.cjs +28 -0
- package/dist/codegen/index.cjs.map +1 -1
- package/dist/codegen/index.js +28 -0
- package/dist/codegen/index.js.map +1 -1
- package/dist/collections/MemoryDataCollection.d.ts +8 -0
- package/dist/collections/index.cjs +141 -4
- package/dist/collections/index.cjs.map +1 -1
- package/dist/collections/index.js +141 -4
- package/dist/collections/index.js.map +1 -1
- package/dist/expressions/callSource.d.ts +41 -0
- package/dist/expressions/evaluate.d.ts +3 -0
- package/dist/expressions/fold.d.ts +7 -0
- package/dist/expressions/index.cjs +1985 -242
- package/dist/expressions/index.cjs.map +1 -1
- package/dist/expressions/index.d.ts +2 -0
- package/dist/expressions/index.js +1997 -243
- package/dist/expressions/index.js.map +1 -1
- package/dist/expressions/parser.d.ts +42 -1
- package/dist/expressions/types.d.ts +45 -26
- package/dist/expressions/utils.d.ts +19 -1
- package/dist/index.cjs +3139 -680
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3479 -997
- package/dist/index.js.map +1 -1
- package/dist/performance/index.cjs +6 -4
- package/dist/performance/index.cjs.map +1 -1
- package/dist/performance/index.js +6 -4
- package/dist/performance/index.js.map +1 -1
- package/dist/pipeline/index.cjs +6 -4
- package/dist/pipeline/index.cjs.map +1 -1
- package/dist/pipeline/index.js +6 -4
- package/dist/pipeline/index.js.map +1 -1
- package/dist/plugins/EphemeralDataPlugin.d.ts +8 -0
- package/dist/plugins/index.cjs +2921 -411
- package/dist/plugins/index.cjs.map +1 -1
- package/dist/plugins/index.js +2863 -343
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/query/QueryOptionsCollection.d.ts +48 -10
- package/dist/plugins/query/describeFilter.d.ts +83 -0
- package/dist/plugins/query/explain.d.ts +71 -9
- package/dist/plugins/query/index.d.ts +2 -0
- package/dist/plugins/query/join.d.ts +4 -1
- package/dist/plugins/query/renames.d.ts +27 -0
- package/dist/plugins/query/types.d.ts +50 -4
- package/dist/plugins/translators/SqlTranslator.d.ts +15 -0
- package/dist/schema/PropertyInfo.d.ts +0 -1
- package/dist/schema/SchemaDefinition.d.ts +8 -0
- package/dist/schema/changeTracker.d.ts +10 -0
- package/dist/schema/index.cjs +298 -288
- package/dist/schema/index.cjs.map +1 -1
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +301 -290
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/types.d.ts +8 -7
- package/dist/schema/utils/storageDates.d.ts +25 -0
- package/dist/transfer/index.cjs.map +1 -1
- package/dist/transfer/index.js.map +1 -1
- package/dist/utilities/index.cjs +306 -68
- package/dist/utilities/index.cjs.map +1 -1
- package/dist/utilities/index.js +306 -68
- package/dist/utilities/index.js.map +1 -1
- package/package.json +2 -2
- package/dist/codegen/utils.d.ts +0 -22
|
@@ -9,18 +9,11 @@ export declare class QueryOptionsCollection<T> {
|
|
|
9
9
|
private nextExecutionReason;
|
|
10
10
|
private nextIndex;
|
|
11
11
|
private enumeratedItems;
|
|
12
|
+
private dirty;
|
|
13
|
+
/** The collection a `splitAt`/`split` half came from. A capability report belongs to it. */
|
|
14
|
+
private origin;
|
|
12
15
|
/** Cuts over to memory execution, keeping the first cause. See `MemoryExecutionReason`. */
|
|
13
16
|
private cutOverToMemory;
|
|
14
|
-
/**
|
|
15
|
-
* True when `split()` or `splitAt()` produced this collection.
|
|
16
|
-
*
|
|
17
|
-
* Those rebuild each half by re-adding its options, which re-derives execution targets
|
|
18
|
-
* without the options that caused them — a post-join filter alone in the memory half
|
|
19
|
-
* derives back to `"database"`. Anything reading `target` as a report of where work runs
|
|
20
|
-
* has to reject a derived collection; see `explainQuery`.
|
|
21
|
-
*/
|
|
22
|
-
private derived;
|
|
23
|
-
get isDerived(): boolean;
|
|
24
17
|
get items(): Map<keyof QueryOptionValueMap<unknown>, QueryCollectionItem<any, any>[]>;
|
|
25
18
|
get isEmpty(): boolean;
|
|
26
19
|
static EMPTY<R>(): QueryOptionsCollection<R>;
|
|
@@ -45,8 +38,53 @@ export declare class QueryOptionsCollection<T> {
|
|
|
45
38
|
* the shared collection before executing. Without restoring, a re-executed terminal —
|
|
46
39
|
* the whole point of a subscribed queryable — stacks its option a second time and
|
|
47
40
|
* runs it over the first execution's scalar result.
|
|
41
|
+
*
|
|
42
|
+
* The item objects are shared with the snapshot. Nothing reports on them, because every
|
|
43
|
+
* dispatch sends a `forDispatch` copy, so a restore brings back no reports.
|
|
48
44
|
*/
|
|
49
45
|
snapshot(): () => void;
|
|
46
|
+
/** Takes an item as it stands — same object, same index, same target and reason. */
|
|
47
|
+
private adopt;
|
|
48
|
+
/**
|
|
49
|
+
* A plugin reporting that its engine cannot express one option.
|
|
50
|
+
*
|
|
51
|
+
* Core marks the rest of the database phase `not-reached`, because the database has to stop
|
|
52
|
+
* there — a window applied in front of a filter that was not applied returns the wrong rows.
|
|
53
|
+
* Passing the cascade through core is what makes it impossible for a plugin to mark a
|
|
54
|
+
* non-contiguous cut.
|
|
55
|
+
*
|
|
56
|
+
* A report names a culprit and never un-names one, so reports commute.
|
|
57
|
+
*
|
|
58
|
+
* The option is not moved to the memory arm. It stays where it was planned, which is what keeps
|
|
59
|
+
* a redirect distinguishable from something core sent to memory in the first place.
|
|
60
|
+
*/
|
|
61
|
+
reportMissingCapability(item: QueryCollectionItem<any, any>): void;
|
|
62
|
+
/**
|
|
63
|
+
* A plugin reporting that its engine would answer one option differently from JavaScript.
|
|
64
|
+
*
|
|
65
|
+
* Same cascade as `reportMissingCapability`, and a separate reason because the caller can act on
|
|
66
|
+
* one and not the other. See `DatabaseExecutionReason`.
|
|
67
|
+
*/
|
|
68
|
+
reportEngineDivergence(item: QueryCollectionItem<any, any>): void;
|
|
69
|
+
private report;
|
|
70
|
+
/**
|
|
71
|
+
* A copy of the collection for one dispatch to a plugin, with nothing reported on it.
|
|
72
|
+
*
|
|
73
|
+
* Capability is answered per dispatch, so a report is only an answer for the execution that
|
|
74
|
+
* produced it. Reports are written onto items, and the items of a queryable's collection
|
|
75
|
+
* outlive any one execution: a snapshot shares them, and a subscription dispatches the same
|
|
76
|
+
* query on every change. A report left on them replays options the plugin did run on the
|
|
77
|
+
* next execution, such as a `skip` applied twice over rows already windowed, or hands a
|
|
78
|
+
* renamed filter to memory that the engine could have run.
|
|
79
|
+
*
|
|
80
|
+
* Each item keeps its index, name, value and target. A half from `split`/`splitAt` is copied
|
|
81
|
+
* with a copy of its origin, and its items are that copy's items, so a report on the half still
|
|
82
|
+
* cascades over the whole dispatch without reaching the collection it was copied from.
|
|
83
|
+
*/
|
|
84
|
+
forDispatch(): QueryOptionsCollection<T>;
|
|
85
|
+
private copyForDispatch;
|
|
86
|
+
/** The options the database did not run, in the order they were written. */
|
|
87
|
+
notExecuted(): QueryCollectionItem<any, any>[];
|
|
50
88
|
split(): {
|
|
51
89
|
memory: QueryOptionsCollection<T>;
|
|
52
90
|
database: QueryOptionsCollection<T>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { Expression } from "../../expressions";
|
|
2
|
+
/**
|
|
3
|
+
* Saying what a backend was asked to do, with the values pulled out.
|
|
4
|
+
*
|
|
5
|
+
* `explain` already carries `{ text, parameters }` per executed query, and the SQL plugins fill
|
|
6
|
+
* both in — a statement with `?` and the values bound to it. Every other backend reported a
|
|
7
|
+
* placeholder: Dexie said `filter(<predicate>)`, which names nothing, and a key-value store said
|
|
8
|
+
* only that it scanned. The predicate was the one thing a reader wanted and the one thing missing.
|
|
9
|
+
*
|
|
10
|
+
* Two renderings live here, and neither knows about a specific engine:
|
|
11
|
+
*
|
|
12
|
+
* - `describeFilterAsJs` — the predicate as JavaScript, for a backend with no query language of
|
|
13
|
+
* its own. It reads like what the caller wrote, which is what they are looking for.
|
|
14
|
+
* - `parameteriseDocument` — for a backend whose query IS a document. Values become `?` and are
|
|
15
|
+
* collected in order, so a Mango selector and an MQL filter both come out in their own shape
|
|
16
|
+
* with the values listed beside them.
|
|
17
|
+
*
|
|
18
|
+
* Pulling values out is not decoration. It is what makes two runs of one query comparable, and
|
|
19
|
+
* what keeps a value out of the text when that text is logged.
|
|
20
|
+
*/
|
|
21
|
+
export type ParameterisedQuery = {
|
|
22
|
+
/** The query in its own language, with each value replaced by `?`. */
|
|
23
|
+
text: string;
|
|
24
|
+
/** The values, in the order their placeholders appear. */
|
|
25
|
+
parameters: unknown[];
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* The predicate as JavaScript, with every value replaced by `?`.
|
|
29
|
+
*
|
|
30
|
+
* Rendered from the parsed tree rather than from the function's source. The tree is what the
|
|
31
|
+
* backend was actually given, so this cannot drift from what ran; and a value reaching the tree
|
|
32
|
+
* as a literal is indistinguishable from one arriving through a params object, which is what
|
|
33
|
+
* makes both come out as `?` the way SQL treats them.
|
|
34
|
+
*/
|
|
35
|
+
export declare const describeFilterAsJs: (expression: Expression) => ParameterisedQuery;
|
|
36
|
+
/**
|
|
37
|
+
* Marks a value inside a query document so it is replaced by `?` rather than printed.
|
|
38
|
+
*
|
|
39
|
+
* A document language carries its values inline, so there is nothing in the shape itself to say
|
|
40
|
+
* which parts are operators and which are data. A dialect wraps the data as it builds the
|
|
41
|
+
* document, and `parameteriseDocument` reads the wrapper.
|
|
42
|
+
*/
|
|
43
|
+
declare const PARAMETER: unique symbol;
|
|
44
|
+
export type ParameterHolder = {
|
|
45
|
+
readonly [PARAMETER]: unknown;
|
|
46
|
+
};
|
|
47
|
+
export declare const parameter: (value: unknown) => ParameterHolder;
|
|
48
|
+
/**
|
|
49
|
+
* Renders a query DOCUMENT with its values replaced by `?`.
|
|
50
|
+
*
|
|
51
|
+
* Language-agnostic on purpose: an MQL filter and a Mango selector are both plain objects, and so
|
|
52
|
+
* is whatever a future document store wants reported. The dialect decides the shape; this only
|
|
53
|
+
* decides how it is written down.
|
|
54
|
+
*
|
|
55
|
+
* A value not wrapped by `parameter` is structural — an operator name, a field path, a nesting
|
|
56
|
+
* level — and is printed as it is. That is the whole distinction, and it has to be made where the
|
|
57
|
+
* document is built, because by the time it is an object the two are the same kind of thing.
|
|
58
|
+
*/
|
|
59
|
+
export declare const parameteriseDocument: (document: unknown) => ParameterisedQuery;
|
|
60
|
+
/**
|
|
61
|
+
* Every filter on a query, as one description.
|
|
62
|
+
*
|
|
63
|
+
* Filters accumulate — `.where(a).where(b)` is `a && b` — so they are reported as one predicate
|
|
64
|
+
* rather than several, which is how the caller thinks of them and how a SQL plugin renders them
|
|
65
|
+
* into one `WHERE`. Parameters run left to right across the whole thing, matching the text.
|
|
66
|
+
*
|
|
67
|
+
* A filter that could not be parsed falls back to its source. Mixing the two is deliberate: one
|
|
68
|
+
* unparsable filter does not make the others unreadable, and seeing which one it was is the
|
|
69
|
+
* point.
|
|
70
|
+
*/
|
|
71
|
+
export declare const describeFilters: (filters: readonly {
|
|
72
|
+
expression: Expression;
|
|
73
|
+
filter?: unknown;
|
|
74
|
+
}[]) => ParameterisedQuery;
|
|
75
|
+
/**
|
|
76
|
+
* A predicate core could not parse, shown as the caller wrote it.
|
|
77
|
+
*
|
|
78
|
+
* This is the case where the source matters most: an unparsable filter is why the query did not
|
|
79
|
+
* push down, and the reason codes say that it happened without showing what it was. There are no
|
|
80
|
+
* parameters — nothing was extracted, because nothing was understood.
|
|
81
|
+
*/
|
|
82
|
+
export declare const describeUnparsableFilter: (filter: unknown, reason?: string) => ParameterisedQuery;
|
|
83
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DatabaseExecutionReason, MemoryExecutionReason, QueryOptionName } from "./types";
|
|
2
2
|
import { QueryOptionsCollection } from "./QueryOptionsCollection";
|
|
3
3
|
/**
|
|
4
4
|
* One sentence per reason code, written for someone meeting pushdown for the first time.
|
|
@@ -24,25 +24,68 @@ export type ExplainedOption = {
|
|
|
24
24
|
detail?: Record<string, unknown>;
|
|
25
25
|
};
|
|
26
26
|
export declare const EXECUTED_QUERIES_UNSUPPORTED = "This plugin did not report what it executed. It may not support explain.";
|
|
27
|
+
/**
|
|
28
|
+
* Why an option planned for the database did not run there. `executed` has no sentence: it needs no
|
|
29
|
+
* explaining, and a step made of executed options is a database step like any other.
|
|
30
|
+
*/
|
|
31
|
+
export declare const DATABASE_EXECUTION_EXPLANATIONS: Record<Exclude<DatabaseExecutionReason, "executed">, string>;
|
|
32
|
+
/**
|
|
33
|
+
* Where a step ran.
|
|
34
|
+
*
|
|
35
|
+
* A database step names WHICH database, because a cross-plugin join reads from more than one — and a
|
|
36
|
+
* name alone does not say whether the second was PostgreSQL or PouchDB, which is the difference
|
|
37
|
+
* between a statement a reader recognises and one they cannot place.
|
|
38
|
+
*/
|
|
39
|
+
export type ExecutedIn = {
|
|
40
|
+
kind: "database";
|
|
41
|
+
database: string;
|
|
42
|
+
plugin: string;
|
|
43
|
+
} | {
|
|
44
|
+
kind: "memory";
|
|
45
|
+
};
|
|
46
|
+
/** Why a step is not in the database. `executed` never appears: those steps ARE in the database. */
|
|
47
|
+
export type StepReason = MemoryExecutionReason | Exclude<DatabaseExecutionReason, "executed">;
|
|
48
|
+
/**
|
|
49
|
+
* One run of options in one place.
|
|
50
|
+
*
|
|
51
|
+
* A union, so a memory step cannot carry statements it could not have run and a database step cannot
|
|
52
|
+
* carry a reason for not being in the database.
|
|
53
|
+
*/
|
|
27
54
|
export type ExecutionStep = {
|
|
28
55
|
step: number;
|
|
29
56
|
of: number;
|
|
30
|
-
executedIn:
|
|
31
|
-
|
|
57
|
+
executedIn: Extract<ExecutedIn, {
|
|
58
|
+
kind: "database";
|
|
59
|
+
}>;
|
|
32
60
|
options: ExplainedOption[];
|
|
33
|
-
/**
|
|
34
|
-
executedQueries
|
|
35
|
-
/** Set
|
|
61
|
+
/** What the plugin reported running. Empty when it reported nothing. */
|
|
62
|
+
executedQueries: ExecutedQuery[];
|
|
63
|
+
/** Set instead, when this plugin does not report what it executed. */
|
|
36
64
|
executedQueriesUnsupported?: string;
|
|
37
|
-
|
|
38
|
-
|
|
65
|
+
} | {
|
|
66
|
+
step: number;
|
|
67
|
+
of: number;
|
|
68
|
+
executedIn: Extract<ExecutedIn, {
|
|
69
|
+
kind: "memory";
|
|
70
|
+
}>;
|
|
71
|
+
options: ExplainedOption[];
|
|
72
|
+
reason?: StepReason;
|
|
39
73
|
explanation?: string;
|
|
40
74
|
};
|
|
75
|
+
export type DatabaseStep = Extract<ExecutionStep, {
|
|
76
|
+
executedQueries: ExecutedQuery[];
|
|
77
|
+
}>;
|
|
78
|
+
export type MemoryStep = Exclude<ExecutionStep, DatabaseStep>;
|
|
79
|
+
/**
|
|
80
|
+
* TypeScript does not narrow a union from a discriminant nested inside a property, so the two kinds
|
|
81
|
+
* of step need a guard rather than an inline check.
|
|
82
|
+
*/
|
|
83
|
+
export declare const isDatabaseStep: (step: ExecutionStep) => step is DatabaseStep;
|
|
41
84
|
export type QueryExplanationSummary = {
|
|
42
85
|
database: number;
|
|
43
86
|
memory: number;
|
|
44
87
|
/** Deduped, in first-seen order. Empty when the whole query pushed down. */
|
|
45
|
-
reasons:
|
|
88
|
+
reasons: StepReason[];
|
|
46
89
|
explanation: string;
|
|
47
90
|
};
|
|
48
91
|
export type QueryExplanation = {
|
|
@@ -80,3 +123,22 @@ export declare const explainQuery: (options: QueryOptionsCollection<any>, contex
|
|
|
80
123
|
* original — nothing mutates them, and copying deeper would only look safer than it is.
|
|
81
124
|
*/
|
|
82
125
|
export declare const withExecutedQueries: (explanation: QueryExplanation, executedQueries: ExecutedQuery[]) => QueryExplanation;
|
|
126
|
+
/**
|
|
127
|
+
* Adds the step for a cross-plugin join's inner side.
|
|
128
|
+
*
|
|
129
|
+
* Appended by the executor rather than derived from the options, because the inner side's options
|
|
130
|
+
* live on the join, in its own collection, and were never part of this query's chain. It goes before
|
|
131
|
+
* the memory steps that consume it — the join cannot run until both sides are read.
|
|
132
|
+
*/
|
|
133
|
+
/**
|
|
134
|
+
* Every statement the query ran, across every database it touched, in execution order.
|
|
135
|
+
*
|
|
136
|
+
* A step is a place, so the statements live on the steps — this is for a caller that wants them all
|
|
137
|
+
* without caring which plugin ran which.
|
|
138
|
+
*/
|
|
139
|
+
export declare const executedQueriesOf: (explanation: QueryExplanation) => ExecutedQuery[];
|
|
140
|
+
export declare const withInnerSide: (explanation: QueryExplanation, innerSide: {
|
|
141
|
+
database: string;
|
|
142
|
+
plugin: string;
|
|
143
|
+
executedQueries: ExecutedQuery[];
|
|
144
|
+
}) => QueryExplanation;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
export * from './describeFilter';
|
|
1
2
|
export * from './explain';
|
|
2
3
|
export * from './formatExplanation';
|
|
3
4
|
export * from './join';
|
|
4
5
|
export * from './Query';
|
|
5
6
|
export * from './QueryOptionsCollection';
|
|
7
|
+
export * from './renames';
|
|
6
8
|
export * from './types';
|
|
7
9
|
export * from './similarity';
|
|
@@ -5,6 +5,7 @@ import type { DbPluginQueryEvent } from "../types";
|
|
|
5
5
|
import type { ITranslatedValue } from "../translators/types";
|
|
6
6
|
import { QueryOptionsCollection } from "./QueryOptionsCollection";
|
|
7
7
|
import { QueryOptionValueMap } from "./types";
|
|
8
|
+
import { ExecutedQuery } from "./explain";
|
|
8
9
|
export type JoinKind = "inner" | "left";
|
|
9
10
|
/**
|
|
10
11
|
* One side's join key, as a property path plus the resolved property.
|
|
@@ -165,7 +166,9 @@ export declare const loadJoinInnerSide: <TRoot extends {}, TShape>(event: DbPlug
|
|
|
165
166
|
* before anything else — so it is optional, and its absence costs a wider inner read rather
|
|
166
167
|
* than a wrong one.
|
|
167
168
|
*/
|
|
168
|
-
outerKeys?: ReadonlySet<unknown> | null
|
|
169
|
+
outerKeys?: ReadonlySet<unknown> | null,
|
|
170
|
+
/** Where the inner read reports what it executed. Defaults to the outer read's own list. */
|
|
171
|
+
innerExecutedQueries?: ExecutedQuery[]) => void;
|
|
169
172
|
/**
|
|
170
173
|
* Interprets a join by running TWO ordinary queries through the plugin's own read path.
|
|
171
174
|
*
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { QueryOptionsCollection } from "./QueryOptionsCollection";
|
|
2
|
+
/**
|
|
3
|
+
* The options that name a property by what the caller wrote, and so can name a renamed one.
|
|
4
|
+
*
|
|
5
|
+
* `sum`, `min`, `max` and `distinct` are not among them: they carry no property, and read what the
|
|
6
|
+
* `map` in front of them projected. A report on that `map` ends the database phase, so they run in
|
|
7
|
+
* memory behind it.
|
|
8
|
+
*/
|
|
9
|
+
export type PropertyReadingOption = "filter" | "sort" | "nearest" | "map" | "group";
|
|
10
|
+
/**
|
|
11
|
+
* Hands back every option over a property stored under a `.from()` name, for the datastore to run
|
|
12
|
+
* in memory.
|
|
13
|
+
*
|
|
14
|
+
* Core keeps such an option with the database, because only the plugin knows whether its backend
|
|
15
|
+
* reads storage names. One that translates the option — SQL renders the column from
|
|
16
|
+
* `getResolvedName()` — needs nothing from here. One that runs the caller's lambda over rows as it
|
|
17
|
+
* stores them reads a key the row does not have, and answers wrongly without an error: that plugin
|
|
18
|
+
* calls this before it reads anything, and the datastore finishes the query after deserialization,
|
|
19
|
+
* where the in-memory names exist.
|
|
20
|
+
*
|
|
21
|
+
* Reported as `missing-capability`: the backend cannot express the option as written, and like
|
|
22
|
+
* every capability, that is only knowable by the plugin.
|
|
23
|
+
*
|
|
24
|
+
* @param names Which options to check, for a plugin that resolves some of them itself — Mongo renders
|
|
25
|
+
* filters and sorts through the stored path, and runs `nearest`, `map` and `group` in JavaScript.
|
|
26
|
+
*/
|
|
27
|
+
export declare const reportRenamedProperties: (options: QueryOptionsCollection<any>, names?: readonly PropertyReadingOption[]) => void;
|
|
@@ -14,7 +14,16 @@ export type QueryField = {
|
|
|
14
14
|
sourceName: string;
|
|
15
15
|
destinationName: string;
|
|
16
16
|
isRename: boolean;
|
|
17
|
+
/** The property the field's value is read from, when it reads exactly one. */
|
|
17
18
|
property?: PropertyInfo<unknown>;
|
|
19
|
+
/** Every property the field's value is read from. Absent when the selector could not be parsed. */
|
|
20
|
+
reads?: PropertyInfo<unknown>[];
|
|
21
|
+
/**
|
|
22
|
+
* `false` when the value is computed from `property` rather than being it, as in `x.createdDate.getTime()`,
|
|
23
|
+
* or when the selector could not be parsed. Absent on a field built from a property rather than a
|
|
24
|
+
* selector, which is that property.
|
|
25
|
+
*/
|
|
26
|
+
isDirectProperty?: boolean;
|
|
18
27
|
getter: <T>(data: Record<string, unknown>) => T;
|
|
19
28
|
};
|
|
20
29
|
export type QueryOptionExecutionTarget = "database" | "memory";
|
|
@@ -27,22 +36,57 @@ export type QueryOptionName = keyof QueryOptionValueMap<unknown>;
|
|
|
27
36
|
* never returns to `"database"`, so the code recorded is the FIRST cause and it stays on every
|
|
28
37
|
* option after it. Reporting a later one would name a symptom of this one.
|
|
29
38
|
*/
|
|
30
|
-
|
|
39
|
+
/** Why core planned an option for memory, decided when the option is added. */
|
|
40
|
+
export type MemoryExecutionReason = "not-parsable" | "unmapped-property" | "map-rename" | "after-nearest" | "after-join" | "cross-plugin-join" | "predicate-error" | "after-window";
|
|
41
|
+
/**
|
|
42
|
+
* What became of an option planned for the database.
|
|
43
|
+
*
|
|
44
|
+
* `missing-capability` and `engine-divergence` are the only values a plugin writes, and the only
|
|
45
|
+
* ones core cannot derive: an engine's capabilities are not knowable from here. SQLite's `REGEXP`
|
|
46
|
+
* exists if the host registered the function and not otherwise, so two instances in one process can
|
|
47
|
+
* differ.
|
|
48
|
+
*
|
|
49
|
+
* They are separate because a developer can act on one and not the other: no way to say it at all,
|
|
50
|
+
* versus an engine that would answer, and answer differently from JavaScript.
|
|
51
|
+
*
|
|
52
|
+
* `not-reached` is the rest of the database phase after either. The database stops there rather than
|
|
53
|
+
* carrying on: a window applied in front of a filter that was not applied returns the wrong rows.
|
|
54
|
+
* Core writes it, so a plugin cannot mark a cascade it does not own.
|
|
55
|
+
*/
|
|
56
|
+
export type DatabaseExecutionReason = "executed" | "missing-capability" | "engine-divergence" | "not-reached";
|
|
57
|
+
/**
|
|
58
|
+
* One option, and where it runs.
|
|
59
|
+
*
|
|
60
|
+
* `target` narrows what `reason` can say, so an option cannot carry a reason that does not belong to
|
|
61
|
+
* the half it was planned for. An option is never moved between arms — the database arm records what
|
|
62
|
+
* became of it, which is what makes a redirect readable:
|
|
63
|
+
*
|
|
64
|
+
* ```ts
|
|
65
|
+
* option.target === "database" && option.reason === "missing-capability"
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
31
68
|
export type QueryOption<T, K extends QueryOptionName> = {
|
|
32
69
|
name: QueryOptionName;
|
|
33
70
|
value: QueryOptionValueMap<T>[K];
|
|
34
|
-
target:
|
|
35
|
-
|
|
36
|
-
|
|
71
|
+
target: "database";
|
|
72
|
+
reason: DatabaseExecutionReason;
|
|
73
|
+
} | {
|
|
74
|
+
name: QueryOptionName;
|
|
75
|
+
value: QueryOptionValueMap<T>[K];
|
|
76
|
+
target: "memory";
|
|
77
|
+
reason: MemoryExecutionReason;
|
|
37
78
|
};
|
|
38
79
|
export type QueryOptionValueMap<T extends {}> = {
|
|
39
80
|
skip: number;
|
|
40
81
|
take: number;
|
|
82
|
+
/** `property`, `reads` and `isDirectProperty` mean what they do on a {@link QueryField}. */
|
|
41
83
|
sort: {
|
|
42
84
|
selector: GenericFunction<T, T[keyof T]>;
|
|
43
85
|
direction: QueryOrdering;
|
|
44
86
|
propertyName: string;
|
|
45
87
|
property?: PropertyInfo<T> | null;
|
|
88
|
+
reads?: PropertyInfo<T>[];
|
|
89
|
+
isDirectProperty?: boolean;
|
|
46
90
|
};
|
|
47
91
|
map: {
|
|
48
92
|
selector: GenericFunction<T, any>;
|
|
@@ -69,6 +113,8 @@ export type QueryOptionValueMap<T extends {}> = {
|
|
|
69
113
|
selector: GenericFunction<T, T[keyof T]>;
|
|
70
114
|
propertyName: string;
|
|
71
115
|
property?: PropertyInfo<T> | null;
|
|
116
|
+
reads?: PropertyInfo<T>[];
|
|
117
|
+
isDirectProperty?: boolean;
|
|
72
118
|
vector: number[];
|
|
73
119
|
count: number;
|
|
74
120
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { QueryOption } from "../query/types";
|
|
2
2
|
import { IQuery } from "../types";
|
|
3
3
|
import { DataTranslator } from "./DataTranslator";
|
|
4
|
+
import { ITranslatedValue } from "./types";
|
|
4
5
|
/**
|
|
5
6
|
* What the statement that produced these rows actually did.
|
|
6
7
|
*
|
|
@@ -16,6 +17,20 @@ export type SqlPushdown = {
|
|
|
16
17
|
export declare class SqlTranslator<TRoot extends {}, TShape> extends DataTranslator<TRoot, TShape> {
|
|
17
18
|
protected readonly pushedDown: SqlPushdown;
|
|
18
19
|
constructor(query: IQuery<TRoot, TShape>, pushedDown?: SqlPushdown);
|
|
20
|
+
/**
|
|
21
|
+
* Dates back as Dates, before the caller's selectors run over the rows.
|
|
22
|
+
*
|
|
23
|
+
* A `group` key and a `map` are the caller's lambdas, run here over rows as the engine returned them.
|
|
24
|
+
* SQLite, D1 and libSQL hand a date back as the TEXT it was stored as, which has no `getFullYear()`
|
|
25
|
+
* and groups apart from the Date the entity holds. Revived at storage paths and in place, which the
|
|
26
|
+
* datastore's deserialization still reads, and after `decodeJsonColumns`, so a date inside a JSON
|
|
27
|
+
* column is revived too. Only a string is converted, so an engine that returns a Date (PostgreSQL,
|
|
28
|
+
* PGlite, MySQL) is left alone, and so is a row already revived.
|
|
29
|
+
*
|
|
30
|
+
* Not a joined statement's rows, which are tuples, each half already deserialized. Nor rows whose
|
|
31
|
+
* `group` or `map` was handed back, which the datastore runs after deserializing them.
|
|
32
|
+
*/
|
|
33
|
+
translate(data: unknown): ITranslatedValue<TShape>;
|
|
19
34
|
count<TResult extends number>(data: unknown, _: QueryOption<TShape, "count">): TResult;
|
|
20
35
|
min<TResult extends string | number | Date>(data: unknown, _: QueryOption<TShape, "min">): TResult;
|
|
21
36
|
max<TResult extends string | number | Date>(data: unknown, _: QueryOption<TShape, "max">): TResult;
|
|
@@ -36,6 +36,14 @@ export declare class SchemaDefinition<T extends {}> extends SchemaBase<T, any> {
|
|
|
36
36
|
*/
|
|
37
37
|
get '~standard'(): StandardJSONSchemaV1.Props<InferCreateType<T>, InferType<T>>;
|
|
38
38
|
private createReturnFunction;
|
|
39
|
+
/**
|
|
40
|
+
* Compiles `builder` into a function taking `fnArgs`.
|
|
41
|
+
*
|
|
42
|
+
* A builder with bindings is compiled one level out: an outer function whose parameters are
|
|
43
|
+
* the bindings, called once here with their values, returns the function that is kept. The
|
|
44
|
+
* bound values become closure variables of that function, so the per-call cost is a context
|
|
45
|
+
* read rather than anything resolved by name.
|
|
46
|
+
*/
|
|
39
47
|
private createFunction;
|
|
40
48
|
modify<R>(builder: (d: {
|
|
41
49
|
function: <UU, I = never>(fn: (entity: InferType<CompiledSchema<T>>, collectionName: CollectionName, injected: I) => UU, injected?: I) => SchemaFunction<UU, I, "unmapped">;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds the proxy factory that change-tracks an entity.
|
|
3
|
+
*
|
|
4
|
+
* Generated schema code receives the result as a bound value — a parameter of the generated
|
|
5
|
+
* factory — and never refers to this module by name. Name references do not survive a minifier,
|
|
6
|
+
* which renames the declaration but cannot see inside generated source text (#40, #46). The
|
|
7
|
+
* returned function holds no per-entity state, so one per compiled schema is shared by every
|
|
8
|
+
* entity it tracks.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createChangeTracker(): <TEntity extends {}>(entity: TEntity, path?: string, parent?: TEntity) => TEntity;
|