@aigne/afs-sqlite 1.11.0-beta → 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/LICENSE.md +17 -84
- package/README.md +3 -6
- 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 +1389 -0
- package/dist/actions/built-in.d.cts +10 -0
- package/dist/actions/built-in.d.cts.map +1 -0
- package/dist/actions/built-in.d.mts +10 -0
- package/dist/actions/built-in.d.mts.map +1 -0
- package/dist/actions/built-in.mjs +1390 -0
- package/dist/actions/built-in.mjs.map +1 -0
- 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 +123 -0
- package/dist/actions/registry.d.cts +73 -0
- package/dist/actions/registry.d.cts.map +1 -0
- package/dist/actions/registry.d.mts +73 -0
- package/dist/actions/registry.d.mts.map +1 -0
- package/dist/actions/registry.mjs +123 -0
- package/dist/actions/registry.mjs.map +1 -0
- package/dist/actions/types.cjs +33 -0
- package/dist/actions/types.d.cts +97 -0
- package/dist/actions/types.d.cts.map +1 -0
- package/dist/actions/types.d.mts +97 -0
- package/dist/actions/types.d.mts.map +1 -0
- package/dist/actions/types.mjs +32 -0
- package/dist/actions/types.mjs.map +1 -0
- package/dist/config.cjs +27 -0
- package/dist/config.d.cts +54 -0
- package/dist/config.d.cts.map +1 -0
- package/dist/config.d.mts +54 -0
- package/dist/config.d.mts.map +1 -0
- package/dist/config.mjs +28 -0
- package/dist/config.mjs.map +1 -0
- package/dist/index.cjs +39 -1324
- package/dist/index.d.cts +15 -758
- package/dist/index.d.mts +15 -758
- package/dist/index.mjs +13 -1299
- package/dist/node/builder.cjs +162 -0
- package/dist/node/builder.d.cts +44 -0
- package/dist/node/builder.d.cts.map +1 -0
- package/dist/node/builder.d.mts +44 -0
- package/dist/node/builder.d.mts.map +1 -0
- package/dist/node/builder.mjs +155 -0
- package/dist/node/builder.mjs.map +1 -0
- package/dist/operations/crud.cjs +132 -0
- package/dist/operations/crud.d.cts +54 -0
- package/dist/operations/crud.d.cts.map +1 -0
- package/dist/operations/crud.d.mts +54 -0
- package/dist/operations/crud.d.mts.map +1 -0
- package/dist/operations/crud.mjs +133 -0
- package/dist/operations/crud.mjs.map +1 -0
- package/dist/operations/query-builder.cjs +77 -0
- package/dist/operations/query-builder.d.cts +34 -0
- package/dist/operations/query-builder.d.cts.map +1 -0
- package/dist/operations/query-builder.d.mts +34 -0
- package/dist/operations/query-builder.d.mts.map +1 -0
- package/dist/operations/query-builder.mjs +72 -0
- package/dist/operations/query-builder.mjs.map +1 -0
- package/dist/operations/search.cjs +135 -0
- package/dist/operations/search.d.cts +75 -0
- package/dist/operations/search.d.cts.map +1 -0
- package/dist/operations/search.d.mts +75 -0
- package/dist/operations/search.d.mts.map +1 -0
- package/dist/operations/search.mjs +135 -0
- package/dist/operations/search.mjs.map +1 -0
- package/dist/router/path-router.cjs +71 -0
- package/dist/router/path-router.d.cts +39 -0
- package/dist/router/path-router.d.cts.map +1 -0
- package/dist/router/path-router.d.mts +39 -0
- package/dist/router/path-router.d.mts.map +1 -0
- package/dist/router/path-router.mjs +68 -0
- package/dist/router/path-router.mjs.map +1 -0
- package/dist/router/types.d.cts +34 -0
- package/dist/router/types.d.cts.map +1 -0
- package/dist/router/types.d.mts +34 -0
- package/dist/router/types.d.mts.map +1 -0
- package/dist/schema/introspector.cjs +160 -0
- package/dist/schema/introspector.d.cts +49 -0
- package/dist/schema/introspector.d.cts.map +1 -0
- package/dist/schema/introspector.d.mts +49 -0
- package/dist/schema/introspector.d.mts.map +1 -0
- package/dist/schema/introspector.mjs +161 -0
- package/dist/schema/introspector.mjs.map +1 -0
- 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.cjs +15 -0
- package/dist/schema/types.d.cts +104 -0
- package/dist/schema/types.d.cts.map +1 -0
- package/dist/schema/types.d.mts +104 -0
- package/dist/schema/types.d.mts.map +1 -0
- package/dist/schema/types.mjs +15 -0
- package/dist/schema/types.mjs.map +1 -0
- package/dist/sqlite-afs.cjs +836 -0
- package/dist/sqlite-afs.d.cts +330 -0
- package/dist/sqlite-afs.d.cts.map +1 -0
- package/dist/sqlite-afs.d.mts +330 -0
- package/dist/sqlite-afs.d.mts.map +1 -0
- package/dist/sqlite-afs.mjs +838 -0
- package/dist/sqlite-afs.mjs.map +1 -0
- package/package.json +6 -5
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
const require_types = require('./types.cjs');
|
|
2
|
+
let _aigne_sqlite = require("@aigne/sqlite");
|
|
3
|
+
|
|
4
|
+
//#region src/schema/introspector.ts
|
|
5
|
+
/**
|
|
6
|
+
* Executes a raw SQL query and returns all rows
|
|
7
|
+
*/
|
|
8
|
+
async function execAll(db, query) {
|
|
9
|
+
return db.all(_aigne_sqlite.sql.raw(query)).execute();
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Executes a raw SQL query (for INSERT, UPDATE, DELETE)
|
|
13
|
+
*/
|
|
14
|
+
async function execRun(db, query) {
|
|
15
|
+
await db.run(_aigne_sqlite.sql.raw(query)).execute();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Maps raw PRAGMA table_info row to ColumnInfo
|
|
19
|
+
*/
|
|
20
|
+
function mapColumn(row) {
|
|
21
|
+
return {
|
|
22
|
+
name: row.name,
|
|
23
|
+
type: row.type,
|
|
24
|
+
notnull: row.notnull === 1,
|
|
25
|
+
pk: row.pk,
|
|
26
|
+
dfltValue: row.dflt_value
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Maps raw PRAGMA foreign_key_list row to ForeignKeyInfo
|
|
31
|
+
*/
|
|
32
|
+
function mapForeignKey(row) {
|
|
33
|
+
return {
|
|
34
|
+
id: row.id,
|
|
35
|
+
seq: row.seq,
|
|
36
|
+
table: row.table,
|
|
37
|
+
from: row.from,
|
|
38
|
+
to: row.to,
|
|
39
|
+
onUpdate: row.on_update,
|
|
40
|
+
onDelete: row.on_delete,
|
|
41
|
+
match: row.match
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Maps raw PRAGMA index_list row to IndexInfo
|
|
46
|
+
*/
|
|
47
|
+
function mapIndex(row) {
|
|
48
|
+
return {
|
|
49
|
+
seq: row.seq,
|
|
50
|
+
name: row.name,
|
|
51
|
+
unique: row.unique === 1,
|
|
52
|
+
origin: row.origin,
|
|
53
|
+
partial: row.partial === 1
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Schema introspector that uses SQLite PRAGMA queries to discover database schema
|
|
58
|
+
*/
|
|
59
|
+
var SchemaIntrospector = class {
|
|
60
|
+
/**
|
|
61
|
+
* Introspects all tables in the database
|
|
62
|
+
* @param db - Drizzle database instance
|
|
63
|
+
* @param options - Introspection options
|
|
64
|
+
* @returns Map of table name to TableSchema
|
|
65
|
+
*/
|
|
66
|
+
async introspect(db, options) {
|
|
67
|
+
const schemas = /* @__PURE__ */ new Map();
|
|
68
|
+
const tablesResult = await execAll(db, `
|
|
69
|
+
SELECT name FROM sqlite_master
|
|
70
|
+
WHERE type = 'table'
|
|
71
|
+
AND name NOT LIKE 'sqlite_%'
|
|
72
|
+
AND name NOT LIKE '%_fts%'
|
|
73
|
+
ORDER BY name
|
|
74
|
+
`);
|
|
75
|
+
for (const { name } of tablesResult) {
|
|
76
|
+
if (require_types.SYSTEM_TABLES.includes(name)) continue;
|
|
77
|
+
if (options?.tables && !options.tables.includes(name)) continue;
|
|
78
|
+
if (options?.excludeTables?.includes(name)) continue;
|
|
79
|
+
const schema = await this.introspectTable(db, name);
|
|
80
|
+
schemas.set(name, schema);
|
|
81
|
+
}
|
|
82
|
+
return schemas;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Introspects a single table
|
|
86
|
+
* @param db - Drizzle database instance
|
|
87
|
+
* @param tableName - Name of the table to introspect
|
|
88
|
+
* @returns TableSchema for the specified table
|
|
89
|
+
*/
|
|
90
|
+
async introspectTable(db, tableName) {
|
|
91
|
+
const columns = (await execAll(db, `PRAGMA table_info("${tableName}")`)).map(mapColumn);
|
|
92
|
+
return {
|
|
93
|
+
name: tableName,
|
|
94
|
+
columns,
|
|
95
|
+
primaryKey: columns.filter((c) => c.pk > 0).map((c) => c.name),
|
|
96
|
+
foreignKeys: (await execAll(db, `PRAGMA foreign_key_list("${tableName}")`)).map(mapForeignKey),
|
|
97
|
+
indexes: (await execAll(db, `PRAGMA index_list("${tableName}")`)).map(mapIndex)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Gets the primary key column name for a table
|
|
102
|
+
* Returns the first PK column, or 'rowid' if no explicit PK
|
|
103
|
+
*/
|
|
104
|
+
getPrimaryKeyColumn(schema) {
|
|
105
|
+
if (schema.primaryKey.length > 0 && schema.primaryKey[0]) return schema.primaryKey[0];
|
|
106
|
+
return "rowid";
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Checks if a table has FTS (Full-Text Search) enabled
|
|
110
|
+
*/
|
|
111
|
+
async hasFTS(db, tableName) {
|
|
112
|
+
return (await execAll(db, `
|
|
113
|
+
SELECT name FROM sqlite_master
|
|
114
|
+
WHERE type = 'table'
|
|
115
|
+
AND name = '${`${tableName}_fts`}'
|
|
116
|
+
`)).length > 0;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Creates FTS5 table for full-text search on specified columns
|
|
120
|
+
*/
|
|
121
|
+
async createFTS(db, tableName, columns, options) {
|
|
122
|
+
const ftsTableName = `${tableName}_fts`;
|
|
123
|
+
const contentTable = options?.contentTable ?? tableName;
|
|
124
|
+
const contentRowid = options?.contentRowid ?? "rowid";
|
|
125
|
+
const columnList = columns.join(", ");
|
|
126
|
+
await execRun(db, `
|
|
127
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS "${ftsTableName}" USING fts5(
|
|
128
|
+
${columnList},
|
|
129
|
+
content="${contentTable}",
|
|
130
|
+
content_rowid="${contentRowid}"
|
|
131
|
+
)
|
|
132
|
+
`);
|
|
133
|
+
await execRun(db, `
|
|
134
|
+
CREATE TRIGGER IF NOT EXISTS "${tableName}_ai" AFTER INSERT ON "${tableName}" BEGIN
|
|
135
|
+
INSERT INTO "${ftsTableName}"(rowid, ${columnList}) VALUES (new.${contentRowid}, ${columns.map((c) => `new."${c}"`).join(", ")});
|
|
136
|
+
END
|
|
137
|
+
`);
|
|
138
|
+
await execRun(db, `
|
|
139
|
+
CREATE TRIGGER IF NOT EXISTS "${tableName}_ad" AFTER DELETE ON "${tableName}" BEGIN
|
|
140
|
+
INSERT INTO "${ftsTableName}"("${ftsTableName}", rowid, ${columnList}) VALUES ('delete', old.${contentRowid}, ${columns.map((c) => `old."${c}"`).join(", ")});
|
|
141
|
+
END
|
|
142
|
+
`);
|
|
143
|
+
await execRun(db, `
|
|
144
|
+
CREATE TRIGGER IF NOT EXISTS "${tableName}_au" AFTER UPDATE ON "${tableName}" BEGIN
|
|
145
|
+
INSERT INTO "${ftsTableName}"("${ftsTableName}", rowid, ${columnList}) VALUES ('delete', old.${contentRowid}, ${columns.map((c) => `old."${c}"`).join(", ")});
|
|
146
|
+
INSERT INTO "${ftsTableName}"(rowid, ${columnList}) VALUES (new.${contentRowid}, ${columns.map((c) => `new."${c}"`).join(", ")});
|
|
147
|
+
END
|
|
148
|
+
`);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Rebuilds FTS index for a table (useful after bulk inserts)
|
|
152
|
+
*/
|
|
153
|
+
async rebuildFTS(db, tableName) {
|
|
154
|
+
const ftsTableName = `${tableName}_fts`;
|
|
155
|
+
await execRun(db, `INSERT INTO "${ftsTableName}"("${ftsTableName}") VALUES ('rebuild')`);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
//#endregion
|
|
160
|
+
exports.SchemaIntrospector = SchemaIntrospector;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { TableSchema } from "./types.cjs";
|
|
2
|
+
import { LibSQLDatabase } from "drizzle-orm/libsql";
|
|
3
|
+
|
|
4
|
+
//#region src/schema/introspector.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Schema introspector that uses SQLite PRAGMA queries to discover database schema
|
|
7
|
+
*/
|
|
8
|
+
declare class SchemaIntrospector {
|
|
9
|
+
/**
|
|
10
|
+
* Introspects all tables in the database
|
|
11
|
+
* @param db - Drizzle database instance
|
|
12
|
+
* @param options - Introspection options
|
|
13
|
+
* @returns Map of table name to TableSchema
|
|
14
|
+
*/
|
|
15
|
+
introspect(db: LibSQLDatabase, options?: {
|
|
16
|
+
/** Whitelist of tables to include */tables?: string[]; /** 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) */contentTable?: string; /** Content rowid column (defaults to 'rowid') */
|
|
40
|
+
contentRowid?: string;
|
|
41
|
+
}): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Rebuilds FTS index for a table (useful after bulk inserts)
|
|
44
|
+
*/
|
|
45
|
+
rebuildFTS(db: LibSQLDatabase, tableName: string): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { SchemaIntrospector };
|
|
49
|
+
//# sourceMappingURL=introspector.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introspector.d.cts","names":[],"sources":["../../src/schema/introspector.ts"],"mappings":";;;;;;AAwEA;cAAa,kBAAA;;;;;;;EAOL,UAAA,CACJ,EAAA,EAAI,cAAA,EACJ,OAAA;IAkD4D,qCAhD1D,MAAA,aAiGa;IA/Fb,aAAA;EAAA,IAED,OAAA,CAAQ,GAAA,SAAY,WAAA;EAuHpB;;;;;;EA3EG,eAAA,CAAgB,EAAA,EAAI,cAAA,EAAgB,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAnDpE;;;;EAyFF,mBAAA,CAAoB,MAAA,EAAQ,WAAA;EAlFjB;;;EA6FL,MAAA,CAAO,EAAA,EAAI,cAAA,EAAgB,SAAA,WAAoB,OAAA;EAjD/B;;;EAiEhB,SAAA,CACJ,EAAA,EAAI,cAAA,EACJ,SAAA,UACA,OAAA,YACA,OAAA;IA/BF,4CAiCI,YAAA,WAjCgB;IAmChB,YAAA;EAAA,IAED,OAAA;EA1BU;;;EA6EP,UAAA,CAAW,EAAA,EAAI,cAAA,EAAgB,SAAA,WAAoB,OAAA;AAAA"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { TableSchema } from "./types.mjs";
|
|
2
|
+
import { LibSQLDatabase } from "drizzle-orm/libsql";
|
|
3
|
+
|
|
4
|
+
//#region src/schema/introspector.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Schema introspector that uses SQLite PRAGMA queries to discover database schema
|
|
7
|
+
*/
|
|
8
|
+
declare class SchemaIntrospector {
|
|
9
|
+
/**
|
|
10
|
+
* Introspects all tables in the database
|
|
11
|
+
* @param db - Drizzle database instance
|
|
12
|
+
* @param options - Introspection options
|
|
13
|
+
* @returns Map of table name to TableSchema
|
|
14
|
+
*/
|
|
15
|
+
introspect(db: LibSQLDatabase, options?: {
|
|
16
|
+
/** Whitelist of tables to include */tables?: string[]; /** 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) */contentTable?: string; /** Content rowid column (defaults to 'rowid') */
|
|
40
|
+
contentRowid?: string;
|
|
41
|
+
}): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Rebuilds FTS index for a table (useful after bulk inserts)
|
|
44
|
+
*/
|
|
45
|
+
rebuildFTS(db: LibSQLDatabase, tableName: string): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
//#endregion
|
|
48
|
+
export { SchemaIntrospector };
|
|
49
|
+
//# sourceMappingURL=introspector.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introspector.d.mts","names":[],"sources":["../../src/schema/introspector.ts"],"mappings":";;;;;;AAwEA;cAAa,kBAAA;;;;;;;EAOL,UAAA,CACJ,EAAA,EAAI,cAAA,EACJ,OAAA;IAkD4D,qCAhD1D,MAAA,aAiGa;IA/Fb,aAAA;EAAA,IAED,OAAA,CAAQ,GAAA,SAAY,WAAA;EAuHpB;;;;;;EA3EG,eAAA,CAAgB,EAAA,EAAI,cAAA,EAAgB,SAAA,WAAoB,OAAA,CAAQ,WAAA;EAnDpE;;;;EAyFF,mBAAA,CAAoB,MAAA,EAAQ,WAAA;EAlFjB;;;EA6FL,MAAA,CAAO,EAAA,EAAI,cAAA,EAAgB,SAAA,WAAoB,OAAA;EAjD/B;;;EAiEhB,SAAA,CACJ,EAAA,EAAI,cAAA,EACJ,SAAA,UACA,OAAA,YACA,OAAA;IA/BF,4CAiCI,YAAA,WAjCgB;IAmChB,YAAA;EAAA,IAED,OAAA;EA1BU;;;EA6EP,UAAA,CAAW,EAAA,EAAI,cAAA,EAAgB,SAAA,WAAoB,OAAA;AAAA"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { SYSTEM_TABLES } from "./types.mjs";
|
|
2
|
+
import { sql } from "@aigne/sqlite";
|
|
3
|
+
|
|
4
|
+
//#region src/schema/introspector.ts
|
|
5
|
+
/**
|
|
6
|
+
* Executes a raw SQL query and returns all rows
|
|
7
|
+
*/
|
|
8
|
+
async function execAll(db, query) {
|
|
9
|
+
return db.all(sql.raw(query)).execute();
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Executes a raw SQL query (for INSERT, UPDATE, DELETE)
|
|
13
|
+
*/
|
|
14
|
+
async function execRun(db, query) {
|
|
15
|
+
await db.run(sql.raw(query)).execute();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Maps raw PRAGMA table_info row to ColumnInfo
|
|
19
|
+
*/
|
|
20
|
+
function mapColumn(row) {
|
|
21
|
+
return {
|
|
22
|
+
name: row.name,
|
|
23
|
+
type: row.type,
|
|
24
|
+
notnull: row.notnull === 1,
|
|
25
|
+
pk: row.pk,
|
|
26
|
+
dfltValue: row.dflt_value
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Maps raw PRAGMA foreign_key_list row to ForeignKeyInfo
|
|
31
|
+
*/
|
|
32
|
+
function mapForeignKey(row) {
|
|
33
|
+
return {
|
|
34
|
+
id: row.id,
|
|
35
|
+
seq: row.seq,
|
|
36
|
+
table: row.table,
|
|
37
|
+
from: row.from,
|
|
38
|
+
to: row.to,
|
|
39
|
+
onUpdate: row.on_update,
|
|
40
|
+
onDelete: row.on_delete,
|
|
41
|
+
match: row.match
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Maps raw PRAGMA index_list row to IndexInfo
|
|
46
|
+
*/
|
|
47
|
+
function mapIndex(row) {
|
|
48
|
+
return {
|
|
49
|
+
seq: row.seq,
|
|
50
|
+
name: row.name,
|
|
51
|
+
unique: row.unique === 1,
|
|
52
|
+
origin: row.origin,
|
|
53
|
+
partial: row.partial === 1
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Schema introspector that uses SQLite PRAGMA queries to discover database schema
|
|
58
|
+
*/
|
|
59
|
+
var SchemaIntrospector = class {
|
|
60
|
+
/**
|
|
61
|
+
* Introspects all tables in the database
|
|
62
|
+
* @param db - Drizzle database instance
|
|
63
|
+
* @param options - Introspection options
|
|
64
|
+
* @returns Map of table name to TableSchema
|
|
65
|
+
*/
|
|
66
|
+
async introspect(db, options) {
|
|
67
|
+
const schemas = /* @__PURE__ */ new Map();
|
|
68
|
+
const tablesResult = await execAll(db, `
|
|
69
|
+
SELECT name FROM sqlite_master
|
|
70
|
+
WHERE type = 'table'
|
|
71
|
+
AND name NOT LIKE 'sqlite_%'
|
|
72
|
+
AND name NOT LIKE '%_fts%'
|
|
73
|
+
ORDER BY name
|
|
74
|
+
`);
|
|
75
|
+
for (const { name } of tablesResult) {
|
|
76
|
+
if (SYSTEM_TABLES.includes(name)) continue;
|
|
77
|
+
if (options?.tables && !options.tables.includes(name)) continue;
|
|
78
|
+
if (options?.excludeTables?.includes(name)) continue;
|
|
79
|
+
const schema = await this.introspectTable(db, name);
|
|
80
|
+
schemas.set(name, schema);
|
|
81
|
+
}
|
|
82
|
+
return schemas;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Introspects a single table
|
|
86
|
+
* @param db - Drizzle database instance
|
|
87
|
+
* @param tableName - Name of the table to introspect
|
|
88
|
+
* @returns TableSchema for the specified table
|
|
89
|
+
*/
|
|
90
|
+
async introspectTable(db, tableName) {
|
|
91
|
+
const columns = (await execAll(db, `PRAGMA table_info("${tableName}")`)).map(mapColumn);
|
|
92
|
+
return {
|
|
93
|
+
name: tableName,
|
|
94
|
+
columns,
|
|
95
|
+
primaryKey: columns.filter((c) => c.pk > 0).map((c) => c.name),
|
|
96
|
+
foreignKeys: (await execAll(db, `PRAGMA foreign_key_list("${tableName}")`)).map(mapForeignKey),
|
|
97
|
+
indexes: (await execAll(db, `PRAGMA index_list("${tableName}")`)).map(mapIndex)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Gets the primary key column name for a table
|
|
102
|
+
* Returns the first PK column, or 'rowid' if no explicit PK
|
|
103
|
+
*/
|
|
104
|
+
getPrimaryKeyColumn(schema) {
|
|
105
|
+
if (schema.primaryKey.length > 0 && schema.primaryKey[0]) return schema.primaryKey[0];
|
|
106
|
+
return "rowid";
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Checks if a table has FTS (Full-Text Search) enabled
|
|
110
|
+
*/
|
|
111
|
+
async hasFTS(db, tableName) {
|
|
112
|
+
return (await execAll(db, `
|
|
113
|
+
SELECT name FROM sqlite_master
|
|
114
|
+
WHERE type = 'table'
|
|
115
|
+
AND name = '${`${tableName}_fts`}'
|
|
116
|
+
`)).length > 0;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Creates FTS5 table for full-text search on specified columns
|
|
120
|
+
*/
|
|
121
|
+
async createFTS(db, tableName, columns, options) {
|
|
122
|
+
const ftsTableName = `${tableName}_fts`;
|
|
123
|
+
const contentTable = options?.contentTable ?? tableName;
|
|
124
|
+
const contentRowid = options?.contentRowid ?? "rowid";
|
|
125
|
+
const columnList = columns.join(", ");
|
|
126
|
+
await execRun(db, `
|
|
127
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS "${ftsTableName}" USING fts5(
|
|
128
|
+
${columnList},
|
|
129
|
+
content="${contentTable}",
|
|
130
|
+
content_rowid="${contentRowid}"
|
|
131
|
+
)
|
|
132
|
+
`);
|
|
133
|
+
await execRun(db, `
|
|
134
|
+
CREATE TRIGGER IF NOT EXISTS "${tableName}_ai" AFTER INSERT ON "${tableName}" BEGIN
|
|
135
|
+
INSERT INTO "${ftsTableName}"(rowid, ${columnList}) VALUES (new.${contentRowid}, ${columns.map((c) => `new."${c}"`).join(", ")});
|
|
136
|
+
END
|
|
137
|
+
`);
|
|
138
|
+
await execRun(db, `
|
|
139
|
+
CREATE TRIGGER IF NOT EXISTS "${tableName}_ad" AFTER DELETE ON "${tableName}" BEGIN
|
|
140
|
+
INSERT INTO "${ftsTableName}"("${ftsTableName}", rowid, ${columnList}) VALUES ('delete', old.${contentRowid}, ${columns.map((c) => `old."${c}"`).join(", ")});
|
|
141
|
+
END
|
|
142
|
+
`);
|
|
143
|
+
await execRun(db, `
|
|
144
|
+
CREATE TRIGGER IF NOT EXISTS "${tableName}_au" AFTER UPDATE ON "${tableName}" BEGIN
|
|
145
|
+
INSERT INTO "${ftsTableName}"("${ftsTableName}", rowid, ${columnList}) VALUES ('delete', old.${contentRowid}, ${columns.map((c) => `old."${c}"`).join(", ")});
|
|
146
|
+
INSERT INTO "${ftsTableName}"(rowid, ${columnList}) VALUES (new.${contentRowid}, ${columns.map((c) => `new."${c}"`).join(", ")});
|
|
147
|
+
END
|
|
148
|
+
`);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Rebuilds FTS index for a table (useful after bulk inserts)
|
|
152
|
+
*/
|
|
153
|
+
async rebuildFTS(db, tableName) {
|
|
154
|
+
const ftsTableName = `${tableName}_fts`;
|
|
155
|
+
await execRun(db, `INSERT INTO "${ftsTableName}"("${ftsTableName}") VALUES ('rebuild')`);
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
//#endregion
|
|
160
|
+
export { SchemaIntrospector };
|
|
161
|
+
//# sourceMappingURL=introspector.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"introspector.mjs","names":[],"sources":["../../src/schema/introspector.ts"],"sourcesContent":["import { sql } from \"@aigne/sqlite\";\nimport type { LibSQLDatabase } from \"drizzle-orm/libsql\";\nimport {\n type ColumnInfo,\n type ForeignKeyInfo,\n type IndexInfo,\n type PragmaForeignKeyRow,\n type PragmaIndexListRow,\n type PragmaTableInfoRow,\n SYSTEM_TABLES,\n type TableSchema,\n} from \"./types.js\";\n\n/**\n * Executes a raw SQL query and returns all rows\n */\nasync function execAll<T>(db: LibSQLDatabase, query: string): Promise<T[]> {\n return db.all<T>(sql.raw(query)).execute();\n}\n\n/**\n * Executes a raw SQL query (for INSERT, UPDATE, DELETE)\n */\nasync function execRun(db: LibSQLDatabase, query: string): Promise<void> {\n await db.run(sql.raw(query)).execute();\n}\n\n/**\n * Maps raw PRAGMA table_info row to ColumnInfo\n */\nfunction mapColumn(row: PragmaTableInfoRow): ColumnInfo {\n return {\n name: row.name,\n type: row.type,\n notnull: row.notnull === 1,\n pk: row.pk,\n dfltValue: row.dflt_value,\n };\n}\n\n/**\n * Maps raw PRAGMA foreign_key_list row to ForeignKeyInfo\n */\nfunction mapForeignKey(row: PragmaForeignKeyRow): ForeignKeyInfo {\n return {\n id: row.id,\n seq: row.seq,\n table: row.table,\n from: row.from,\n to: row.to,\n onUpdate: row.on_update,\n onDelete: row.on_delete,\n match: row.match,\n };\n}\n\n/**\n * Maps raw PRAGMA index_list row to IndexInfo\n */\nfunction mapIndex(row: PragmaIndexListRow): IndexInfo {\n return {\n seq: row.seq,\n name: row.name,\n unique: row.unique === 1,\n origin: row.origin,\n partial: row.partial === 1,\n };\n}\n\n/**\n * Schema introspector that uses SQLite PRAGMA queries to discover database schema\n */\nexport class SchemaIntrospector {\n /**\n * Introspects all tables in the database\n * @param db - Drizzle database instance\n * @param options - Introspection options\n * @returns Map of table name to TableSchema\n */\n async introspect(\n db: LibSQLDatabase,\n options?: {\n /** Whitelist of tables to include */\n tables?: string[];\n /** Tables to exclude */\n excludeTables?: string[];\n },\n ): Promise<Map<string, TableSchema>> {\n const schemas = new Map<string, TableSchema>();\n\n // Get all user tables (exclude system tables and FTS tables)\n const tablesResult = await execAll<{ name: string }>(\n db,\n `\n SELECT name FROM sqlite_master\n WHERE type = 'table'\n AND name NOT LIKE 'sqlite_%'\n AND name NOT LIKE '%_fts%'\n ORDER BY name\n `,\n );\n\n for (const { name } of tablesResult) {\n // Skip system tables\n if (SYSTEM_TABLES.includes(name as (typeof SYSTEM_TABLES)[number])) {\n continue;\n }\n\n // Apply whitelist filter\n if (options?.tables && !options.tables.includes(name)) {\n continue;\n }\n\n // Apply exclude filter\n if (options?.excludeTables?.includes(name)) {\n continue;\n }\n\n const schema = await this.introspectTable(db, name);\n schemas.set(name, schema);\n }\n\n return schemas;\n }\n\n /**\n * Introspects a single table\n * @param db - Drizzle database instance\n * @param tableName - Name of the table to introspect\n * @returns TableSchema for the specified table\n */\n async introspectTable(db: LibSQLDatabase, tableName: string): Promise<TableSchema> {\n // Get column information\n const columnsResult = await execAll<PragmaTableInfoRow>(\n db,\n `PRAGMA table_info(\"${tableName}\")`,\n );\n const columns = columnsResult.map(mapColumn);\n\n // Get primary key columns (pk > 0 indicates part of primary key)\n const primaryKey = columns.filter((c) => c.pk > 0).map((c) => c.name);\n\n // Get foreign keys\n const fksResult = await execAll<PragmaForeignKeyRow>(\n db,\n `PRAGMA foreign_key_list(\"${tableName}\")`,\n );\n const foreignKeys = fksResult.map(mapForeignKey);\n\n // Get indexes\n const indexesResult = await execAll<PragmaIndexListRow>(\n db,\n `PRAGMA index_list(\"${tableName}\")`,\n );\n const indexes = indexesResult.map(mapIndex);\n\n return {\n name: tableName,\n columns,\n primaryKey,\n foreignKeys,\n indexes,\n };\n }\n\n /**\n * Gets the primary key column name for a table\n * Returns the first PK column, or 'rowid' if no explicit PK\n */\n getPrimaryKeyColumn(schema: TableSchema): string {\n if (schema.primaryKey.length > 0 && schema.primaryKey[0]) {\n return schema.primaryKey[0];\n }\n // SQLite tables without explicit PK use rowid\n return \"rowid\";\n }\n\n /**\n * Checks if a table has FTS (Full-Text Search) enabled\n */\n async hasFTS(db: LibSQLDatabase, tableName: string): Promise<boolean> {\n const ftsTableName = `${tableName}_fts`;\n const result = await execAll<{ name: string }>(\n db,\n `\n SELECT name FROM sqlite_master\n WHERE type = 'table'\n AND name = '${ftsTableName}'\n `,\n );\n return result.length > 0;\n }\n\n /**\n * Creates FTS5 table for full-text search on specified columns\n */\n async createFTS(\n db: LibSQLDatabase,\n tableName: string,\n columns: string[],\n options?: {\n /** Content table (defaults to tableName) */\n contentTable?: string;\n /** Content rowid column (defaults to 'rowid') */\n contentRowid?: string;\n },\n ): Promise<void> {\n const ftsTableName = `${tableName}_fts`;\n const contentTable = options?.contentTable ?? tableName;\n const contentRowid = options?.contentRowid ?? \"rowid\";\n const columnList = columns.join(\", \");\n\n // Create FTS5 virtual table\n await execRun(\n db,\n `\n CREATE VIRTUAL TABLE IF NOT EXISTS \"${ftsTableName}\" USING fts5(\n ${columnList},\n content=\"${contentTable}\",\n content_rowid=\"${contentRowid}\"\n )\n `,\n );\n\n // Create triggers to keep FTS in sync\n await execRun(\n db,\n `\n CREATE TRIGGER IF NOT EXISTS \"${tableName}_ai\" AFTER INSERT ON \"${tableName}\" BEGIN\n INSERT INTO \"${ftsTableName}\"(rowid, ${columnList}) VALUES (new.${contentRowid}, ${columns.map((c) => `new.\"${c}\"`).join(\", \")});\n END\n `,\n );\n\n await execRun(\n db,\n `\n CREATE TRIGGER IF NOT EXISTS \"${tableName}_ad\" AFTER DELETE ON \"${tableName}\" BEGIN\n INSERT INTO \"${ftsTableName}\"(\"${ftsTableName}\", rowid, ${columnList}) VALUES ('delete', old.${contentRowid}, ${columns.map((c) => `old.\"${c}\"`).join(\", \")});\n END\n `,\n );\n\n await execRun(\n db,\n `\n CREATE TRIGGER IF NOT EXISTS \"${tableName}_au\" AFTER UPDATE ON \"${tableName}\" BEGIN\n INSERT INTO \"${ftsTableName}\"(\"${ftsTableName}\", rowid, ${columnList}) VALUES ('delete', old.${contentRowid}, ${columns.map((c) => `old.\"${c}\"`).join(\", \")});\n INSERT INTO \"${ftsTableName}\"(rowid, ${columnList}) VALUES (new.${contentRowid}, ${columns.map((c) => `new.\"${c}\"`).join(\", \")});\n END\n `,\n );\n }\n\n /**\n * Rebuilds FTS index for a table (useful after bulk inserts)\n */\n async rebuildFTS(db: LibSQLDatabase, tableName: string): Promise<void> {\n const ftsTableName = `${tableName}_fts`;\n await execRun(db, `INSERT INTO \"${ftsTableName}\"(\"${ftsTableName}\") VALUES ('rebuild')`);\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
const require_types = require('./types.cjs');
|
|
2
|
+
const require_introspector = require('./introspector.cjs');
|
|
3
|
+
let _aigne_sqlite = require("@aigne/sqlite");
|
|
4
|
+
|
|
5
|
+
//#region src/schema/service.ts
|
|
6
|
+
/**
|
|
7
|
+
* Executes a raw SQL query and returns all rows
|
|
8
|
+
*/
|
|
9
|
+
async function execAll(db, query) {
|
|
10
|
+
return db.all(_aigne_sqlite.sql.raw(query)).execute();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Schema service that queries schema on-demand (no caching)
|
|
14
|
+
*
|
|
15
|
+
* SQLite PRAGMA queries are extremely fast, so real-time queries
|
|
16
|
+
* are preferred over caching to avoid staleness issues.
|
|
17
|
+
*/
|
|
18
|
+
var SchemaService = class {
|
|
19
|
+
introspector = new require_introspector.SchemaIntrospector();
|
|
20
|
+
constructor(db, options) {
|
|
21
|
+
this.db = db;
|
|
22
|
+
this.options = options;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Gets schema for a specific table (real-time query)
|
|
26
|
+
*/
|
|
27
|
+
async getSchema(tableName) {
|
|
28
|
+
if (!tableName) return;
|
|
29
|
+
if (require_types.SYSTEM_TABLES.includes(tableName)) return;
|
|
30
|
+
if (this.options?.tables && !this.options.tables.includes(tableName)) return;
|
|
31
|
+
if (this.options?.excludeTables?.includes(tableName)) return;
|
|
32
|
+
if (!await this.hasTable(tableName)) return;
|
|
33
|
+
return this.introspector.introspectTable(this.db, tableName);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Checks if a table exists (real-time query)
|
|
37
|
+
*/
|
|
38
|
+
async hasTable(tableName) {
|
|
39
|
+
if (!tableName) return false;
|
|
40
|
+
if (require_types.SYSTEM_TABLES.includes(tableName)) return false;
|
|
41
|
+
if (this.options?.tables && !this.options.tables.includes(tableName)) return false;
|
|
42
|
+
if (this.options?.excludeTables?.includes(tableName)) return false;
|
|
43
|
+
return ((await execAll(this.db, `SELECT COUNT(*) as count FROM sqlite_master WHERE type = 'table' AND name = '${tableName.replace(/'/g, "''")}'`))[0]?.count ?? 0) > 0;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Gets all table schemas (real-time query)
|
|
47
|
+
*/
|
|
48
|
+
async getAllSchemas() {
|
|
49
|
+
return this.introspector.introspect(this.db, {
|
|
50
|
+
tables: this.options?.tables,
|
|
51
|
+
excludeTables: this.options?.excludeTables
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Lists all table names (real-time query)
|
|
56
|
+
*/
|
|
57
|
+
async listTableNames() {
|
|
58
|
+
return (await execAll(this.db, `
|
|
59
|
+
SELECT name FROM sqlite_master
|
|
60
|
+
WHERE type = 'table'
|
|
61
|
+
AND name NOT LIKE 'sqlite_%'
|
|
62
|
+
AND name NOT LIKE '%_fts%'
|
|
63
|
+
ORDER BY name
|
|
64
|
+
`)).map((r) => r.name).filter((name) => {
|
|
65
|
+
if (require_types.SYSTEM_TABLES.includes(name)) return false;
|
|
66
|
+
if (this.options?.tables && !this.options.tables.includes(name)) return false;
|
|
67
|
+
if (this.options?.excludeTables?.includes(name)) return false;
|
|
68
|
+
return true;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Gets the count of tables
|
|
73
|
+
*/
|
|
74
|
+
async getTableCount() {
|
|
75
|
+
return (await this.listTableNames()).length;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Gets the primary key column name for a table
|
|
79
|
+
*/
|
|
80
|
+
getPrimaryKeyColumn(schema) {
|
|
81
|
+
return this.introspector.getPrimaryKeyColumn(schema);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
exports.SchemaService = SchemaService;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { TableSchema } from "./types.cjs";
|
|
2
|
+
import { LibSQLDatabase } from "drizzle-orm/libsql";
|
|
3
|
+
|
|
4
|
+
//#region src/schema/service.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Options for schema service
|
|
7
|
+
*/
|
|
8
|
+
interface SchemaServiceOptions {
|
|
9
|
+
/** Whitelist of tables to include */
|
|
10
|
+
tables?: string[];
|
|
11
|
+
/** Tables to exclude */
|
|
12
|
+
excludeTables?: string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Schema service that queries schema on-demand (no caching)
|
|
16
|
+
*
|
|
17
|
+
* SQLite PRAGMA queries are extremely fast, so real-time queries
|
|
18
|
+
* are preferred over caching to avoid staleness issues.
|
|
19
|
+
*/
|
|
20
|
+
declare class SchemaService {
|
|
21
|
+
private db;
|
|
22
|
+
private options?;
|
|
23
|
+
private introspector;
|
|
24
|
+
constructor(db: LibSQLDatabase, options?: SchemaServiceOptions | undefined);
|
|
25
|
+
/**
|
|
26
|
+
* Gets schema for a specific table (real-time query)
|
|
27
|
+
*/
|
|
28
|
+
getSchema(tableName: string): Promise<TableSchema | undefined>;
|
|
29
|
+
/**
|
|
30
|
+
* Checks if a table exists (real-time query)
|
|
31
|
+
*/
|
|
32
|
+
hasTable(tableName: string): Promise<boolean>;
|
|
33
|
+
/**
|
|
34
|
+
* Gets all table schemas (real-time query)
|
|
35
|
+
*/
|
|
36
|
+
getAllSchemas(): Promise<Map<string, TableSchema>>;
|
|
37
|
+
/**
|
|
38
|
+
* Lists all table names (real-time query)
|
|
39
|
+
*/
|
|
40
|
+
listTableNames(): Promise<string[]>;
|
|
41
|
+
/**
|
|
42
|
+
* Gets the count of tables
|
|
43
|
+
*/
|
|
44
|
+
getTableCount(): Promise<number>;
|
|
45
|
+
/**
|
|
46
|
+
* Gets the primary key column name for a table
|
|
47
|
+
*/
|
|
48
|
+
getPrimaryKeyColumn(schema: TableSchema): string;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { SchemaService, SchemaServiceOptions };
|
|
52
|
+
//# sourceMappingURL=service.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.cts","names":[],"sources":["../../src/schema/service.ts"],"mappings":";;;;;;AAeA;UAAiB,oBAAA;;EAEf,MAAA;EAEa;EAAb,aAAA;AAAA;;;;;;;cASW,aAAA;EAAA,QAID,EAAA;EAAA,QACA,OAAA;EAAA,QAJF,YAAA;cAGE,EAAA,EAAI,cAAA,EACJ,OAAA,GAAU,oBAAA;EA0HQ;;;EApHtB,SAAA,CAAU,SAAA,WAAoB,OAAA,CAAQ,WAAA;EANlC;;;EAuCJ,QAAA,CAAS,SAAA,WAAoB,OAAA;EAxCzB;;;EAuEJ,aAAA,CAAA,GAAiB,OAAA,CAAQ,GAAA,SAAY,WAAA;EAhE3B;;;EA0EV,cAAA,CAAA,GAAkB,OAAA;EAzCT;;;EA2ET,aAAA,CAAA,GAAiB,OAAA;EA5CQ;;;EAoD/B,mBAAA,CAAoB,MAAA,EAAQ,WAAA;AAAA"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { TableSchema } from "./types.mjs";
|
|
2
|
+
import { LibSQLDatabase } from "drizzle-orm/libsql";
|
|
3
|
+
|
|
4
|
+
//#region src/schema/service.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Options for schema service
|
|
7
|
+
*/
|
|
8
|
+
interface SchemaServiceOptions {
|
|
9
|
+
/** Whitelist of tables to include */
|
|
10
|
+
tables?: string[];
|
|
11
|
+
/** Tables to exclude */
|
|
12
|
+
excludeTables?: string[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Schema service that queries schema on-demand (no caching)
|
|
16
|
+
*
|
|
17
|
+
* SQLite PRAGMA queries are extremely fast, so real-time queries
|
|
18
|
+
* are preferred over caching to avoid staleness issues.
|
|
19
|
+
*/
|
|
20
|
+
declare class SchemaService {
|
|
21
|
+
private db;
|
|
22
|
+
private options?;
|
|
23
|
+
private introspector;
|
|
24
|
+
constructor(db: LibSQLDatabase, options?: SchemaServiceOptions | undefined);
|
|
25
|
+
/**
|
|
26
|
+
* Gets schema for a specific table (real-time query)
|
|
27
|
+
*/
|
|
28
|
+
getSchema(tableName: string): Promise<TableSchema | undefined>;
|
|
29
|
+
/**
|
|
30
|
+
* Checks if a table exists (real-time query)
|
|
31
|
+
*/
|
|
32
|
+
hasTable(tableName: string): Promise<boolean>;
|
|
33
|
+
/**
|
|
34
|
+
* Gets all table schemas (real-time query)
|
|
35
|
+
*/
|
|
36
|
+
getAllSchemas(): Promise<Map<string, TableSchema>>;
|
|
37
|
+
/**
|
|
38
|
+
* Lists all table names (real-time query)
|
|
39
|
+
*/
|
|
40
|
+
listTableNames(): Promise<string[]>;
|
|
41
|
+
/**
|
|
42
|
+
* Gets the count of tables
|
|
43
|
+
*/
|
|
44
|
+
getTableCount(): Promise<number>;
|
|
45
|
+
/**
|
|
46
|
+
* Gets the primary key column name for a table
|
|
47
|
+
*/
|
|
48
|
+
getPrimaryKeyColumn(schema: TableSchema): string;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { SchemaService, SchemaServiceOptions };
|
|
52
|
+
//# sourceMappingURL=service.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.mts","names":[],"sources":["../../src/schema/service.ts"],"mappings":";;;;;;AAeA;UAAiB,oBAAA;;EAEf,MAAA;EAEa;EAAb,aAAA;AAAA;;;;;;;cASW,aAAA;EAAA,QAID,EAAA;EAAA,QACA,OAAA;EAAA,QAJF,YAAA;cAGE,EAAA,EAAI,cAAA,EACJ,OAAA,GAAU,oBAAA;EA0HQ;;;EApHtB,SAAA,CAAU,SAAA,WAAoB,OAAA,CAAQ,WAAA;EANlC;;;EAuCJ,QAAA,CAAS,SAAA,WAAoB,OAAA;EAxCzB;;;EAuEJ,aAAA,CAAA,GAAiB,OAAA,CAAQ,GAAA,SAAY,WAAA;EAhE3B;;;EA0EV,cAAA,CAAA,GAAkB,OAAA;EAzCT;;;EA2ET,aAAA,CAAA,GAAiB,OAAA;EA5CQ;;;EAoD/B,mBAAA,CAAoB,MAAA,EAAQ,WAAA;AAAA"}
|