@browserlessapi/inferlo 0.0.0-stage → 0.3.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 +127 -2
- package/dist/ai/index.d.ts +96 -0
- package/dist/ai/index.js +327 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/providers.d.ts +97 -0
- package/dist/ai/providers.js +204 -0
- package/dist/ai/providers.js.map +1 -0
- package/dist/app.d.ts +94 -0
- package/dist/app.js +365 -0
- package/dist/app.js.map +1 -0
- package/dist/auth.d.ts +29 -0
- package/dist/auth.js +61 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +467 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/db/memory.d.ts +2 -0
- package/dist/db/memory.js +128 -0
- package/dist/db/memory.js.map +1 -0
- package/dist/db/migrate.d.ts +84 -0
- package/dist/db/migrate.js +355 -0
- package/dist/db/migrate.js.map +1 -0
- package/dist/db/postgres.d.ts +37 -0
- package/dist/db/postgres.js +338 -0
- package/dist/db/postgres.js.map +1 -0
- package/dist/db/table.d.ts +72 -0
- package/dist/db/table.js +177 -0
- package/dist/db/table.js.map +1 -0
- package/dist/db/types.d.ts +36 -0
- package/dist/db/types.js +2 -0
- package/dist/db/types.js.map +1 -0
- package/dist/describe.d.ts +56 -0
- package/dist/describe.js +64 -0
- package/dist/describe.js.map +1 -0
- package/dist/env.d.ts +19 -0
- package/dist/env.js +72 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.d.ts +40 -0
- package/dist/errors.js +99 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.d.ts +18 -0
- package/dist/mcp.js +166 -0
- package/dist/mcp.js.map +1 -0
- package/dist/model.d.ts +36 -0
- package/dist/model.js +76 -0
- package/dist/model.js.map +1 -0
- package/dist/openapi.d.ts +6 -0
- package/dist/openapi.js +71 -0
- package/dist/openapi.js.map +1 -0
- package/dist/route.d.ts +125 -0
- package/dist/route.js +28 -0
- package/dist/route.js.map +1 -0
- package/dist/schema.d.ts +156 -0
- package/dist/schema.js +430 -0
- package/dist/schema.js.map +1 -0
- package/dist/serve.d.ts +11 -0
- package/dist/serve.js +83 -0
- package/dist/serve.js.map +1 -0
- package/dist/testing.d.ts +16 -0
- package/dist/testing.js +30 -0
- package/dist/testing.js.map +1 -0
- package/llms.txt +27 -0
- package/package.json +82 -4
- package/templates/app/AGENTS.md +53 -0
- package/templates/app/CLAUDE.md +1 -0
- package/templates/app/README.md +14 -0
- package/templates/app/_env.example +5 -0
- package/templates/app/_gitignore +3 -0
- package/templates/app/package.json.tpl +31 -0
- package/templates/app/src/app.ts +38 -0
- package/templates/app/src/models.ts +31 -0
- package/templates/app/src/routes/health.ts +3 -0
- package/templates/app/src/routes/notes.ts +56 -0
- package/templates/app/src/server.ts +16 -0
- package/templates/app/test/notes.test.ts +50 -0
- package/templates/app/tsconfig.json +17 -0
package/dist/cli/main.js
ADDED
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
3
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
4
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
5
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
return path;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* inferlo CLI. Every command supports --json for machine-readable output, so AI coding agents
|
|
12
|
+
* can drive it directly.
|
|
13
|
+
*/
|
|
14
|
+
import { spawn } from "node:child_process";
|
|
15
|
+
import { existsSync } from "node:fs";
|
|
16
|
+
import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
19
|
+
import { InferloError } from "../errors.js";
|
|
20
|
+
import { INFERLO_VERSION } from "../describe.js";
|
|
21
|
+
import { applyMigrations, planMigration } from "../db/migrate.js";
|
|
22
|
+
const HELP = `inferlo ${INFERLO_VERSION}
|
|
23
|
+
|
|
24
|
+
Usage: inferlo <command> [options]
|
|
25
|
+
|
|
26
|
+
Commands:
|
|
27
|
+
new <dir> Create a new Inferlo project
|
|
28
|
+
dev Run the server and restart on changes (src/server.ts)
|
|
29
|
+
describe Print the app map: routes, models, auth, AI
|
|
30
|
+
check Typecheck, load the app and run tests
|
|
31
|
+
db push [--dry-run] Create missing tables, columns and indexes
|
|
32
|
+
db migrate [name] Write migrations/NNNN_name.sql for model changes (--dry-run to preview,
|
|
33
|
+
--allow-drop to include drops of tables, columns and indexes,
|
|
34
|
+
--allow-change to include default and required changes)
|
|
35
|
+
db migrate --apply Run pending migration files
|
|
36
|
+
openapi [--out file] Print or write the OpenAPI document
|
|
37
|
+
add resource <name> Generate a model plus list/get/create/update/delete routes
|
|
38
|
+
version Print the Inferlo version
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
--json Machine-readable output (for AI agents and scripts)
|
|
42
|
+
--entry <file> App module (default: package.json "inferlo.entry" or src/app.ts)
|
|
43
|
+
`;
|
|
44
|
+
function parseArgs(argv) {
|
|
45
|
+
const out = { _: [], flags: {} };
|
|
46
|
+
for (let i = 0; i < argv.length; i++) {
|
|
47
|
+
const a = argv[i];
|
|
48
|
+
if (a.startsWith("--")) {
|
|
49
|
+
const [k, v] = a.slice(2).split("=", 2);
|
|
50
|
+
if (v !== undefined)
|
|
51
|
+
out.flags[k] = v;
|
|
52
|
+
else if (argv[i + 1] && !argv[i + 1].startsWith("--") && ["entry", "out"].includes(k))
|
|
53
|
+
out.flags[k] = argv[++i];
|
|
54
|
+
else
|
|
55
|
+
out.flags[k] = true;
|
|
56
|
+
}
|
|
57
|
+
else
|
|
58
|
+
out._.push(a);
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
const cwd = process.cwd();
|
|
63
|
+
async function readPackage(dir = cwd) {
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(await readFile(path.join(dir, "package.json"), "utf8"));
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function entryFile(args) {
|
|
72
|
+
const pkg = await readPackage();
|
|
73
|
+
const file = args.flags.entry || pkg?.inferlo?.entry || pkg?.kairo?.entry || "src/app.ts";
|
|
74
|
+
return path.resolve(cwd, file);
|
|
75
|
+
}
|
|
76
|
+
async function loadApp(args) {
|
|
77
|
+
const file = await entryFile(args);
|
|
78
|
+
if (!existsSync(file)) {
|
|
79
|
+
throw new InferloError("IL8001", `App entry ${path.relative(cwd, file)} not found.`, {
|
|
80
|
+
fix: 'Create src/app.ts exporting `app`, pass --entry <file>, or set "inferlo": { "entry": "..." } in package.json.',
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
const mod = await import(__rewriteRelativeImportExtension(pathToFileURL(file).href));
|
|
84
|
+
const app = mod.app ?? mod.default;
|
|
85
|
+
if (!app || typeof app.describe !== "function") {
|
|
86
|
+
throw new InferloError("IL8002", `${path.relative(cwd, file)} does not export an Inferlo app.`, { fix: "Add: export const app = createApp({ ... })" });
|
|
87
|
+
}
|
|
88
|
+
return app;
|
|
89
|
+
}
|
|
90
|
+
function print(data, json, text) {
|
|
91
|
+
if (json || !text)
|
|
92
|
+
console.log(JSON.stringify(data, null, 2));
|
|
93
|
+
else
|
|
94
|
+
console.log(text());
|
|
95
|
+
}
|
|
96
|
+
function run(cmd, argv, options = {}) {
|
|
97
|
+
return new Promise((resolve) => {
|
|
98
|
+
const child = spawn(cmd, argv, { cwd, stdio: options.capture ? ["ignore", "pipe", "pipe"] : "inherit", shell: process.platform === "win32" });
|
|
99
|
+
let output = "";
|
|
100
|
+
child.stdout?.on("data", (d) => (output += d));
|
|
101
|
+
child.stderr?.on("data", (d) => (output += d));
|
|
102
|
+
child.on("error", (e) => resolve({ code: 127, output: String(e) }));
|
|
103
|
+
child.on("close", (code) => resolve({ code: code ?? 1, output }));
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// ---------------------------------------------------------------------------------------------
|
|
107
|
+
async function cmdDescribe(args) {
|
|
108
|
+
const app = await loadApp(args);
|
|
109
|
+
const d = app.describe();
|
|
110
|
+
print(d, Boolean(args.flags.json), () => {
|
|
111
|
+
const lines = [`${d.name} ${d.version} (inferlo ${d.inferlo}, db: ${d.database}, auth: ${d.auth ? "on" : "off"})`, "", "Models"];
|
|
112
|
+
for (const m of d.models) {
|
|
113
|
+
lines.push(` ${m.name}`);
|
|
114
|
+
for (const [k, f] of Object.entries(m.fields)) {
|
|
115
|
+
const extra = [f.required ? "required" : "", f.unique ? "unique" : "", f.references ? `-> ${f.references}` : "", f.values ? f.values.join("|") : ""].filter(Boolean).join(", ");
|
|
116
|
+
lines.push(` ${k.padEnd(16)} ${f.type}${extra ? ` (${extra})` : ""}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
lines.push("", "Routes");
|
|
120
|
+
for (const r of d.routes)
|
|
121
|
+
lines.push(` ${r.method.padEnd(6)} ${r.path.padEnd(28)} auth=${r.auth}${r.tool ? ` tool=${r.tool}` : ""}${r.name ? ` (${r.name})` : ""}`);
|
|
122
|
+
lines.push("", `AI: ${d.ai.configured ? Object.entries(d.ai.aliases).map(([a, ids]) => `${a} = ${ids.join(" > ")}`).join("; ") || "configured" : "not configured"}`);
|
|
123
|
+
if (d.endpoints.openapi)
|
|
124
|
+
lines.push(`OpenAPI: ${d.endpoints.openapi}`);
|
|
125
|
+
if (d.endpoints.mcp)
|
|
126
|
+
lines.push(`MCP: ${d.endpoints.mcp}`);
|
|
127
|
+
return lines.join("\n");
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
async function cmdOpenapi(args) {
|
|
131
|
+
const app = await loadApp(args);
|
|
132
|
+
const doc = JSON.stringify(app.openapi(), null, 2);
|
|
133
|
+
if (typeof args.flags.out === "string") {
|
|
134
|
+
await writeFile(path.resolve(cwd, args.flags.out), doc + "\n");
|
|
135
|
+
print({ ok: true, file: args.flags.out }, Boolean(args.flags.json), () => `Wrote ${args.flags.out}`);
|
|
136
|
+
}
|
|
137
|
+
else
|
|
138
|
+
console.log(doc);
|
|
139
|
+
}
|
|
140
|
+
async function cmdDb(args) {
|
|
141
|
+
if (args._[1] === "migrate")
|
|
142
|
+
return cmdMigrate(args);
|
|
143
|
+
if (args._[1] !== "push")
|
|
144
|
+
throw new InferloError("IL8003", `Unknown db command "${args._[1] ?? ""}".`, { fix: "Use: inferlo db push [--dry-run] or inferlo db migrate [name] [--dry-run | --apply]" });
|
|
145
|
+
const app = await loadApp(args);
|
|
146
|
+
const dryRun = Boolean(args.flags["dry-run"]);
|
|
147
|
+
const statements = await app.db.$sync({ dryRun });
|
|
148
|
+
await app.db.$close();
|
|
149
|
+
print({ ok: true, dryRun, statements }, Boolean(args.flags.json), () => statements.length ? `${dryRun ? "Would run" : "Ran"}:\n\n${statements.join(";\n\n")};` : "Database is up to date.");
|
|
150
|
+
}
|
|
151
|
+
const MIGRATIONS_DIR = "migrations";
|
|
152
|
+
async function migrationFiles(dir) {
|
|
153
|
+
if (!existsSync(dir))
|
|
154
|
+
return [];
|
|
155
|
+
return (await readdir(dir)).filter((f) => /^\d{4}_[A-Za-z0-9_-]+\.sql$/.test(f)).sort();
|
|
156
|
+
}
|
|
157
|
+
async function cmdMigrate(args) {
|
|
158
|
+
const json = Boolean(args.flags.json);
|
|
159
|
+
const dir = path.join(cwd, MIGRATIONS_DIR);
|
|
160
|
+
const app = await loadApp(args);
|
|
161
|
+
try {
|
|
162
|
+
if (args.flags.apply) {
|
|
163
|
+
const files = await migrationFiles(dir);
|
|
164
|
+
const migrations = await Promise.all(files.map(async (f) => ({ name: f.slice(0, -4), sql: await readFile(path.join(dir, f), "utf8") })));
|
|
165
|
+
let edited = [];
|
|
166
|
+
const applied = await applyMigrations(app.db, migrations, { onEdited: (names) => (edited = names) });
|
|
167
|
+
if (edited.length && !json) {
|
|
168
|
+
const files = edited.map((name) => `${MIGRATIONS_DIR}/${name}.sql`).join(", ");
|
|
169
|
+
console.error(`Warning IL4018: ${files} ${edited.length > 1 ? "were" : "was"} edited after being applied, so the change was not run. Restore the applied SQL (git checkout) and put the change in a new migration: inferlo db migrate <name>`);
|
|
170
|
+
}
|
|
171
|
+
print({ ok: true, applied, edited }, json, () => (applied.length ? `Applied:\n${applied.map((a) => ` ${a}`).join("\n")}` : "No pending migrations."));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const snapshotFile = path.join(dir, "snapshot.json");
|
|
175
|
+
let previous;
|
|
176
|
+
if (existsSync(snapshotFile)) {
|
|
177
|
+
try {
|
|
178
|
+
previous = JSON.parse(await readFile(snapshotFile, "utf8"));
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
previous = null;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
const plan = planMigration(app.models, previous, { allowDrop: Boolean(args.flags["allow-drop"]), allowChange: Boolean(args.flags["allow-change"]) });
|
|
185
|
+
const dryRun = Boolean(args.flags["dry-run"]);
|
|
186
|
+
const dropNote = (plan.drops.length ? `\n\nThis migration deletes data: ${plan.drops.join(", ")}.` : "") +
|
|
187
|
+
(plan.changes.length ? `\n\nThis migration changes columns: ${plan.changes.join(", ")}.` : "");
|
|
188
|
+
if (!plan.statements.length || dryRun) {
|
|
189
|
+
print({ ok: true, dryRun, file: null, statements: plan.statements, drops: plan.drops, changes: plan.changes }, json, () => plan.statements.length ? `Would write:\n\n${plan.statements.join(";\n\n")};${dropNote}` : "No model changes since the last migration.");
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const files = await migrationFiles(dir);
|
|
193
|
+
const last = files.length ? Number(files[files.length - 1].slice(0, 4)) : 0;
|
|
194
|
+
const slug = String(args._[2] ?? "migration").toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 60) || "migration";
|
|
195
|
+
const file = `${MIGRATIONS_DIR}/${String(last + 1).padStart(4, "0")}_${slug}.sql`;
|
|
196
|
+
await mkdir(dir, { recursive: true });
|
|
197
|
+
const warning = (plan.drops.length ? `-- WARNING: this migration deletes data (${plan.drops.join(", ")}). Back up first.\n` : "") +
|
|
198
|
+
(plan.changes.length ? `-- This migration changes columns: ${plan.changes.join(", ")}. Making a column required fails (IL4020) if rows still have NULL in it.\n` : "");
|
|
199
|
+
await writeFile(path.join(cwd, file), `-- Generated by inferlo db migrate. Review before applying with: inferlo db migrate --apply\n${warning}\n${plan.statements.join(";\n\n")};\n`);
|
|
200
|
+
await writeFile(snapshotFile, JSON.stringify(plan.snapshot, null, 2) + "\n");
|
|
201
|
+
print({ ok: true, dryRun: false, file, statements: plan.statements, drops: plan.drops, changes: plan.changes }, json, () => `Wrote ${file}${dropNote}\nReview it, then run: inferlo db migrate --apply`);
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
await app.db.$close();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async function cmdCheck(args) {
|
|
208
|
+
const json = Boolean(args.flags.json);
|
|
209
|
+
const steps = [];
|
|
210
|
+
const timed = async (name, fn) => {
|
|
211
|
+
const step = { name, ok: true, durationMs: 0, errors: [] };
|
|
212
|
+
const start = Date.now();
|
|
213
|
+
try {
|
|
214
|
+
await fn(step);
|
|
215
|
+
}
|
|
216
|
+
catch (error) {
|
|
217
|
+
step.ok = false;
|
|
218
|
+
const e = error;
|
|
219
|
+
step.errors.push({ code: e.code, message: e.message ?? String(error), fix: e.fix });
|
|
220
|
+
}
|
|
221
|
+
step.durationMs = Date.now() - start;
|
|
222
|
+
steps.push(step);
|
|
223
|
+
if (!json)
|
|
224
|
+
console.log(`${step.skipped ? "skip" : step.ok ? "ok " : "FAIL"} ${name} (${step.durationMs} ms)`);
|
|
225
|
+
};
|
|
226
|
+
await timed("typecheck", async (step) => {
|
|
227
|
+
const tsc = path.join(cwd, "node_modules", ".bin", "tsc");
|
|
228
|
+
if (!existsSync(path.join(cwd, "tsconfig.json")) || !existsSync(tsc)) {
|
|
229
|
+
step.skipped = true;
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const { code, output } = await run(tsc, ["--noEmit", "--pretty", "false"], { capture: true });
|
|
233
|
+
if (code !== 0) {
|
|
234
|
+
step.ok = false;
|
|
235
|
+
for (const line of output.split("\n")) {
|
|
236
|
+
const m = /^(.+?)\((\d+),\d+\): error (TS\d+): (.*)$/.exec(line.trim());
|
|
237
|
+
if (m)
|
|
238
|
+
step.errors.push({ file: m[1], line: Number(m[2]), code: m[3], message: m[4] });
|
|
239
|
+
}
|
|
240
|
+
if (!step.errors.length)
|
|
241
|
+
step.errors.push({ message: output.trim().slice(0, 4000) });
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
await timed("load", async () => {
|
|
245
|
+
await loadApp(args);
|
|
246
|
+
});
|
|
247
|
+
await timed("test", async (step) => {
|
|
248
|
+
const pkg = await readPackage();
|
|
249
|
+
if (!pkg?.scripts?.test) {
|
|
250
|
+
step.skipped = true;
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const { code, output } = await run("npm", ["test", "--silent"], { capture: true });
|
|
254
|
+
if (code !== 0) {
|
|
255
|
+
step.ok = false;
|
|
256
|
+
step.output = output.slice(-6000);
|
|
257
|
+
step.errors.push({ message: "Tests failed. See output." });
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
const ok = steps.every((s) => s.ok);
|
|
261
|
+
if (json)
|
|
262
|
+
console.log(JSON.stringify({ ok, steps }, null, 2));
|
|
263
|
+
else {
|
|
264
|
+
for (const s of steps.filter((s) => !s.ok)) {
|
|
265
|
+
console.log(`\n${s.name}:`);
|
|
266
|
+
for (const e of s.errors)
|
|
267
|
+
console.log(` ${e.file ? `${e.file}:${e.line} ` : ""}${e.code ? e.code + " " : ""}${e.message}${e.fix ? `\n Fix: ${e.fix}` : ""}`);
|
|
268
|
+
if (s.output)
|
|
269
|
+
console.log(s.output);
|
|
270
|
+
}
|
|
271
|
+
console.log(ok ? "\nAll checks passed." : "\nChecks failed.");
|
|
272
|
+
}
|
|
273
|
+
process.exitCode = ok ? 0 : 1;
|
|
274
|
+
}
|
|
275
|
+
async function cmdDev(args) {
|
|
276
|
+
const pkg = await readPackage();
|
|
277
|
+
const server = path.resolve(cwd, args.flags.entry || pkg?.inferlo?.server || pkg?.kairo?.server || "src/server.ts");
|
|
278
|
+
if (!existsSync(server))
|
|
279
|
+
throw new InferloError("IL8001", `Server file ${path.relative(cwd, server)} not found.`, { fix: "Create src/server.ts that calls app.listen()." });
|
|
280
|
+
const isBun = Boolean(globalThis.Bun);
|
|
281
|
+
const cmd = isBun ? "bun" : process.execPath;
|
|
282
|
+
const argv = isBun ? ["--watch", server] : ["--watch", "--env-file-if-exists=.env", server];
|
|
283
|
+
const { code } = await run(cmd, argv);
|
|
284
|
+
process.exitCode = code;
|
|
285
|
+
}
|
|
286
|
+
// --- generators --------------------------------------------------------------------------
|
|
287
|
+
const templatesDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..", "templates");
|
|
288
|
+
async function copyTemplate(from, to, vars, created) {
|
|
289
|
+
await mkdir(to, { recursive: true });
|
|
290
|
+
for (const entry of await readdir(from, { withFileTypes: true })) {
|
|
291
|
+
const src = path.join(from, entry.name);
|
|
292
|
+
const name = entry.name.replace(/^_/, ".").replace(/\.tpl$/, "");
|
|
293
|
+
const dest = path.join(to, name);
|
|
294
|
+
if (entry.isDirectory())
|
|
295
|
+
await copyTemplate(src, dest, vars, created);
|
|
296
|
+
else {
|
|
297
|
+
let text = await readFile(src, "utf8");
|
|
298
|
+
for (const [k, v] of Object.entries(vars))
|
|
299
|
+
text = text.replaceAll(`{{${k}}}`, v);
|
|
300
|
+
await writeFile(dest, text);
|
|
301
|
+
created.push(dest);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
async function cmdNew(args) {
|
|
306
|
+
const dir = args._[1];
|
|
307
|
+
if (!dir)
|
|
308
|
+
throw new InferloError("IL8004", "Missing project directory.", { fix: "Use: inferlo new my-app" });
|
|
309
|
+
const target = path.resolve(cwd, dir);
|
|
310
|
+
if (existsSync(target) && (await readdir(target)).length)
|
|
311
|
+
throw new InferloError("IL8005", `${dir} already exists and is not empty.`);
|
|
312
|
+
const name = path.basename(target).toLowerCase().replace(/[^a-z0-9-]/g, "-");
|
|
313
|
+
const created = [];
|
|
314
|
+
await copyTemplate(path.join(templatesDir, "app"), target, { name, inferloVersion: INFERLO_VERSION, inferloDependency: `^${INFERLO_VERSION}` }, created);
|
|
315
|
+
print({ ok: true, dir, files: created.map((f) => path.relative(cwd, f)) }, Boolean(args.flags.json), () => [`Created ${dir}`, "", "Next:", ` cd ${dir}`, " npm install", " npm run dev", "", "AGENTS.md explains the conventions to AI coding agents."].join("\n"));
|
|
316
|
+
}
|
|
317
|
+
function pascal(name) {
|
|
318
|
+
return name.replace(/(^|[_-])([a-z])/g, (_, __, c) => c.toUpperCase());
|
|
319
|
+
}
|
|
320
|
+
function singularOf(name) {
|
|
321
|
+
return name.endsWith("ies") ? name.slice(0, -3) + "y" : name.endsWith("s") ? name.slice(0, -1) : name;
|
|
322
|
+
}
|
|
323
|
+
async function cmdAdd(args) {
|
|
324
|
+
const kind = args._[1];
|
|
325
|
+
const raw = args._[2];
|
|
326
|
+
if (kind !== "resource" || !raw)
|
|
327
|
+
throw new InferloError("IL8006", "Use: inferlo add resource <plural_name>, e.g. inferlo add resource invoices");
|
|
328
|
+
const table = raw.toLowerCase().replace(/-/g, "_");
|
|
329
|
+
if (!/^[a-z][a-z0-9_]*$/.test(table))
|
|
330
|
+
throw new InferloError("IL4005", `"${raw}" is not a valid table name.`, { fix: "Use lowercase letters, digits and underscores." });
|
|
331
|
+
const Model = pascal(singularOf(table));
|
|
332
|
+
const routesDir = path.join(cwd, "src", "routes");
|
|
333
|
+
const routeFile = path.join(routesDir, `${table}.ts`);
|
|
334
|
+
if (existsSync(routeFile))
|
|
335
|
+
throw new InferloError("IL8005", `src/routes/${table}.ts already exists.`);
|
|
336
|
+
const changes = [];
|
|
337
|
+
const manual = [];
|
|
338
|
+
const modelsFile = path.join(cwd, "src", "models.ts");
|
|
339
|
+
const modelCode = `export const ${Model} = model("${table}", {\n name: t.string().max(200),\n ownerId: t.ref("users"),\n});\n`;
|
|
340
|
+
if (existsSync(modelsFile)) {
|
|
341
|
+
let text = await readFile(modelsFile, "utf8");
|
|
342
|
+
if (text.includes("// inferlo:models")) {
|
|
343
|
+
text = text.replace("// inferlo:models", `${modelCode}\n// inferlo:models`);
|
|
344
|
+
text = text.replace(/export const models = \[([^\]]*)\]/, (m, list) => `export const models = [${list.trim() ? list.trim().replace(/,\s*$/, "") + ", " : ""}${Model}]`);
|
|
345
|
+
await writeFile(modelsFile, text);
|
|
346
|
+
changes.push("src/models.ts");
|
|
347
|
+
}
|
|
348
|
+
else
|
|
349
|
+
manual.push(`Add to src/models.ts:\n${modelCode}\nand add ${Model} to the models array.`);
|
|
350
|
+
}
|
|
351
|
+
else
|
|
352
|
+
manual.push(`Create the ${Model} model:\n${modelCode}`);
|
|
353
|
+
const routeCode = `import { route, t, notFound } from "@browserlessapi/inferlo";
|
|
354
|
+
import { ${Model} } from "../models.ts";
|
|
355
|
+
|
|
356
|
+
const IdParams = t.object({ id: t.uuid() });
|
|
357
|
+
|
|
358
|
+
export const list${pascal(table)} = route
|
|
359
|
+
.get("/${table}", {
|
|
360
|
+
summary: "List ${table}",
|
|
361
|
+
query: t.object({ limit: t.int().min(1).max(100).default(20), offset: t.int().min(0).default(0) }),
|
|
362
|
+
tool: true,
|
|
363
|
+
})
|
|
364
|
+
.handle(({ query, user, db }) =>
|
|
365
|
+
db.${table}.findMany({ where: { ownerId: user.id }, orderBy: { createdAt: "desc" }, limit: query.limit, offset: query.offset }),
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
export const get${Model} = route
|
|
369
|
+
.get("/${table}/:id", { params: IdParams, summary: "Get one ${singularOf(table)}", tool: true })
|
|
370
|
+
.handle(async ({ params, user, db }) => {
|
|
371
|
+
const row = await db.${table}.get(params.id);
|
|
372
|
+
if (row.ownerId !== user.id) throw notFound();
|
|
373
|
+
return row;
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
export const create${Model} = route
|
|
377
|
+
.post("/${table}", { body: ${Model}.omit("ownerId"), summary: "Create a ${singularOf(table)}", tool: true })
|
|
378
|
+
.handle(({ body, user, db, status }) => {
|
|
379
|
+
status(201);
|
|
380
|
+
return db.${table}.insert({ ...body, ownerId: user.id });
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
export const update${Model} = route
|
|
384
|
+
.patch("/${table}/:id", { params: IdParams, body: ${Model}.omit("ownerId").partial(), summary: "Update a ${singularOf(table)}" })
|
|
385
|
+
.handle(async ({ params, body, user, db }) => {
|
|
386
|
+
const row = await db.${table}.get(params.id);
|
|
387
|
+
if (row.ownerId !== user.id) throw notFound();
|
|
388
|
+
return db.${table}.update(row.id, body);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
export const delete${Model} = route
|
|
392
|
+
.delete("/${table}/:id", { params: IdParams, summary: "Delete a ${singularOf(table)}" })
|
|
393
|
+
.handle(async ({ params, user, db }) => {
|
|
394
|
+
const row = await db.${table}.get(params.id);
|
|
395
|
+
if (row.ownerId !== user.id) throw notFound();
|
|
396
|
+
await db.${table}.delete(row.id);
|
|
397
|
+
});
|
|
398
|
+
`;
|
|
399
|
+
await mkdir(routesDir, { recursive: true });
|
|
400
|
+
await writeFile(routeFile, routeCode);
|
|
401
|
+
changes.push(`src/routes/${table}.ts`);
|
|
402
|
+
const appFile = path.join(cwd, "src", "app.ts");
|
|
403
|
+
if (existsSync(appFile)) {
|
|
404
|
+
let text = await readFile(appFile, "utf8");
|
|
405
|
+
if (text.includes("// inferlo:routes")) {
|
|
406
|
+
text = text.replace(/^(import .*\n)(?![\s\S]*^import )/m, `$1import * as ${table} from "./routes/${table}.ts";\n`);
|
|
407
|
+
text = text.replace(/routes: \[([^\]]*)\]/, (_m, list) => `routes: [${list.trim() ? list.trim().replace(/,\s*$/, "") + ", " : ""}${table}]`);
|
|
408
|
+
await writeFile(appFile, text);
|
|
409
|
+
changes.push("src/app.ts");
|
|
410
|
+
}
|
|
411
|
+
else
|
|
412
|
+
manual.push(`Add to src/app.ts:\nimport * as ${table} from "./routes/${table}.ts";\nand add ${table} to createApp({ routes: [...] }).`);
|
|
413
|
+
}
|
|
414
|
+
print({ ok: true, changed: changes, manual }, Boolean(args.flags.json), () => [`Updated: ${changes.join(", ")}`, ...manual.map((m) => `\nTo do:\n${m}`), "", "Then run: inferlo db push && inferlo check"].join("\n"));
|
|
415
|
+
}
|
|
416
|
+
// ---------------------------------------------------------------------------------------------
|
|
417
|
+
async function main() {
|
|
418
|
+
const args = parseArgs(process.argv.slice(2));
|
|
419
|
+
const command = args._[0];
|
|
420
|
+
try {
|
|
421
|
+
switch (command) {
|
|
422
|
+
case "new":
|
|
423
|
+
return await cmdNew(args);
|
|
424
|
+
case "dev":
|
|
425
|
+
return await cmdDev(args);
|
|
426
|
+
case "describe":
|
|
427
|
+
return await cmdDescribe(args);
|
|
428
|
+
case "check":
|
|
429
|
+
return await cmdCheck(args);
|
|
430
|
+
case "db":
|
|
431
|
+
return await cmdDb(args);
|
|
432
|
+
case "openapi":
|
|
433
|
+
return await cmdOpenapi(args);
|
|
434
|
+
case "add":
|
|
435
|
+
return await cmdAdd(args);
|
|
436
|
+
case "version":
|
|
437
|
+
case "--version":
|
|
438
|
+
case "-v":
|
|
439
|
+
return console.log(INFERLO_VERSION);
|
|
440
|
+
case undefined:
|
|
441
|
+
case "help":
|
|
442
|
+
case "--help":
|
|
443
|
+
case "-h":
|
|
444
|
+
return console.log(HELP);
|
|
445
|
+
default:
|
|
446
|
+
throw new InferloError("IL8000", `Unknown command "${command}".`, { fix: "Run inferlo help to see all commands." });
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
catch (error) {
|
|
450
|
+
const json = Boolean(args.flags.json);
|
|
451
|
+
if (error instanceof InferloError) {
|
|
452
|
+
if (json)
|
|
453
|
+
console.log(JSON.stringify({ ok: false, ...error.toJSON(), message: error.message }, null, 2));
|
|
454
|
+
else
|
|
455
|
+
console.error(error.format());
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
if (json)
|
|
459
|
+
console.log(JSON.stringify({ ok: false, error: { code: "IL9000", message: String(error?.message ?? error) } }, null, 2));
|
|
460
|
+
else
|
|
461
|
+
console.error(error);
|
|
462
|
+
}
|
|
463
|
+
process.exitCode = 1;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
await main();
|
|
467
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";;;;;;;;;AACA;;;GAGG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvE,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAElE,MAAM,IAAI,GAAG,WAAW,eAAe;;;;;;;;;;;;;;;;;;;;;CAqBtC,CAAC;AAOF,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,GAAG,GAAS,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACnB,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACvB,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAiC,CAAC;YACxE,IAAI,CAAC,KAAK,SAAS;gBAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;iBACjC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAE,CAAC;;gBAC7G,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;QAC3B,CAAC;;YAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;AAE1B,KAAK,UAAU,WAAW,CAAC,GAAG,GAAG,GAAG;IAClC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,IAAU;IACjC,MAAM,GAAG,GAAG,MAAM,WAAW,EAAE,CAAC;IAChC,MAAM,IAAI,GAAI,IAAI,CAAC,KAAK,CAAC,KAAgB,IAAI,GAAG,EAAE,OAAO,EAAE,KAAK,IAAI,GAAG,EAAE,KAAK,EAAE,KAAK,IAAI,YAAY,CAAC;IACtG,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC;AAED,KAAK,UAAU,OAAO,CAAC,IAAU;IAC/B,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,aAAa,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,aAAa,EAAE;YACnF,GAAG,EAAE,+GAA+G;SACrH,CAAC,CAAC;IACL,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,MAAM,kCAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EAAC,CAAC;IACnD,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC;IACnC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,CAAC,QAAQ,KAAK,UAAU,EAAE,CAAC;QAC/C,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC,kCAAkC,EAAE,EAAE,GAAG,EAAE,4CAA4C,EAAE,CAAC,CAAC;IACzJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,KAAK,CAAC,IAAa,EAAE,IAAa,EAAE,IAAmB;IAC9D,IAAI,IAAI,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;;QACzD,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,GAAG,CAAC,GAAW,EAAE,IAAc,EAAE,UAAiC,EAAE;IAC3E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC,CAAC;QAC9I,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/C,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC;QAC/C,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACpE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,gGAAgG;AAEhG,KAAK,UAAU,WAAW,CAAC,IAAU;IACnC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;IACzB,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE;QACtC,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO,cAAc,CAAC,CAAC,OAAO,SAAS,CAAC,CAAC,QAAQ,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,EAAE,EAAE,QAAQ,CAAC,CAAC;QAClI,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;YACzB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC1B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAM,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;gBACnD,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAChL,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC5E,CAAC;QACH,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvK,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAW,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC;QAC/K,IAAI,CAAC,CAAC,SAAS,CAAC,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;QACvE,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG;YAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,CAAC;QAC3D,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,IAAU;IAClC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IACnD,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,CAAC;QAC/D,KAAK,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC;IACvG,CAAC;;QAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,KAAK,UAAU,KAAK,CAAC,IAAU;IAC7B,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS;QAAE,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;IACrD,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM;QAAE,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,uBAAuB,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,qFAAqF,EAAE,CAAC,CAAC;IACvM,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAa,MAAM,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5D,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CACrE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,QAAQ,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,yBAAyB,CACnH,CAAC;AACJ,CAAC;AAED,MAAM,cAAc,GAAG,YAAY,CAAC;AAEpC,KAAK,UAAU,cAAc,CAAC,GAAW;IACvC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,6BAA6B,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC1F,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,IAAU;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;YACxC,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACzI,IAAI,MAAM,GAAa,EAAE,CAAC;YAC1B,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC;YACrG,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,GAAG,cAAc,IAAI,IAAI,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC/E,OAAO,CAAC,KAAK,CACX,mBAAmB,KAAK,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,iKAAiK,CAChO,CAAC;YACJ,CAAC;YACD,KAAK,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC;YACvJ,OAAO;QACT,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;QACrD,IAAI,QAAiB,CAAC;QACtB,IAAI,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC;gBACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;YAC9D,CAAC;YAAC,MAAM,CAAC;gBACP,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;QACH,CAAC;QACD,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,QAAiB,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9J,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;QAC9C,MAAM,QAAQ,GACZ,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,oCAAoC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACvF,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,uCAAuC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACjG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC;YACtC,KAAK,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CACxH,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,mBAAmB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC,CAAC,4CAA4C,CACvI,CAAC;YACF,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,cAAc,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,WAAW,CAAC;QAC5I,MAAM,IAAI,GAAG,GAAG,cAAc,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,IAAI,MAAM,CAAC;QAClF,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,MAAM,OAAO,GACX,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,4CAA4C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC;YACjH,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,sCAAsC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,4EAA4E,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACzK,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,gGAAgG,OAAO,KAAK,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACtL,MAAM,SAAS,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7E,KAAK,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,SAAS,IAAI,GAAG,QAAQ,mDAAmD,CAAC,CAAC;IAC3M,CAAC;YAAS,CAAC;QACT,MAAM,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC;IACxB,CAAC;AACH,CAAC;AAWD,KAAK,UAAU,QAAQ,CAAC,IAAU;IAChC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,KAAK,GAAW,EAAE,CAAC;IACzB,MAAM,KAAK,GAAG,KAAK,EAAE,IAAY,EAAE,EAAiC,EAAE,EAAE;QACtE,MAAM,IAAI,GAAS,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;QACjE,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;QACjB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC;YAChB,MAAM,CAAC,GAAG,KAAqB,CAAC;YAChC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACtF,CAAC;QACD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,IAAI,CAAC,IAAI;YAAE,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,KAAK,IAAI,CAAC,UAAU,MAAM,CAAC,CAAC;IAClH,CAAC,CAAC;IAEF,MAAM,KAAK,CAAC,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACtC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QAC1D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,OAAO;QACT,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9F,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC;YAChB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACtC,MAAM,CAAC,GAAG,2CAA2C,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;gBACxE,IAAI,CAAC;oBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAE,EAAE,CAAC,CAAC;YAC1F,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM;gBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;QACvF,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,EAAE;QAC7B,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACjC,MAAM,GAAG,GAAG,MAAM,WAAW,EAAE,CAAC;QAChC,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,OAAO;QACT,CAAC;QACD,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACnF,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;YACf,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC;YAChB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpC,IAAI,IAAI;QAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;SACzD,CAAC;QACJ,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;YAC3C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;YAC5B,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM;gBAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACjK,IAAI,CAAC,CAAC,MAAM;gBAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,CAAC,QAAQ,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAU;IAC9B,MAAM,GAAG,GAAG,MAAM,WAAW,EAAE,CAAC;IAChC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAG,IAAI,CAAC,KAAK,CAAC,KAAgB,IAAI,GAAG,EAAE,OAAO,EAAE,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,MAAM,IAAI,eAAe,CAAC,CAAC;IAChI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,eAAe,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,aAAa,EAAE,EAAE,GAAG,EAAE,+CAA+C,EAAE,CAAC,CAAC;IAC5K,MAAM,KAAK,GAAG,OAAO,CAAE,UAAgC,CAAC,GAAG,CAAC,CAAC;IAC7D,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IAC7C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,2BAA2B,EAAE,MAAM,CAAC,CAAC;IAC5F,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACtC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC1B,CAAC;AAED,4FAA4F;AAE5F,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;AAEzG,KAAK,UAAU,YAAY,CAAC,IAAY,EAAE,EAAU,EAAE,IAA4B,EAAE,OAAiB;IACnG,MAAM,KAAK,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrC,KAAK,MAAM,KAAK,IAAI,MAAM,OAAO,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACjE,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACjE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;QACjC,IAAI,KAAK,CAAC,WAAW,EAAE;YAAE,MAAM,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;aACjE,CAAC;YACJ,IAAI,IAAI,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YACvC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;gBAAE,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACjF,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAU;IAC9B,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,4BAA4B,EAAE,EAAE,GAAG,EAAE,yBAAyB,EAAE,CAAC,CAAC;IAC7G,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACtC,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;QAAE,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,GAAG,GAAG,mCAAmC,CAAC,CAAC;IACtI,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IAC7E,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,IAAI,eAAe,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;IACzJ,KAAK,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CACxG,CAAC,WAAW,GAAG,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,QAAQ,GAAG,EAAE,EAAE,eAAe,EAAE,eAAe,EAAE,EAAE,EAAE,yDAAyD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAC3J,CAAC;AACJ,CAAC;AAED,SAAS,MAAM,CAAC,IAAY;IAC1B,OAAO,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AACjF,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACxG,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAU;IAC9B,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvB,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,IAAI,KAAK,UAAU,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,6EAA6E,CAAC,CAAC;IACjJ,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACnD,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,IAAI,GAAG,8BAA8B,EAAE,EAAE,GAAG,EAAE,gDAAgD,EAAE,CAAC,CAAC;IACzK,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IACxC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,KAAK,KAAK,CAAC,CAAC;IACtD,IAAI,UAAU,CAAC,SAAS,CAAC;QAAE,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,cAAc,KAAK,qBAAqB,CAAC,CAAC;IACtG,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,gBAAgB,KAAK,aAAa,KAAK,uEAAuE,CAAC;IACjI,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC3B,IAAI,IAAI,GAAG,MAAM,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC9C,IAAI,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACvC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,SAAS,qBAAqB,CAAC,CAAC;YAC5E,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,oCAAoC,EAAE,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE,CAAC,0BAA0B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;YAChL,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAChC,CAAC;;YAAM,MAAM,CAAC,IAAI,CAAC,0BAA0B,SAAS,aAAa,KAAK,uBAAuB,CAAC,CAAC;IACnG,CAAC;;QAAM,MAAM,CAAC,IAAI,CAAC,cAAc,KAAK,YAAY,SAAS,EAAE,CAAC,CAAC;IAE/D,MAAM,SAAS,GAAG;WACT,KAAK;;;;mBAIG,MAAM,CAAC,KAAK,CAAC;WACrB,KAAK;qBACK,KAAK;;;;;SAKjB,KAAK;;;kBAGI,KAAK;WACZ,KAAK,gDAAgD,UAAU,CAAC,KAAK,CAAC;;2BAEtD,KAAK;;;;;qBAKX,KAAK;YACd,KAAK,cAAc,KAAK,wCAAwC,UAAU,CAAC,KAAK,CAAC;;;gBAG7E,KAAK;;;qBAGA,KAAK;aACb,KAAK,oCAAoC,KAAK,kDAAkD,UAAU,CAAC,KAAK,CAAC;;2BAEnG,KAAK;;gBAEhB,KAAK;;;qBAGA,KAAK;cACZ,KAAK,iDAAiD,UAAU,CAAC,KAAK,CAAC;;2BAE1D,KAAK;;eAEjB,KAAK;;CAEnB,CAAC;IACA,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,MAAM,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;IACtC,OAAO,CAAC,IAAI,CAAC,cAAc,KAAK,KAAK,CAAC,CAAC;IAEvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;IAChD,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,IAAI,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC3C,IAAI,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACvC,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,oCAAoC,EAAE,iBAAiB,KAAK,mBAAmB,KAAK,SAAS,CAAC,CAAC;YACnH,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,sBAAsB,EAAE,CAAC,EAAE,EAAE,IAAY,EAAE,EAAE,CAAC,YAAY,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,GAAG,CAAC,CAAC;YACrJ,MAAM,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC7B,CAAC;;YAAM,MAAM,CAAC,IAAI,CAAC,mCAAmC,KAAK,mBAAmB,KAAK,kBAAkB,KAAK,mCAAmC,CAAC,CAAC;IACjJ,CAAC;IAED,KAAK,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,CAC3E,CAAC,YAAY,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,4CAA4C,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CACxI,CAAC;AACJ,CAAC;AAED,gGAAgG;AAEhG,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,CAAC;QACH,QAAQ,OAAO,EAAE,CAAC;YAChB,KAAK,KAAK;gBACR,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5B,KAAK,KAAK;gBACR,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5B,KAAK,UAAU;gBACb,OAAO,MAAM,WAAW,CAAC,IAAI,CAAC,CAAC;YACjC,KAAK,OAAO;gBACV,OAAO,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC9B,KAAK,IAAI;gBACP,OAAO,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;YAC3B,KAAK,SAAS;gBACZ,OAAO,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;YAChC,KAAK,KAAK;gBACR,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;YAC5B,KAAK,SAAS,CAAC;YACf,KAAK,WAAW,CAAC;YACjB,KAAK,IAAI;gBACP,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;YACtC,KAAK,SAAS,CAAC;YACf,KAAK,MAAM,CAAC;YACZ,KAAK,QAAQ,CAAC;YACd,KAAK,IAAI;gBACP,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC3B;gBACE,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,oBAAoB,OAAO,IAAI,EAAE,EAAE,GAAG,EAAE,uCAAuC,EAAE,CAAC,CAAC;QACxH,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,KAAK,YAAY,YAAY,EAAE,CAAC;YAClC,IAAI,IAAI;gBAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;;gBACpG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACrC,CAAC;aAAM,CAAC;YACN,IAAI,IAAI;gBAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAE,KAAe,EAAE,OAAO,IAAI,KAAK,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;;gBACzI,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;QACD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,MAAM,IAAI,EAAE,CAAC"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory adapter for tests, prototypes and examples. Data is lost when the process exits.
|
|
3
|
+
* Enforces unique fields the same way Postgres does (IL4004, HTTP 409).
|
|
4
|
+
*/
|
|
5
|
+
import { InferloError } from "../errors.js";
|
|
6
|
+
function compare(a, b) {
|
|
7
|
+
const x = a instanceof Date ? a.getTime() : a;
|
|
8
|
+
const y = b instanceof Date ? b.getTime() : b;
|
|
9
|
+
if (x === y)
|
|
10
|
+
return 0;
|
|
11
|
+
if (x === null || x === undefined)
|
|
12
|
+
return 1;
|
|
13
|
+
if (y === null || y === undefined)
|
|
14
|
+
return -1;
|
|
15
|
+
return x < y ? -1 : 1;
|
|
16
|
+
}
|
|
17
|
+
function likeToRegex(pattern, flags) {
|
|
18
|
+
const escaped = pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/%/g, ".*").replace(/_/g, ".");
|
|
19
|
+
return new RegExp(`^${escaped}$`, flags);
|
|
20
|
+
}
|
|
21
|
+
function matches(row, conditions) {
|
|
22
|
+
return conditions.every(({ field, op, value }) => {
|
|
23
|
+
const v = row[field];
|
|
24
|
+
switch (op) {
|
|
25
|
+
case "eq":
|
|
26
|
+
return compare(v, value) === 0 && v !== null && v !== undefined;
|
|
27
|
+
case "ne":
|
|
28
|
+
return v !== null && v !== undefined && compare(v, value) !== 0;
|
|
29
|
+
case "gt":
|
|
30
|
+
return v != null && compare(v, value) > 0;
|
|
31
|
+
case "gte":
|
|
32
|
+
return v != null && compare(v, value) >= 0;
|
|
33
|
+
case "lt":
|
|
34
|
+
return v != null && compare(v, value) < 0;
|
|
35
|
+
case "lte":
|
|
36
|
+
return v != null && compare(v, value) <= 0;
|
|
37
|
+
case "in":
|
|
38
|
+
return value.some((x) => compare(v, x) === 0);
|
|
39
|
+
case "notIn":
|
|
40
|
+
return v != null && !value.some((x) => compare(v, x) === 0);
|
|
41
|
+
case "like":
|
|
42
|
+
return typeof v === "string" && likeToRegex(String(value), "").test(v);
|
|
43
|
+
case "ilike":
|
|
44
|
+
return typeof v === "string" && likeToRegex(String(value), "i").test(v);
|
|
45
|
+
case "isNull":
|
|
46
|
+
return value ? v === null || v === undefined : v !== null && v !== undefined;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
function clone(row) {
|
|
51
|
+
return structuredClone(row);
|
|
52
|
+
}
|
|
53
|
+
export function memory() {
|
|
54
|
+
const tables = new Map();
|
|
55
|
+
const rowsOf = (model) => {
|
|
56
|
+
let rows = tables.get(model.name);
|
|
57
|
+
if (!rows)
|
|
58
|
+
tables.set(model.name, (rows = []));
|
|
59
|
+
return rows;
|
|
60
|
+
};
|
|
61
|
+
const checkUnique = (model, candidate, ignoreId) => {
|
|
62
|
+
for (const [field, schema] of Object.entries(model.fields)) {
|
|
63
|
+
if (!schema.def.unique || candidate[field] == null)
|
|
64
|
+
continue;
|
|
65
|
+
const clash = rowsOf(model).find((r) => r.id !== ignoreId && compare(r[field], candidate[field]) === 0);
|
|
66
|
+
if (clash) {
|
|
67
|
+
throw new InferloError("IL4004", `A ${model.name} row with this ${field} already exists.`, { status: 409, details: { table: model.name, field } });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
return {
|
|
72
|
+
dialect: "memory",
|
|
73
|
+
async insert(model, row) {
|
|
74
|
+
checkUnique(model, row);
|
|
75
|
+
const stored = clone(row);
|
|
76
|
+
for (const key of Object.keys(model.fields))
|
|
77
|
+
if (!(key in stored))
|
|
78
|
+
stored[key] = null;
|
|
79
|
+
rowsOf(model).push(stored);
|
|
80
|
+
return clone(stored);
|
|
81
|
+
},
|
|
82
|
+
async select(model, query) {
|
|
83
|
+
let rows = rowsOf(model).filter((r) => matches(r, query.where));
|
|
84
|
+
if (query.orderBy.length) {
|
|
85
|
+
rows = [...rows].sort((a, b) => {
|
|
86
|
+
for (const [field, dir] of query.orderBy) {
|
|
87
|
+
const c = compare(a[field], b[field]);
|
|
88
|
+
if (c !== 0)
|
|
89
|
+
return dir === "asc" ? c : -c;
|
|
90
|
+
}
|
|
91
|
+
return 0;
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
const start = query.offset ?? 0;
|
|
95
|
+
return rows.slice(start, query.limit === undefined ? undefined : start + query.limit).map(clone);
|
|
96
|
+
},
|
|
97
|
+
async update(model, where, patch) {
|
|
98
|
+
const out = [];
|
|
99
|
+
for (const row of rowsOf(model)) {
|
|
100
|
+
if (!matches(row, where))
|
|
101
|
+
continue;
|
|
102
|
+
checkUnique(model, { ...row, ...patch }, row.id);
|
|
103
|
+
Object.assign(row, clone(patch));
|
|
104
|
+
out.push(clone(row));
|
|
105
|
+
}
|
|
106
|
+
return out;
|
|
107
|
+
},
|
|
108
|
+
async delete(model, where) {
|
|
109
|
+
const rows = rowsOf(model);
|
|
110
|
+
const keep = rows.filter((r) => !matches(r, where));
|
|
111
|
+
const removed = rows.length - keep.length;
|
|
112
|
+
tables.set(model.name, keep);
|
|
113
|
+
return removed;
|
|
114
|
+
},
|
|
115
|
+
async count(model, where) {
|
|
116
|
+
return rowsOf(model).filter((r) => matches(r, where)).length;
|
|
117
|
+
},
|
|
118
|
+
async sync(models) {
|
|
119
|
+
for (const m of models)
|
|
120
|
+
rowsOf(m);
|
|
121
|
+
return [];
|
|
122
|
+
},
|
|
123
|
+
async close() {
|
|
124
|
+
tables.clear();
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=memory.js.map
|