@lovrozagar/oat 0.1.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/LICENSE +21 -0
- package/README.md +401 -0
- package/bin/oat.js +2 -0
- package/dist/cli.js +386 -0
- package/dist/config/define-config.d.ts +165 -0
- package/dist/config/define-config.d.ts.map +1 -0
- package/dist/config/define-config.js +24 -0
- package/dist/config/define-config.js.map +1 -0
- package/dist/config/load.d.ts +10 -0
- package/dist/config/load.d.ts.map +1 -0
- package/dist/config/load.js +61 -0
- package/dist/config/load.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +9 -0
- package/dist/reference/defects.d.ts +254 -0
- package/dist/reference/defects.d.ts.map +1 -0
- package/dist/reference/defects.js +265 -0
- package/dist/reference/defects.js.map +1 -0
- package/dist/reference/dialect.d.ts +104 -0
- package/dist/reference/dialect.d.ts.map +1 -0
- package/dist/reference/dialect.js +174 -0
- package/dist/reference/dialect.js.map +1 -0
- package/dist/reference/http.d.ts +79 -0
- package/dist/reference/http.d.ts.map +1 -0
- package/dist/reference/http.js +889 -0
- package/dist/reference/http.js.map +1 -0
- package/dist/reference/model.d.ts +56 -0
- package/dist/reference/model.d.ts.map +1 -0
- package/dist/reference/model.js +156 -0
- package/dist/reference/model.js.map +1 -0
- package/dist/reference/query.d.ts +45 -0
- package/dist/reference/query.d.ts.map +1 -0
- package/dist/reference/query.js +353 -0
- package/dist/reference/query.js.map +1 -0
- package/dist/reference/spec.d.ts +13 -0
- package/dist/reference/spec.d.ts.map +1 -0
- package/dist/reference/spec.js +547 -0
- package/dist/reference/spec.js.map +1 -0
- package/dist/reference/store-api.d.ts +59 -0
- package/dist/reference/store-api.d.ts.map +1 -0
- package/dist/reference/store-api.js +76 -0
- package/dist/reference/store-api.js.map +1 -0
- package/dist/reference/stores/memory.d.ts +27 -0
- package/dist/reference/stores/memory.d.ts.map +1 -0
- package/dist/reference/stores/memory.js +97 -0
- package/dist/reference/stores/memory.js.map +1 -0
- package/dist/reference/stores/postgres.d.ts +61 -0
- package/dist/reference/stores/postgres.d.ts.map +1 -0
- package/dist/reference/stores/postgres.js +406 -0
- package/dist/reference/stores/postgres.js.map +1 -0
- package/dist/reference/stores/sqlite-driver.d.ts +54 -0
- package/dist/reference/stores/sqlite-driver.d.ts.map +1 -0
- package/dist/reference/stores/sqlite-driver.js +99 -0
- package/dist/reference/stores/sqlite-driver.js.map +1 -0
- package/dist/reference/stores/sqlite.d.ts +68 -0
- package/dist/reference/stores/sqlite.d.ts.map +1 -0
- package/dist/reference/stores/sqlite.js +464 -0
- package/dist/reference/stores/sqlite.js.map +1 -0
- package/dist/report/console.d.ts +33 -0
- package/dist/report/console.d.ts.map +1 -0
- package/dist/report/console.js +237 -0
- package/dist/report/console.js.map +1 -0
- package/dist/report/matrix.d.ts +131 -0
- package/dist/report/matrix.d.ts.map +1 -0
- package/dist/report/matrix.js +865 -0
- package/dist/report/matrix.js.map +1 -0
- package/dist/report/render.d.ts +66 -0
- package/dist/report/render.d.ts.map +1 -0
- package/dist/report/render.js +423 -0
- package/dist/report/render.js.map +1 -0
- package/dist/runtime/async.d.ts +34 -0
- package/dist/runtime/async.d.ts.map +1 -0
- package/dist/runtime/async.js +130 -0
- package/dist/runtime/async.js.map +1 -0
- package/dist/runtime/auth.d.ts +46 -0
- package/dist/runtime/auth.d.ts.map +1 -0
- package/dist/runtime/auth.js +236 -0
- package/dist/runtime/auth.js.map +1 -0
- package/dist/runtime/checks.d.ts +89 -0
- package/dist/runtime/checks.d.ts.map +1 -0
- package/dist/runtime/checks.js +3400 -0
- package/dist/runtime/checks.js.map +1 -0
- package/dist/runtime/client.d.ts +65 -0
- package/dist/runtime/client.d.ts.map +1 -0
- package/dist/runtime/client.js +122 -0
- package/dist/runtime/client.js.map +1 -0
- package/dist/runtime/finding.d.ts +50 -0
- package/dist/runtime/finding.d.ts.map +1 -0
- package/dist/runtime/finding.js +50 -0
- package/dist/runtime/finding.js.map +1 -0
- package/dist/runtime/fixture.d.ts +20 -0
- package/dist/runtime/fixture.d.ts.map +1 -0
- package/dist/runtime/fixture.js +175 -0
- package/dist/runtime/fixture.js.map +1 -0
- package/dist/runtime/progress.d.ts +41 -0
- package/dist/runtime/progress.d.ts.map +1 -0
- package/dist/runtime/progress.js +186 -0
- package/dist/runtime/progress.js.map +1 -0
- package/dist/runtime/run.d.ts +69 -0
- package/dist/runtime/run.d.ts.map +1 -0
- package/dist/runtime/run.js +575 -0
- package/dist/runtime/run.js.map +1 -0
- package/dist/runtime/teardown.d.ts +38 -0
- package/dist/runtime/teardown.d.ts.map +1 -0
- package/dist/runtime/teardown.js +129 -0
- package/dist/runtime/teardown.js.map +1 -0
- package/dist/runtime/validate.d.ts +31 -0
- package/dist/runtime/validate.d.ts.map +1 -0
- package/dist/runtime/validate.js +111 -0
- package/dist/runtime/validate.js.map +1 -0
- package/dist/runtime/world.d.ts +49 -0
- package/dist/runtime/world.d.ts.map +1 -0
- package/dist/runtime/world.js +119 -0
- package/dist/runtime/world.js.map +1 -0
- package/dist/spec/collection.d.ts +31 -0
- package/dist/spec/collection.d.ts.map +1 -0
- package/dist/spec/collection.js +121 -0
- package/dist/spec/collection.js.map +1 -0
- package/dist/spec/conventions.d.ts +103 -0
- package/dist/spec/conventions.d.ts.map +1 -0
- package/dist/spec/conventions.js +275 -0
- package/dist/spec/conventions.js.map +1 -0
- package/dist/spec/extensions.d.ts +74 -0
- package/dist/spec/extensions.d.ts.map +1 -0
- package/dist/spec/extensions.js +335 -0
- package/dist/spec/extensions.js.map +1 -0
- package/dist/spec/graph.d.ts +89 -0
- package/dist/spec/graph.d.ts.map +1 -0
- package/dist/spec/graph.js +318 -0
- package/dist/spec/graph.js.map +1 -0
- package/dist/spec/load.d.ts +36 -0
- package/dist/spec/load.d.ts.map +1 -0
- package/dist/spec/load.js +166 -0
- package/dist/spec/load.js.map +1 -0
- package/dist/spec/types.d.ts +57 -0
- package/dist/spec/types.d.ts.map +1 -0
- package/dist/spec/types.js +24 -0
- package/dist/spec/types.js.map +1 -0
- package/labs/README.md +130 -0
- package/labs/annotated-openapi.yaml +311 -0
- package/labs/anyrow.config.ts +107 -0
- package/labs/demo.mjs +124 -0
- package/labs/local.config.ts +41 -0
- package/labs/minimal.config.ts +32 -0
- package/package.json +80 -0
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Postgres-backed storage for the reference backend.
|
|
3
|
+
*
|
|
4
|
+
* Present because Postgres disagrees with SQLite in exactly the places API contracts are
|
|
5
|
+
* ambiguous, which makes the pair a differential oracle rather than a redundant one:
|
|
6
|
+
*
|
|
7
|
+
* - `ORDER BY x ASC` puts NULLs **last**; SQLite puts them first.
|
|
8
|
+
* - Types are enforced, so bad input is rejected rather than silently coerced.
|
|
9
|
+
* - Collation is locale-aware, so ordering of unicode and mixed case is a real decision.
|
|
10
|
+
* - `LIKE` is case-sensitive and `ILIKE` genuinely differs — on SQLite the two are
|
|
11
|
+
* indistinguishable for ASCII, which makes an ilike check structurally untestable there.
|
|
12
|
+
*
|
|
13
|
+
* Each server instance gets its own scratch database, dropped on close, so runs never collide.
|
|
14
|
+
*/
|
|
15
|
+
import postgres from "postgres";
|
|
16
|
+
import { ENTITIES, OVERCLAIMED_FIELD, fieldsWhere } from "../model.js";
|
|
17
|
+
import { decodeCursor, encodeCursor, project, SqlError, splitTopLevel, stripParens, } from "../store-api.js";
|
|
18
|
+
const PG_TYPE = {
|
|
19
|
+
boolean: "boolean",
|
|
20
|
+
integer: "bigint",
|
|
21
|
+
number: "double precision",
|
|
22
|
+
string: "text",
|
|
23
|
+
};
|
|
24
|
+
function ident(name) {
|
|
25
|
+
return `"${name.replace(/"/g, '""')}"`;
|
|
26
|
+
}
|
|
27
|
+
export class PgStore {
|
|
28
|
+
sql;
|
|
29
|
+
admin;
|
|
30
|
+
dbName;
|
|
31
|
+
defects;
|
|
32
|
+
sequence = 0;
|
|
33
|
+
constructor(sql, admin, dbName, defects) {
|
|
34
|
+
this.sql = sql;
|
|
35
|
+
this.admin = admin;
|
|
36
|
+
this.dbName = dbName;
|
|
37
|
+
this.defects = defects;
|
|
38
|
+
}
|
|
39
|
+
static async create(defects) {
|
|
40
|
+
const dbName = `oat_ref_${process.pid}_${Date.now().toString(36)}${Math.floor(Math.random() * 1e6).toString(36)}`;
|
|
41
|
+
const admin = postgres({ database: "postgres", max: 1, onnotice: () => { } });
|
|
42
|
+
await admin.unsafe(`CREATE DATABASE ${ident(dbName)}`);
|
|
43
|
+
const sql = postgres({ database: dbName, max: 4, onnotice: () => { } });
|
|
44
|
+
const store = new PgStore(sql, admin, dbName, defects);
|
|
45
|
+
await store.migrate();
|
|
46
|
+
return store;
|
|
47
|
+
}
|
|
48
|
+
async close() {
|
|
49
|
+
await this.sql.end({ timeout: 5 });
|
|
50
|
+
/* Drop with FORCE: a lingering session would otherwise leave scratch databases behind on
|
|
51
|
+
* every run, which is the same litter problem oat reports in the systems it tests. */
|
|
52
|
+
try {
|
|
53
|
+
await this.admin.unsafe(`DROP DATABASE IF EXISTS ${ident(this.dbName)} WITH (FORCE)`);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
await this.admin.end({ timeout: 5 });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async migrate() {
|
|
60
|
+
/* A case-insensitive collation that genuinely differs from the database default.
|
|
61
|
+
*
|
|
62
|
+
* The scratch database inherits the cluster's locale, which here is C — so `COLLATE "C"`
|
|
63
|
+
* would be a no-op and the collation defect would be invisible. Declaring an explicit ICU
|
|
64
|
+
* collation makes the disagreement real regardless of how the cluster was initialised. */
|
|
65
|
+
await this.sql.unsafe(`CREATE COLLATION oat_ci (provider = icu, locale = 'und-u-ks-level2', deterministic = false)`);
|
|
66
|
+
for (const entity of ENTITIES) {
|
|
67
|
+
const columns = entity.fields.map((field) => {
|
|
68
|
+
const notNull = field.required === true ? " NOT NULL" : "";
|
|
69
|
+
return `${ident(this.physical(field.name))} ${PG_TYPE[field.type]}${notNull}`;
|
|
70
|
+
});
|
|
71
|
+
await this.sql.unsafe(`CREATE TABLE ${ident(entity.plural)} (${columns.join(", ")}, PRIMARY KEY (${ident(this.physical(entity.identity))}))`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** The stored column for a field — diverges from the declared name only under the defect. */
|
|
75
|
+
physical(name) {
|
|
76
|
+
return this.defects.has("COLUMN_NAME_MISMATCH") && name === "name" ? "mislabelled_name" : name;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Explicit projection, aliased back to declared names.
|
|
80
|
+
*
|
|
81
|
+
* Under COLUMN_NAME_MISMATCH the read asks for a column that does not exist. Postgres errors
|
|
82
|
+
* outright where SQLite's double-quoted-string fallback silently yields the identifier as a
|
|
83
|
+
* literal — the same defect, two failure modes, which is the point of running both.
|
|
84
|
+
*/
|
|
85
|
+
selectList(entity) {
|
|
86
|
+
return entity.fields
|
|
87
|
+
.map((f) => {
|
|
88
|
+
if (!this.defects.has("COLUMN_NAME_MISMATCH") || f.name !== "name") {
|
|
89
|
+
return `${ident(f.name)} AS ${ident(f.name)}`;
|
|
90
|
+
}
|
|
91
|
+
return `'${f.name}'::text AS ${ident(f.name)}`;
|
|
92
|
+
})
|
|
93
|
+
.join(", ");
|
|
94
|
+
}
|
|
95
|
+
nextId(prefix) {
|
|
96
|
+
this.sequence += 1;
|
|
97
|
+
return `${prefix}_${String(this.sequence).padStart(6, "0")}`;
|
|
98
|
+
}
|
|
99
|
+
now() {
|
|
100
|
+
return 1_700_000_000_000 + this.sequence * 1000;
|
|
101
|
+
}
|
|
102
|
+
async insert(entity, record) {
|
|
103
|
+
const names = entity.fields.map((f) => f.name).filter((n) => record[n] !== undefined);
|
|
104
|
+
const columns = names.map((n) => ident(this.physical(n))).join(", ");
|
|
105
|
+
const holes = names.map((_, i) => `$${i + 1}`).join(", ");
|
|
106
|
+
await this.sql.unsafe(`INSERT INTO ${ident(entity.plural)} (${columns}) VALUES (${holes})`, names.map((n) => toPg(record[n])));
|
|
107
|
+
return (await this.byId(entity, String(record[entity.identity]))) ?? record;
|
|
108
|
+
}
|
|
109
|
+
async byId(entity, id) {
|
|
110
|
+
const rows = await this.sql.unsafe(`SELECT ${this.selectList(entity)} FROM ${ident(entity.plural)} WHERE ${ident(this.physical(entity.identity))} = $1`, [id]);
|
|
111
|
+
const row = rows[0];
|
|
112
|
+
return row === undefined ? null : this.decode(entity, row);
|
|
113
|
+
}
|
|
114
|
+
async update(entity, id, patch) {
|
|
115
|
+
if (this.defects.has("CONCURRENT_WRITE_LOST"))
|
|
116
|
+
return this.readModifyWrite(entity, id, patch);
|
|
117
|
+
const names = Object.keys(patch).filter((n) => entity.fields.some((f) => f.name === n));
|
|
118
|
+
if (names.length > 0) {
|
|
119
|
+
const assignments = names.map((n, i) => `${ident(this.physical(n))} = $${i + 1}`).join(", ");
|
|
120
|
+
await this.sql.unsafe(`UPDATE ${ident(entity.plural)} SET ${assignments} WHERE ${ident(this.physical(entity.identity))} = $${names.length + 1}`, [...names.map((n) => toPg(patch[n])), id]);
|
|
121
|
+
}
|
|
122
|
+
return this.byId(entity, id);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Reads the row, yields, then writes every column back — the `save(entity)` pattern.
|
|
126
|
+
*
|
|
127
|
+
* Under concurrency the second writer reinstates whatever it read before the first writer
|
|
128
|
+
* committed, so a patch to a different field is silently reverted. The yield is what makes
|
|
129
|
+
* the window observable rather than dependent on scheduler luck.
|
|
130
|
+
*/
|
|
131
|
+
async readModifyWrite(entity, id, patch) {
|
|
132
|
+
const current = await this.byId(entity, id);
|
|
133
|
+
if (current === null)
|
|
134
|
+
return null;
|
|
135
|
+
await new Promise((resolve) => setTimeout(resolve, 15));
|
|
136
|
+
const merged = { ...current, ...patch };
|
|
137
|
+
const names = entity.fields.map((f) => f.name);
|
|
138
|
+
const assignments = names.map((n, i) => `${ident(this.physical(n))} = $${i + 1}`).join(", ");
|
|
139
|
+
await this.sql.unsafe(`UPDATE ${ident(entity.plural)} SET ${assignments} WHERE ${ident(this.physical(entity.identity))} = $${names.length + 1}`, [...names.map((n) => toPg(merged[n])), id]);
|
|
140
|
+
return this.byId(entity, id);
|
|
141
|
+
}
|
|
142
|
+
async remove(entity, id) {
|
|
143
|
+
await this.sql.unsafe(`DELETE FROM ${ident(entity.plural)} WHERE ${ident(this.physical(entity.identity))} = $1`, [id]);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Restores declared shapes. `bigint` arrives as a string from the wire protocol and would
|
|
147
|
+
* fail its own response schema, and a NULL column must read back as null rather than absent.
|
|
148
|
+
*/
|
|
149
|
+
decode(entity, row) {
|
|
150
|
+
const out = {};
|
|
151
|
+
for (const field of entity.fields) {
|
|
152
|
+
const raw = row[field.name];
|
|
153
|
+
if (raw === undefined || raw === null) {
|
|
154
|
+
out[field.name] = null;
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
out[field.name] =
|
|
158
|
+
field.type === "integer"
|
|
159
|
+
? Number(raw)
|
|
160
|
+
: field.type === "number"
|
|
161
|
+
? Number(raw)
|
|
162
|
+
: field.type === "boolean"
|
|
163
|
+
? raw === true
|
|
164
|
+
: raw;
|
|
165
|
+
}
|
|
166
|
+
return out;
|
|
167
|
+
}
|
|
168
|
+
async query(entity, scope, params, options) {
|
|
169
|
+
const where = [];
|
|
170
|
+
const args = [];
|
|
171
|
+
const hole = () => `$${args.length + 1}`;
|
|
172
|
+
const scoped = !(this.defects.has("TENANT_LEAK_VIA_FILTER") && params.filter !== undefined);
|
|
173
|
+
for (const parent of scoped ? entity.parents : []) {
|
|
174
|
+
const value = scope[parent];
|
|
175
|
+
if (value === undefined)
|
|
176
|
+
continue;
|
|
177
|
+
if (!entity.fields.some((f) => f.name === parent))
|
|
178
|
+
continue;
|
|
179
|
+
where.push(`${ident(this.physical(parent))} = ${hole()}`);
|
|
180
|
+
args.push(value);
|
|
181
|
+
}
|
|
182
|
+
const soft = options.softDeleteField;
|
|
183
|
+
if (soft !== undefined && !this.defects.has("SOFT_DELETE_LEAK")) {
|
|
184
|
+
if (params.filter?.includes(soft) !== true) {
|
|
185
|
+
where.push(`${ident(this.physical(soft))} IS NULL`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (params.filter !== undefined && params.filter !== "") {
|
|
189
|
+
where.push(this.compileFilter(params.filter, entity, args));
|
|
190
|
+
}
|
|
191
|
+
if (params.q !== undefined && params.q !== "" && !this.defects.has("SEARCH_IGNORED")) {
|
|
192
|
+
const searchable = fieldsWhere(entity, "searchable");
|
|
193
|
+
if (searchable.length > 0) {
|
|
194
|
+
const clauses = searchable.map((f) => {
|
|
195
|
+
args.push(`%${escapeLike(params.q ?? "")}%`);
|
|
196
|
+
return `${ident(this.physical(f))}::text ILIKE $${args.length} ESCAPE '\\'`;
|
|
197
|
+
});
|
|
198
|
+
where.push(`(${clauses.join(" OR ")})`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
const dropNulls = [];
|
|
202
|
+
const orderSql = this.compileOrder(params.order, entity, dropNulls);
|
|
203
|
+
for (const field of dropNulls)
|
|
204
|
+
where.push(`${ident(this.physical(field))} IS NOT NULL`);
|
|
205
|
+
const whereSql = where.length > 0 ? ` WHERE ${where.join(" AND ")}` : "";
|
|
206
|
+
const countWhere = this.defects.has("COUNT_IGNORES_FILTER") ? "" : whereSql;
|
|
207
|
+
const countArgs = this.defects.has("COUNT_IGNORES_FILTER") ? [] : args;
|
|
208
|
+
const countRows = (await this.sql.unsafe(`SELECT COUNT(*)::bigint AS n FROM ${ident(entity.plural)}${countWhere}`, countArgs));
|
|
209
|
+
const total = Number(countRows[0]?.n ?? 0);
|
|
210
|
+
const requested = params.limit ?? entity.defaultLimit;
|
|
211
|
+
const limit = this.defects.has("LIMIT_EXCEEDS_MAX")
|
|
212
|
+
? requested
|
|
213
|
+
: Math.min(requested, entity.maxLimit);
|
|
214
|
+
let offset;
|
|
215
|
+
let page;
|
|
216
|
+
if (params.cursor !== undefined && params.cursor !== "") {
|
|
217
|
+
const afterId = decodeCursor(params.cursor);
|
|
218
|
+
/* The cursor boundary must be resolved under exactly the listing's ordering. Under the
|
|
219
|
+
* defect it is resolved with a different collation, so the index found here is not the
|
|
220
|
+
* index the listing would have produced and the page boundary lands elsewhere. */
|
|
221
|
+
/* Collation "C" against the listing's locale default: the two disagree on case and on
|
|
222
|
+
* anything non-ASCII, so the boundary resolves to a different row. */
|
|
223
|
+
const cursorOrderSql = this.defects.has("COLLATION_INCONSISTENT")
|
|
224
|
+
? orderSql.replace(/(".*?")( (?:ASC|DESC))/g, "$1 COLLATE oat_ci$2")
|
|
225
|
+
: orderSql;
|
|
226
|
+
const ordered = (await this.sql.unsafe(`SELECT ${ident(this.physical(entity.identity))} AS id FROM ${ident(entity.plural)}${whereSql}${cursorOrderSql}`, args));
|
|
227
|
+
const index = ordered.findIndex((r) => String(r.id) === afterId);
|
|
228
|
+
offset = index === -1 ? 0 : index + (this.defects.has("CURSOR_DRIFT") ? 0 : 1);
|
|
229
|
+
page = null;
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
const requestedPage = Math.max(params.page ?? 1, 1);
|
|
233
|
+
offset =
|
|
234
|
+
(requestedPage - 1) * limit +
|
|
235
|
+
(this.defects.has("OFF_BY_ONE_PAGE") && requestedPage > 1 ? 1 : 0);
|
|
236
|
+
page = requestedPage;
|
|
237
|
+
}
|
|
238
|
+
const limitSql = this.defects.has("LIMIT_IGNORED") ? "ALL" : String(limit);
|
|
239
|
+
const rows = (await this.sql.unsafe(`SELECT ${this.selectList(entity)} FROM ${ident(entity.plural)}${whereSql}${orderSql} LIMIT ${limitSql} OFFSET ${offset}`, args));
|
|
240
|
+
const effective = this.defects.has("EMPTY_RESULT_RETURNS_ALL") && rows.length === 0 && where.length > 0
|
|
241
|
+
? (await this.sql.unsafe(`SELECT ${this.selectList(entity)} FROM ${ident(entity.plural)}${orderSql} LIMIT ${limitSql} OFFSET ${offset}`, []))
|
|
242
|
+
: rows;
|
|
243
|
+
const decoded = effective.map((row) => this.decode(entity, row));
|
|
244
|
+
const transformed = options.transform === undefined ? decoded : decoded.map((r) => options.transform?.(r) ?? r);
|
|
245
|
+
const last = transformed.at(-1);
|
|
246
|
+
const hasMore = this.defects.has("HASMORE_ALWAYS_FALSE") ? false : offset + decoded.length < total;
|
|
247
|
+
return {
|
|
248
|
+
count: this.defects.has("COUNT_ALWAYS_ZERO") ? 0 : total,
|
|
249
|
+
hasMore,
|
|
250
|
+
items: transformed.map((row) => project(row, params.select, this.defects.has("SELECT_IGNORED"), this.defects.has("SPEC_OVERCLAIMS_SELECTABLE") ? [OVERCLAIMED_FIELD] : [])),
|
|
251
|
+
limit,
|
|
252
|
+
nextCursor: hasMore && last !== undefined ? encodeCursor(String(last[entity.identity])) : null,
|
|
253
|
+
page,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
compileFilter(expression, entity, args) {
|
|
257
|
+
const trimmed = expression.trim();
|
|
258
|
+
const hole = (value) => {
|
|
259
|
+
args.push(value);
|
|
260
|
+
return `$${args.length}`;
|
|
261
|
+
};
|
|
262
|
+
const group = /^(and|or)\((.*)\)$/s.exec(trimmed);
|
|
263
|
+
if (group?.[1] && group[2] !== undefined) {
|
|
264
|
+
const parts = splitTopLevel(group[2]).map((p) => this.compileFilter(p, entity, args));
|
|
265
|
+
if (parts.length === 0)
|
|
266
|
+
throw new SqlError("invalid_filter", "empty filter group");
|
|
267
|
+
const effective = this.defects.has("FILTER_GROUP_COMBINATOR_SWAPPED")
|
|
268
|
+
? (group[1] === "and" ? "or" : "and")
|
|
269
|
+
: group[1];
|
|
270
|
+
return `(${parts.join(effective === "and" ? " AND " : " OR ")})`;
|
|
271
|
+
}
|
|
272
|
+
const segments = trimmed.split(".");
|
|
273
|
+
if (segments.length < 3) {
|
|
274
|
+
throw new SqlError("invalid_filter", `malformed filter term "${trimmed}"`);
|
|
275
|
+
}
|
|
276
|
+
const [field, op] = segments;
|
|
277
|
+
const raw = segments.slice(2).join(".");
|
|
278
|
+
/* Under the overclaim defect the backend refuses a field the document still declares
|
|
279
|
+
* filterable — the backend is not wrong to refuse, the document is wrong to promise. */
|
|
280
|
+
const filterable = this.defects.has("SPEC_OVERCLAIMS_FILTERABLE")
|
|
281
|
+
? fieldsWhere(entity, "filterable").filter((f) => f !== OVERCLAIMED_FIELD)
|
|
282
|
+
: fieldsWhere(entity, "filterable");
|
|
283
|
+
if (!filterable.includes(field)) {
|
|
284
|
+
if (this.defects.has("FILTER_IGNORED"))
|
|
285
|
+
return "TRUE";
|
|
286
|
+
throw new SqlError("invalid_filter", `field "${field}" is not filterable`);
|
|
287
|
+
}
|
|
288
|
+
const declared = entity.fields.find((f) => f.name === field);
|
|
289
|
+
const numeric = declared?.type === "integer" || declared?.type === "number";
|
|
290
|
+
/* Compare as text unless the column is genuinely numeric: Postgres refuses to compare a
|
|
291
|
+
* bigint against an arbitrary string, and the grammar's values arrive untyped. Under the
|
|
292
|
+
* defect even numeric columns go through text, which is what makes `amount > 9` miss 10. */
|
|
293
|
+
const asText = !numeric || this.defects.has("NUMERIC_COMPARED_AS_TEXT");
|
|
294
|
+
const ref = ident(this.physical(field));
|
|
295
|
+
const cast = asText ? "::text" : "";
|
|
296
|
+
switch (op) {
|
|
297
|
+
case "eq":
|
|
298
|
+
if (this.defects.has("FILTER_EQ_NOT_APPLIED"))
|
|
299
|
+
return "TRUE";
|
|
300
|
+
return `${ref}${cast} = ${hole(coerce(raw, asText ? undefined : declared))}`;
|
|
301
|
+
case "neq":
|
|
302
|
+
/* NULL must be re-admitted explicitly: `col <> x` is NULL, not true, for NULL rows,
|
|
303
|
+
* so they silently vanish without the IS NULL branch. */
|
|
304
|
+
return this.defects.has("NEQ_DROPS_NULLS")
|
|
305
|
+
? `${ref}${cast} <> ${hole(coerce(raw, asText ? undefined : declared))}`
|
|
306
|
+
: `(${ref}${cast} <> ${hole(coerce(raw, asText ? undefined : declared))} OR ${ref} IS NULL)`;
|
|
307
|
+
case "gt":
|
|
308
|
+
return `${ref}${cast} > ${hole(coerce(raw, asText ? undefined : declared))}`;
|
|
309
|
+
case "gte":
|
|
310
|
+
return `${ref}${cast} >= ${hole(coerce(raw, asText ? undefined : declared))}`;
|
|
311
|
+
case "lt":
|
|
312
|
+
return `${ref}${cast} < ${hole(coerce(raw, asText ? undefined : declared))}`;
|
|
313
|
+
case "lte":
|
|
314
|
+
return `${ref}${cast} <= ${hole(coerce(raw, asText ? undefined : declared))}`;
|
|
315
|
+
case "in":
|
|
316
|
+
case "nin": {
|
|
317
|
+
const members = stripParens(raw)
|
|
318
|
+
.split(",")
|
|
319
|
+
.map((s) => coerce(s.trim(), asText ? undefined : declared));
|
|
320
|
+
const holes = members.map((m) => hole(m)).join(", ");
|
|
321
|
+
return op === "in" ? `${ref}${cast} IN (${holes})` : `${ref}${cast} NOT IN (${holes})`;
|
|
322
|
+
}
|
|
323
|
+
case "is":
|
|
324
|
+
if (raw === "null")
|
|
325
|
+
return `${ref} IS NULL`;
|
|
326
|
+
if (raw === "true")
|
|
327
|
+
return `${ref} IS TRUE`;
|
|
328
|
+
if (raw === "false")
|
|
329
|
+
return `${ref} IS FALSE`;
|
|
330
|
+
throw new SqlError("invalid_filter", `is.${raw} is not a recognised predicate`);
|
|
331
|
+
case "like":
|
|
332
|
+
case "ilike": {
|
|
333
|
+
const pattern = this.defects.has("LIKE_UNESCAPED")
|
|
334
|
+
? raw.replace(/\*/g, "%")
|
|
335
|
+
: escapeLike(raw).replace(/\*/g, "%");
|
|
336
|
+
/* Postgres distinguishes these; SQLite cannot for ASCII. Honouring the distinction
|
|
337
|
+
* is only meaningful on an engine that has it. */
|
|
338
|
+
const operator = op === "ilike" ? "ILIKE" : "LIKE";
|
|
339
|
+
return `${ref}${cast} ${operator} ${hole(pattern)} ESCAPE '\\'`;
|
|
340
|
+
}
|
|
341
|
+
default:
|
|
342
|
+
throw new SqlError("invalid_filter", `unknown operator "${op}"`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
compileOrder(expression, entity, dropNulls) {
|
|
346
|
+
if (this.defects.has("ORDER_IGNORED"))
|
|
347
|
+
return "";
|
|
348
|
+
const terms = [];
|
|
349
|
+
if (expression !== undefined && expression !== "") {
|
|
350
|
+
for (const raw of splitTopLevel(expression)) {
|
|
351
|
+
const [field, ...modifiers] = raw.split(".");
|
|
352
|
+
/* Under the overclaim defect the backend refuses a field the document still declares
|
|
353
|
+
* sortable — the backend is not wrong to refuse, the document is wrong to promise. */
|
|
354
|
+
const sortable = this.defects.has("SPEC_OVERCLAIMS_SORTABLE")
|
|
355
|
+
? fieldsWhere(entity, "sortable").filter((f) => f !== OVERCLAIMED_FIELD)
|
|
356
|
+
: fieldsWhere(entity, "sortable");
|
|
357
|
+
if (field === undefined || !sortable.includes(field)) {
|
|
358
|
+
throw new SqlError("invalid_order", `field "${field ?? ""}" is not sortable`);
|
|
359
|
+
}
|
|
360
|
+
const descending = modifiers.includes("desc");
|
|
361
|
+
const nullsFirst = modifiers.includes("nullsfirst")
|
|
362
|
+
? true
|
|
363
|
+
: modifiers.includes("nullslast")
|
|
364
|
+
? false
|
|
365
|
+
: descending;
|
|
366
|
+
const declared = entity.fields.find((f) => f.name === field);
|
|
367
|
+
const numeric = declared?.type === "integer" || declared?.type === "number";
|
|
368
|
+
const ref = numeric && this.defects.has("NUMERIC_COMPARED_AS_TEXT")
|
|
369
|
+
? `${ident(this.physical(field))}::text`
|
|
370
|
+
: ident(this.physical(field));
|
|
371
|
+
terms.push(`${ref} ${descending ? "DESC" : "ASC"} NULLS ${nullsFirst ? "FIRST" : "LAST"}`);
|
|
372
|
+
if (descending && this.defects.has("SORT_DESC_DROPS_NULLS"))
|
|
373
|
+
dropNulls.push(field);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (this.defects.has("UNSTABLE_SORT")) {
|
|
377
|
+
terms.push("random()");
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
terms.push(`${ident(this.physical(entity.identity))} ASC`);
|
|
381
|
+
}
|
|
382
|
+
return terms.length > 0 ? ` ORDER BY ${terms.join(", ")}` : "";
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function toPg(value) {
|
|
386
|
+
if (value === undefined)
|
|
387
|
+
return null;
|
|
388
|
+
if (value !== null && typeof value === "object")
|
|
389
|
+
return JSON.stringify(value);
|
|
390
|
+
return value;
|
|
391
|
+
}
|
|
392
|
+
function coerce(raw, field) {
|
|
393
|
+
if (raw === "null")
|
|
394
|
+
return null;
|
|
395
|
+
if (field?.type === "integer" || field?.type === "number") {
|
|
396
|
+
const n = Number(raw);
|
|
397
|
+
if (Number.isNaN(n))
|
|
398
|
+
throw new SqlError("invalid_filter", `"${raw}" is not a number`);
|
|
399
|
+
return n;
|
|
400
|
+
}
|
|
401
|
+
return raw;
|
|
402
|
+
}
|
|
403
|
+
function escapeLike(value) {
|
|
404
|
+
return value.replace(/[\\%_]/g, (ch) => `\\${ch}`);
|
|
405
|
+
}
|
|
406
|
+
//# sourceMappingURL=postgres.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgres.js","sourceRoot":"","sources":["../../../src/reference/stores/postgres.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,QAAQ,MAAM,UAAU,CAAA;AAE/B,OAAO,EAAE,QAAQ,EAAiC,iBAAiB,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACrG,OAAO,EACN,YAAY,EACZ,YAAY,EACZ,OAAO,EAKP,QAAQ,EACR,aAAa,EACb,WAAW,GAEX,MAAM,iBAAiB,CAAA;AAOxB,MAAM,OAAO,GAAqC;IACjD,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,QAAQ;IACjB,MAAM,EAAE,kBAAkB;IAC1B,MAAM,EAAE,MAAM;CACd,CAAA;AAED,SAAS,KAAK,CAAC,IAAY;IAC1B,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAA;AACvC,CAAC;AAED,MAAM,OAAO,OAAO;IAID;IACA;IACA;IACA;IANV,QAAQ,GAAG,CAAC,CAAA;IAEpB,YACkB,GAAQ,EACR,KAAU,EACV,MAAc,EACd,OAAkB;QAHlB,QAAG,GAAH,GAAG,CAAK;QACR,UAAK,GAAL,KAAK,CAAK;QACV,WAAM,GAAN,MAAM,CAAQ;QACd,YAAO,GAAP,OAAO,CAAW;IACjC,CAAC;IAEJ,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAkB;QACrC,MAAM,MAAM,GAAG,WAAW,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAA;QACjH,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC,CAAA;QAC5E,MAAM,KAAK,CAAC,MAAM,CAAC,mBAAmB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;QACtD,MAAM,GAAG,GAAG,QAAQ,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC,CAAA;QACtE,MAAM,KAAK,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;QACtD,MAAM,KAAK,CAAC,OAAO,EAAE,CAAA;QACrB,OAAO,KAAK,CAAA;IACb,CAAC;IAED,KAAK,CAAC,KAAK;QACV,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAA;QAClC;8FACsF;QACtF,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,2BAA2B,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAA;QACtF,CAAC;gBAAS,CAAC;YACV,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAA;QACrC,CAAC;IACF,CAAC;IAEO,KAAK,CAAC,OAAO;QACpB;;;;kGAI0F;QAC1F,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CACpB,6FAA6F,CAC7F,CAAA;QACD,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;gBAC3C,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAA;gBAC1D,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,EAAE,CAAA;YAC9E,CAAC,CAAC,CAAA;YACF,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CACpB,gBAAgB,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CACtH,CAAA;QACF,CAAC;IACF,CAAC;IAED,6FAA6F;IACrF,QAAQ,CAAC,IAAY;QAC5B,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,IAAI,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAA;IAC/F,CAAC;IAED;;;;;;OAMG;IACK,UAAU,CAAC,MAAiB;QACnC,OAAO,MAAM,CAAC,MAAM;aAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACV,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACpE,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAA;YAC9C,CAAC;YACD,OAAO,IAAI,CAAC,CAAC,IAAI,cAAc,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAA;QAC/C,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,CAAC,CAAA;IACb,CAAC;IAED,MAAM,CAAC,MAAc;QACpB,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAA;QAClB,OAAO,GAAG,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAA;IAC7D,CAAC;IAED,GAAG;QACF,OAAO,iBAAiB,GAAG,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAA;IAChD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAiB,EAAE,MAAW;QAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAA;QACrF,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACpE,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACzD,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CACpB,eAAe,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,OAAO,aAAa,KAAK,GAAG,EACpE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CACjC,CAAA;QACD,OAAO,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAA;IAC5E,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAiB,EAAE,EAAU;QACvC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CACjC,UAAU,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,EACpH,CAAC,EAAE,CAAC,CACJ,CAAA;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAoB,CAAA;QACtC,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IAC3D,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAiB,EAAE,EAAU,EAAE,KAAU;QACrD,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;YAAE,OAAO,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,CAAC,CAAA;QAC7F,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAA;QACvF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YAC5F,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CACpB,UAAU,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,WAAW,UAAU,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,EACzH,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACzC,CAAA;QACF,CAAC;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAC7B,CAAC;IAED;;;;;;OAMG;IACK,KAAK,CAAC,eAAe,CAAC,MAAiB,EAAE,EAAU,EAAE,KAAU;QACtE,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QAC3C,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,IAAI,CAAA;QACjC,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAA;QACvD,MAAM,MAAM,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,KAAK,EAAE,CAAA;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAC9C,MAAM,WAAW,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QAC5F,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CACpB,UAAU,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,WAAW,UAAU,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,EACzH,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAC1C,CAAA;QACD,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAC7B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAiB,EAAE,EAAU;QACzC,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CACpB,eAAe,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,EACzF,CAAC,EAAE,CAAC,CACJ,CAAA;IACF,CAAC;IAED;;;OAGG;IACK,MAAM,CAAC,MAAiB,EAAE,GAAQ;QACzC,MAAM,GAAG,GAAQ,EAAE,CAAA;QACnB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YACnC,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YAC3B,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACvC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;gBACtB,SAAQ;YACT,CAAC;YACD,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;gBACd,KAAK,CAAC,IAAI,KAAK,SAAS;oBACvB,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;oBACb,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ;wBACxB,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;wBACb,CAAC,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS;4BACzB,CAAC,CAAC,GAAG,KAAK,IAAI;4BACd,CAAC,CAAC,GAAG,CAAA;QACV,CAAC;QACD,OAAO,GAAG,CAAA;IACX,CAAC;IAED,KAAK,CAAC,KAAK,CACV,MAAiB,EACjB,KAA6B,EAC7B,MAAmB,EACnB,OAAqB;QAErB,MAAM,KAAK,GAAa,EAAE,CAAA;QAC1B,MAAM,IAAI,GAAc,EAAE,CAAA;QAC1B,MAAM,IAAI,GAAG,GAAW,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAA;QAEhD,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAA;QAC3F,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACnD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAA;YAC3B,IAAI,KAAK,KAAK,SAAS;gBAAE,SAAQ;YACjC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;gBAAE,SAAQ;YAC3D,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAA;YACzD,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACjB,CAAC;QAED,MAAM,IAAI,GAAG,OAAO,CAAC,eAAe,CAAA;QACpC,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACjE,IAAI,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC5C,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAA;YACpD,CAAC;QACF,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;YACzD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;QAC5D,CAAC;QAED,IAAI,MAAM,CAAC,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACtF,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;YACpD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3B,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;oBACpC,IAAI,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAA;oBAC5C,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,iBAAiB,IAAI,CAAC,MAAM,cAAc,CAAA;gBAC5E,CAAC,CAAC,CAAA;gBACF,KAAK,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YACxC,CAAC;QACF,CAAC;QAED,MAAM,SAAS,GAAa,EAAE,CAAA;QAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAAA;QACnE,KAAK,MAAM,KAAK,IAAI,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,cAAc,CAAC,CAAA;QAEvF,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QAExE,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAA;QAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;QACtE,MAAM,SAAS,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CACvC,qCAAqC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,UAAU,EAAE,EACxE,SAAS,CACT,CAAoC,CAAA;QACrC,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;QAE1C,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,YAAY,CAAA;QACrD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;YAClD,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;QAEvC,IAAI,MAAc,CAAA;QAClB,IAAI,IAAmB,CAAA;QACvB,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;YACzD,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YAC3C;;8FAEkF;YAClF;kFACsE;YACtE,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;gBAChE,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,yBAAyB,EAAE,qBAAqB,CAAC;gBACpE,CAAC,CAAC,QAAQ,CAAA;YACX,MAAM,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CACrC,UAAU,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,eAAe,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,QAAQ,GAAG,cAAc,EAAE,EAChH,IAAI,CACJ,CAAqC,CAAA;YACtC,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,CAAA;YAChE,MAAM,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAC9E,IAAI,GAAG,IAAI,CAAA;QACZ,CAAC;aAAM,CAAC;YACP,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;YACnD,MAAM;gBACL,CAAC,aAAa,GAAG,CAAC,CAAC,GAAG,KAAK;oBAC3B,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,IAAI,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YACnE,IAAI,GAAG,aAAa,CAAA;QACrB,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;QAC1E,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CAClC,UAAU,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,QAAQ,GAAG,QAAQ,UAAU,QAAQ,WAAW,MAAM,EAAE,EACzH,IAAI,CACJ,CAAqB,CAAA;QAEtB,MAAM,SAAS,GACd,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;YACpF,CAAC,CAAE,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,MAAM,CACvB,UAAU,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,QAAQ,UAAU,QAAQ,WAAW,MAAM,EAAE,EAC9G,EAAE,CACF,CAAsB;YACxB,CAAC,CAAC,IAAI,CAAA;QAER,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;QAChE,MAAM,WAAW,GAChB,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QAC5F,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,KAAK,CAAA;QAElG,OAAO;YACN,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK;YACxD,OAAO;YACP,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAC9B,OAAO,CACN,GAAG,EACH,MAAM,CAAC,MAAM,EACb,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAClC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAE,CACzE,CACD;YACD,KAAK;YACL,UAAU,EACT,OAAO,IAAI,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;YACnF,IAAI;SACJ,CAAA;IACF,CAAC;IAEO,aAAa,CAAC,UAAkB,EAAE,MAAiB,EAAE,IAAe;QAC3E,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,EAAE,CAAA;QACjC,MAAM,IAAI,GAAG,CAAC,KAAc,EAAU,EAAE;YACvC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YAChB,OAAO,IAAI,IAAI,CAAC,MAAM,EAAE,CAAA;QACzB,CAAC,CAAA;QAED,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACjD,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;YAC1C,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAA;YACrF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAM,IAAI,QAAQ,CAAC,gBAAgB,EAAE,oBAAoB,CAAC,CAAA;YAClF,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC;gBACpE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;gBACrC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;YACX,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAA;QACjE,CAAC;QAED,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QACnC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,QAAQ,CAAC,gBAAgB,EAAE,0BAA0B,OAAO,GAAG,CAAC,CAAA;QAC3E,CAAC;QACD,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,QAAyC,CAAA;QAC7D,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAEvC;gGACwF;QACxF,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC;YAChE,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,iBAAiB,CAAC;YAC1E,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;QACpC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACjC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;gBAAE,OAAO,MAAM,CAAA;YACrD,MAAM,IAAI,QAAQ,CAAC,gBAAgB,EAAE,UAAU,KAAK,qBAAqB,CAAC,CAAA;QAC3E,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAA;QAC5D,MAAM,OAAO,GAAG,QAAQ,EAAE,IAAI,KAAK,SAAS,IAAI,QAAQ,EAAE,IAAI,KAAK,QAAQ,CAAA;QAC3E;;oGAE4F;QAC5F,MAAM,MAAM,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAA;QACvE,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;QACvC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;QAEnC,QAAQ,EAAE,EAAE,CAAC;YACZ,KAAK,IAAI;gBACR,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;oBAAE,OAAO,MAAM,CAAA;gBAC5D,OAAO,GAAG,GAAG,GAAG,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAA;YAC7E,KAAK,KAAK;gBACT;yEACyD;gBACzD,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;oBACzC,CAAC,CAAC,GAAG,GAAG,GAAG,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE;oBACxE,CAAC,CAAC,IAAI,GAAG,GAAG,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,GAAG,WAAW,CAAA;YAC9F,KAAK,IAAI;gBACR,OAAO,GAAG,GAAG,GAAG,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAA;YAC7E,KAAK,KAAK;gBACT,OAAO,GAAG,GAAG,GAAG,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAA;YAC9E,KAAK,IAAI;gBACR,OAAO,GAAG,GAAG,GAAG,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAA;YAC7E,KAAK,KAAK;gBACT,OAAO,GAAG,GAAG,GAAG,IAAI,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAA;YAC9E,KAAK,IAAI,CAAC;YACV,KAAK,KAAK,CAAC,CAAC,CAAC;gBACZ,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,CAAC;qBAC9B,KAAK,CAAC,GAAG,CAAC;qBACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;gBAC7D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBACpD,OAAO,EAAE,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,IAAI,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,IAAI,YAAY,KAAK,GAAG,CAAA;YACvF,CAAC;YACD,KAAK,IAAI;gBACR,IAAI,GAAG,KAAK,MAAM;oBAAE,OAAO,GAAG,GAAG,UAAU,CAAA;gBAC3C,IAAI,GAAG,KAAK,MAAM;oBAAE,OAAO,GAAG,GAAG,UAAU,CAAA;gBAC3C,IAAI,GAAG,KAAK,OAAO;oBAAE,OAAO,GAAG,GAAG,WAAW,CAAA;gBAC7C,MAAM,IAAI,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,gCAAgC,CAAC,CAAA;YAChF,KAAK,MAAM,CAAC;YACZ,KAAK,OAAO,CAAC,CAAC,CAAC;gBACd,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;oBACjD,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;oBACzB,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;gBACtC;kEACkD;gBAClD,MAAM,QAAQ,GAAG,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAA;gBAClD,OAAO,GAAG,GAAG,GAAG,IAAI,IAAI,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,cAAc,CAAA;YAChE,CAAC;YACD;gBACC,MAAM,IAAI,QAAQ,CAAC,gBAAgB,EAAE,qBAAqB,EAAE,GAAG,CAAC,CAAA;QAClE,CAAC;IACF,CAAC;IAEO,YAAY,CACnB,UAA8B,EAC9B,MAAiB,EACjB,SAAmB;QAEnB,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;YAAE,OAAO,EAAE,CAAA;QAChD,MAAM,KAAK,GAAa,EAAE,CAAA;QAE1B,IAAI,UAAU,KAAK,SAAS,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;YACnD,KAAK,MAAM,GAAG,IAAI,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC7C,MAAM,CAAC,KAAK,EAAE,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;gBAC5C;sGACsF;gBACtF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;oBAC5D,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,iBAAiB,CAAC;oBACxE,CAAC,CAAC,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,CAAA;gBAClC,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBACtD,MAAM,IAAI,QAAQ,CAAC,eAAe,EAAE,UAAU,KAAK,IAAI,EAAE,mBAAmB,CAAC,CAAA;gBAC9E,CAAC;gBACD,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;gBAC7C,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,CAAC,YAAY,CAAC;oBAClD,CAAC,CAAC,IAAI;oBACN,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC;wBAChC,CAAC,CAAC,KAAK;wBACP,CAAC,CAAC,UAAU,CAAA;gBACd,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAA;gBAC5D,MAAM,OAAO,GAAG,QAAQ,EAAE,IAAI,KAAK,SAAS,IAAI,QAAQ,EAAE,IAAI,KAAK,QAAQ,CAAA;gBAC3E,MAAM,GAAG,GACR,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC;oBACtD,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,QAAQ;oBACxC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAA;gBAC/B,KAAK,CAAC,IAAI,CACT,GAAG,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,UAAU,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,CAC9E,CAAA;gBACD,IAAI,UAAU,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC;oBAAE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACnF,CAAC;QACF,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;YACvC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACvB,CAAC;aAAM,CAAC;YACP,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAA;QAC3D,CAAC;QAED,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,aAAa,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IAC/D,CAAC;CACD;AAED,SAAS,IAAI,CAAC,KAAc;IAC3B,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAA;IACpC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC7E,OAAO,KAAgB,CAAA;AACxB,CAAC;AAED,SAAS,MAAM,CAAC,GAAW,EAAE,KAA2B;IACvD,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,IAAI,CAAA;IAC/B,IAAI,KAAK,EAAE,IAAI,KAAK,SAAS,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3D,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAA;QACrB,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAAE,MAAM,IAAI,QAAQ,CAAC,gBAAgB,EAAE,IAAI,GAAG,mBAAmB,CAAC,CAAA;QACrF,OAAO,CAAC,CAAA;IACT,CAAC;IACD,OAAO,GAAG,CAAA;AACX,CAAC;AAED,SAAS,UAAU,CAAC,KAAa;IAChC,OAAO,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AACnD,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the SQLite-dialect store reaches an engine.
|
|
3
|
+
*
|
|
4
|
+
* The store builds SQL; the driver runs it. Splitting them buys the thing an in-process database
|
|
5
|
+
* cannot give: a *networked* SQLite, where every statement is a round trip, results arrive as
|
|
6
|
+
* decoded JSON rather than native values, and the engine is a different build with different
|
|
7
|
+
* compile-time flags. Cloudflare D1 leaves double-quoted-string fallback ON, which `node:sqlite`
|
|
8
|
+
* compiles off — so a DDL/read naming mismatch is an error on one and silent wrong data on the
|
|
9
|
+
* other. Only a real D1 can demonstrate which of those a given check survives.
|
|
10
|
+
*
|
|
11
|
+
* `node:sqlite` is imported dynamically and only by its own driver. Importing it at module scope
|
|
12
|
+
* aborts any process started without `--experimental-sqlite`, which has taken down the CLI and
|
|
13
|
+
* the Postgres path once each.
|
|
14
|
+
*/
|
|
15
|
+
export type SqlValue = string | number | null | Uint8Array;
|
|
16
|
+
export type SqlRow = Record<string, unknown>;
|
|
17
|
+
export interface SqliteDriver {
|
|
18
|
+
/** Human-readable engine name, used in reports so a finding names where it was observed. */
|
|
19
|
+
readonly engine: string;
|
|
20
|
+
/**
|
|
21
|
+
* Whether the engine resolves an unknown double-quoted identifier to a string literal
|
|
22
|
+
* instead of erroring — SQLite's double-quoted-string misfeature.
|
|
23
|
+
*
|
|
24
|
+
* `node:sqlite` compiles it off, D1 leaves it on. That difference decides whether a
|
|
25
|
+
* DDL/read naming mismatch is a loud error or silent wrong data, so the fixture has to know
|
|
26
|
+
* which it is: on a DQS engine it can express the bug in its natural form and let the engine
|
|
27
|
+
* produce the damage, and elsewhere it must emit the resulting literal directly.
|
|
28
|
+
*/
|
|
29
|
+
readonly dqs: boolean;
|
|
30
|
+
/** Statement with no bound parameters and no results — DDL. */
|
|
31
|
+
exec(sql: string): Promise<void>;
|
|
32
|
+
/** Statement with no results. */
|
|
33
|
+
run(sql: string, args: SqlValue[]): Promise<void>;
|
|
34
|
+
/** Statement returning rows. */
|
|
35
|
+
all(sql: string, args: SqlValue[]): Promise<SqlRow[]>;
|
|
36
|
+
close(): Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
/** In-process SQLite via `node:sqlite`. Requires `--experimental-sqlite` on Node 22. */
|
|
39
|
+
export declare function nodeSqliteDriver(): Promise<SqliteDriver>;
|
|
40
|
+
export interface D1Config {
|
|
41
|
+
accountId: string;
|
|
42
|
+
databaseId: string;
|
|
43
|
+
apiToken: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Cloudflare D1 over its HTTP query API.
|
|
47
|
+
*
|
|
48
|
+
* Every call is a network round trip to a shared, persistent database — which is the point. A
|
|
49
|
+
* store that only ever ran against an in-process engine cannot show what happens when writes
|
|
50
|
+
* take milliseconds to become visible, when the engine is someone else's build, or when two
|
|
51
|
+
* runs share one database.
|
|
52
|
+
*/
|
|
53
|
+
export declare function d1Driver(config: D1Config): SqliteDriver;
|
|
54
|
+
//# sourceMappingURL=sqlite-driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-driver.d.ts","sourceRoot":"","sources":["../../../src/reference/stores/sqlite-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,UAAU,CAAA;AAE1D,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAE5C,MAAM,WAAW,YAAY;IAC5B,4FAA4F;IAC5F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB;;;;;;;;OAQG;IACH,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,+DAA+D;IAC/D,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAChC,iCAAiC;IACjC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACjD,gCAAgC;IAChC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACrD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACtB;AAED,wFAAwF;AACxF,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,YAAY,CAAC,CAqB9D;AAED,MAAM,WAAW,QAAQ;IACxB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;CAChB;AAQD;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,YAAY,CA8CvD"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the SQLite-dialect store reaches an engine.
|
|
3
|
+
*
|
|
4
|
+
* The store builds SQL; the driver runs it. Splitting them buys the thing an in-process database
|
|
5
|
+
* cannot give: a *networked* SQLite, where every statement is a round trip, results arrive as
|
|
6
|
+
* decoded JSON rather than native values, and the engine is a different build with different
|
|
7
|
+
* compile-time flags. Cloudflare D1 leaves double-quoted-string fallback ON, which `node:sqlite`
|
|
8
|
+
* compiles off — so a DDL/read naming mismatch is an error on one and silent wrong data on the
|
|
9
|
+
* other. Only a real D1 can demonstrate which of those a given check survives.
|
|
10
|
+
*
|
|
11
|
+
* `node:sqlite` is imported dynamically and only by its own driver. Importing it at module scope
|
|
12
|
+
* aborts any process started without `--experimental-sqlite`, which has taken down the CLI and
|
|
13
|
+
* the Postgres path once each.
|
|
14
|
+
*/
|
|
15
|
+
/** In-process SQLite via `node:sqlite`. Requires `--experimental-sqlite` on Node 22. */
|
|
16
|
+
export async function nodeSqliteDriver() {
|
|
17
|
+
const { DatabaseSync } = await import("node:sqlite");
|
|
18
|
+
const db = new DatabaseSync(":memory:");
|
|
19
|
+
db.exec("PRAGMA foreign_keys = OFF");
|
|
20
|
+
return {
|
|
21
|
+
async all(sql, args) {
|
|
22
|
+
return db.prepare(sql).all(...args);
|
|
23
|
+
},
|
|
24
|
+
async close() {
|
|
25
|
+
db.close();
|
|
26
|
+
},
|
|
27
|
+
dqs: false,
|
|
28
|
+
engine: "sqlite",
|
|
29
|
+
async exec(sql) {
|
|
30
|
+
db.exec(sql);
|
|
31
|
+
},
|
|
32
|
+
async run(sql, args) {
|
|
33
|
+
db.prepare(sql).run(...args);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Cloudflare D1 over its HTTP query API.
|
|
39
|
+
*
|
|
40
|
+
* Every call is a network round trip to a shared, persistent database — which is the point. A
|
|
41
|
+
* store that only ever ran against an in-process engine cannot show what happens when writes
|
|
42
|
+
* take milliseconds to become visible, when the engine is someone else's build, or when two
|
|
43
|
+
* runs share one database.
|
|
44
|
+
*/
|
|
45
|
+
export function d1Driver(config) {
|
|
46
|
+
const endpoint = `https://api.cloudflare.com/client/v4/accounts/${config.accountId}` +
|
|
47
|
+
`/d1/database/${config.databaseId}/query`;
|
|
48
|
+
async function send(sql, params) {
|
|
49
|
+
const response = await fetch(endpoint, {
|
|
50
|
+
body: JSON.stringify({ params: params.map(encode), sql }),
|
|
51
|
+
headers: {
|
|
52
|
+
authorization: `Bearer ${config.apiToken}`,
|
|
53
|
+
"content-type": "application/json",
|
|
54
|
+
},
|
|
55
|
+
method: "POST",
|
|
56
|
+
});
|
|
57
|
+
const body = (await response.json());
|
|
58
|
+
if (!response.ok || !body.success) {
|
|
59
|
+
const detail = body.errors?.map((error) => `${error.code}: ${error.message}`).join("; ")
|
|
60
|
+
?? `HTTP ${response.status}`;
|
|
61
|
+
/* Deliberately a plain Error, not SqlError: a transport or quota failure is not the
|
|
62
|
+
* backend rejecting the caller's input, and dressing it up as a 400 would let an
|
|
63
|
+
* outage read as a well-behaved validation response. */
|
|
64
|
+
throw new Error(`D1 query failed (${detail}) for: ${sql.slice(0, 160)}`);
|
|
65
|
+
}
|
|
66
|
+
return body.result?.[0]?.results ?? [];
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
async all(sql, args) {
|
|
70
|
+
return send(sql, args);
|
|
71
|
+
},
|
|
72
|
+
async close() {
|
|
73
|
+
/* Stateless HTTP — nothing to release. Table teardown is the store's job. */
|
|
74
|
+
},
|
|
75
|
+
/* Verified against a live D1, not assumed: `SELECT "no_such_col"` returns the string
|
|
76
|
+
* "no_such_col" for every row, where node:sqlite raises "no such column". */
|
|
77
|
+
dqs: true,
|
|
78
|
+
engine: "d1",
|
|
79
|
+
async exec(sql) {
|
|
80
|
+
await send(sql, []);
|
|
81
|
+
},
|
|
82
|
+
async run(sql, args) {
|
|
83
|
+
await send(sql, args);
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* D1 binds parameters as JSON, so a value's JSON type is its storage class. Booleans have no
|
|
89
|
+
* SQLite representation and would arrive as `true`/`false` literals; the store already narrows
|
|
90
|
+
* to 0/1 before binding, and this is the backstop for anything that slips past.
|
|
91
|
+
*/
|
|
92
|
+
function encode(value) {
|
|
93
|
+
if (value === null)
|
|
94
|
+
return null;
|
|
95
|
+
if (value instanceof Uint8Array)
|
|
96
|
+
return Buffer.from(value).toString("base64");
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=sqlite-driver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-driver.js","sourceRoot":"","sources":["../../../src/reference/stores/sqlite-driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AA4BH,wFAAwF;AACxF,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACrC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAA;IACpD,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,UAAU,CAAC,CAAA;IACvC,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAA;IAEpC,OAAO;QACN,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI;YAClB,OAAO,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAI,IAAgB,CAAa,CAAA;QAC7D,CAAC;QACD,KAAK,CAAC,KAAK;YACV,EAAE,CAAC,KAAK,EAAE,CAAA;QACX,CAAC;QACD,GAAG,EAAE,KAAK;QACV,MAAM,EAAE,QAAQ;QAChB,KAAK,CAAC,IAAI,CAAC,GAAG;YACb,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACb,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI;YAClB,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAI,IAAgB,CAAC,CAAA;QAC1C,CAAC;KACD,CAAA;AACF,CAAC;AAcD;;;;;;;GAOG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAgB;IACxC,MAAM,QAAQ,GACb,iDAAiD,MAAM,CAAC,SAAS,EAAE;QACnE,gBAAgB,MAAM,CAAC,UAAU,QAAQ,CAAA;IAE1C,KAAK,UAAU,IAAI,CAAC,GAAW,EAAE,MAAkB;QAClD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,QAAQ,EAAE;YACtC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC;YACzD,OAAO,EAAE;gBACR,aAAa,EAAE,UAAU,MAAM,CAAC,QAAQ,EAAE;gBAC1C,cAAc,EAAE,kBAAkB;aAClC;YACD,MAAM,EAAE,MAAM;SACd,CAAC,CAAA;QAEF,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAe,CAAA;QAClD,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACnC,MAAM,MAAM,GACX,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;mBACtE,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAA;YAC7B;;oEAEwD;YACxD,MAAM,IAAI,KAAK,CAAC,oBAAoB,MAAM,UAAU,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;QACzE,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAA;IACvC,CAAC;IAED,OAAO;QACN,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI;YAClB,OAAO,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QACvB,CAAC;QACD,KAAK,CAAC,KAAK;YACV,6EAA6E;QAC9E,CAAC;QACD;qFAC6E;QAC7E,GAAG,EAAE,IAAI;QACT,MAAM,EAAE,IAAI;QACZ,KAAK,CAAC,IAAI,CAAC,GAAG;YACb,MAAM,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAA;QACpB,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI;YAClB,MAAM,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;QACtB,CAAC;KACD,CAAA;AACF,CAAC;AAED;;;;GAIG;AACH,SAAS,MAAM,CAAC,KAAe;IAC9B,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAC/B,IAAI,KAAK,YAAY,UAAU;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;IAC7E,OAAO,KAAK,CAAA;AACb,CAAC"}
|