@aigne/afs-sqlite 1.11.0-beta.1 → 1.11.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
- package/dist/_virtual/rolldown_runtime.mjs +7 -0
- package/dist/actions/built-in.cjs +1262 -15
- package/dist/actions/built-in.d.cts.map +1 -1
- package/dist/actions/built-in.d.mts.map +1 -1
- package/dist/actions/built-in.mjs +1262 -15
- package/dist/actions/built-in.mjs.map +1 -1
- package/dist/actions/operators.cjs +156 -0
- package/dist/actions/operators.mjs +157 -0
- package/dist/actions/operators.mjs.map +1 -0
- package/dist/actions/registry.cjs +35 -3
- package/dist/actions/registry.d.cts +36 -17
- package/dist/actions/registry.d.cts.map +1 -1
- package/dist/actions/registry.d.mts +36 -17
- package/dist/actions/registry.d.mts.map +1 -1
- package/dist/actions/registry.mjs +35 -3
- package/dist/actions/registry.mjs.map +1 -1
- package/dist/actions/types.cjs +33 -0
- package/dist/actions/types.d.cts +46 -5
- package/dist/actions/types.d.cts.map +1 -1
- package/dist/actions/types.d.mts +46 -5
- package/dist/actions/types.d.mts.map +1 -1
- package/dist/actions/types.mjs +32 -0
- package/dist/actions/types.mjs.map +1 -0
- package/dist/config.cjs +1 -1
- package/dist/config.d.cts +9 -36
- package/dist/config.d.cts.map +1 -1
- package/dist/config.d.mts +9 -36
- package/dist/config.d.mts.map +1 -1
- package/dist/config.mjs +1 -1
- package/dist/config.mjs.map +1 -1
- package/dist/index.cjs +4 -3
- package/dist/index.d.cts +4 -3
- package/dist/index.d.mts +4 -3
- package/dist/index.mjs +3 -2
- package/dist/node/builder.cjs +74 -91
- package/dist/node/builder.d.cts +11 -15
- package/dist/node/builder.d.cts.map +1 -1
- package/dist/node/builder.d.mts +11 -15
- package/dist/node/builder.d.mts.map +1 -1
- package/dist/node/builder.mjs +72 -89
- package/dist/node/builder.mjs.map +1 -1
- package/dist/operations/crud.cjs +24 -68
- package/dist/operations/crud.d.cts +23 -38
- package/dist/operations/crud.d.cts.map +1 -1
- package/dist/operations/crud.d.mts +23 -38
- package/dist/operations/crud.d.mts.map +1 -1
- package/dist/operations/crud.mjs +25 -69
- package/dist/operations/crud.mjs.map +1 -1
- package/dist/operations/query-builder.cjs +2 -2
- package/dist/operations/query-builder.d.cts.map +1 -1
- package/dist/operations/query-builder.d.mts.map +1 -1
- package/dist/operations/query-builder.mjs +2 -2
- package/dist/operations/query-builder.mjs.map +1 -1
- package/dist/operations/search.cjs +5 -11
- package/dist/operations/search.d.cts +19 -23
- package/dist/operations/search.d.cts.map +1 -1
- package/dist/operations/search.d.mts +19 -23
- package/dist/operations/search.d.mts.map +1 -1
- package/dist/operations/search.mjs +5 -11
- package/dist/operations/search.mjs.map +1 -1
- package/dist/router/path-router.cjs +7 -15
- package/dist/router/path-router.d.cts +4 -7
- package/dist/router/path-router.d.cts.map +1 -1
- package/dist/router/path-router.d.mts +4 -7
- package/dist/router/path-router.d.mts.map +1 -1
- package/dist/router/path-router.mjs +7 -15
- package/dist/router/path-router.mjs.map +1 -1
- package/dist/router/types.d.cts.map +1 -1
- package/dist/router/types.d.mts.map +1 -1
- package/dist/schema/introspector.d.cts +19 -19
- package/dist/schema/introspector.d.cts.map +1 -1
- package/dist/schema/introspector.d.mts +19 -19
- package/dist/schema/introspector.d.mts.map +1 -1
- package/dist/schema/service.cjs +86 -0
- package/dist/schema/service.d.cts +52 -0
- package/dist/schema/service.d.cts.map +1 -0
- package/dist/schema/service.d.mts +52 -0
- package/dist/schema/service.d.mts.map +1 -0
- package/dist/schema/service.mjs +87 -0
- package/dist/schema/service.mjs.map +1 -0
- package/dist/schema/types.d.cts.map +1 -1
- package/dist/schema/types.d.mts.map +1 -1
- package/dist/sqlite-afs.cjs +693 -121
- package/dist/sqlite-afs.d.cts +279 -101
- package/dist/sqlite-afs.d.cts.map +1 -1
- package/dist/sqlite-afs.d.mts +279 -101
- package/dist/sqlite-afs.d.mts.map +1 -1
- package/dist/sqlite-afs.mjs +696 -123
- package/dist/sqlite-afs.mjs.map +1 -1
- package/package.json +5 -4
package/dist/sqlite-afs.mjs
CHANGED
|
@@ -1,34 +1,48 @@
|
|
|
1
|
+
import { __require } from "./_virtual/rolldown_runtime.mjs";
|
|
1
2
|
import { registerBuiltInActions } from "./actions/built-in.mjs";
|
|
2
3
|
import { ActionsRegistry } from "./actions/registry.mjs";
|
|
3
4
|
import { sqliteAFSConfigSchema } from "./config.mjs";
|
|
4
|
-
import { buildActionsListEntry } from "./node/builder.mjs";
|
|
5
|
+
import { buildActionsListEntry, buildRootActionsListEntry, buildRootEntry, buildTableActionsListEntry, buildTableEntry } from "./node/builder.mjs";
|
|
5
6
|
import { CRUDOperations } from "./operations/crud.mjs";
|
|
6
7
|
import { FTSSearch, createFTSConfig } from "./operations/search.mjs";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { initDatabase } from "@aigne/sqlite";
|
|
8
|
+
import { SchemaService } from "./schema/service.mjs";
|
|
9
|
+
import { __decorate } from "./_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs";
|
|
10
|
+
import { initDatabase, sql } from "@aigne/sqlite";
|
|
11
|
+
import { AFSNotFoundError } from "@aigne/afs";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
import { AFSBaseProvider, Actions, Delete, Explain, List, Meta, Read, Search, Stat, Write } from "@aigne/afs/provider";
|
|
10
14
|
|
|
11
15
|
//#region src/sqlite-afs.ts
|
|
12
16
|
/**
|
|
13
17
|
* SQLite AFS Module
|
|
14
18
|
*
|
|
15
19
|
* Exposes SQLite databases as AFS nodes with full CRUD support,
|
|
16
|
-
* schema introspection, FTS5 search, and virtual paths (
|
|
20
|
+
* schema introspection, FTS5 search, and virtual paths (.meta, .actions).
|
|
17
21
|
*/
|
|
18
|
-
var SQLiteAFS = class SQLiteAFS {
|
|
22
|
+
var SQLiteAFS = class SQLiteAFS extends AFSBaseProvider {
|
|
19
23
|
name;
|
|
20
24
|
description;
|
|
21
25
|
accessMode;
|
|
22
26
|
db;
|
|
23
|
-
|
|
24
|
-
router;
|
|
27
|
+
schemaService;
|
|
25
28
|
crud;
|
|
26
29
|
ftsSearch;
|
|
27
30
|
actions;
|
|
28
31
|
ftsConfig;
|
|
29
32
|
initialized = false;
|
|
30
33
|
constructor(options) {
|
|
34
|
+
super();
|
|
31
35
|
this.options = options;
|
|
36
|
+
if (options.localPath && !options.url) options.url = `file:${options.localPath}`;
|
|
37
|
+
if (options.url.startsWith("file:")) {
|
|
38
|
+
const { existsSync, mkdirSync, writeFileSync } = __require("node:fs");
|
|
39
|
+
const { dirname } = __require("node:path");
|
|
40
|
+
const dbPath = options.url.slice(5);
|
|
41
|
+
if (!existsSync(dbPath)) {
|
|
42
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
43
|
+
writeFileSync(dbPath, "");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
32
46
|
this.name = options.name ?? "sqlite-afs";
|
|
33
47
|
this.description = options.description ?? `SQLite database: ${options.url}`;
|
|
34
48
|
this.accessMode = options.accessMode ?? "readwrite";
|
|
@@ -42,20 +56,24 @@ var SQLiteAFS = class SQLiteAFS {
|
|
|
42
56
|
static schema() {
|
|
43
57
|
return sqliteAFSConfigSchema;
|
|
44
58
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
59
|
+
static manifest() {
|
|
60
|
+
return {
|
|
61
|
+
name: "sqlite",
|
|
62
|
+
description: "SQLite database — tables as directories, rows as nodes.\n- Browse tables and rows, full-text search (FTS5), schema introspection\n- Exec actions: `insert`, `update`, `delete` at table/row level, custom SQL\n- Path structure: `/{table}/{primary-key}`",
|
|
63
|
+
uriTemplate: "sqlite://{localPath+}",
|
|
64
|
+
category: "database",
|
|
65
|
+
schema: z.object({ localPath: z.string() }),
|
|
66
|
+
tags: ["sqlite", "database"]
|
|
67
|
+
};
|
|
50
68
|
}
|
|
51
69
|
/**
|
|
52
|
-
*
|
|
70
|
+
* Loads a module instance from configuration
|
|
53
71
|
*/
|
|
54
|
-
async
|
|
55
|
-
|
|
72
|
+
static async load({ config } = {}) {
|
|
73
|
+
return new SQLiteAFS(sqliteAFSConfigSchema.parse(config));
|
|
56
74
|
}
|
|
57
75
|
/**
|
|
58
|
-
* Initializes the database connection and
|
|
76
|
+
* Initializes the database connection and schema service
|
|
59
77
|
*/
|
|
60
78
|
async initialize() {
|
|
61
79
|
if (this.initialized) return;
|
|
@@ -64,158 +82,672 @@ var SQLiteAFS = class SQLiteAFS {
|
|
|
64
82
|
wal: this.options.wal ?? true
|
|
65
83
|
});
|
|
66
84
|
const db = this.db;
|
|
67
|
-
this.
|
|
85
|
+
this.schemaService = new SchemaService(db, {
|
|
68
86
|
tables: this.options.tables,
|
|
69
87
|
excludeTables: this.options.excludeTables
|
|
70
88
|
});
|
|
71
|
-
this.
|
|
72
|
-
this.
|
|
73
|
-
this.ftsSearch = new FTSSearch(db, this.schemas, this.ftsConfig, "");
|
|
89
|
+
this.crud = new CRUDOperations(db, this.schemaService, "");
|
|
90
|
+
this.ftsSearch = new FTSSearch(db, this.schemaService, this.ftsConfig, "");
|
|
74
91
|
this.initialized = true;
|
|
75
92
|
}
|
|
76
93
|
/**
|
|
77
|
-
* Ensures the module is initialized
|
|
94
|
+
* Ensures the module is initialized.
|
|
95
|
+
* This is called automatically by handlers, but can also be called
|
|
96
|
+
* manually to trigger initialization (e.g., in tests).
|
|
78
97
|
*/
|
|
79
98
|
async ensureInitialized() {
|
|
80
99
|
if (!this.initialized) await this.initialize();
|
|
81
100
|
}
|
|
82
101
|
/**
|
|
83
|
-
*
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
* List all tables
|
|
103
|
+
* Note: list() returns only children, never the path itself (per new semantics)
|
|
104
|
+
*/
|
|
105
|
+
async listTablesHandler(_ctx) {
|
|
106
|
+
await this.ensureInitialized();
|
|
107
|
+
return { data: (await this.crud.listTables()).data };
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* List rows in a table
|
|
111
|
+
* Note: list() returns only children (rows), never the table itself (per new semantics)
|
|
112
|
+
*/
|
|
113
|
+
async listTableHandler(ctx) {
|
|
114
|
+
await this.ensureInitialized();
|
|
115
|
+
if (!await this.schemaService.getSchema(ctx.params.table)) throw new AFSNotFoundError(`/${ctx.params.table}`);
|
|
116
|
+
return { data: (await this.crud.listTable(ctx.params.table, ctx.options)).data };
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* List a row - rows are leaf nodes with no children
|
|
120
|
+
* Note: list() returns only children, never the path itself (per new semantics)
|
|
121
|
+
*/
|
|
122
|
+
async listRowHandler(ctx) {
|
|
123
|
+
await this.ensureInitialized();
|
|
124
|
+
if (!(await this.crud.readRow(ctx.params.table, ctx.params.pk)).data) throw new AFSNotFoundError(`/${ctx.params.table}/${ctx.params.pk}`);
|
|
125
|
+
return { data: [] };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* List actions for a row
|
|
129
|
+
*/
|
|
130
|
+
async listActionsHandler(ctx) {
|
|
131
|
+
await this.ensureInitialized();
|
|
132
|
+
const schema = await this.schemaService.getSchema(ctx.params.table);
|
|
133
|
+
if (!schema) throw new AFSNotFoundError(`/${ctx.params.table}`);
|
|
134
|
+
const actions = this.actions.listWithInfo({ rowLevel: true }, {
|
|
135
|
+
tableSchema: schema,
|
|
136
|
+
tableName: ctx.params.table,
|
|
137
|
+
schemaService: this.schemaService
|
|
138
|
+
});
|
|
139
|
+
return { data: buildActionsListEntry(ctx.params.table, ctx.params.pk, actions, { basePath: "" }) };
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* List actions for a table (table-level actions)
|
|
143
|
+
*/
|
|
144
|
+
async listTableActionsHandler(ctx) {
|
|
145
|
+
await this.ensureInitialized();
|
|
146
|
+
const schema = await this.schemaService.getSchema(ctx.params.table);
|
|
147
|
+
if (!schema) throw new AFSNotFoundError(`/${ctx.params.table}`);
|
|
148
|
+
const actions = this.actions.listWithInfo({ tableLevel: true }, {
|
|
149
|
+
tableSchema: schema,
|
|
150
|
+
tableName: ctx.params.table,
|
|
151
|
+
schemaService: this.schemaService
|
|
152
|
+
});
|
|
153
|
+
return { data: buildTableActionsListEntry(ctx.params.table, actions, { basePath: "" }) };
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* List actions at root level (database-level actions)
|
|
157
|
+
*/
|
|
158
|
+
async listRootActionsHandler(_ctx) {
|
|
159
|
+
await this.ensureInitialized();
|
|
160
|
+
return { data: buildRootActionsListEntry(this.actions.listWithInfo({ rootLevel: true }, { schemaService: this.schemaService }), { basePath: "" }) };
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Read root (database) entry
|
|
164
|
+
*/
|
|
165
|
+
async readRootHandler(_ctx) {
|
|
166
|
+
await this.ensureInitialized();
|
|
167
|
+
return buildRootEntry(await this.schemaService.getAllSchemas(), { basePath: "" });
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Read root metadata (database-level schema information)
|
|
171
|
+
*/
|
|
172
|
+
async readRootMetaHandler(_ctx) {
|
|
173
|
+
await this.ensureInitialized();
|
|
174
|
+
const schemas = await this.schemaService.getAllSchemas();
|
|
175
|
+
const tables = Array.from(schemas.entries()).sort((a, b) => a[0].localeCompare(b[0])).map(([name, schema]) => ({
|
|
176
|
+
name,
|
|
177
|
+
description: `Table with ${schema.columns.length} columns`,
|
|
178
|
+
columnCount: schema.columns.length,
|
|
179
|
+
primaryKey: schema.primaryKey
|
|
180
|
+
}));
|
|
181
|
+
return {
|
|
182
|
+
id: "root:.meta",
|
|
183
|
+
path: "/.meta",
|
|
184
|
+
content: {
|
|
185
|
+
type: "sqlite",
|
|
186
|
+
tableCount: schemas.size,
|
|
187
|
+
tables
|
|
188
|
+
},
|
|
189
|
+
meta: {
|
|
190
|
+
childrenCount: tables.length,
|
|
191
|
+
tables: tables.map((t) => t.name)
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Read capabilities manifest
|
|
197
|
+
* Returns information about available actions at different levels
|
|
198
|
+
*/
|
|
199
|
+
async readCapabilitiesHandler(_ctx) {
|
|
200
|
+
await this.ensureInitialized();
|
|
201
|
+
const actionCatalogs = [];
|
|
202
|
+
const rootActions = this.actions.listWithInfo({ rootLevel: true }, { schemaService: this.schemaService });
|
|
203
|
+
if (rootActions.length > 0) actionCatalogs.push({
|
|
204
|
+
kind: "sqlite:root",
|
|
205
|
+
description: "Database-level operations",
|
|
206
|
+
catalog: rootActions.map((a) => ({
|
|
207
|
+
name: a.name,
|
|
208
|
+
description: a.description,
|
|
209
|
+
inputSchema: a.inputSchema
|
|
210
|
+
})),
|
|
211
|
+
discovery: {
|
|
212
|
+
pathTemplate: "/.actions",
|
|
213
|
+
note: "Available at database root"
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
const tableActions = this.actions.listWithInfo({ tableLevel: true }, { schemaService: this.schemaService });
|
|
217
|
+
if (tableActions.length > 0) actionCatalogs.push({
|
|
218
|
+
kind: "sqlite:table",
|
|
219
|
+
description: "Table-level operations",
|
|
220
|
+
catalog: tableActions.map((a) => ({
|
|
221
|
+
name: a.name,
|
|
222
|
+
description: a.description,
|
|
223
|
+
inputSchema: a.inputSchema
|
|
224
|
+
})),
|
|
225
|
+
discovery: {
|
|
226
|
+
pathTemplate: "/:table/.actions",
|
|
227
|
+
note: "Replace :table with actual table name"
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
const rowActions = this.actions.listWithInfo({ rowLevel: true }, { schemaService: this.schemaService });
|
|
231
|
+
if (rowActions.length > 0) actionCatalogs.push({
|
|
232
|
+
kind: "sqlite:row",
|
|
233
|
+
description: "Row-level operations",
|
|
234
|
+
catalog: rowActions.map((a) => ({
|
|
235
|
+
name: a.name,
|
|
236
|
+
description: a.description,
|
|
237
|
+
inputSchema: a.inputSchema
|
|
238
|
+
})),
|
|
239
|
+
discovery: {
|
|
240
|
+
pathTemplate: "/:table/:pk/.actions",
|
|
241
|
+
note: "Replace :table with table name, :pk with primary key value"
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
return {
|
|
245
|
+
id: "/.meta/.capabilities",
|
|
246
|
+
path: "/.meta/.capabilities",
|
|
247
|
+
content: {
|
|
248
|
+
schemaVersion: 1,
|
|
249
|
+
provider: this.name,
|
|
250
|
+
version: "1.0.0",
|
|
251
|
+
description: this.description,
|
|
252
|
+
tools: [],
|
|
253
|
+
actions: actionCatalogs,
|
|
254
|
+
operations: this.getOperationsDeclaration()
|
|
255
|
+
},
|
|
256
|
+
meta: { kind: "afs:capabilities" }
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Read table (directory) entry
|
|
261
|
+
*/
|
|
262
|
+
async readTableHandler(ctx) {
|
|
263
|
+
await this.ensureInitialized();
|
|
264
|
+
const schema = await this.schemaService.getSchema(ctx.params.table);
|
|
265
|
+
if (!schema) throw new AFSNotFoundError(`/${ctx.params.table}`);
|
|
266
|
+
const rowCount = (await this.db.all(sql.raw(`SELECT COUNT(*) as count FROM "${ctx.params.table}"`)))[0]?.count ?? 0;
|
|
267
|
+
return buildTableEntry(ctx.params.table, schema, {
|
|
268
|
+
basePath: "",
|
|
269
|
+
rowCount
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Read table metadata (table-level schema information)
|
|
274
|
+
*/
|
|
275
|
+
async readTableMetaHandler(ctx) {
|
|
276
|
+
await this.ensureInitialized();
|
|
277
|
+
const schema = await this.schemaService.getSchema(ctx.params.table);
|
|
278
|
+
if (!schema) throw new AFSNotFoundError(`/${ctx.params.table}`);
|
|
279
|
+
const rowCount = (await this.db.all(sql.raw(`SELECT COUNT(*) as count FROM "${ctx.params.table}"`)))[0]?.count ?? 0;
|
|
280
|
+
const columns = schema.columns.map((col) => ({
|
|
281
|
+
name: col.name,
|
|
282
|
+
type: col.type,
|
|
283
|
+
nullable: !col.notnull,
|
|
284
|
+
primaryKey: col.pk > 0,
|
|
285
|
+
defaultValue: col.dfltValue
|
|
286
|
+
}));
|
|
287
|
+
return {
|
|
288
|
+
id: `${ctx.params.table}:.meta`,
|
|
289
|
+
path: `/${ctx.params.table}/.meta`,
|
|
290
|
+
content: {
|
|
291
|
+
table: ctx.params.table,
|
|
292
|
+
columns,
|
|
293
|
+
primaryKey: schema.primaryKey,
|
|
294
|
+
foreignKeys: schema.foreignKeys.map((fk) => ({
|
|
295
|
+
column: fk.from,
|
|
296
|
+
referencesTable: fk.table,
|
|
297
|
+
referencesColumn: fk.to,
|
|
298
|
+
onUpdate: fk.onUpdate,
|
|
299
|
+
onDelete: fk.onDelete
|
|
300
|
+
})),
|
|
301
|
+
indexes: schema.indexes.map((idx) => ({
|
|
302
|
+
name: idx.name,
|
|
303
|
+
unique: idx.unique,
|
|
304
|
+
origin: idx.origin
|
|
305
|
+
})),
|
|
306
|
+
rowCount
|
|
307
|
+
},
|
|
308
|
+
meta: {
|
|
309
|
+
table: ctx.params.table,
|
|
310
|
+
description: `Table "${ctx.params.table}" with ${columns.length} columns`,
|
|
311
|
+
childrenCount: rowCount,
|
|
312
|
+
columnCount: columns.length,
|
|
313
|
+
columns: columns.map((c) => c.name),
|
|
314
|
+
primaryKey: schema.primaryKey
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Read a row
|
|
320
|
+
*/
|
|
321
|
+
async readRowHandler(ctx) {
|
|
322
|
+
await this.ensureInitialized();
|
|
323
|
+
return (await this.crud.readRow(ctx.params.table, ctx.params.pk)).data;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Get row metadata (@meta suffix - SQLite-specific)
|
|
327
|
+
*/
|
|
328
|
+
async getMetaHandler(ctx) {
|
|
329
|
+
await this.ensureInitialized();
|
|
330
|
+
return (await this.crud.getMeta(ctx.params.table, ctx.params.pk)).data;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Get row metadata (.meta suffix - row-level schema information)
|
|
334
|
+
*/
|
|
335
|
+
async getRowDotMetaHandler(ctx) {
|
|
336
|
+
await this.ensureInitialized();
|
|
337
|
+
const schema = await this.schemaService.getSchema(ctx.params.table);
|
|
338
|
+
if (!schema) throw new AFSNotFoundError(`/${ctx.params.table}`);
|
|
339
|
+
if (!(await this.crud.readRow(ctx.params.table, ctx.params.pk)).data) throw new AFSNotFoundError(`/${ctx.params.table}/${ctx.params.pk}`);
|
|
340
|
+
const pkColumn = schema.primaryKey[0] ?? "rowid";
|
|
341
|
+
return {
|
|
342
|
+
id: `${ctx.params.table}:${ctx.params.pk}:.meta`,
|
|
343
|
+
path: `/${ctx.params.table}/${ctx.params.pk}/.meta`,
|
|
344
|
+
content: {
|
|
345
|
+
table: ctx.params.table,
|
|
346
|
+
primaryKey: pkColumn,
|
|
347
|
+
primaryKeyValue: ctx.params.pk,
|
|
348
|
+
columns: schema.columns.map((col) => ({
|
|
349
|
+
name: col.name,
|
|
350
|
+
type: col.type,
|
|
351
|
+
nullable: !col.notnull,
|
|
352
|
+
primaryKey: col.pk > 0
|
|
353
|
+
})),
|
|
354
|
+
foreignKeys: schema.foreignKeys.map((fk) => ({
|
|
355
|
+
column: fk.from,
|
|
356
|
+
referencesTable: fk.table,
|
|
357
|
+
referencesColumn: fk.to
|
|
358
|
+
}))
|
|
359
|
+
},
|
|
360
|
+
meta: {
|
|
361
|
+
table: ctx.params.table,
|
|
362
|
+
primaryKeyValue: ctx.params.pk,
|
|
363
|
+
columns: schema.columns.map((col) => col.name)
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Create a new row
|
|
369
|
+
*/
|
|
370
|
+
async createRowHandler(ctx, content) {
|
|
371
|
+
await this.ensureInitialized();
|
|
372
|
+
return this.crud.createRow(ctx.params.table, content.content ?? content);
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Update an existing row
|
|
376
|
+
*/
|
|
377
|
+
async updateRowHandler(ctx, content) {
|
|
378
|
+
await this.ensureInitialized();
|
|
379
|
+
return this.crud.updateRow(ctx.params.table, ctx.params.pk, content.content ?? content);
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Execute action via write (for triggering row-level actions)
|
|
383
|
+
*/
|
|
384
|
+
async executeActionWriteHandler(ctx, content) {
|
|
385
|
+
await this.ensureInitialized();
|
|
386
|
+
return this.executeAction(ctx.params.table, ctx.params.pk, ctx.params.action, content.content ?? content);
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Execute action via write (for triggering table-level actions)
|
|
390
|
+
*/
|
|
391
|
+
async executeTableActionWriteHandler(ctx, content) {
|
|
392
|
+
await this.ensureInitialized();
|
|
393
|
+
return this.executeAction(ctx.params.table, void 0, ctx.params.action, content.content ?? content);
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Execute action via write (for triggering root-level actions)
|
|
397
|
+
*/
|
|
398
|
+
async executeRootActionWriteHandler(ctx, content) {
|
|
399
|
+
await this.ensureInitialized();
|
|
400
|
+
return this.executeRootAction(ctx.params.action, content.content ?? content);
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Delete a table entry (not supported - always throws)
|
|
404
|
+
*/
|
|
405
|
+
async deleteTableHandler(ctx) {
|
|
406
|
+
await this.ensureInitialized();
|
|
407
|
+
if (!await this.schemaService.hasTable(ctx.params.table)) throw new AFSNotFoundError(`/${ctx.params.table}`);
|
|
408
|
+
throw new Error(`Cannot delete table '${ctx.params.table}'. Use SQL directly to drop tables.`);
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Delete a row
|
|
412
|
+
*/
|
|
413
|
+
async deleteRowHandler(ctx) {
|
|
414
|
+
await this.ensureInitialized();
|
|
415
|
+
return this.crud.deleteRow(ctx.params.table, ctx.params.pk);
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Search all tables
|
|
419
|
+
*/
|
|
420
|
+
async searchAllHandler(_ctx, query, options) {
|
|
421
|
+
await this.ensureInitialized();
|
|
422
|
+
return this.ftsSearch.search(query, options);
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Search a specific table
|
|
426
|
+
*/
|
|
427
|
+
async searchTableHandler(ctx, query, options) {
|
|
428
|
+
await this.ensureInitialized();
|
|
429
|
+
return this.ftsSearch.searchTable(ctx.params.table, query, options);
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Get stat for root (database level)
|
|
433
|
+
*/
|
|
434
|
+
async statRootHandler(_ctx) {
|
|
435
|
+
await this.ensureInitialized();
|
|
436
|
+
const schemas = await this.schemaService.getAllSchemas();
|
|
437
|
+
const actions = this.actions.listWithInfo({ rootLevel: true }, { schemaService: this.schemaService });
|
|
438
|
+
return { data: {
|
|
439
|
+
id: "/",
|
|
440
|
+
path: "/",
|
|
441
|
+
meta: {
|
|
442
|
+
kind: "sqlite:database",
|
|
443
|
+
kinds: ["sqlite:database", "afs:node"],
|
|
444
|
+
tableCount: schemas.size,
|
|
445
|
+
childrenCount: schemas.size
|
|
446
|
+
},
|
|
447
|
+
actions: actions.length > 0 ? actions.map((a) => ({
|
|
448
|
+
name: a.name,
|
|
449
|
+
description: a.description
|
|
450
|
+
})) : void 0
|
|
451
|
+
} };
|
|
102
452
|
}
|
|
103
453
|
/**
|
|
104
|
-
*
|
|
105
|
-
*/
|
|
106
|
-
async
|
|
107
|
-
await this.ensureInitialized();
|
|
108
|
-
const
|
|
109
|
-
if (!
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
454
|
+
* Get stat for a table
|
|
455
|
+
*/
|
|
456
|
+
async statTableHandler(ctx) {
|
|
457
|
+
await this.ensureInitialized();
|
|
458
|
+
const schema = await this.schemaService.getSchema(ctx.params.table);
|
|
459
|
+
if (!schema) throw new AFSNotFoundError(`/${ctx.params.table}`);
|
|
460
|
+
const rowCount = (await this.db.all(sql.raw(`SELECT COUNT(*) as count FROM "${ctx.params.table}"`)))[0]?.count ?? 0;
|
|
461
|
+
const actions = this.actions.listWithInfo({ tableLevel: true }, {
|
|
462
|
+
tableSchema: schema,
|
|
463
|
+
tableName: ctx.params.table,
|
|
464
|
+
schemaService: this.schemaService
|
|
465
|
+
});
|
|
466
|
+
const columns = schema.columns.map((col) => ({
|
|
467
|
+
name: col.name,
|
|
468
|
+
type: col.type,
|
|
469
|
+
nullable: !col.notnull,
|
|
470
|
+
primaryKey: col.pk > 0
|
|
471
|
+
}));
|
|
472
|
+
return { data: {
|
|
473
|
+
id: ctx.params.table,
|
|
474
|
+
path: `/${ctx.params.table}`,
|
|
475
|
+
meta: {
|
|
476
|
+
kind: "sqlite:table",
|
|
477
|
+
kinds: ["sqlite:table", "afs:node"],
|
|
478
|
+
table: ctx.params.table,
|
|
479
|
+
columnCount: schema.columns.length,
|
|
480
|
+
columns,
|
|
481
|
+
primaryKey: schema.primaryKey[0],
|
|
482
|
+
childrenCount: rowCount
|
|
483
|
+
},
|
|
484
|
+
actions: actions.length > 0 ? actions.map((a) => ({
|
|
485
|
+
name: a.name,
|
|
486
|
+
description: a.description
|
|
487
|
+
})) : void 0
|
|
488
|
+
} };
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Get stat for a row
|
|
492
|
+
*/
|
|
493
|
+
async statRowHandler(ctx) {
|
|
494
|
+
await this.ensureInitialized();
|
|
495
|
+
const schema = await this.schemaService.getSchema(ctx.params.table);
|
|
496
|
+
if (!schema) throw new AFSNotFoundError(`/${ctx.params.table}`);
|
|
497
|
+
if (!(await this.crud.readRow(ctx.params.table, ctx.params.pk)).data) throw new AFSNotFoundError(`/${ctx.params.table}/${ctx.params.pk}`);
|
|
498
|
+
const actions = this.actions.listWithInfo({ rowLevel: true }, {
|
|
499
|
+
tableSchema: schema,
|
|
500
|
+
tableName: ctx.params.table,
|
|
501
|
+
schemaService: this.schemaService
|
|
502
|
+
});
|
|
503
|
+
const columns = schema.columns.map((col) => ({
|
|
504
|
+
name: col.name,
|
|
505
|
+
type: col.type,
|
|
506
|
+
nullable: !col.notnull,
|
|
507
|
+
primaryKey: col.pk > 0
|
|
508
|
+
}));
|
|
509
|
+
return { data: {
|
|
510
|
+
id: ctx.params.pk,
|
|
511
|
+
path: `/${ctx.params.table}/${ctx.params.pk}`,
|
|
512
|
+
meta: {
|
|
513
|
+
kind: "sqlite:row",
|
|
514
|
+
kinds: ["sqlite:row", "afs:node"],
|
|
515
|
+
table: ctx.params.table,
|
|
516
|
+
primaryKey: ctx.params.pk,
|
|
517
|
+
columnCount: schema.columns.length,
|
|
518
|
+
columns,
|
|
519
|
+
childrenCount: 0
|
|
520
|
+
},
|
|
521
|
+
actions: actions.length > 0 ? actions.map((a) => ({
|
|
522
|
+
name: a.name,
|
|
523
|
+
description: a.description
|
|
524
|
+
})) : void 0
|
|
525
|
+
} };
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Explain root (database level)
|
|
529
|
+
*/
|
|
530
|
+
async explainRootHandler(ctx) {
|
|
531
|
+
await this.ensureInitialized();
|
|
532
|
+
const format = ctx.options?.format || "markdown";
|
|
533
|
+
const schemas = await this.schemaService.getAllSchemas();
|
|
534
|
+
const tables = Array.from(schemas.values());
|
|
535
|
+
const lines = [];
|
|
536
|
+
if (format === "markdown") {
|
|
537
|
+
lines.push(`# ${this.name}`);
|
|
538
|
+
lines.push("");
|
|
539
|
+
lines.push(`**Type:** SQLite Database`);
|
|
540
|
+
lines.push(`**Tables:** ${tables.length}`);
|
|
541
|
+
lines.push("");
|
|
542
|
+
if (tables.length > 0) {
|
|
543
|
+
lines.push("## Tables");
|
|
544
|
+
lines.push("");
|
|
545
|
+
lines.push("| Table | Columns | Primary Key |");
|
|
546
|
+
lines.push("|-------|---------|-------------|");
|
|
547
|
+
for (const table of tables) {
|
|
548
|
+
const pk = table.primaryKey.join(", ") || "rowid";
|
|
549
|
+
lines.push(`| ${table.name} | ${table.columns.length} | ${pk} |`);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
} else {
|
|
553
|
+
lines.push(`${this.name} (SQLite Database)`);
|
|
554
|
+
lines.push(`Tables: ${tables.length}`);
|
|
555
|
+
for (const table of tables) lines.push(` - ${table.name} (${table.columns.length} columns)`);
|
|
124
556
|
}
|
|
557
|
+
return {
|
|
558
|
+
content: lines.join("\n"),
|
|
559
|
+
format
|
|
560
|
+
};
|
|
125
561
|
}
|
|
126
562
|
/**
|
|
127
|
-
*
|
|
128
|
-
*/
|
|
129
|
-
async
|
|
130
|
-
await this.ensureInitialized();
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
if (!
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
563
|
+
* Explain a table
|
|
564
|
+
*/
|
|
565
|
+
async explainTableHandler(ctx) {
|
|
566
|
+
await this.ensureInitialized();
|
|
567
|
+
const format = ctx.options?.format || "markdown";
|
|
568
|
+
const schema = await this.schemaService.getSchema(ctx.params.table);
|
|
569
|
+
if (!schema) throw new AFSNotFoundError(`/${ctx.params.table}`);
|
|
570
|
+
const rowCount = (await this.db.all(sql.raw(`SELECT COUNT(*) as count FROM "${ctx.params.table}"`)))[0]?.count ?? 0;
|
|
571
|
+
const lines = [];
|
|
572
|
+
if (format === "markdown") {
|
|
573
|
+
lines.push(`# ${ctx.params.table}`);
|
|
574
|
+
lines.push("");
|
|
575
|
+
lines.push(`**Type:** SQLite Table`);
|
|
576
|
+
lines.push(`**Rows:** ${rowCount}`);
|
|
577
|
+
lines.push(`**Primary Key:** ${schema.primaryKey.join(", ") || "rowid"}`);
|
|
578
|
+
lines.push("");
|
|
579
|
+
lines.push("## Columns");
|
|
580
|
+
lines.push("");
|
|
581
|
+
lines.push("| Column | Type | Nullable | Primary Key | Default |");
|
|
582
|
+
lines.push("|--------|------|----------|-------------|---------|");
|
|
583
|
+
for (const col of schema.columns) {
|
|
584
|
+
const nullable = col.notnull ? "NO" : "YES";
|
|
585
|
+
const pk = col.pk > 0 ? "YES" : "";
|
|
586
|
+
const dflt = col.dfltValue !== null && col.dfltValue !== void 0 ? String(col.dfltValue) : "";
|
|
587
|
+
lines.push(`| ${col.name} | ${col.type} | ${nullable} | ${pk} | ${dflt} |`);
|
|
588
|
+
}
|
|
589
|
+
if (schema.indexes.length > 0) {
|
|
590
|
+
lines.push("");
|
|
591
|
+
lines.push("## Indexes");
|
|
592
|
+
lines.push("");
|
|
593
|
+
for (const idx of schema.indexes) {
|
|
594
|
+
const uniqueStr = idx.unique ? " (UNIQUE)" : "";
|
|
595
|
+
lines.push(`- **${idx.name}**${uniqueStr}`);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
if (schema.foreignKeys.length > 0) {
|
|
599
|
+
lines.push("");
|
|
600
|
+
lines.push("## Foreign Keys");
|
|
601
|
+
lines.push("");
|
|
602
|
+
for (const fk of schema.foreignKeys) lines.push(`- \`${fk.from}\` → \`${fk.table}\`(\`${fk.to}\`) ON DELETE ${fk.onDelete}`);
|
|
603
|
+
}
|
|
604
|
+
} else {
|
|
605
|
+
lines.push(`${ctx.params.table} (SQLite Table)`);
|
|
606
|
+
lines.push(`Rows: ${rowCount}`);
|
|
607
|
+
lines.push(`Primary Key: ${schema.primaryKey.join(", ") || "rowid"}`);
|
|
608
|
+
lines.push(`Columns: ${schema.columns.map((c) => `${c.name} (${c.type})`).join(", ")}`);
|
|
609
|
+
if (schema.indexes.length > 0) lines.push(`Indexes: ${schema.indexes.map((i) => i.name).join(", ")}`);
|
|
610
|
+
if (schema.foreignKeys.length > 0) lines.push(`Foreign Keys: ${schema.foreignKeys.map((fk) => `${fk.from} → ${fk.table}(${fk.to})`).join(", ")}`);
|
|
145
611
|
}
|
|
612
|
+
return {
|
|
613
|
+
content: lines.join("\n"),
|
|
614
|
+
format
|
|
615
|
+
};
|
|
146
616
|
}
|
|
147
617
|
/**
|
|
148
|
-
*
|
|
618
|
+
* Explain a row
|
|
149
619
|
*/
|
|
150
|
-
async
|
|
620
|
+
async explainRowHandler(ctx) {
|
|
151
621
|
await this.ensureInitialized();
|
|
152
|
-
|
|
153
|
-
const
|
|
154
|
-
if (!
|
|
155
|
-
|
|
156
|
-
|
|
622
|
+
const format = ctx.options?.format || "markdown";
|
|
623
|
+
const schema = await this.schemaService.getSchema(ctx.params.table);
|
|
624
|
+
if (!schema) throw new AFSNotFoundError(`/${ctx.params.table}`);
|
|
625
|
+
const result = await this.crud.readRow(ctx.params.table, ctx.params.pk);
|
|
626
|
+
if (!result.data) throw new AFSNotFoundError(`/${ctx.params.table}/${ctx.params.pk}`);
|
|
627
|
+
const rowContent = result.data.content;
|
|
628
|
+
const pkColumn = schema.primaryKey[0] ?? "rowid";
|
|
629
|
+
const lines = [];
|
|
630
|
+
if (format === "markdown") {
|
|
631
|
+
lines.push(`# ${ctx.params.table}/${ctx.params.pk}`);
|
|
632
|
+
lines.push("");
|
|
633
|
+
lines.push(`**Table:** ${ctx.params.table}`);
|
|
634
|
+
lines.push(`**Primary Key:** ${pkColumn} = ${ctx.params.pk}`);
|
|
635
|
+
lines.push("");
|
|
636
|
+
if (rowContent) {
|
|
637
|
+
lines.push("## Values");
|
|
638
|
+
lines.push("");
|
|
639
|
+
lines.push("| Column | Value |");
|
|
640
|
+
lines.push("|--------|-------|");
|
|
641
|
+
for (const col of schema.columns) {
|
|
642
|
+
const val = rowContent[col.name];
|
|
643
|
+
const displayVal = val === null || val === void 0 ? "*null*" : truncateValue(String(val), 100);
|
|
644
|
+
lines.push(`| ${col.name} | ${displayVal} |`);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
} else {
|
|
648
|
+
lines.push(`${ctx.params.table}/${ctx.params.pk} (SQLite Row)`);
|
|
649
|
+
lines.push(`Table: ${ctx.params.table}, ${pkColumn} = ${ctx.params.pk}`);
|
|
650
|
+
if (rowContent) for (const col of schema.columns) {
|
|
651
|
+
const val = rowContent[col.name];
|
|
652
|
+
lines.push(` ${col.name}: ${val === null || val === void 0 ? "null" : truncateValue(String(val), 100)}`);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return {
|
|
656
|
+
content: lines.join("\n"),
|
|
657
|
+
format
|
|
658
|
+
};
|
|
157
659
|
}
|
|
158
660
|
/**
|
|
159
|
-
*
|
|
661
|
+
* Execute action via exec (row-level)
|
|
160
662
|
*/
|
|
161
|
-
async
|
|
663
|
+
async handleRowActionExec(ctx, args) {
|
|
162
664
|
await this.ensureInitialized();
|
|
163
|
-
|
|
164
|
-
if (match?.params.table) return this.ftsSearch.searchTable(match.params.table, query, options);
|
|
165
|
-
return this.ftsSearch.search(query, options);
|
|
665
|
+
return this.executeActionRaw(ctx.params.table, ctx.params.pk, ctx.params.action, args);
|
|
166
666
|
}
|
|
167
667
|
/**
|
|
168
|
-
*
|
|
668
|
+
* Execute action via exec (table-level)
|
|
169
669
|
*/
|
|
170
|
-
async
|
|
670
|
+
async handleTableActionExec(ctx, args) {
|
|
171
671
|
await this.ensureInitialized();
|
|
172
|
-
|
|
173
|
-
if (match?.action === "executeAction" && match.params.table && match.params.action) return { data: (await this.executeAction(match.params.table, match.params.pk, match.params.action, args)).data };
|
|
174
|
-
throw new Error(`Exec not supported for path: ${path}`);
|
|
672
|
+
return this.executeActionRaw(ctx.params.table, void 0, ctx.params.action, args);
|
|
175
673
|
}
|
|
176
674
|
/**
|
|
177
|
-
*
|
|
675
|
+
* Execute action via exec (root-level)
|
|
178
676
|
*/
|
|
179
|
-
|
|
180
|
-
|
|
677
|
+
async handleRootActionExec(ctx, args) {
|
|
678
|
+
await this.ensureInitialized();
|
|
679
|
+
return this.executeRootActionRaw(ctx.params.action, args);
|
|
181
680
|
}
|
|
182
681
|
/**
|
|
183
|
-
* Executes an action
|
|
682
|
+
* Executes an action and returns raw result (for exec handlers)
|
|
683
|
+
* Returns AFSExecResult structure: { success: boolean, data?: Record<string, unknown> }
|
|
184
684
|
*/
|
|
185
|
-
async
|
|
186
|
-
if (!this.
|
|
685
|
+
async executeActionRaw(table, pk, actionName, params) {
|
|
686
|
+
if (!await this.schemaService.getSchema(table)) throw new AFSNotFoundError(`/${table}`);
|
|
187
687
|
let row;
|
|
188
688
|
if (pk) row = (await this.crud.readRow(table, pk)).data?.content;
|
|
189
689
|
const ctx = {
|
|
190
690
|
db: this.db,
|
|
191
|
-
|
|
691
|
+
schemaService: this.schemaService,
|
|
192
692
|
table,
|
|
193
693
|
pk,
|
|
194
694
|
row,
|
|
195
|
-
module: {
|
|
196
|
-
refreshSchema: () => this.refreshSchema(),
|
|
197
|
-
exportTable: (t, f) => this.exportTable(t, f)
|
|
198
|
-
}
|
|
695
|
+
module: { exportTable: (t, f) => this.exportTable(t, f) }
|
|
199
696
|
};
|
|
200
697
|
const result = await this.actions.execute(actionName, ctx, params);
|
|
201
698
|
if (!result.success) throw new Error(result.message ?? "Action failed");
|
|
699
|
+
if (Array.isArray(result.data)) return {
|
|
700
|
+
success: true,
|
|
701
|
+
data: { data: result.data }
|
|
702
|
+
};
|
|
703
|
+
return {
|
|
704
|
+
success: true,
|
|
705
|
+
data: result.data
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Executes a root-level action and returns raw result (for exec handlers)
|
|
710
|
+
* Returns AFSExecResult structure: { success: boolean, data?: Record<string, unknown> }
|
|
711
|
+
*/
|
|
712
|
+
async executeRootActionRaw(actionName, params) {
|
|
713
|
+
const ctx = {
|
|
714
|
+
db: this.db,
|
|
715
|
+
schemaService: this.schemaService,
|
|
716
|
+
table: "",
|
|
717
|
+
module: { exportTable: (t, f) => this.exportTable(t, f) }
|
|
718
|
+
};
|
|
719
|
+
const result = await this.actions.execute(actionName, ctx, params);
|
|
720
|
+
if (!result.success) throw new Error(result.message ?? "Action failed");
|
|
721
|
+
if (Array.isArray(result.data)) return {
|
|
722
|
+
success: true,
|
|
723
|
+
data: { data: result.data }
|
|
724
|
+
};
|
|
725
|
+
return {
|
|
726
|
+
success: true,
|
|
727
|
+
data: result.data
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Executes an action (for write handlers - wraps in AFSEntry)
|
|
732
|
+
*/
|
|
733
|
+
async executeAction(table, pk, actionName, params) {
|
|
734
|
+
const result = await this.executeActionRaw(table, pk, actionName, params);
|
|
202
735
|
return { data: {
|
|
203
|
-
id: `${table}:${pk ?? ""}
|
|
204
|
-
path: pk ? `/${table}/${pk}
|
|
205
|
-
content: result
|
|
736
|
+
id: `${table}:${pk ?? ""}:.actions:${actionName}`,
|
|
737
|
+
path: pk ? `/${table}/${pk}/.actions/${actionName}` : `/${table}/.actions/${actionName}`,
|
|
738
|
+
content: result
|
|
206
739
|
} };
|
|
207
740
|
}
|
|
208
741
|
/**
|
|
209
|
-
*
|
|
742
|
+
* Executes a root-level action (for write handlers - wraps in AFSEntry)
|
|
210
743
|
*/
|
|
211
|
-
async
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
this.ftsSearch.setSchemas(this.schemas);
|
|
744
|
+
async executeRootAction(actionName, params) {
|
|
745
|
+
const result = await this.executeRootActionRaw(actionName, params);
|
|
746
|
+
return { data: {
|
|
747
|
+
id: `:.actions:${actionName}`,
|
|
748
|
+
path: `/.actions/${actionName}`,
|
|
749
|
+
content: result
|
|
750
|
+
} };
|
|
219
751
|
}
|
|
220
752
|
/**
|
|
221
753
|
* Exports table data in specified format
|
|
@@ -223,8 +755,8 @@ var SQLiteAFS = class SQLiteAFS {
|
|
|
223
755
|
async exportTable(table, format) {
|
|
224
756
|
const listResult = await this.crud.listTable(table, { limit: 1e4 });
|
|
225
757
|
if (format === "csv") {
|
|
226
|
-
const schema = this.
|
|
227
|
-
if (!schema) throw new
|
|
758
|
+
const schema = await this.schemaService.getSchema(table);
|
|
759
|
+
if (!schema) throw new AFSNotFoundError(`/${table}`);
|
|
228
760
|
return `${schema.columns.map((c) => c.name).join(",")}\n${listResult.data.map((entry) => {
|
|
229
761
|
const content = entry.content;
|
|
230
762
|
return schema.columns.map((c) => {
|
|
@@ -248,9 +780,11 @@ var SQLiteAFS = class SQLiteAFS {
|
|
|
248
780
|
}
|
|
249
781
|
/**
|
|
250
782
|
* Gets table schemas (for external access)
|
|
783
|
+
* Note: This queries the database on-demand
|
|
251
784
|
*/
|
|
252
|
-
getSchemas() {
|
|
253
|
-
|
|
785
|
+
async getSchemas() {
|
|
786
|
+
await this.ensureInitialized();
|
|
787
|
+
return this.schemaService.getAllSchemas();
|
|
254
788
|
}
|
|
255
789
|
/**
|
|
256
790
|
* Gets the database instance (for advanced operations)
|
|
@@ -259,6 +793,45 @@ var SQLiteAFS = class SQLiteAFS {
|
|
|
259
793
|
return this.db;
|
|
260
794
|
}
|
|
261
795
|
};
|
|
796
|
+
__decorate([List("/")], SQLiteAFS.prototype, "listTablesHandler", null);
|
|
797
|
+
__decorate([List("/:table")], SQLiteAFS.prototype, "listTableHandler", null);
|
|
798
|
+
__decorate([List("/:table/:pk")], SQLiteAFS.prototype, "listRowHandler", null);
|
|
799
|
+
__decorate([Actions("/:table/:pk")], SQLiteAFS.prototype, "listActionsHandler", null);
|
|
800
|
+
__decorate([Actions("/:table")], SQLiteAFS.prototype, "listTableActionsHandler", null);
|
|
801
|
+
__decorate([Actions("/")], SQLiteAFS.prototype, "listRootActionsHandler", null);
|
|
802
|
+
__decorate([Read("/")], SQLiteAFS.prototype, "readRootHandler", null);
|
|
803
|
+
__decorate([Meta("/")], SQLiteAFS.prototype, "readRootMetaHandler", null);
|
|
804
|
+
__decorate([Read("/.meta/.capabilities")], SQLiteAFS.prototype, "readCapabilitiesHandler", null);
|
|
805
|
+
__decorate([Read("/:table")], SQLiteAFS.prototype, "readTableHandler", null);
|
|
806
|
+
__decorate([Meta("/:table")], SQLiteAFS.prototype, "readTableMetaHandler", null);
|
|
807
|
+
__decorate([Read("/:table/:pk")], SQLiteAFS.prototype, "readRowHandler", null);
|
|
808
|
+
__decorate([Read("/:table/:pk/@meta")], SQLiteAFS.prototype, "getMetaHandler", null);
|
|
809
|
+
__decorate([Meta("/:table/:pk")], SQLiteAFS.prototype, "getRowDotMetaHandler", null);
|
|
810
|
+
__decorate([Write("/:table/new")], SQLiteAFS.prototype, "createRowHandler", null);
|
|
811
|
+
__decorate([Write("/:table/:pk")], SQLiteAFS.prototype, "updateRowHandler", null);
|
|
812
|
+
__decorate([Write("/:table/:pk/.actions/:action")], SQLiteAFS.prototype, "executeActionWriteHandler", null);
|
|
813
|
+
__decorate([Write("/:table/.actions/:action")], SQLiteAFS.prototype, "executeTableActionWriteHandler", null);
|
|
814
|
+
__decorate([Write("/.actions/:action")], SQLiteAFS.prototype, "executeRootActionWriteHandler", null);
|
|
815
|
+
__decorate([Delete("/:table")], SQLiteAFS.prototype, "deleteTableHandler", null);
|
|
816
|
+
__decorate([Delete("/:table/:pk")], SQLiteAFS.prototype, "deleteRowHandler", null);
|
|
817
|
+
__decorate([Search("/")], SQLiteAFS.prototype, "searchAllHandler", null);
|
|
818
|
+
__decorate([Search("/:table")], SQLiteAFS.prototype, "searchTableHandler", null);
|
|
819
|
+
__decorate([Stat("/")], SQLiteAFS.prototype, "statRootHandler", null);
|
|
820
|
+
__decorate([Stat("/:table")], SQLiteAFS.prototype, "statTableHandler", null);
|
|
821
|
+
__decorate([Stat("/:table/:pk")], SQLiteAFS.prototype, "statRowHandler", null);
|
|
822
|
+
__decorate([Explain("/")], SQLiteAFS.prototype, "explainRootHandler", null);
|
|
823
|
+
__decorate([Explain("/:table")], SQLiteAFS.prototype, "explainTableHandler", null);
|
|
824
|
+
__decorate([Explain("/:table/:pk")], SQLiteAFS.prototype, "explainRowHandler", null);
|
|
825
|
+
__decorate([Actions.Exec("/:table/:pk")], SQLiteAFS.prototype, "handleRowActionExec", null);
|
|
826
|
+
__decorate([Actions.Exec("/:table")], SQLiteAFS.prototype, "handleTableActionExec", null);
|
|
827
|
+
__decorate([Actions.Exec("/")], SQLiteAFS.prototype, "handleRootActionExec", null);
|
|
828
|
+
/**
|
|
829
|
+
* Truncate a string value for display purposes.
|
|
830
|
+
*/
|
|
831
|
+
function truncateValue(value, maxLength) {
|
|
832
|
+
if (value.length <= maxLength) return value;
|
|
833
|
+
return `${value.slice(0, maxLength)}...`;
|
|
834
|
+
}
|
|
262
835
|
|
|
263
836
|
//#endregion
|
|
264
837
|
export { SQLiteAFS };
|