@dalgo/firestore 0.1.0 → 0.4.1
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 +93 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/query.d.ts.map +1 -1
- package/dist/query.js +27 -0
- package/dist/query.js.map +1 -1
- package/dist/tugql-plan.d.ts +68 -0
- package/dist/tugql-plan.d.ts.map +1 -0
- package/dist/tugql-plan.js +292 -0
- package/dist/tugql-plan.js.map +1 -0
- package/dist/tugql.d.ts +58 -0
- package/dist/tugql.d.ts.map +1 -0
- package/dist/tugql.js +128 -0
- package/dist/tugql.js.map +1 -0
- package/package.json +10 -6
package/README.md
CHANGED
|
@@ -11,7 +11,9 @@ including apps that query an OpenVaultDB Firestore database directly.
|
|
|
11
11
|
pnpm add @dalgo/core @dalgo/firestore firebase
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
The adapter uses the separately published `@dalgo/core` contracts.
|
|
14
|
+
The adapter uses the separately published `@dalgo/core` contracts. Its required
|
|
15
|
+
peer range is `@dalgo/core >=0.8.0 <0.9.0`, the first core line with the TugQL
|
|
16
|
+
names.
|
|
15
17
|
|
|
16
18
|
## Browser setup
|
|
17
19
|
|
|
@@ -66,6 +68,96 @@ const db = new FirestoreDatabase(getFirestore(app, openVaultDatabaseId));
|
|
|
66
68
|
The adapter appends document ID as a deterministic final ordering field. Use
|
|
67
69
|
the returned `nextCursor` rather than constructing pagination values manually.
|
|
68
70
|
|
|
71
|
+
## Recursive TugQL
|
|
72
|
+
|
|
73
|
+
Run recursive TugQL through `executeRecursiveTugQLQuery` from `@dalgo/core`.
|
|
74
|
+
The core sends Firestore ordinary bounded leaf queries; a direct recursive AST
|
|
75
|
+
is rejected before Firestore query compilation. `EXISTS` can stop its logical
|
|
76
|
+
evaluation after a match, while each Firestore leaf query remains a Web SDK
|
|
77
|
+
page request and cannot promise physical first-record stopping within that page.
|
|
78
|
+
|
|
79
|
+
### TugQL from a browser (read-only)
|
|
80
|
+
|
|
81
|
+
`runFirestoreTugQL(firestore, resolved, options?)` runs a query resolved by
|
|
82
|
+
`resolveTugQL(document, { ..., schemaless: true })` and returns
|
|
83
|
+
`{ columns, rows }`. Import it from `@dalgo/firestore/tugql`, which imports no
|
|
84
|
+
Firestore write API, so a browser host can run user queries on the signed-in
|
|
85
|
+
user's own session.
|
|
86
|
+
|
|
87
|
+
- A slash `FROM` (`FROM spaces/abc/ext/datatug/projects`) resolves to
|
|
88
|
+
`schema: spaces/abc/ext/datatug`, read as the parent document path
|
|
89
|
+
(`firestoreParentKey`). An odd segment count is refused, naming the path,
|
|
90
|
+
before any read.
|
|
91
|
+
- `__key__` is the document id. It may be selected, compared and ordered on;
|
|
92
|
+
every row of a query without `SELECT` carries it as its first column,
|
|
93
|
+
followed by the union of the returned documents' fields in first-seen order.
|
|
94
|
+
- A query over one collection whose only condition is `__key__ = <value>`
|
|
95
|
+
reads that one document (`getDoc`) and returns zero or one row.
|
|
96
|
+
|
|
97
|
+
#### Queries run as Firestore queries
|
|
98
|
+
|
|
99
|
+
Any other query must be expressible as **one Firestore query**, so Firestore
|
|
100
|
+
reads only matching documents through its indexes. That holds when the query:
|
|
101
|
+
|
|
102
|
+
- reads one collection: no JOIN, derived `FROM`, subquery, `GROUP BY`,
|
|
103
|
+
`HAVING` or aggregate;
|
|
104
|
+
- has a `WHERE` that is an `AND` of comparisons of one field (or `__key__`)
|
|
105
|
+
with a value, using `=`, `!=`, `<`, `<=`, `>`, `>=`, `in` or `not-in`;
|
|
106
|
+
- compares only with strings, finite numbers and booleans (or lists of them),
|
|
107
|
+
never with `NULL`, after parameters are bound;
|
|
108
|
+
- stays within Firestore's limits: at most 30 `in` disjunctions (the product
|
|
109
|
+
of all `in` list sizes), at most 10 `not-in` values, at most one `!=` or
|
|
110
|
+
`not-in`, and no `not-in` together with `in` or `!=`;
|
|
111
|
+
- orders by fields (or `__key__`), ascending or descending;
|
|
112
|
+
- names fields plainly: a dotted name (`a.b`) or a `__name__`-style name is
|
|
113
|
+
refused, because Firestore would read a nested or reserved path while
|
|
114
|
+
DALgo-JS reads the literal key.
|
|
115
|
+
|
|
116
|
+
The adapter sends every comparison as a `where`, every `ORDER BY` entry as an
|
|
117
|
+
`orderBy`, and a `limit` of `LIMIT + OFFSET` (or `maxFetchedRows + 1` without
|
|
118
|
+
`LIMIT`). DALgo-JS then re-applies `WHERE`, `ORDER BY`, `OFFSET`, `LIMIT` and
|
|
119
|
+
`SELECT` to the documents returned. Inequality fields are also sent as
|
|
120
|
+
explicit `orderBy`s, in the order Firestore itself would use, so a query such as
|
|
121
|
+
`rank > 3` needs no composite index. An empty `in` list returns no rows without
|
|
122
|
+
a read; `LIMIT + OFFSET` over `maxFetchedRows` (10,000 by default) fails with
|
|
123
|
+
`query_limit` at `limit` before any read.
|
|
124
|
+
|
|
125
|
+
**OFFSET rows are read and billed.** The Firestore Web SDK has no offset, so
|
|
126
|
+
`LIMIT 5 OFFSET 10` reads 15 documents and DALgo-JS skips the first 10.
|
|
127
|
+
|
|
128
|
+
**Firestore semantics, not in-memory TugQL.** A pushed query returns what
|
|
129
|
+
Firestore selects:
|
|
130
|
+
|
|
131
|
+
- `ORDER BY` a field excludes documents that lack that field;
|
|
132
|
+
- range and `!=` filters match only values of the operand's type;
|
|
133
|
+
- `!=` and `not-in` exclude documents that lack the field, but match stored
|
|
134
|
+
`null`s, which DALgo-JS then drops; with a `LIMIT` such a query can return
|
|
135
|
+
fewer rows than the limit;
|
|
136
|
+
- DALgo-JS re-sorts the rows with JavaScript comparison (UTF-16 code units,
|
|
137
|
+
no cross-type order), so their order can differ from Firestore's for
|
|
138
|
+
non-ASCII strings or mixed-type fields.
|
|
139
|
+
|
|
140
|
+
A missing composite index fails with Firestore's own `failed-precondition`
|
|
141
|
+
error and its index-creation link; the adapter never retries in memory.
|
|
142
|
+
|
|
143
|
+
#### Refusal and `allowInMemoryEvaluation`
|
|
144
|
+
|
|
145
|
+
Any other query fails **before the first read** with a
|
|
146
|
+
`FirestoreTugQLRefusedError` whose `code` is `in_memory_evaluation`, `path` is
|
|
147
|
+
the first offending node (`where`, `where.and[1]`, `orderBy[0]`,
|
|
148
|
+
`from.joins[0]`, `groupBy`, `columns[0]`, …) and `reason` names the failed
|
|
149
|
+
condition (`OR`, `field compared with field`, `comparison with NULL`,
|
|
150
|
+
`` `in` disjunctions exceed 30 ``, `JOIN`, …).
|
|
151
|
+
|
|
152
|
+
`runFirestoreTugQL(firestore, resolved, { allowInMemoryEvaluation: true })`
|
|
153
|
+
runs such a query the old way instead: unfiltered collection scans bounded by
|
|
154
|
+
`maxFetchedRows`, evaluated in memory by DALgo-JS. Every scanned document is a
|
|
155
|
+
billed read, and a collection over the budget fails with `query_limit`. Browser
|
|
156
|
+
hosts running user queries should not set it.
|
|
157
|
+
|
|
158
|
+
`planFirestoreTugQL(query, options)` returns the plan without reading, and the
|
|
159
|
+
`reader` option injects the `getDocs`/`getDoc` functions (for tests).
|
|
160
|
+
|
|
69
161
|
## Point reads and transactions
|
|
70
162
|
|
|
71
163
|
```ts
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC"}
|
package/dist/query.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EAYL,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,KAAK,EAEX,MAAM,oBAAoB,CAAC;AAG5B,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;CAC3C;
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,eAAe,EACrB,MAAM,aAAa,CAAC;AACrB,OAAO,EAYL,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,KAAK,EAEX,MAAM,oBAAoB,CAAC;AAG5B,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;CAC3C;AA0BD,wBAAgB,0BAA0B,CAAC,CAAC,EAC1C,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,GACrB,OAAO,CAsBT;AA2BD,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,GAC3B,sBAAsB,CAAC,CAAC,CAAC,CAoC3B;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,SAAS,UAAU,CAAC,CAAC,CAAC,EAAE,GAC/B,WAAW,CAMb"}
|
package/dist/query.js
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
import { DOCUMENT_ID, Key, UnsupportedError, } from "@dalgo/core";
|
|
2
2
|
import { collection, collectionGroup, documentId, endAt, endBefore, limit, orderBy, query as createQuery, startAfter, startAt, where, } from "firebase/firestore";
|
|
3
3
|
import { firestoreCollectionPath } from "./path.js";
|
|
4
|
+
function assertLeafQuery(value) {
|
|
5
|
+
const reject = () => { throw new UnsupportedError("recursive TugQL requires the core recursive executor"); };
|
|
6
|
+
if (typeof value !== "object" || value === null)
|
|
7
|
+
reject();
|
|
8
|
+
const query = value;
|
|
9
|
+
const queryKeys = new Set(["source", "filters", "orders", "limit", "offset", "startAt", "startAfter", "endAt", "endBefore"]);
|
|
10
|
+
if (Object.keys(query).some((key) => !queryKeys.has(key)))
|
|
11
|
+
reject();
|
|
12
|
+
const source = query.source;
|
|
13
|
+
if (typeof source !== "object" || source === null)
|
|
14
|
+
reject();
|
|
15
|
+
const relation = source;
|
|
16
|
+
const sourceKeys = new Set(["kind", "name", "parent", "codec"]);
|
|
17
|
+
if ((relation.kind !== "collection" && relation.kind !== "collection-group") || Object.keys(relation).some((key) => !sourceKeys.has(key)))
|
|
18
|
+
reject();
|
|
19
|
+
if (!Array.isArray(query.filters) || !Array.isArray(query.orders))
|
|
20
|
+
reject();
|
|
21
|
+
const filterKeys = new Set(["field", "operator", "value"]);
|
|
22
|
+
const orderKeys = new Set(["field", "direction"]);
|
|
23
|
+
const filters = query.filters;
|
|
24
|
+
const orders = query.orders;
|
|
25
|
+
if (filters.some((item) => typeof item !== "object" || item === null || Object.keys(item).some((key) => !filterKeys.has(key))))
|
|
26
|
+
reject();
|
|
27
|
+
if (orders.some((item) => typeof item !== "object" || item === null || Object.keys(item).some((key) => !orderKeys.has(key))))
|
|
28
|
+
reject();
|
|
29
|
+
}
|
|
4
30
|
function firestoreField(field) {
|
|
5
31
|
return field === DOCUMENT_ID ? documentId() : field;
|
|
6
32
|
}
|
|
@@ -40,6 +66,7 @@ function addCursor(constraints, value, orderCount, createConstraint) {
|
|
|
40
66
|
constraints.push(createConstraint(...value.values));
|
|
41
67
|
}
|
|
42
68
|
export function compileFirestoreQuery(firestore, dalQuery) {
|
|
69
|
+
assertLeafQuery(dalQuery);
|
|
43
70
|
if ((dalQuery.offset ?? 0) !== 0) {
|
|
44
71
|
throw new UnsupportedError("Firestore Web SDK query offsets");
|
|
45
72
|
}
|
package/dist/query.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../src/query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { type QueryFilter, type QueryOrder, type RecursiveTugQLQuery, type RecursiveTugQLRelation } from "@dalgo/core";
|
|
2
|
+
/** The reserved TugQL field name of a record's own key (the Firestore document id). */
|
|
3
|
+
export declare const TUGQL_KEY_FIELD: "__key__";
|
|
4
|
+
type Data = Record<string, unknown>;
|
|
5
|
+
/** The fetched-row budget of DALgo-JS's recursive executor when none is set. */
|
|
6
|
+
export declare const DEFAULT_MAX_FETCHED_ROWS = 10000;
|
|
7
|
+
/** Firestore's limit on the disjunctions of one query (the product of `in` list sizes). */
|
|
8
|
+
export declare const MAX_DISJUNCTIONS = 30;
|
|
9
|
+
/** Firestore's limit on the values of one `not-in` list. */
|
|
10
|
+
export declare const MAX_NOT_IN_VALUES = 10;
|
|
11
|
+
/** The options the planner reads. */
|
|
12
|
+
export interface FirestoreTugQLPlanOptions {
|
|
13
|
+
readonly allowInMemoryEvaluation?: boolean;
|
|
14
|
+
readonly maxFetchedRows?: number;
|
|
15
|
+
}
|
|
16
|
+
/** The refusal codes of the planner. */
|
|
17
|
+
export type FirestoreTugQLRefusalCode = "in_memory_evaluation" | "query_limit";
|
|
18
|
+
/** How runFirestoreTugQL answers a query. */
|
|
19
|
+
export type FirestoreTugQLPlan =
|
|
20
|
+
/** One Firestore query answers DALgo-JS's single leaf scan. */
|
|
21
|
+
{
|
|
22
|
+
readonly kind: "pushed";
|
|
23
|
+
readonly filters: readonly QueryFilter<Data>[];
|
|
24
|
+
readonly orders: readonly QueryOrder<Data>[];
|
|
25
|
+
readonly limit: number;
|
|
26
|
+
}
|
|
27
|
+
/** One `getDoc` of the document `id` answers the single leaf scan. */
|
|
28
|
+
| {
|
|
29
|
+
readonly kind: "key";
|
|
30
|
+
readonly id: string;
|
|
31
|
+
}
|
|
32
|
+
/** No document can match: the leaf scan is answered with no read. */
|
|
33
|
+
| {
|
|
34
|
+
readonly kind: "empty";
|
|
35
|
+
}
|
|
36
|
+
/** Bounded collection scans evaluated by DALgo-JS (`allowInMemoryEvaluation` only). */
|
|
37
|
+
| {
|
|
38
|
+
readonly kind: "in-memory";
|
|
39
|
+
} | {
|
|
40
|
+
readonly kind: "refused";
|
|
41
|
+
readonly code: FirestoreTugQLRefusalCode;
|
|
42
|
+
readonly path: string;
|
|
43
|
+
readonly reason: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* The error of a refused TugQL query, thrown before any Firestore read. Its
|
|
47
|
+
* message has the `<code> at <path>: <reason>` form of DALgo-JS's executor
|
|
48
|
+
* errors (for example `query_limit at root.from: fetched_rows`).
|
|
49
|
+
*/
|
|
50
|
+
export declare class FirestoreTugQLRefusedError extends Error {
|
|
51
|
+
readonly code: FirestoreTugQLRefusalCode;
|
|
52
|
+
/** The zero-based path of the first offending node, for example `where.and[1]`. */
|
|
53
|
+
readonly path: string;
|
|
54
|
+
/** The condition of REQ:pushable-shape that failed, for example `OR`. */
|
|
55
|
+
readonly reason: string;
|
|
56
|
+
constructor(code: FirestoreTugQLRefusalCode, path: string, reason: string);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Plans a resolved TugQL query whose parameters are already bound (every
|
|
60
|
+
* `@name` is a literal). A pure function of the query and the options.
|
|
61
|
+
*/
|
|
62
|
+
export declare function planFirestoreTugQL(query: RecursiveTugQLQuery, options?: FirestoreTugQLPlanOptions): FirestoreTugQLPlan;
|
|
63
|
+
/** Collects every table relation of the query tree, nested queries included. */
|
|
64
|
+
export declare function tableRelations(query: RecursiveTugQLQuery): RecursiveTugQLRelation[];
|
|
65
|
+
/** The adapter's document-id validation: a value that can name a Firestore document. */
|
|
66
|
+
export declare function validDocumentId(value: unknown): value is string;
|
|
67
|
+
export {};
|
|
68
|
+
//# sourceMappingURL=tugql-plan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tugql-plan.d.ts","sourceRoot":"","sources":["../src/tugql-plan.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,WAAW,EAEhB,KAAK,UAAU,EAIf,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC5B,MAAM,aAAa,CAAC;AAErB,uFAAuF;AACvF,eAAO,MAAM,eAAe,EAAG,SAAkB,CAAC;AAElD,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpC,gFAAgF;AAChF,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAE/C,2FAA2F;AAC3F,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,4DAA4D;AAC5D,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC,qCAAqC;AACrC,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAC3C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,wCAAwC;AACxC,MAAM,MAAM,yBAAyB,GAAG,sBAAsB,GAAG,aAAa,CAAC;AAE/E,6CAA6C;AAC7C,MAAM,MAAM,kBAAkB;AAC5B,+DAA+D;AAC7D;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE;AACnJ,sEAAsE;GACpE;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE;AAC/C,qEAAqE;GACnE;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE;AAC5B,uFAAuF;GACrF;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GAC9B;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3H;;;;GAIG;AACH,qBAAa,0BAA2B,SAAQ,KAAK;IACnD,SAAgB,IAAI,EAAE,yBAAyB,CAAC;IAChD,mFAAmF;IACnF,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,yEAAyE;IACzE,SAAgB,MAAM,EAAE,MAAM,CAAC;gBAEZ,IAAI,EAAE,yBAAyB,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAOjF;AAOD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,mBAAmB,EAAE,OAAO,GAAE,yBAA8B,GAAG,kBAAkB,CAW1H;AAED,gFAAgF;AAChF,wBAAgB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,sBAAsB,EAAE,CAcnF;AAmBD,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAG/D"}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
// The pure TugQL pushdown planner of the Firestore adapter (spec
|
|
2
|
+
// firestore-tugql-pushdown in dal-go/dalgo). It decides, from a resolved and
|
|
3
|
+
// bound TugQL query and the options alone, whether runFirestoreTugQL answers
|
|
4
|
+
// the query with one Firestore query, one document read, no read at all, an
|
|
5
|
+
// in-memory evaluation (opt-in only), or a refusal. It never touches Firestore.
|
|
6
|
+
import { DOCUMENT_ID, } from "@dalgo/core";
|
|
7
|
+
/** The reserved TugQL field name of a record's own key (the Firestore document id). */
|
|
8
|
+
export const TUGQL_KEY_FIELD = "__key__";
|
|
9
|
+
/** The fetched-row budget of DALgo-JS's recursive executor when none is set. */
|
|
10
|
+
export const DEFAULT_MAX_FETCHED_ROWS = 10_000;
|
|
11
|
+
/** Firestore's limit on the disjunctions of one query (the product of `in` list sizes). */
|
|
12
|
+
export const MAX_DISJUNCTIONS = 30;
|
|
13
|
+
/** Firestore's limit on the values of one `not-in` list. */
|
|
14
|
+
export const MAX_NOT_IN_VALUES = 10;
|
|
15
|
+
/**
|
|
16
|
+
* The error of a refused TugQL query, thrown before any Firestore read. Its
|
|
17
|
+
* message has the `<code> at <path>: <reason>` form of DALgo-JS's executor
|
|
18
|
+
* errors (for example `query_limit at root.from: fetched_rows`).
|
|
19
|
+
*/
|
|
20
|
+
export class FirestoreTugQLRefusedError extends Error {
|
|
21
|
+
code;
|
|
22
|
+
/** The zero-based path of the first offending node, for example `where.and[1]`. */
|
|
23
|
+
path;
|
|
24
|
+
/** The condition of REQ:pushable-shape that failed, for example `OR`. */
|
|
25
|
+
reason;
|
|
26
|
+
constructor(code, path, reason) {
|
|
27
|
+
super(`${code} at ${path}: ${reason}`);
|
|
28
|
+
this.name = "FirestoreTugQLRefusedError";
|
|
29
|
+
this.code = code;
|
|
30
|
+
this.path = path;
|
|
31
|
+
this.reason = reason;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
const refuse = (path, reason, code = "in_memory_evaluation") => ({ kind: "refused", code, path, reason });
|
|
35
|
+
/**
|
|
36
|
+
* Plans a resolved TugQL query whose parameters are already bound (every
|
|
37
|
+
* `@name` is a literal). A pure function of the query and the options.
|
|
38
|
+
*/
|
|
39
|
+
export function planFirestoreTugQL(query, options = {}) {
|
|
40
|
+
const maxFetchedRows = options.maxFetchedRows ?? DEFAULT_MAX_FETCHED_ROWS;
|
|
41
|
+
if (query.limit !== undefined && query.limit + (query.offset ?? 0) > maxFetchedRows) {
|
|
42
|
+
return refuse("limit", `LIMIT plus OFFSET exceeds maxFetchedRows (${maxFetchedRows.toString()})`, "query_limit");
|
|
43
|
+
}
|
|
44
|
+
const keyed = tableRelations(query).length === 1 ? keyEquality(query) : notKeyed;
|
|
45
|
+
if (keyed !== notKeyed)
|
|
46
|
+
return validDocumentId(keyed) ? { kind: "key", id: keyed } : { kind: "empty" };
|
|
47
|
+
const pushed = pushedPlan(query, maxFetchedRows);
|
|
48
|
+
if (pushed.kind !== "refused" || options.allowInMemoryEvaluation !== true)
|
|
49
|
+
return pushed;
|
|
50
|
+
return { kind: "in-memory" };
|
|
51
|
+
}
|
|
52
|
+
/** Collects every table relation of the query tree, nested queries included. */
|
|
53
|
+
export function tableRelations(query) {
|
|
54
|
+
const found = [];
|
|
55
|
+
const visit = (value) => {
|
|
56
|
+
if (Array.isArray(value)) {
|
|
57
|
+
for (const item of value)
|
|
58
|
+
visit(item);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (typeof value !== "object" || value === null)
|
|
62
|
+
return;
|
|
63
|
+
const node = value;
|
|
64
|
+
if (node.kind === "table" && Array.isArray(node.joins))
|
|
65
|
+
found.push(node);
|
|
66
|
+
for (const child of Object.values(node))
|
|
67
|
+
visit(child);
|
|
68
|
+
};
|
|
69
|
+
visit(query);
|
|
70
|
+
return found;
|
|
71
|
+
}
|
|
72
|
+
const notKeyed = Symbol("not-keyed");
|
|
73
|
+
/** Recognizes a WHERE whose only condition is `__key__ = <literal>` and returns the literal. */
|
|
74
|
+
function keyEquality(query) {
|
|
75
|
+
// Only a direct collection scan can be answered by one document read; a
|
|
76
|
+
// derived FROM (or a join) filters rows the inner query produced.
|
|
77
|
+
if (query.from.kind !== "table" || query.from.joins.length > 0)
|
|
78
|
+
return notKeyed;
|
|
79
|
+
const where = query.where;
|
|
80
|
+
if (where?.kind !== "comparison" || where.operator !== "==")
|
|
81
|
+
return notKeyed;
|
|
82
|
+
const names = new Set(["", query.from.alias, query.from.name]);
|
|
83
|
+
const isKey = (side) => side.kind === "field"
|
|
84
|
+
&& side.field.field === TUGQL_KEY_FIELD && names.has(side.field.source);
|
|
85
|
+
return isKey(where.left) && where.right.kind === "literal" ? where.right.value
|
|
86
|
+
: isKey(where.right) && where.left.kind === "literal" ? where.left.value
|
|
87
|
+
: notKeyed;
|
|
88
|
+
}
|
|
89
|
+
/** The adapter's document-id validation: a value that can name a Firestore document. */
|
|
90
|
+
export function validDocumentId(value) {
|
|
91
|
+
return typeof value === "string" && value !== "" && value !== "." && value !== ".."
|
|
92
|
+
&& !value.includes("/") && !/^__.*__$/u.test(value);
|
|
93
|
+
}
|
|
94
|
+
function pushedPlan(query, maxFetchedRows) {
|
|
95
|
+
const relation = query.from;
|
|
96
|
+
if (relation.kind !== "table")
|
|
97
|
+
return refuse("from", "derived source");
|
|
98
|
+
if (relation.joins.length > 0)
|
|
99
|
+
return refuse("from.joins[0]", "JOIN");
|
|
100
|
+
if ("scan" in relation && relation.scan !== undefined)
|
|
101
|
+
return refuse("from", "relation scan limit");
|
|
102
|
+
const where = query.where === undefined ? { filters: [], empty: false } : whereFilters(query.where);
|
|
103
|
+
if ("kind" in where)
|
|
104
|
+
return where;
|
|
105
|
+
if (query.groupBy !== undefined)
|
|
106
|
+
return refuse("groupBy", "GROUP BY");
|
|
107
|
+
if (query.having !== undefined)
|
|
108
|
+
return refuse("having", "HAVING");
|
|
109
|
+
const orders = [];
|
|
110
|
+
for (const [index, order] of (query.orderBy ?? []).entries()) {
|
|
111
|
+
const field = firestoreField(order.field.field);
|
|
112
|
+
if (field === undefined)
|
|
113
|
+
return refuse(`orderBy[${index.toString()}]`, `field name "${order.field.field}" is not a plain Firestore field`);
|
|
114
|
+
orders.push({ field, direction: order.direction });
|
|
115
|
+
}
|
|
116
|
+
for (const [index, column] of (query.columns ?? []).entries()) {
|
|
117
|
+
const problem = columnProblem(column);
|
|
118
|
+
if (problem !== undefined)
|
|
119
|
+
return refuse(`columns[${index.toString()}]`, problem);
|
|
120
|
+
}
|
|
121
|
+
if (where.empty)
|
|
122
|
+
return { kind: "empty" };
|
|
123
|
+
return {
|
|
124
|
+
kind: "pushed",
|
|
125
|
+
filters: where.filters,
|
|
126
|
+
orders: withInequalityOrders(orders, where.filters),
|
|
127
|
+
limit: query.limit === undefined ? maxFetchedRows + 1 : query.limit + (query.offset ?? 0),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
function columnProblem(column) {
|
|
131
|
+
const visit = (expression) => {
|
|
132
|
+
if (expression.kind === "query")
|
|
133
|
+
return "subquery";
|
|
134
|
+
if (expression.kind === "aggregate")
|
|
135
|
+
return "aggregate";
|
|
136
|
+
if (expression.kind === "binary")
|
|
137
|
+
return visit(expression.left) ?? visit(expression.right);
|
|
138
|
+
return undefined;
|
|
139
|
+
};
|
|
140
|
+
return visit(column.expression);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Firestore orders a query with inequality filters by those fields (after the
|
|
144
|
+
* explicit orders, before the document id). compileFirestoreQuery appends an
|
|
145
|
+
* explicit document-id order, which would otherwise come first and demand a
|
|
146
|
+
* composite index, so the inequality fields are listed explicitly, exactly
|
|
147
|
+
* where Firestore itself would put them.
|
|
148
|
+
*/
|
|
149
|
+
function withInequalityOrders(orders, filters) {
|
|
150
|
+
const ordered = new Set(orders.map(({ field }) => field));
|
|
151
|
+
const direction = orders.at(-1)?.direction ?? "asc";
|
|
152
|
+
const inequalities = filters
|
|
153
|
+
.filter(({ field, operator }) => field !== DOCUMENT_ID && !["==", "in"].includes(operator))
|
|
154
|
+
.map(({ field }) => field)
|
|
155
|
+
.filter((field) => !ordered.has(field));
|
|
156
|
+
return [...orders, ...[...new Set(inequalities)].sort().map((field) => ({ field, direction }))];
|
|
157
|
+
}
|
|
158
|
+
function flatten(condition, path, into) {
|
|
159
|
+
if (condition.kind === "and") {
|
|
160
|
+
for (const [index, child] of condition.conditions.entries())
|
|
161
|
+
flatten(child, `${path}.and[${index.toString()}]`, into);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
into.push({ condition, path });
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const SCALAR_OPERATORS = new Set(["==", "!=", "<", "<=", ">", ">="]);
|
|
168
|
+
const FLIPPED = {
|
|
169
|
+
"==": "==", "!=": "!=", "<": ">", "<=": ">=", ">": "<", ">=": "<=",
|
|
170
|
+
in: "in", "not-in": "not-in", "array-contains": "array-contains", "array-contains-any": "array-contains-any",
|
|
171
|
+
};
|
|
172
|
+
function whereFilters(where) {
|
|
173
|
+
const conjuncts = [];
|
|
174
|
+
flatten(where, "where", conjuncts);
|
|
175
|
+
const filters = [];
|
|
176
|
+
let empty = false;
|
|
177
|
+
let disjunctions = 1;
|
|
178
|
+
let inCount = 0;
|
|
179
|
+
let notEqualCount = 0;
|
|
180
|
+
let notInCount = 0;
|
|
181
|
+
for (const { condition, path } of conjuncts) {
|
|
182
|
+
const filter = conjunctFilter(condition);
|
|
183
|
+
if ("reason" in filter)
|
|
184
|
+
return refuse(path, filter.reason);
|
|
185
|
+
if (filter.kind === "empty") {
|
|
186
|
+
empty = true;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (filter.kind === "none")
|
|
190
|
+
continue;
|
|
191
|
+
const { operator, value } = filter.filter;
|
|
192
|
+
if ((operator === "not-in" && inCount + notEqualCount > 0) || ((operator === "in" || operator === "!=") && notInCount > 0)) {
|
|
193
|
+
return refuse(path, "`not-in` combined with `in` or `!=`");
|
|
194
|
+
}
|
|
195
|
+
if ((operator === "!=" || operator === "not-in") && notEqualCount + notInCount > 0)
|
|
196
|
+
return refuse(path, "more than one `!=` or `not-in`");
|
|
197
|
+
if (operator === "in") {
|
|
198
|
+
disjunctions *= value.length;
|
|
199
|
+
if (disjunctions > MAX_DISJUNCTIONS)
|
|
200
|
+
return refuse(path, `\`in\` disjunctions exceed ${MAX_DISJUNCTIONS.toString()}`);
|
|
201
|
+
inCount += 1;
|
|
202
|
+
}
|
|
203
|
+
if (operator === "not-in") {
|
|
204
|
+
if (value.length > MAX_NOT_IN_VALUES)
|
|
205
|
+
return refuse(path, `\`not-in\` list exceeds ${MAX_NOT_IN_VALUES.toString()} values`);
|
|
206
|
+
notInCount += 1;
|
|
207
|
+
}
|
|
208
|
+
if (operator === "!=")
|
|
209
|
+
notEqualCount += 1;
|
|
210
|
+
filters.push(filter.filter);
|
|
211
|
+
}
|
|
212
|
+
return { filters, empty };
|
|
213
|
+
}
|
|
214
|
+
const NOT_COMPARISON = {
|
|
215
|
+
and: "AND", or: "OR", "is-null": "IS NULL", "is-not-null": "IS NOT NULL", exists: "EXISTS subquery", "not-exists": "NOT EXISTS subquery",
|
|
216
|
+
};
|
|
217
|
+
function conjunctFilter(condition) {
|
|
218
|
+
if (condition.kind !== "comparison")
|
|
219
|
+
return { reason: NOT_COMPARISON[condition.kind] };
|
|
220
|
+
const { left, right } = condition;
|
|
221
|
+
if (!SCALAR_OPERATORS.has(condition.operator) && condition.operator !== "in" && condition.operator !== "not-in") {
|
|
222
|
+
return { reason: `operator ${condition.operator}` };
|
|
223
|
+
}
|
|
224
|
+
if (left.kind === "query" || right.kind === "query")
|
|
225
|
+
return { reason: "subquery" };
|
|
226
|
+
if (left.kind === "field" && right.kind === "field")
|
|
227
|
+
return { reason: "field compared with field" };
|
|
228
|
+
const field = left.kind === "field" ? left : right.kind === "field" ? right : undefined;
|
|
229
|
+
if (field === undefined)
|
|
230
|
+
return { reason: "no field operand" };
|
|
231
|
+
const operand = field === left ? right : left;
|
|
232
|
+
if (field === right && !SCALAR_OPERATORS.has(condition.operator))
|
|
233
|
+
return { reason: `field on the right of ${condition.operator}` };
|
|
234
|
+
const operator = field === left ? condition.operator : FLIPPED[condition.operator];
|
|
235
|
+
if (operand.kind === "param")
|
|
236
|
+
return { reason: `unbound parameter @${operand.name}` };
|
|
237
|
+
if (operand.kind !== "literal" && operand.kind !== "values")
|
|
238
|
+
return { reason: `${operand.kind} expression` };
|
|
239
|
+
const value = operand.kind === "literal" ? operand.value : operand.values;
|
|
240
|
+
const name = firestoreField(field.field.field);
|
|
241
|
+
const isKey = name === DOCUMENT_ID;
|
|
242
|
+
if (name === undefined)
|
|
243
|
+
return { reason: `field name "${field.field.field}" is not a plain Firestore field` };
|
|
244
|
+
if (operator === "in" || operator === "not-in") {
|
|
245
|
+
if (!Array.isArray(value))
|
|
246
|
+
return { reason: `${operator} needs a list` };
|
|
247
|
+
const values = value;
|
|
248
|
+
for (const item of values) {
|
|
249
|
+
const problem = valueProblem(item);
|
|
250
|
+
if (problem !== undefined)
|
|
251
|
+
return { reason: problem };
|
|
252
|
+
}
|
|
253
|
+
// A value that names no document can neither match nor exclude a document.
|
|
254
|
+
const kept = isKey ? values.filter(validDocumentId) : values;
|
|
255
|
+
if (kept.length === 0)
|
|
256
|
+
return operator === "in" ? { kind: "empty" } : { kind: "none" };
|
|
257
|
+
return { kind: "filter", filter: { field: name, operator, value: kept } };
|
|
258
|
+
}
|
|
259
|
+
const problem = valueProblem(value);
|
|
260
|
+
if (problem !== undefined)
|
|
261
|
+
return { reason: problem };
|
|
262
|
+
if (isKey && !validDocumentId(value)) {
|
|
263
|
+
if (operator === "==")
|
|
264
|
+
return { kind: "empty" };
|
|
265
|
+
if (operator === "!=")
|
|
266
|
+
return { kind: "none" };
|
|
267
|
+
return { reason: "`__key__` compared with a value that is not a document id" };
|
|
268
|
+
}
|
|
269
|
+
return { kind: "filter", filter: { field: name, operator, value } };
|
|
270
|
+
}
|
|
271
|
+
function valueProblem(value) {
|
|
272
|
+
if (value === null || value === undefined)
|
|
273
|
+
return "comparison with NULL";
|
|
274
|
+
if (typeof value === "string" || typeof value === "boolean")
|
|
275
|
+
return undefined;
|
|
276
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
277
|
+
return undefined;
|
|
278
|
+
return "value is not a string, finite number or boolean";
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* The Firestore field path of a TugQL field: the name itself when Firestore
|
|
282
|
+
* reads it as that one top-level field. A dotted or special name would be
|
|
283
|
+
* read by Firestore as another (nested or reserved) field, so it is refused.
|
|
284
|
+
*/
|
|
285
|
+
function firestoreField(name) {
|
|
286
|
+
if (name === TUGQL_KEY_FIELD)
|
|
287
|
+
return DOCUMENT_ID;
|
|
288
|
+
if (name === "" || /[.~*/[\]`]/u.test(name) || /^__.*__$/u.test(name))
|
|
289
|
+
return undefined;
|
|
290
|
+
return name;
|
|
291
|
+
}
|
|
292
|
+
//# sourceMappingURL=tugql-plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tugql-plan.js","sourceRoot":"","sources":["../src/tugql-plan.ts"],"names":[],"mappings":"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"}
|
package/dist/tugql.d.ts
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type CollectionSource, type Key, type RecursiveQueryExecutionOptions, type RecursiveTugQLQuery, type RecursiveTugQLRelation, type TugQLResolved } from "@dalgo/core";
|
|
2
|
+
import { type DocumentReference, type DocumentSnapshot, type Firestore, type Query, type QuerySnapshot } from "firebase/firestore";
|
|
3
|
+
export { FirestoreTugQLRefusedError, planFirestoreTugQL, TUGQL_KEY_FIELD, type FirestoreTugQLPlan, type FirestoreTugQLPlanOptions, type FirestoreTugQLRefusalCode, } from "./tugql-plan.js";
|
|
4
|
+
type Data = Record<string, unknown>;
|
|
5
|
+
/**
|
|
6
|
+
* The Firestore read functions runFirestoreTugQL uses (REQ:read-seam). The
|
|
7
|
+
* default is the Web SDK's own `getDocs` and `getDoc`; a test can inject a
|
|
8
|
+
* reader that counts reads, inspects the query, or returns fakes.
|
|
9
|
+
*/
|
|
10
|
+
export interface FirestoreTugQLReader {
|
|
11
|
+
getDocs(query: Query): Promise<QuerySnapshot>;
|
|
12
|
+
getDoc(reference: DocumentReference): Promise<DocumentSnapshot>;
|
|
13
|
+
}
|
|
14
|
+
/** Options of {@link runFirestoreTugQL}; the source mapping is the adapter's own. */
|
|
15
|
+
export interface FirestoreTugQLOptions extends Omit<RecursiveQueryExecutionOptions, "resolveSource"> {
|
|
16
|
+
/**
|
|
17
|
+
* Allows a query that cannot run as one Firestore query (an OR, a JOIN, a
|
|
18
|
+
* subquery, GROUP BY, …) to run as bounded collection scans evaluated in
|
|
19
|
+
* memory by DALgo-JS. Every scanned document is a billed read. Without it
|
|
20
|
+
* such a query fails with `in_memory_evaluation` before any read.
|
|
21
|
+
*/
|
|
22
|
+
readonly allowInMemoryEvaluation?: boolean;
|
|
23
|
+
/** The read functions; the Firestore Web SDK's by default. */
|
|
24
|
+
readonly reader?: FirestoreTugQLReader;
|
|
25
|
+
}
|
|
26
|
+
/** The tabular result of a TugQL query run against Firestore. */
|
|
27
|
+
export interface FirestoreTugQLResult {
|
|
28
|
+
/**
|
|
29
|
+
* Output column names. Without SELECT: `__key__` first, then the union of
|
|
30
|
+
* the returned documents' fields in first-seen order. With SELECT: exactly
|
|
31
|
+
* the selected columns.
|
|
32
|
+
*/
|
|
33
|
+
readonly columns: readonly string[];
|
|
34
|
+
readonly rows: readonly Data[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Builds the DALgo key of a TugQL `schema` read as a Firestore parent path
|
|
38
|
+
* (`spaces/abc/ext/datatug`). The path must name a document: an even number
|
|
39
|
+
* of non-empty segments.
|
|
40
|
+
*/
|
|
41
|
+
export declare function firestoreParentKey(schema: string): Key<string>;
|
|
42
|
+
/** Maps a resolved TugQL table relation to the Firestore collection it reads. */
|
|
43
|
+
export declare function firestoreTugQLSource(relation: RecursiveTugQLRelation): CollectionSource<Data>;
|
|
44
|
+
/**
|
|
45
|
+
* Runs a resolved TugQL query (from `resolveTugQL` with `schemaless: true`,
|
|
46
|
+
* parameters bound) against Firestore, reads only. Every table relation's
|
|
47
|
+
* parent path is checked before the first read. Then the query is planned
|
|
48
|
+
* ({@link planFirestoreTugQL}):
|
|
49
|
+
* - a query whose only condition is `__key__ = <value>` reads that one document;
|
|
50
|
+
* - a single-collection query with an AND of field-to-value comparisons runs
|
|
51
|
+
* as one Firestore query carrying its WHERE, ORDER BY and LIMIT;
|
|
52
|
+
* - any other query fails with `in_memory_evaluation` before any read, unless
|
|
53
|
+
* `allowInMemoryEvaluation` is set.
|
|
54
|
+
* DALgo-JS then applies WHERE, ORDER BY, OFFSET, LIMIT and SELECT to the
|
|
55
|
+
* documents read. An error of a Firestore read reaches the caller unchanged.
|
|
56
|
+
*/
|
|
57
|
+
export declare function runFirestoreTugQL(firestore: Firestore, resolved: TugQLResolved | RecursiveTugQLQuery, options?: FirestoreTugQLOptions): Promise<FirestoreTugQLResult>;
|
|
58
|
+
//# sourceMappingURL=tugql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tugql.d.ts","sourceRoot":"","sources":["../src/tugql.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,gBAAgB,EAErB,KAAK,GAAG,EAGR,KAAK,8BAA8B,EAEnC,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAE3B,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AACrB,OAAO,EAIL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,SAAS,EACd,KAAK,KAAK,EACV,KAAK,aAAa,EACnB,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EACL,0BAA0B,EAC1B,kBAAkB,EAClB,eAAe,EACf,KAAK,kBAAkB,EACvB,KAAK,yBAAyB,EAC9B,KAAK,yBAAyB,GAC/B,MAAM,iBAAiB,CAAC;AAEzB,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEpC;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC9C,MAAM,CAAC,SAAS,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;CACjE;AAID,qFAAqF;AACrF,MAAM,WAAW,qBAAsB,SAAQ,IAAI,CAAC,8BAA8B,EAAE,eAAe,CAAC;IAClG;;;;;OAKG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAC3C,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC;CACxC;AAED,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,IAAI,EAAE,SAAS,IAAI,EAAE,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAS9D;AAED,iFAAiF;AACjF,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAO7F;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,aAAa,GAAG,mBAAmB,EAC7C,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,oBAAoB,CAAC,CAU/B"}
|
package/dist/tugql.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// Read-only TugQL execution against the Firestore Web SDK. This module must
|
|
2
|
+
// never import a Firestore write API (test/tugql.test.ts checks the import
|
|
3
|
+
// graph statically): browser hosts import it as `@dalgo/firestore/tugql`
|
|
4
|
+
// to run user queries on the signed-in user's own session.
|
|
5
|
+
import { executeRecursiveTugQLQuery, } from "@dalgo/core";
|
|
6
|
+
import { doc, getDoc, getDocs, } from "firebase/firestore";
|
|
7
|
+
import { firestoreCollectionPath, keyFromDocumentPath } from "./path.js";
|
|
8
|
+
import { compileFirestoreQuery } from "./query.js";
|
|
9
|
+
import { FirestoreTugQLRefusedError, planFirestoreTugQL, tableRelations, TUGQL_KEY_FIELD } from "./tugql-plan.js";
|
|
10
|
+
export { FirestoreTugQLRefusedError, planFirestoreTugQL, TUGQL_KEY_FIELD, } from "./tugql-plan.js";
|
|
11
|
+
const webSDKReader = { getDocs, getDoc };
|
|
12
|
+
/**
|
|
13
|
+
* Builds the DALgo key of a TugQL `schema` read as a Firestore parent path
|
|
14
|
+
* (`spaces/abc/ext/datatug`). The path must name a document: an even number
|
|
15
|
+
* of non-empty segments.
|
|
16
|
+
*/
|
|
17
|
+
export function firestoreParentKey(schema) {
|
|
18
|
+
if (schema.split("/").includes("")) {
|
|
19
|
+
throw new TypeError(`Firestore parent path "${schema}" has an empty segment`);
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
return keyFromDocumentPath(schema);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
throw new TypeError(`Firestore parent path "${schema}" must name a document (an even number of segments)`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Maps a resolved TugQL table relation to the Firestore collection it reads. */
|
|
29
|
+
export function firestoreTugQLSource(relation) {
|
|
30
|
+
if (relation.kind !== "table" || relation.name === undefined) {
|
|
31
|
+
throw new TypeError("a Firestore TugQL source must be a named table relation");
|
|
32
|
+
}
|
|
33
|
+
return relation.schema === undefined
|
|
34
|
+
? { kind: "collection", name: relation.name }
|
|
35
|
+
: { kind: "collection", name: relation.name, parent: firestoreParentKey(relation.schema) };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Runs a resolved TugQL query (from `resolveTugQL` with `schemaless: true`,
|
|
39
|
+
* parameters bound) against Firestore, reads only. Every table relation's
|
|
40
|
+
* parent path is checked before the first read. Then the query is planned
|
|
41
|
+
* ({@link planFirestoreTugQL}):
|
|
42
|
+
* - a query whose only condition is `__key__ = <value>` reads that one document;
|
|
43
|
+
* - a single-collection query with an AND of field-to-value comparisons runs
|
|
44
|
+
* as one Firestore query carrying its WHERE, ORDER BY and LIMIT;
|
|
45
|
+
* - any other query fails with `in_memory_evaluation` before any read, unless
|
|
46
|
+
* `allowInMemoryEvaluation` is set.
|
|
47
|
+
* DALgo-JS then applies WHERE, ORDER BY, OFFSET, LIMIT and SELECT to the
|
|
48
|
+
* documents read. An error of a Firestore read reaches the caller unchanged.
|
|
49
|
+
*/
|
|
50
|
+
export async function runFirestoreTugQL(firestore, resolved, options = {}) {
|
|
51
|
+
const query = "kind" in resolved ? resolved : resolved.query;
|
|
52
|
+
for (const relation of tableRelations(query))
|
|
53
|
+
firestoreTugQLSource(relation);
|
|
54
|
+
const { allowInMemoryEvaluation = false, reader = webSDKReader, ...execution } = options;
|
|
55
|
+
const plan = planFirestoreTugQL(query, { ...execution, allowInMemoryEvaluation });
|
|
56
|
+
if (plan.kind === "refused")
|
|
57
|
+
throw new FirestoreTugQLRefusedError(plan.code, plan.path, plan.reason);
|
|
58
|
+
const page = await executeRecursiveTugQLQuery(planExecutor(firestore, reader, plan), query, { ...execution, resolveSource: firestoreTugQLSource });
|
|
59
|
+
const rows = page.records.map((record) => record.data);
|
|
60
|
+
return { columns: outputColumns(query.columns, rows), rows };
|
|
61
|
+
}
|
|
62
|
+
function planExecutor(firestore, reader, plan) {
|
|
63
|
+
switch (plan.kind) {
|
|
64
|
+
case "pushed": return pushedExecutor(firestore, reader, plan);
|
|
65
|
+
case "key": return documentExecutor(firestore, reader, plan.id);
|
|
66
|
+
case "empty": return emptyExecutor;
|
|
67
|
+
case "in-memory": return collectionExecutor(firestore, reader);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function outputColumns(columns, rows) {
|
|
71
|
+
if (columns !== undefined) {
|
|
72
|
+
return columns.map(({ as, expression }) => as
|
|
73
|
+
?? (expression.kind === "field" ? expression.field.field
|
|
74
|
+
: expression.kind === "aggregate" ? expression.function
|
|
75
|
+
: expression.kind === "query" ? expression.query.as ?? "" : ""));
|
|
76
|
+
}
|
|
77
|
+
const names = new Set([TUGQL_KEY_FIELD]);
|
|
78
|
+
for (const row of rows)
|
|
79
|
+
for (const name of Object.keys(row))
|
|
80
|
+
names.add(name);
|
|
81
|
+
return [...names];
|
|
82
|
+
}
|
|
83
|
+
function withKey(snapshot, key) {
|
|
84
|
+
// A real document field literally named __key__ cannot be addressed.
|
|
85
|
+
const data = Object.fromEntries(Object.entries(snapshot.data() ?? {}).filter(([name]) => name !== TUGQL_KEY_FIELD));
|
|
86
|
+
return { key, exists: true, data: { [TUGQL_KEY_FIELD]: snapshot.id, ...data } };
|
|
87
|
+
}
|
|
88
|
+
async function readQuery(reader, firestore, structured) {
|
|
89
|
+
const snapshot = await reader.getDocs(compileFirestoreQuery(firestore, structured).query);
|
|
90
|
+
const records = snapshot.docs.map((document) => withKey(document, keyFromDocumentPath(document.ref.path)));
|
|
91
|
+
return { records: records };
|
|
92
|
+
}
|
|
93
|
+
/** Answers every leaf scan with an unfiltered, bounded collection read (opt-in only). */
|
|
94
|
+
function collectionExecutor(firestore, reader) {
|
|
95
|
+
return { query: (structured) => readQuery(reader, firestore, structured) };
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Answers DALgo-JS's single leaf scan with the pushed Firestore query: the
|
|
99
|
+
* scan's own source, with the plan's filters, orders and limit.
|
|
100
|
+
*/
|
|
101
|
+
function pushedExecutor(firestore, reader, plan) {
|
|
102
|
+
return {
|
|
103
|
+
query: (structured) => readQuery(reader, firestore, {
|
|
104
|
+
source: structured.source,
|
|
105
|
+
filters: plan.filters,
|
|
106
|
+
orders: plan.orders,
|
|
107
|
+
limit: plan.limit,
|
|
108
|
+
}),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/** Answers the single leaf scan of a key-equality query with one document read. */
|
|
112
|
+
function documentExecutor(firestore, reader, id) {
|
|
113
|
+
return {
|
|
114
|
+
async query(structured) {
|
|
115
|
+
if (structured.source.kind !== "collection")
|
|
116
|
+
throw new TypeError("a keyed read needs a collection source");
|
|
117
|
+
const path = `${firestoreCollectionPath(structured.source)}/${id}`;
|
|
118
|
+
const snapshot = await reader.getDoc(doc(firestore, path));
|
|
119
|
+
const records = snapshot.exists() ? [withKey(snapshot, keyFromDocumentPath(path))] : [];
|
|
120
|
+
return { records: records };
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/** Answers the leaf scan of a query no document can match, without a read. */
|
|
125
|
+
const emptyExecutor = {
|
|
126
|
+
query: () => Promise.resolve({ records: [] }),
|
|
127
|
+
};
|
|
128
|
+
//# sourceMappingURL=tugql.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tugql.js","sourceRoot":"","sources":["../src/tugql.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dalgo/firestore",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Firestore Web SDK adapter for DALgo TypeScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@11.20.0",
|
|
@@ -9,6 +9,10 @@
|
|
|
9
9
|
".": {
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./tugql": {
|
|
14
|
+
"types": "./dist/tugql.d.ts",
|
|
15
|
+
"import": "./dist/tugql.js"
|
|
12
16
|
}
|
|
13
17
|
},
|
|
14
18
|
"files": [
|
|
@@ -18,11 +22,11 @@
|
|
|
18
22
|
],
|
|
19
23
|
"scripts": {
|
|
20
24
|
"build": "tsc -p tsconfig.build.json",
|
|
21
|
-
"check": "eslint . && vitest run --exclude test
|
|
25
|
+
"check": "eslint . && vitest run --exclude 'test/*.integration.test.ts' && tsc -p tsconfig.build.json",
|
|
22
26
|
"lint": "eslint .",
|
|
23
27
|
"prepack": "npm run build",
|
|
24
|
-
"test": "vitest run --exclude test
|
|
25
|
-
"test:emulator": "pnpm --package firebase-tools@15.30.2 dlx firebase emulators:exec --only firestore --project demo-dalgo-js-e2e \"vitest run
|
|
28
|
+
"test": "vitest run --exclude 'test/*.integration.test.ts'",
|
|
29
|
+
"test:emulator": "pnpm --package firebase-tools@15.30.2 dlx firebase emulators:exec --only firestore --project demo-dalgo-js-e2e \"vitest run integration.test\"",
|
|
26
30
|
"test:watch": "vitest"
|
|
27
31
|
},
|
|
28
32
|
"repository": {
|
|
@@ -42,11 +46,11 @@
|
|
|
42
46
|
"node": ">=20"
|
|
43
47
|
},
|
|
44
48
|
"peerDependencies": {
|
|
45
|
-
"@dalgo/core": "
|
|
49
|
+
"@dalgo/core": ">=0.8.0 <0.9.0",
|
|
46
50
|
"firebase": "^12.19.0"
|
|
47
51
|
},
|
|
48
52
|
"devDependencies": {
|
|
49
|
-
"@dalgo/core": "
|
|
53
|
+
"@dalgo/core": "0.8.1",
|
|
50
54
|
"@eslint/js": "10.0.1",
|
|
51
55
|
"eslint": "10.11.0",
|
|
52
56
|
"firebase": "12.19.0",
|