@aigne/afs-sqlite 1.0.1-beta
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/CHANGELOG.md +29 -0
- package/LICENSE.md +93 -0
- package/README.md +277 -0
- package/lib/cjs/actions/built-in.d.ts +5 -0
- package/lib/cjs/actions/built-in.js +165 -0
- package/lib/cjs/actions/registry.d.ts +49 -0
- package/lib/cjs/actions/registry.js +102 -0
- package/lib/cjs/actions/types.d.ts +51 -0
- package/lib/cjs/actions/types.js +2 -0
- package/lib/cjs/config.d.ts +89 -0
- package/lib/cjs/config.js +33 -0
- package/lib/cjs/index.d.ts +13 -0
- package/lib/cjs/index.js +47 -0
- package/lib/cjs/node/builder.d.ts +43 -0
- package/lib/cjs/node/builder.js +187 -0
- package/lib/cjs/operations/crud.d.ts +64 -0
- package/lib/cjs/operations/crud.js +225 -0
- package/lib/cjs/operations/query-builder.d.ts +37 -0
- package/lib/cjs/operations/query-builder.js +102 -0
- package/lib/cjs/operations/search.d.ts +75 -0
- package/lib/cjs/operations/search.js +172 -0
- package/lib/cjs/package.json +3 -0
- package/lib/cjs/router/path-router.d.ts +38 -0
- package/lib/cjs/router/path-router.js +90 -0
- package/lib/cjs/router/types.d.ts +30 -0
- package/lib/cjs/router/types.js +2 -0
- package/lib/cjs/schema/introspector.d.ts +48 -0
- package/lib/cjs/schema/introspector.js +186 -0
- package/lib/cjs/schema/types.d.ts +104 -0
- package/lib/cjs/schema/types.js +13 -0
- package/lib/cjs/sqlite-afs.d.ts +144 -0
- package/lib/cjs/sqlite-afs.js +337 -0
- package/lib/dts/actions/built-in.d.ts +5 -0
- package/lib/dts/actions/registry.d.ts +49 -0
- package/lib/dts/actions/types.d.ts +51 -0
- package/lib/dts/config.d.ts +89 -0
- package/lib/dts/index.d.ts +13 -0
- package/lib/dts/node/builder.d.ts +43 -0
- package/lib/dts/operations/crud.d.ts +64 -0
- package/lib/dts/operations/query-builder.d.ts +37 -0
- package/lib/dts/operations/search.d.ts +75 -0
- package/lib/dts/router/path-router.d.ts +38 -0
- package/lib/dts/router/types.d.ts +30 -0
- package/lib/dts/schema/introspector.d.ts +48 -0
- package/lib/dts/schema/types.d.ts +104 -0
- package/lib/dts/sqlite-afs.d.ts +144 -0
- package/lib/esm/actions/built-in.d.ts +5 -0
- package/lib/esm/actions/built-in.js +162 -0
- package/lib/esm/actions/registry.d.ts +49 -0
- package/lib/esm/actions/registry.js +98 -0
- package/lib/esm/actions/types.d.ts +51 -0
- package/lib/esm/actions/types.js +1 -0
- package/lib/esm/config.d.ts +89 -0
- package/lib/esm/config.js +30 -0
- package/lib/esm/index.d.ts +13 -0
- package/lib/esm/index.js +17 -0
- package/lib/esm/node/builder.d.ts +43 -0
- package/lib/esm/node/builder.js +177 -0
- package/lib/esm/operations/crud.d.ts +64 -0
- package/lib/esm/operations/crud.js +221 -0
- package/lib/esm/operations/query-builder.d.ts +37 -0
- package/lib/esm/operations/query-builder.js +92 -0
- package/lib/esm/operations/search.d.ts +75 -0
- package/lib/esm/operations/search.js +167 -0
- package/lib/esm/package.json +3 -0
- package/lib/esm/router/path-router.d.ts +38 -0
- package/lib/esm/router/path-router.js +83 -0
- package/lib/esm/router/types.d.ts +30 -0
- package/lib/esm/router/types.js +1 -0
- package/lib/esm/schema/introspector.d.ts +48 -0
- package/lib/esm/schema/introspector.js +182 -0
- package/lib/esm/schema/types.d.ts +104 -0
- package/lib/esm/schema/types.js +10 -0
- package/lib/esm/sqlite-afs.d.ts +144 -0
- package/lib/esm/sqlite-afs.js +333 -0
- package/package.json +71 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createPathRouter = createPathRouter;
|
|
4
|
+
exports.matchPath = matchPath;
|
|
5
|
+
exports.buildPath = buildPath;
|
|
6
|
+
exports.isVirtualPath = isVirtualPath;
|
|
7
|
+
exports.getVirtualPathType = getVirtualPathType;
|
|
8
|
+
const radix3_1 = require("radix3");
|
|
9
|
+
/**
|
|
10
|
+
* Creates a radix3 router for SQLite AFS path routing
|
|
11
|
+
*
|
|
12
|
+
* Routes:
|
|
13
|
+
* - / → listTables
|
|
14
|
+
* - /:table → listTable
|
|
15
|
+
* - /:table/new → createRow
|
|
16
|
+
* - /:table/@schema → getSchema
|
|
17
|
+
* - /:table/:pk → readRow
|
|
18
|
+
* - /:table/:pk/@attr → listAttributes
|
|
19
|
+
* - /:table/:pk/@attr/:column → getAttribute
|
|
20
|
+
* - /:table/:pk/@meta → getMeta
|
|
21
|
+
* - /:table/:pk/@actions → listActions
|
|
22
|
+
* - /:table/:pk/@actions/:action → executeAction
|
|
23
|
+
*/
|
|
24
|
+
function createPathRouter() {
|
|
25
|
+
return (0, radix3_1.createRouter)({
|
|
26
|
+
routes: {
|
|
27
|
+
// Root - list all tables
|
|
28
|
+
"/": { action: "listTables" },
|
|
29
|
+
// Table-level routes
|
|
30
|
+
"/:table": { action: "listTable" },
|
|
31
|
+
"/:table/new": { action: "createRow" },
|
|
32
|
+
"/:table/@schema": { action: "getSchema" },
|
|
33
|
+
// Row-level routes
|
|
34
|
+
"/:table/:pk": { action: "readRow" },
|
|
35
|
+
"/:table/:pk/@attr": { action: "listAttributes" },
|
|
36
|
+
"/:table/:pk/@attr/:column": { action: "getAttribute" },
|
|
37
|
+
"/:table/:pk/@meta": { action: "getMeta" },
|
|
38
|
+
"/:table/:pk/@actions": { action: "listActions" },
|
|
39
|
+
"/:table/:pk/@actions/:action": { action: "executeAction" },
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Parses a path and returns the matched route with params
|
|
45
|
+
* @param router - The radix3 router instance
|
|
46
|
+
* @param path - The path to match
|
|
47
|
+
* @returns RouteMatch if matched, undefined otherwise
|
|
48
|
+
*/
|
|
49
|
+
function matchPath(router, path) {
|
|
50
|
+
const result = router.lookup(path);
|
|
51
|
+
if (!result)
|
|
52
|
+
return undefined;
|
|
53
|
+
return {
|
|
54
|
+
action: result.action,
|
|
55
|
+
params: (result.params ?? {}),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Builds a path from components
|
|
60
|
+
*/
|
|
61
|
+
function buildPath(table, pk, suffix) {
|
|
62
|
+
const parts = ["/"];
|
|
63
|
+
if (table)
|
|
64
|
+
parts.push(table);
|
|
65
|
+
if (pk)
|
|
66
|
+
parts.push(pk);
|
|
67
|
+
if (suffix)
|
|
68
|
+
parts.push(suffix);
|
|
69
|
+
return parts.join("/").replace(/\/+/g, "/");
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Checks if a path segment is a virtual path (@attr, @meta, @actions, @schema)
|
|
73
|
+
*/
|
|
74
|
+
function isVirtualPath(segment) {
|
|
75
|
+
return segment.startsWith("@");
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Gets the type of virtual path
|
|
79
|
+
*/
|
|
80
|
+
function getVirtualPathType(segment) {
|
|
81
|
+
if (segment === "@attr")
|
|
82
|
+
return "attr";
|
|
83
|
+
if (segment === "@meta")
|
|
84
|
+
return "meta";
|
|
85
|
+
if (segment === "@actions")
|
|
86
|
+
return "actions";
|
|
87
|
+
if (segment === "@schema")
|
|
88
|
+
return "schema";
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route action types for SQLite AFS
|
|
3
|
+
*/
|
|
4
|
+
export type RouteAction = "listTables" | "listTable" | "readRow" | "createRow" | "getSchema" | "listAttributes" | "getAttribute" | "getMeta" | "listActions" | "executeAction";
|
|
5
|
+
/**
|
|
6
|
+
* Route data associated with each path pattern
|
|
7
|
+
*/
|
|
8
|
+
export interface RouteData {
|
|
9
|
+
/** The action to perform for this route */
|
|
10
|
+
action: RouteAction;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Route match result with params
|
|
14
|
+
*/
|
|
15
|
+
export interface RouteMatch extends RouteData {
|
|
16
|
+
params: RouteParams;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Dynamic route parameters extracted from path
|
|
20
|
+
*/
|
|
21
|
+
export interface RouteParams {
|
|
22
|
+
/** Table name */
|
|
23
|
+
table?: string;
|
|
24
|
+
/** Primary key value */
|
|
25
|
+
pk?: string;
|
|
26
|
+
/** Column name for attribute access */
|
|
27
|
+
column?: string;
|
|
28
|
+
/** Action name for @actions */
|
|
29
|
+
action?: string;
|
|
30
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { LibSQLDatabase } from "drizzle-orm/libsql";
|
|
2
|
+
import { type TableSchema } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Schema introspector that uses SQLite PRAGMA queries to discover database schema
|
|
5
|
+
*/
|
|
6
|
+
export declare class SchemaIntrospector {
|
|
7
|
+
/**
|
|
8
|
+
* Introspects all tables in the database
|
|
9
|
+
* @param db - Drizzle database instance
|
|
10
|
+
* @param options - Introspection options
|
|
11
|
+
* @returns Map of table name to TableSchema
|
|
12
|
+
*/
|
|
13
|
+
introspect(db: LibSQLDatabase, options?: {
|
|
14
|
+
/** Whitelist of tables to include */
|
|
15
|
+
tables?: string[];
|
|
16
|
+
/** Tables to exclude */
|
|
17
|
+
excludeTables?: string[];
|
|
18
|
+
}): Promise<Map<string, TableSchema>>;
|
|
19
|
+
/**
|
|
20
|
+
* Introspects a single table
|
|
21
|
+
* @param db - Drizzle database instance
|
|
22
|
+
* @param tableName - Name of the table to introspect
|
|
23
|
+
* @returns TableSchema for the specified table
|
|
24
|
+
*/
|
|
25
|
+
introspectTable(db: LibSQLDatabase, tableName: string): Promise<TableSchema>;
|
|
26
|
+
/**
|
|
27
|
+
* Gets the primary key column name for a table
|
|
28
|
+
* Returns the first PK column, or 'rowid' if no explicit PK
|
|
29
|
+
*/
|
|
30
|
+
getPrimaryKeyColumn(schema: TableSchema): string;
|
|
31
|
+
/**
|
|
32
|
+
* Checks if a table has FTS (Full-Text Search) enabled
|
|
33
|
+
*/
|
|
34
|
+
hasFTS(db: LibSQLDatabase, tableName: string): Promise<boolean>;
|
|
35
|
+
/**
|
|
36
|
+
* Creates FTS5 table for full-text search on specified columns
|
|
37
|
+
*/
|
|
38
|
+
createFTS(db: LibSQLDatabase, tableName: string, columns: string[], options?: {
|
|
39
|
+
/** Content table (defaults to tableName) */
|
|
40
|
+
contentTable?: string;
|
|
41
|
+
/** Content rowid column (defaults to 'rowid') */
|
|
42
|
+
contentRowid?: string;
|
|
43
|
+
}): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Rebuilds FTS index for a table (useful after bulk inserts)
|
|
46
|
+
*/
|
|
47
|
+
rebuildFTS(db: LibSQLDatabase, tableName: string): Promise<void>;
|
|
48
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SchemaIntrospector = void 0;
|
|
4
|
+
const sqlite_1 = require("@aigne/sqlite");
|
|
5
|
+
const types_js_1 = require("./types.js");
|
|
6
|
+
/**
|
|
7
|
+
* Executes a raw SQL query and returns all rows
|
|
8
|
+
*/
|
|
9
|
+
async function execAll(db, query) {
|
|
10
|
+
return db.all(sqlite_1.sql.raw(query)).execute();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Executes a raw SQL query (for INSERT, UPDATE, DELETE)
|
|
14
|
+
*/
|
|
15
|
+
async function execRun(db, query) {
|
|
16
|
+
await db.run(sqlite_1.sql.raw(query)).execute();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Maps raw PRAGMA table_info row to ColumnInfo
|
|
20
|
+
*/
|
|
21
|
+
function mapColumn(row) {
|
|
22
|
+
return {
|
|
23
|
+
name: row.name,
|
|
24
|
+
type: row.type,
|
|
25
|
+
notnull: row.notnull === 1,
|
|
26
|
+
pk: row.pk,
|
|
27
|
+
dfltValue: row.dflt_value,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Maps raw PRAGMA foreign_key_list row to ForeignKeyInfo
|
|
32
|
+
*/
|
|
33
|
+
function mapForeignKey(row) {
|
|
34
|
+
return {
|
|
35
|
+
id: row.id,
|
|
36
|
+
seq: row.seq,
|
|
37
|
+
table: row.table,
|
|
38
|
+
from: row.from,
|
|
39
|
+
to: row.to,
|
|
40
|
+
onUpdate: row.on_update,
|
|
41
|
+
onDelete: row.on_delete,
|
|
42
|
+
match: row.match,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Maps raw PRAGMA index_list row to IndexInfo
|
|
47
|
+
*/
|
|
48
|
+
function mapIndex(row) {
|
|
49
|
+
return {
|
|
50
|
+
seq: row.seq,
|
|
51
|
+
name: row.name,
|
|
52
|
+
unique: row.unique === 1,
|
|
53
|
+
origin: row.origin,
|
|
54
|
+
partial: row.partial === 1,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Schema introspector that uses SQLite PRAGMA queries to discover database schema
|
|
59
|
+
*/
|
|
60
|
+
class SchemaIntrospector {
|
|
61
|
+
/**
|
|
62
|
+
* Introspects all tables in the database
|
|
63
|
+
* @param db - Drizzle database instance
|
|
64
|
+
* @param options - Introspection options
|
|
65
|
+
* @returns Map of table name to TableSchema
|
|
66
|
+
*/
|
|
67
|
+
async introspect(db, options) {
|
|
68
|
+
const schemas = new Map();
|
|
69
|
+
// Get all user tables (exclude system tables and FTS tables)
|
|
70
|
+
const tablesResult = await execAll(db, `
|
|
71
|
+
SELECT name FROM sqlite_master
|
|
72
|
+
WHERE type = 'table'
|
|
73
|
+
AND name NOT LIKE 'sqlite_%'
|
|
74
|
+
AND name NOT LIKE '%_fts%'
|
|
75
|
+
ORDER BY name
|
|
76
|
+
`);
|
|
77
|
+
for (const { name } of tablesResult) {
|
|
78
|
+
// Skip system tables
|
|
79
|
+
if (types_js_1.SYSTEM_TABLES.includes(name)) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
// Apply whitelist filter
|
|
83
|
+
if (options?.tables && !options.tables.includes(name)) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
// Apply exclude filter
|
|
87
|
+
if (options?.excludeTables?.includes(name)) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const schema = await this.introspectTable(db, name);
|
|
91
|
+
schemas.set(name, schema);
|
|
92
|
+
}
|
|
93
|
+
return schemas;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Introspects a single table
|
|
97
|
+
* @param db - Drizzle database instance
|
|
98
|
+
* @param tableName - Name of the table to introspect
|
|
99
|
+
* @returns TableSchema for the specified table
|
|
100
|
+
*/
|
|
101
|
+
async introspectTable(db, tableName) {
|
|
102
|
+
// Get column information
|
|
103
|
+
const columnsResult = await execAll(db, `PRAGMA table_info("${tableName}")`);
|
|
104
|
+
const columns = columnsResult.map(mapColumn);
|
|
105
|
+
// Get primary key columns (pk > 0 indicates part of primary key)
|
|
106
|
+
const primaryKey = columns.filter((c) => c.pk > 0).map((c) => c.name);
|
|
107
|
+
// Get foreign keys
|
|
108
|
+
const fksResult = await execAll(db, `PRAGMA foreign_key_list("${tableName}")`);
|
|
109
|
+
const foreignKeys = fksResult.map(mapForeignKey);
|
|
110
|
+
// Get indexes
|
|
111
|
+
const indexesResult = await execAll(db, `PRAGMA index_list("${tableName}")`);
|
|
112
|
+
const indexes = indexesResult.map(mapIndex);
|
|
113
|
+
return {
|
|
114
|
+
name: tableName,
|
|
115
|
+
columns,
|
|
116
|
+
primaryKey,
|
|
117
|
+
foreignKeys,
|
|
118
|
+
indexes,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Gets the primary key column name for a table
|
|
123
|
+
* Returns the first PK column, or 'rowid' if no explicit PK
|
|
124
|
+
*/
|
|
125
|
+
getPrimaryKeyColumn(schema) {
|
|
126
|
+
if (schema.primaryKey.length > 0 && schema.primaryKey[0]) {
|
|
127
|
+
return schema.primaryKey[0];
|
|
128
|
+
}
|
|
129
|
+
// SQLite tables without explicit PK use rowid
|
|
130
|
+
return "rowid";
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Checks if a table has FTS (Full-Text Search) enabled
|
|
134
|
+
*/
|
|
135
|
+
async hasFTS(db, tableName) {
|
|
136
|
+
const ftsTableName = `${tableName}_fts`;
|
|
137
|
+
const result = await execAll(db, `
|
|
138
|
+
SELECT name FROM sqlite_master
|
|
139
|
+
WHERE type = 'table'
|
|
140
|
+
AND name = '${ftsTableName}'
|
|
141
|
+
`);
|
|
142
|
+
return result.length > 0;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Creates FTS5 table for full-text search on specified columns
|
|
146
|
+
*/
|
|
147
|
+
async createFTS(db, tableName, columns, options) {
|
|
148
|
+
const ftsTableName = `${tableName}_fts`;
|
|
149
|
+
const contentTable = options?.contentTable ?? tableName;
|
|
150
|
+
const contentRowid = options?.contentRowid ?? "rowid";
|
|
151
|
+
const columnList = columns.join(", ");
|
|
152
|
+
// Create FTS5 virtual table
|
|
153
|
+
await execRun(db, `
|
|
154
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS "${ftsTableName}" USING fts5(
|
|
155
|
+
${columnList},
|
|
156
|
+
content="${contentTable}",
|
|
157
|
+
content_rowid="${contentRowid}"
|
|
158
|
+
)
|
|
159
|
+
`);
|
|
160
|
+
// Create triggers to keep FTS in sync
|
|
161
|
+
await execRun(db, `
|
|
162
|
+
CREATE TRIGGER IF NOT EXISTS "${tableName}_ai" AFTER INSERT ON "${tableName}" BEGIN
|
|
163
|
+
INSERT INTO "${ftsTableName}"(rowid, ${columnList}) VALUES (new.${contentRowid}, ${columns.map((c) => `new."${c}"`).join(", ")});
|
|
164
|
+
END
|
|
165
|
+
`);
|
|
166
|
+
await execRun(db, `
|
|
167
|
+
CREATE TRIGGER IF NOT EXISTS "${tableName}_ad" AFTER DELETE ON "${tableName}" BEGIN
|
|
168
|
+
INSERT INTO "${ftsTableName}"("${ftsTableName}", rowid, ${columnList}) VALUES ('delete', old.${contentRowid}, ${columns.map((c) => `old."${c}"`).join(", ")});
|
|
169
|
+
END
|
|
170
|
+
`);
|
|
171
|
+
await execRun(db, `
|
|
172
|
+
CREATE TRIGGER IF NOT EXISTS "${tableName}_au" AFTER UPDATE ON "${tableName}" BEGIN
|
|
173
|
+
INSERT INTO "${ftsTableName}"("${ftsTableName}", rowid, ${columnList}) VALUES ('delete', old.${contentRowid}, ${columns.map((c) => `old."${c}"`).join(", ")});
|
|
174
|
+
INSERT INTO "${ftsTableName}"(rowid, ${columnList}) VALUES (new.${contentRowid}, ${columns.map((c) => `new."${c}"`).join(", ")});
|
|
175
|
+
END
|
|
176
|
+
`);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Rebuilds FTS index for a table (useful after bulk inserts)
|
|
180
|
+
*/
|
|
181
|
+
async rebuildFTS(db, tableName) {
|
|
182
|
+
const ftsTableName = `${tableName}_fts`;
|
|
183
|
+
await execRun(db, `INSERT INTO "${ftsTableName}"("${ftsTableName}") VALUES ('rebuild')`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
exports.SchemaIntrospector = SchemaIntrospector;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Column information from SQLite PRAGMA table_info
|
|
3
|
+
*/
|
|
4
|
+
export interface ColumnInfo {
|
|
5
|
+
/** Column name */
|
|
6
|
+
name: string;
|
|
7
|
+
/** SQLite type (INTEGER, TEXT, REAL, BLOB, etc.) */
|
|
8
|
+
type: string;
|
|
9
|
+
/** Whether the column has NOT NULL constraint */
|
|
10
|
+
notnull: boolean;
|
|
11
|
+
/** Whether this column is part of the primary key */
|
|
12
|
+
pk: number;
|
|
13
|
+
/** Default value for the column */
|
|
14
|
+
dfltValue: unknown;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Foreign key information from SQLite PRAGMA foreign_key_list
|
|
18
|
+
*/
|
|
19
|
+
export interface ForeignKeyInfo {
|
|
20
|
+
/** Foreign key id */
|
|
21
|
+
id: number;
|
|
22
|
+
/** Sequence number for composite foreign keys */
|
|
23
|
+
seq: number;
|
|
24
|
+
/** Referenced table */
|
|
25
|
+
table: string;
|
|
26
|
+
/** Column in this table */
|
|
27
|
+
from: string;
|
|
28
|
+
/** Column in referenced table */
|
|
29
|
+
to: string;
|
|
30
|
+
/** ON UPDATE action */
|
|
31
|
+
onUpdate: string;
|
|
32
|
+
/** ON DELETE action */
|
|
33
|
+
onDelete: string;
|
|
34
|
+
/** MATCH clause */
|
|
35
|
+
match: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Index information from SQLite PRAGMA index_list
|
|
39
|
+
*/
|
|
40
|
+
export interface IndexInfo {
|
|
41
|
+
/** Index sequence number */
|
|
42
|
+
seq: number;
|
|
43
|
+
/** Index name */
|
|
44
|
+
name: string;
|
|
45
|
+
/** Whether this is a unique index */
|
|
46
|
+
unique: boolean;
|
|
47
|
+
/** Origin of the index (c = CREATE INDEX, u = UNIQUE constraint, pk = PRIMARY KEY) */
|
|
48
|
+
origin: string;
|
|
49
|
+
/** Whether the index is partial */
|
|
50
|
+
partial: boolean;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Complete schema information for a single table
|
|
54
|
+
*/
|
|
55
|
+
export interface TableSchema {
|
|
56
|
+
/** Table name */
|
|
57
|
+
name: string;
|
|
58
|
+
/** Column definitions */
|
|
59
|
+
columns: ColumnInfo[];
|
|
60
|
+
/** Primary key column names */
|
|
61
|
+
primaryKey: string[];
|
|
62
|
+
/** Foreign key relationships */
|
|
63
|
+
foreignKeys: ForeignKeyInfo[];
|
|
64
|
+
/** Indexes on this table */
|
|
65
|
+
indexes: IndexInfo[];
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Raw PRAGMA table_info result row
|
|
69
|
+
*/
|
|
70
|
+
export interface PragmaTableInfoRow {
|
|
71
|
+
cid: number;
|
|
72
|
+
name: string;
|
|
73
|
+
type: string;
|
|
74
|
+
notnull: number;
|
|
75
|
+
dflt_value: unknown;
|
|
76
|
+
pk: number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Raw PRAGMA foreign_key_list result row
|
|
80
|
+
*/
|
|
81
|
+
export interface PragmaForeignKeyRow {
|
|
82
|
+
id: number;
|
|
83
|
+
seq: number;
|
|
84
|
+
table: string;
|
|
85
|
+
from: string;
|
|
86
|
+
to: string;
|
|
87
|
+
on_update: string;
|
|
88
|
+
on_delete: string;
|
|
89
|
+
match: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Raw PRAGMA index_list result row
|
|
93
|
+
*/
|
|
94
|
+
export interface PragmaIndexListRow {
|
|
95
|
+
seq: number;
|
|
96
|
+
name: string;
|
|
97
|
+
unique: number;
|
|
98
|
+
origin: string;
|
|
99
|
+
partial: number;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* System tables that should be excluded from introspection
|
|
103
|
+
*/
|
|
104
|
+
export declare const SYSTEM_TABLES: readonly ["sqlite_sequence", "sqlite_stat1", "sqlite_stat2", "sqlite_stat3", "sqlite_stat4"];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SYSTEM_TABLES = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* System tables that should be excluded from introspection
|
|
6
|
+
*/
|
|
7
|
+
exports.SYSTEM_TABLES = [
|
|
8
|
+
"sqlite_sequence",
|
|
9
|
+
"sqlite_stat1",
|
|
10
|
+
"sqlite_stat2",
|
|
11
|
+
"sqlite_stat3",
|
|
12
|
+
"sqlite_stat4",
|
|
13
|
+
];
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { AFSAccessMode, AFSDeleteOptions, AFSDeleteResult, AFSExecOptions, AFSExecResult, AFSListOptions, AFSListResult, AFSModule, AFSModuleLoadParams, AFSReadOptions, AFSReadResult, AFSRoot, AFSSearchOptions, AFSSearchResult, AFSWriteEntryPayload, AFSWriteOptions, AFSWriteResult } from "@aigne/afs";
|
|
2
|
+
import type { LibSQLDatabase } from "drizzle-orm/libsql";
|
|
3
|
+
import type { ActionContext } from "./actions/types.js";
|
|
4
|
+
import { type SQLiteAFSOptions } from "./config.js";
|
|
5
|
+
import type { TableSchema } from "./schema/types.js";
|
|
6
|
+
/**
|
|
7
|
+
* SQLite AFS Module
|
|
8
|
+
*
|
|
9
|
+
* Exposes SQLite databases as AFS nodes with full CRUD support,
|
|
10
|
+
* schema introspection, FTS5 search, and virtual paths (@attr, @meta, @actions).
|
|
11
|
+
*/
|
|
12
|
+
export declare class SQLiteAFS implements AFSModule {
|
|
13
|
+
private options;
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly description: string;
|
|
16
|
+
readonly accessMode: AFSAccessMode;
|
|
17
|
+
private db;
|
|
18
|
+
private schemas;
|
|
19
|
+
private router;
|
|
20
|
+
private crud;
|
|
21
|
+
private ftsSearch;
|
|
22
|
+
private actions;
|
|
23
|
+
private ftsConfig;
|
|
24
|
+
private initialized;
|
|
25
|
+
constructor(options: SQLiteAFSOptions);
|
|
26
|
+
/**
|
|
27
|
+
* Returns the Zod schema for configuration validation
|
|
28
|
+
*/
|
|
29
|
+
static schema(): import("zod").ZodObject<{
|
|
30
|
+
url: import("zod").ZodString;
|
|
31
|
+
name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
32
|
+
description: import("zod").ZodOptional<import("zod").ZodString>;
|
|
33
|
+
accessMode: import("zod").ZodOptional<import("zod").ZodEnum<["readonly", "readwrite"]>>;
|
|
34
|
+
tables: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
35
|
+
excludeTables: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString, "many">>;
|
|
36
|
+
fts: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
37
|
+
enabled: import("zod").ZodDefault<import("zod").ZodBoolean>;
|
|
38
|
+
tables: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodArray<import("zod").ZodString, "many">>>;
|
|
39
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
40
|
+
enabled: boolean;
|
|
41
|
+
tables?: Record<string, string[]> | undefined;
|
|
42
|
+
}, {
|
|
43
|
+
enabled?: boolean | undefined;
|
|
44
|
+
tables?: Record<string, string[]> | undefined;
|
|
45
|
+
}>>;
|
|
46
|
+
wal: import("zod").ZodDefault<import("zod").ZodOptional<import("zod").ZodBoolean>>;
|
|
47
|
+
}, "strip", import("zod").ZodTypeAny, {
|
|
48
|
+
url: string;
|
|
49
|
+
wal: boolean;
|
|
50
|
+
tables?: string[] | undefined;
|
|
51
|
+
name?: string | undefined;
|
|
52
|
+
description?: string | undefined;
|
|
53
|
+
accessMode?: "readonly" | "readwrite" | undefined;
|
|
54
|
+
excludeTables?: string[] | undefined;
|
|
55
|
+
fts?: {
|
|
56
|
+
enabled: boolean;
|
|
57
|
+
tables?: Record<string, string[]> | undefined;
|
|
58
|
+
} | undefined;
|
|
59
|
+
}, {
|
|
60
|
+
url: string;
|
|
61
|
+
tables?: string[] | undefined;
|
|
62
|
+
name?: string | undefined;
|
|
63
|
+
description?: string | undefined;
|
|
64
|
+
accessMode?: "readonly" | "readwrite" | undefined;
|
|
65
|
+
excludeTables?: string[] | undefined;
|
|
66
|
+
fts?: {
|
|
67
|
+
enabled?: boolean | undefined;
|
|
68
|
+
tables?: Record<string, string[]> | undefined;
|
|
69
|
+
} | undefined;
|
|
70
|
+
wal?: boolean | undefined;
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Loads a module instance from configuration
|
|
74
|
+
*/
|
|
75
|
+
static load({ parsed }: AFSModuleLoadParams): Promise<SQLiteAFS>;
|
|
76
|
+
/**
|
|
77
|
+
* Called when the module is mounted to AFS
|
|
78
|
+
*/
|
|
79
|
+
onMount(_afs: AFSRoot): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Initializes the database connection and introspects schema
|
|
82
|
+
*/
|
|
83
|
+
private initialize;
|
|
84
|
+
/**
|
|
85
|
+
* Ensures the module is initialized
|
|
86
|
+
*/
|
|
87
|
+
private ensureInitialized;
|
|
88
|
+
/**
|
|
89
|
+
* Lists entries at a path
|
|
90
|
+
*/
|
|
91
|
+
list(path: string, options?: AFSListOptions): Promise<AFSListResult>;
|
|
92
|
+
/**
|
|
93
|
+
* Reads an entry at a path
|
|
94
|
+
*/
|
|
95
|
+
read(path: string, _options?: AFSReadOptions): Promise<AFSReadResult>;
|
|
96
|
+
/**
|
|
97
|
+
* Writes an entry at a path
|
|
98
|
+
*/
|
|
99
|
+
write(path: string, content: AFSWriteEntryPayload, _options?: AFSWriteOptions): Promise<AFSWriteResult>;
|
|
100
|
+
/**
|
|
101
|
+
* Deletes an entry at a path
|
|
102
|
+
*/
|
|
103
|
+
delete(path: string, _options?: AFSDeleteOptions): Promise<AFSDeleteResult>;
|
|
104
|
+
/**
|
|
105
|
+
* Searches for entries matching a query
|
|
106
|
+
*/
|
|
107
|
+
search(path: string, query: string, options?: AFSSearchOptions): Promise<AFSSearchResult>;
|
|
108
|
+
/**
|
|
109
|
+
* Executes a module operation
|
|
110
|
+
*/
|
|
111
|
+
exec(path: string, args: Record<string, unknown>, _options: AFSExecOptions): Promise<AFSExecResult>;
|
|
112
|
+
/**
|
|
113
|
+
* Lists available actions for a row
|
|
114
|
+
*/
|
|
115
|
+
private listActions;
|
|
116
|
+
/**
|
|
117
|
+
* Executes an action
|
|
118
|
+
*/
|
|
119
|
+
private executeAction;
|
|
120
|
+
/**
|
|
121
|
+
* Refreshes the schema cache
|
|
122
|
+
*/
|
|
123
|
+
refreshSchema(): Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* Exports table data in specified format
|
|
126
|
+
*/
|
|
127
|
+
exportTable(table: string, format: string): Promise<unknown>;
|
|
128
|
+
/**
|
|
129
|
+
* Registers a custom action
|
|
130
|
+
*/
|
|
131
|
+
registerAction(name: string, handler: (ctx: ActionContext, params: Record<string, unknown>) => Promise<unknown>, options?: {
|
|
132
|
+
description?: string;
|
|
133
|
+
tableLevel?: boolean;
|
|
134
|
+
rowLevel?: boolean;
|
|
135
|
+
}): void;
|
|
136
|
+
/**
|
|
137
|
+
* Gets table schemas (for external access)
|
|
138
|
+
*/
|
|
139
|
+
getSchemas(): Map<string, TableSchema>;
|
|
140
|
+
/**
|
|
141
|
+
* Gets the database instance (for advanced operations)
|
|
142
|
+
*/
|
|
143
|
+
getDatabase(): LibSQLDatabase;
|
|
144
|
+
}
|