@aigne/afs-sqlite 1.11.0-beta → 1.11.0-beta.1
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 +0 -3
- package/dist/actions/built-in.cjs +142 -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 +143 -0
- package/dist/actions/built-in.mjs.map +1 -0
- package/dist/actions/registry.cjs +91 -0
- package/dist/actions/registry.d.cts +54 -0
- package/dist/actions/registry.d.cts.map +1 -0
- package/dist/actions/registry.d.mts +54 -0
- package/dist/actions/registry.d.mts.map +1 -0
- package/dist/actions/registry.mjs +91 -0
- package/dist/actions/registry.mjs.map +1 -0
- package/dist/actions/types.d.cts +56 -0
- package/dist/actions/types.d.cts.map +1 -0
- package/dist/actions/types.d.mts +56 -0
- package/dist/actions/types.d.mts.map +1 -0
- package/dist/config.cjs +27 -0
- package/dist/config.d.cts +81 -0
- package/dist/config.d.cts.map +1 -0
- package/dist/config.d.mts +81 -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 +38 -1324
- package/dist/index.d.cts +14 -758
- package/dist/index.d.mts +14 -758
- package/dist/index.mjs +12 -1299
- package/dist/node/builder.cjs +179 -0
- package/dist/node/builder.d.cts +48 -0
- package/dist/node/builder.d.cts.map +1 -0
- package/dist/node/builder.d.mts +48 -0
- package/dist/node/builder.d.mts.map +1 -0
- package/dist/node/builder.mjs +172 -0
- package/dist/node/builder.mjs.map +1 -0
- package/dist/operations/crud.cjs +176 -0
- package/dist/operations/crud.d.cts +69 -0
- package/dist/operations/crud.d.cts.map +1 -0
- package/dist/operations/crud.d.mts +69 -0
- package/dist/operations/crud.d.mts.map +1 -0
- package/dist/operations/crud.mjs +177 -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 +141 -0
- package/dist/operations/search.d.cts +79 -0
- package/dist/operations/search.d.cts.map +1 -0
- package/dist/operations/search.d.mts +79 -0
- package/dist/operations/search.d.mts.map +1 -0
- package/dist/operations/search.mjs +141 -0
- package/dist/operations/search.mjs.map +1 -0
- package/dist/router/path-router.cjs +79 -0
- package/dist/router/path-router.d.cts +42 -0
- package/dist/router/path-router.d.cts.map +1 -0
- package/dist/router/path-router.d.mts +42 -0
- package/dist/router/path-router.d.mts.map +1 -0
- package/dist/router/path-router.mjs +76 -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/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 +264 -0
- package/dist/sqlite-afs.d.cts +152 -0
- package/dist/sqlite-afs.d.cts.map +1 -0
- package/dist/sqlite-afs.d.mts +152 -0
- package/dist/sqlite-afs.d.mts.map +1 -0
- package/dist/sqlite-afs.mjs +265 -0
- package/dist/sqlite-afs.mjs.map +1 -0
- package/package.json +3 -3
- 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,69 @@
|
|
|
1
|
+
import { TableSchema } from "../schema/types.cjs";
|
|
2
|
+
import { LibSQLDatabase } from "drizzle-orm/libsql";
|
|
3
|
+
import { AFSDeleteResult, AFSListOptions, AFSListResult, AFSReadResult, AFSWriteResult } from "@aigne/afs";
|
|
4
|
+
|
|
5
|
+
//#region src/operations/crud.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* CRUD operations for SQLite AFS
|
|
8
|
+
*/
|
|
9
|
+
declare class CRUDOperations {
|
|
10
|
+
private db;
|
|
11
|
+
private schemas;
|
|
12
|
+
private basePath;
|
|
13
|
+
constructor(db: LibSQLDatabase, schemas: Map<string, TableSchema>, basePath?: string);
|
|
14
|
+
/**
|
|
15
|
+
* Lists all tables
|
|
16
|
+
*/
|
|
17
|
+
listTables(): Promise<AFSListResult>;
|
|
18
|
+
/**
|
|
19
|
+
* Lists rows in a table
|
|
20
|
+
*/
|
|
21
|
+
listTable(table: string, options?: AFSListOptions): Promise<AFSListResult>;
|
|
22
|
+
/**
|
|
23
|
+
* Reads a single row by primary key
|
|
24
|
+
*/
|
|
25
|
+
readRow(table: string, pk: string): Promise<AFSReadResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Gets table schema
|
|
28
|
+
*/
|
|
29
|
+
getSchema(table: string): AFSReadResult;
|
|
30
|
+
/**
|
|
31
|
+
* Lists attributes (columns) for a row
|
|
32
|
+
*/
|
|
33
|
+
listAttributes(table: string, pk: string): Promise<AFSListResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Gets a single attribute (column value) for a row
|
|
36
|
+
*/
|
|
37
|
+
getAttribute(table: string, pk: string, column: string): Promise<AFSReadResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Gets row metadata
|
|
40
|
+
*/
|
|
41
|
+
getMeta(table: string, pk: string): Promise<AFSReadResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Creates a new row in a table
|
|
44
|
+
*/
|
|
45
|
+
createRow(table: string, content: Record<string, unknown>): Promise<AFSWriteResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Updates an existing row
|
|
48
|
+
*/
|
|
49
|
+
updateRow(table: string, pk: string, content: Record<string, unknown>): Promise<AFSWriteResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Deletes a row by primary key
|
|
52
|
+
*/
|
|
53
|
+
deleteRow(table: string, pk: string): Promise<AFSDeleteResult>;
|
|
54
|
+
/**
|
|
55
|
+
* Checks if a table exists
|
|
56
|
+
*/
|
|
57
|
+
hasTable(table: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Gets the schema for a table
|
|
60
|
+
*/
|
|
61
|
+
getTableSchema(table: string): TableSchema | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Updates the schemas map (after refresh)
|
|
64
|
+
*/
|
|
65
|
+
setSchemas(schemas: Map<string, TableSchema>): void;
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { CRUDOperations };
|
|
69
|
+
//# sourceMappingURL=crud.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crud.d.cts","names":[],"sources":["../../src/operations/crud.ts"],"mappings":";;;;;;AA8CA;;cAAa,cAAA;EAAA,QAAA,EAAA;EAAA,QAAA,OAAA;EAAA,QAAA,QAAA;EAAA,YAAA,EAAA,EAEG,cAAA,EAAA,OAAA,EACK,GAAA,SAAY,WAAA,GAAA,QAAA;EAAA;;;EAAA,WAAA,GAOX,OAAA,CAAQ,aAAA;EAAA;;;EAAA,UAAA,KAAA,UAAA,OAAA,GAqBa,cAAA,GAAiB,OAAA,CAAQ,aAAA;EAAA;;;EAAA,QAAA,KAAA,UAAA,EAAA,WAuBxB,OAAA,CAAQ,aAAA;EAAA;;;EAAA,UAAA,KAAA,WAwBxB,aAAA;EAAA;;;EAAA,eAAA,KAAA,UAAA,EAAA,WAauB,OAAA,CAAQ,aAAA;EAAA;;;EAAA,aAAA,KAAA,UAAA,EAAA,UAAA,MAAA,WA0BM,OAAA,CAAQ,aAAA;EAAA;;;EAAA,QAAA,KAAA,UAAA,EAAA,WA+B7B,OAAA,CAAQ,aAAA;EAAA;;;EAAA,UAAA,KAAA,UAAA,OAAA,EAwBV,MAAA,oBAA0B,OAAA,CAAQ,cAAA;EAAA;;;EAAA,UAAA,KAAA,UAAA,EAAA,UAAA,OAAA,EA0C/D,MAAA,oBACR,OAAA,CAAQ,cAAA;EAAA;;;EAAA,UAAA,KAAA,UAAA,EAAA,WA4BiC,OAAA,CAAQ,eAAA;EAAA;;;EAAA,SAAA,KAAA;EAAA;;;EAAA,eAAA,KAAA,WAgCrB,WAAA;EAAA;;;EAAA,WAAA,OAAA,EAOX,GAAA,SAAY,WAAA;AAAA"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { TableSchema } from "../schema/types.mjs";
|
|
2
|
+
import { AFSDeleteResult, AFSListOptions, AFSListResult, AFSReadResult, AFSWriteResult } from "@aigne/afs";
|
|
3
|
+
import { LibSQLDatabase } from "drizzle-orm/libsql";
|
|
4
|
+
|
|
5
|
+
//#region src/operations/crud.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* CRUD operations for SQLite AFS
|
|
8
|
+
*/
|
|
9
|
+
declare class CRUDOperations {
|
|
10
|
+
private db;
|
|
11
|
+
private schemas;
|
|
12
|
+
private basePath;
|
|
13
|
+
constructor(db: LibSQLDatabase, schemas: Map<string, TableSchema>, basePath?: string);
|
|
14
|
+
/**
|
|
15
|
+
* Lists all tables
|
|
16
|
+
*/
|
|
17
|
+
listTables(): Promise<AFSListResult>;
|
|
18
|
+
/**
|
|
19
|
+
* Lists rows in a table
|
|
20
|
+
*/
|
|
21
|
+
listTable(table: string, options?: AFSListOptions): Promise<AFSListResult>;
|
|
22
|
+
/**
|
|
23
|
+
* Reads a single row by primary key
|
|
24
|
+
*/
|
|
25
|
+
readRow(table: string, pk: string): Promise<AFSReadResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Gets table schema
|
|
28
|
+
*/
|
|
29
|
+
getSchema(table: string): AFSReadResult;
|
|
30
|
+
/**
|
|
31
|
+
* Lists attributes (columns) for a row
|
|
32
|
+
*/
|
|
33
|
+
listAttributes(table: string, pk: string): Promise<AFSListResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Gets a single attribute (column value) for a row
|
|
36
|
+
*/
|
|
37
|
+
getAttribute(table: string, pk: string, column: string): Promise<AFSReadResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Gets row metadata
|
|
40
|
+
*/
|
|
41
|
+
getMeta(table: string, pk: string): Promise<AFSReadResult>;
|
|
42
|
+
/**
|
|
43
|
+
* Creates a new row in a table
|
|
44
|
+
*/
|
|
45
|
+
createRow(table: string, content: Record<string, unknown>): Promise<AFSWriteResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Updates an existing row
|
|
48
|
+
*/
|
|
49
|
+
updateRow(table: string, pk: string, content: Record<string, unknown>): Promise<AFSWriteResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Deletes a row by primary key
|
|
52
|
+
*/
|
|
53
|
+
deleteRow(table: string, pk: string): Promise<AFSDeleteResult>;
|
|
54
|
+
/**
|
|
55
|
+
* Checks if a table exists
|
|
56
|
+
*/
|
|
57
|
+
hasTable(table: string): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Gets the schema for a table
|
|
60
|
+
*/
|
|
61
|
+
getTableSchema(table: string): TableSchema | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Updates the schemas map (after refresh)
|
|
64
|
+
*/
|
|
65
|
+
setSchemas(schemas: Map<string, TableSchema>): void;
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { CRUDOperations };
|
|
69
|
+
//# sourceMappingURL=crud.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crud.d.mts","names":[],"sources":["../../src/operations/crud.ts"],"mappings":";;;;;;AA8CA;;cAAa,cAAA;EAAA,QAAA,EAAA;EAAA,QAAA,OAAA;EAAA,QAAA,QAAA;EAAA,YAAA,EAAA,EAEG,cAAA,EAAA,OAAA,EACK,GAAA,SAAY,WAAA,GAAA,QAAA;EAAA;;;EAAA,WAAA,GAOX,OAAA,CAAQ,aAAA;EAAA;;;EAAA,UAAA,KAAA,UAAA,OAAA,GAqBa,cAAA,GAAiB,OAAA,CAAQ,aAAA;EAAA;;;EAAA,QAAA,KAAA,UAAA,EAAA,WAuBxB,OAAA,CAAQ,aAAA;EAAA;;;EAAA,UAAA,KAAA,WAwBxB,aAAA;EAAA;;;EAAA,eAAA,KAAA,UAAA,EAAA,WAauB,OAAA,CAAQ,aAAA;EAAA;;;EAAA,aAAA,KAAA,UAAA,EAAA,UAAA,MAAA,WA0BM,OAAA,CAAQ,aAAA;EAAA;;;EAAA,QAAA,KAAA,UAAA,EAAA,WA+B7B,OAAA,CAAQ,aAAA;EAAA;;;EAAA,UAAA,KAAA,UAAA,OAAA,EAwBV,MAAA,oBAA0B,OAAA,CAAQ,cAAA;EAAA;;;EAAA,UAAA,KAAA,UAAA,EAAA,UAAA,OAAA,EA0C/D,MAAA,oBACR,OAAA,CAAQ,cAAA;EAAA;;;EAAA,UAAA,KAAA,UAAA,EAAA,WA4BiC,OAAA,CAAQ,eAAA;EAAA;;;EAAA,SAAA,KAAA;EAAA;;;EAAA,eAAA,KAAA,WAgCrB,WAAA;EAAA;;;EAAA,WAAA,OAAA,EAOX,GAAA,SAAY,WAAA;AAAA"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { buildAttributeEntry, buildAttributeListEntry, buildMetaEntry, buildRowEntry, buildSchemaEntry, buildTableEntry } from "../node/builder.mjs";
|
|
2
|
+
import { buildDelete, buildGetLastRowId, buildInsert, buildSelectAll, buildSelectByPK, buildUpdate } from "./query-builder.mjs";
|
|
3
|
+
import { sql } from "@aigne/sqlite";
|
|
4
|
+
|
|
5
|
+
//#region src/operations/crud.ts
|
|
6
|
+
/**
|
|
7
|
+
* Executes a raw SQL query and returns all rows
|
|
8
|
+
*/
|
|
9
|
+
async function execAll(db, query) {
|
|
10
|
+
return db.all(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(sql.raw(query)).execute();
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* CRUD operations for SQLite AFS
|
|
20
|
+
*/
|
|
21
|
+
var CRUDOperations = class {
|
|
22
|
+
constructor(db, schemas, basePath = "") {
|
|
23
|
+
this.db = db;
|
|
24
|
+
this.schemas = schemas;
|
|
25
|
+
this.basePath = basePath;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Lists all tables
|
|
29
|
+
*/
|
|
30
|
+
async listTables() {
|
|
31
|
+
const entries = [];
|
|
32
|
+
const buildOptions = { basePath: this.basePath };
|
|
33
|
+
for (const [name, schema] of this.schemas) {
|
|
34
|
+
const rowCount = (await execAll(this.db, `SELECT COUNT(*) as count FROM "${name}"`))[0]?.count ?? 0;
|
|
35
|
+
entries.push(buildTableEntry(name, schema, {
|
|
36
|
+
...buildOptions,
|
|
37
|
+
rowCount
|
|
38
|
+
}));
|
|
39
|
+
}
|
|
40
|
+
return { data: entries };
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Lists rows in a table
|
|
44
|
+
*/
|
|
45
|
+
async listTable(table, options) {
|
|
46
|
+
const schema = this.schemas.get(table);
|
|
47
|
+
if (!schema) return {
|
|
48
|
+
data: [],
|
|
49
|
+
message: `Table '${table}' not found`
|
|
50
|
+
};
|
|
51
|
+
const buildOptions = { basePath: this.basePath };
|
|
52
|
+
const queryStr = buildSelectAll(table, {
|
|
53
|
+
limit: options?.limit ?? 100,
|
|
54
|
+
orderBy: options?.orderBy
|
|
55
|
+
});
|
|
56
|
+
return { data: (await execAll(this.db, queryStr)).map((row) => buildRowEntry(table, schema, row, buildOptions)) };
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Reads a single row by primary key
|
|
60
|
+
*/
|
|
61
|
+
async readRow(table, pk) {
|
|
62
|
+
const schema = this.schemas.get(table);
|
|
63
|
+
if (!schema) return { message: `Table '${table}' not found` };
|
|
64
|
+
const buildOptions = { basePath: this.basePath };
|
|
65
|
+
const row = (await execAll(this.db, buildSelectByPK(table, schema, pk)))[0];
|
|
66
|
+
if (!row) return { message: `Row with pk '${pk}' not found in table '${table}'` };
|
|
67
|
+
return { data: buildRowEntry(table, schema, row, buildOptions) };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Gets table schema
|
|
71
|
+
*/
|
|
72
|
+
getSchema(table) {
|
|
73
|
+
const schema = this.schemas.get(table);
|
|
74
|
+
if (!schema) return { message: `Table '${table}' not found` };
|
|
75
|
+
return { data: buildSchemaEntry(table, schema, { basePath: this.basePath }) };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Lists attributes (columns) for a row
|
|
79
|
+
*/
|
|
80
|
+
async listAttributes(table, pk) {
|
|
81
|
+
const schema = this.schemas.get(table);
|
|
82
|
+
if (!schema) return {
|
|
83
|
+
data: [],
|
|
84
|
+
message: `Table '${table}' not found`
|
|
85
|
+
};
|
|
86
|
+
const buildOptions = { basePath: this.basePath };
|
|
87
|
+
const row = (await execAll(this.db, buildSelectByPK(table, schema, pk)))[0];
|
|
88
|
+
if (!row) return {
|
|
89
|
+
data: [],
|
|
90
|
+
message: `Row with pk '${pk}' not found`
|
|
91
|
+
};
|
|
92
|
+
return { data: buildAttributeListEntry(table, schema, pk, row, buildOptions) };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Gets a single attribute (column value) for a row
|
|
96
|
+
*/
|
|
97
|
+
async getAttribute(table, pk, column) {
|
|
98
|
+
const schema = this.schemas.get(table);
|
|
99
|
+
if (!schema) return { message: `Table '${table}' not found` };
|
|
100
|
+
if (!schema.columns.find((c) => c.name === column)) return { message: `Column '${column}' not found in table '${table}'` };
|
|
101
|
+
const buildOptions = { basePath: this.basePath };
|
|
102
|
+
const rows = await execAll(this.db, buildSelectByPK(table, schema, pk));
|
|
103
|
+
if (rows.length === 0) return { message: `Row with pk '${pk}' not found` };
|
|
104
|
+
return { data: buildAttributeEntry(table, pk, column, rows[0]?.[column], buildOptions) };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Gets row metadata
|
|
108
|
+
*/
|
|
109
|
+
async getMeta(table, pk) {
|
|
110
|
+
const schema = this.schemas.get(table);
|
|
111
|
+
if (!schema) return { message: `Table '${table}' not found` };
|
|
112
|
+
const buildOptions = { basePath: this.basePath };
|
|
113
|
+
const row = (await execAll(this.db, buildSelectByPK(table, schema, pk)))[0];
|
|
114
|
+
if (!row) return { message: `Row with pk '${pk}' not found` };
|
|
115
|
+
return { data: buildMetaEntry(table, schema, pk, row, buildOptions) };
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Creates a new row in a table
|
|
119
|
+
*/
|
|
120
|
+
async createRow(table, content) {
|
|
121
|
+
const schema = this.schemas.get(table);
|
|
122
|
+
if (!schema) throw new Error(`Table '${table}' not found`);
|
|
123
|
+
const buildOptions = { basePath: this.basePath };
|
|
124
|
+
await execRun(this.db, buildInsert(table, schema, content));
|
|
125
|
+
const lastId = (await execAll(this.db, buildGetLastRowId()))[0]?.id;
|
|
126
|
+
if (lastId === void 0) throw new Error("Failed to get last inserted row ID");
|
|
127
|
+
const pkColumn = schema.primaryKey[0] ?? "rowid";
|
|
128
|
+
const pk = content[pkColumn] !== void 0 ? String(content[pkColumn]) : String(lastId);
|
|
129
|
+
const row = (await execAll(this.db, buildSelectByPK(table, schema, pk)))[0];
|
|
130
|
+
if (!row) throw new Error("Failed to fetch inserted row");
|
|
131
|
+
return { data: buildRowEntry(table, schema, row, buildOptions) };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Updates an existing row
|
|
135
|
+
*/
|
|
136
|
+
async updateRow(table, pk, content) {
|
|
137
|
+
const schema = this.schemas.get(table);
|
|
138
|
+
if (!schema) throw new Error(`Table '${table}' not found`);
|
|
139
|
+
const buildOptions = { basePath: this.basePath };
|
|
140
|
+
await execRun(this.db, buildUpdate(table, schema, pk, content));
|
|
141
|
+
const row = (await execAll(this.db, buildSelectByPK(table, schema, pk)))[0];
|
|
142
|
+
if (!row) throw new Error(`Row with pk '${pk}' not found after update`);
|
|
143
|
+
return { data: buildRowEntry(table, schema, row, buildOptions) };
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Deletes a row by primary key
|
|
147
|
+
*/
|
|
148
|
+
async deleteRow(table, pk) {
|
|
149
|
+
const schema = this.schemas.get(table);
|
|
150
|
+
if (!schema) throw new Error(`Table '${table}' not found`);
|
|
151
|
+
if ((await execAll(this.db, buildSelectByPK(table, schema, pk))).length === 0) return { message: `Row with pk '${pk}' not found in table '${table}'` };
|
|
152
|
+
await execRun(this.db, buildDelete(table, schema, pk));
|
|
153
|
+
return { message: `Deleted row '${pk}' from table '${table}'` };
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Checks if a table exists
|
|
157
|
+
*/
|
|
158
|
+
hasTable(table) {
|
|
159
|
+
return this.schemas.has(table);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Gets the schema for a table
|
|
163
|
+
*/
|
|
164
|
+
getTableSchema(table) {
|
|
165
|
+
return this.schemas.get(table);
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Updates the schemas map (after refresh)
|
|
169
|
+
*/
|
|
170
|
+
setSchemas(schemas) {
|
|
171
|
+
this.schemas = schemas;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
//#endregion
|
|
176
|
+
export { CRUDOperations };
|
|
177
|
+
//# sourceMappingURL=crud.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crud.mjs","names":[],"sources":["../../src/operations/crud.ts"],"sourcesContent":["import type {\n AFSDeleteResult,\n AFSEntry,\n AFSListOptions,\n AFSListResult,\n AFSReadResult,\n AFSWriteResult,\n} from \"@aigne/afs\";\nimport { sql } from \"@aigne/sqlite\";\nimport type { LibSQLDatabase } from \"drizzle-orm/libsql\";\nimport {\n type BuildEntryOptions,\n buildAttributeEntry,\n buildAttributeListEntry,\n buildMetaEntry,\n buildRowEntry,\n buildSchemaEntry,\n buildTableEntry,\n} from \"../node/builder.js\";\nimport type { TableSchema } from \"../schema/types.js\";\nimport {\n buildDelete,\n buildGetLastRowId,\n buildInsert,\n buildSelectAll,\n buildSelectByPK,\n buildUpdate,\n} from \"./query-builder.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 * CRUD operations for SQLite AFS\n */\nexport class CRUDOperations {\n constructor(\n private db: LibSQLDatabase,\n private schemas: Map<string, TableSchema>,\n private basePath: string = \"\",\n ) {}\n\n /**\n * Lists all tables\n */\n async listTables(): Promise<AFSListResult> {\n const entries: AFSEntry[] = [];\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n for (const [name, schema] of this.schemas) {\n // Get row count for each table\n const countResult = await execAll<{ count: number }>(\n this.db,\n `SELECT COUNT(*) as count FROM \"${name}\"`,\n );\n const rowCount = countResult[0]?.count ?? 0;\n\n entries.push(buildTableEntry(name, schema, { ...buildOptions, rowCount }));\n }\n\n return { data: entries };\n }\n\n /**\n * Lists rows in a table\n */\n async listTable(table: string, options?: AFSListOptions): Promise<AFSListResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n return { data: [], message: `Table '${table}' not found` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n const queryStr = buildSelectAll(table, {\n limit: options?.limit ?? 100,\n orderBy: options?.orderBy,\n });\n\n const rows = await execAll<Record<string, unknown>>(this.db, queryStr);\n\n const entries = rows.map((row) => buildRowEntry(table, schema, row, buildOptions));\n\n return { data: entries };\n }\n\n /**\n * Reads a single row by primary key\n */\n async readRow(table: string, pk: string): Promise<AFSReadResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n return { message: `Table '${table}' not found` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n const row = rows[0];\n if (!row) {\n return { message: `Row with pk '${pk}' not found in table '${table}'` };\n }\n\n return { data: buildRowEntry(table, schema, row, buildOptions) };\n }\n\n /**\n * Gets table schema\n */\n getSchema(table: string): AFSReadResult {\n const schema = this.schemas.get(table);\n if (!schema) {\n return { message: `Table '${table}' not found` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n return { data: buildSchemaEntry(table, schema, buildOptions) };\n }\n\n /**\n * Lists attributes (columns) for a row\n */\n async listAttributes(table: string, pk: string): Promise<AFSListResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n return { data: [], message: `Table '${table}' not found` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n const row = rows[0];\n if (!row) {\n return { data: [], message: `Row with pk '${pk}' not found` };\n }\n\n return {\n data: buildAttributeListEntry(table, schema, pk, row, buildOptions),\n };\n }\n\n /**\n * Gets a single attribute (column value) for a row\n */\n async getAttribute(table: string, pk: string, column: string): Promise<AFSReadResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n return { message: `Table '${table}' not found` };\n }\n\n // Validate column exists\n const colInfo = schema.columns.find((c) => c.name === column);\n if (!colInfo) {\n return { message: `Column '${column}' not found in table '${table}'` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n if (rows.length === 0) {\n return { message: `Row with pk '${pk}' not found` };\n }\n\n return {\n data: buildAttributeEntry(table, pk, column, rows[0]?.[column], buildOptions),\n };\n }\n\n /**\n * Gets row metadata\n */\n async getMeta(table: string, pk: string): Promise<AFSReadResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n return { message: `Table '${table}' not found` };\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n const row = rows[0];\n if (!row) {\n return { message: `Row with pk '${pk}' not found` };\n }\n\n return { data: buildMetaEntry(table, schema, pk, row, buildOptions) };\n }\n\n /**\n * Creates a new row in a table\n */\n async createRow(table: string, content: Record<string, unknown>): Promise<AFSWriteResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n throw new Error(`Table '${table}' not found`);\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n // Insert the row\n await execRun(this.db, buildInsert(table, schema, content));\n\n // Get the last inserted rowid\n const lastIdResult = await execAll<{ id: number }>(this.db, buildGetLastRowId());\n const lastId = lastIdResult[0]?.id;\n\n if (lastId === undefined) {\n throw new Error(\"Failed to get last inserted row ID\");\n }\n\n // Fetch the inserted row\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n const pk = content[pkColumn] !== undefined ? String(content[pkColumn]) : String(lastId);\n\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n const row = rows[0];\n if (!row) {\n throw new Error(\"Failed to fetch inserted row\");\n }\n\n return { data: buildRowEntry(table, schema, row, buildOptions) };\n }\n\n /**\n * Updates an existing row\n */\n async updateRow(\n table: string,\n pk: string,\n content: Record<string, unknown>,\n ): Promise<AFSWriteResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n throw new Error(`Table '${table}' not found`);\n }\n\n const buildOptions: BuildEntryOptions = { basePath: this.basePath };\n\n // Update the row\n await execRun(this.db, buildUpdate(table, schema, pk, content));\n\n // Fetch the updated row\n const rows = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n const row = rows[0];\n if (!row) {\n throw new Error(`Row with pk '${pk}' not found after update`);\n }\n\n return { data: buildRowEntry(table, schema, row, buildOptions) };\n }\n\n /**\n * Deletes a row by primary key\n */\n async deleteRow(table: string, pk: string): Promise<AFSDeleteResult> {\n const schema = this.schemas.get(table);\n if (!schema) {\n throw new Error(`Table '${table}' not found`);\n }\n\n // Check if row exists first\n const existing = await execAll<Record<string, unknown>>(\n this.db,\n buildSelectByPK(table, schema, pk),\n );\n\n if (existing.length === 0) {\n return { message: `Row with pk '${pk}' not found in table '${table}'` };\n }\n\n // Delete the row\n await execRun(this.db, buildDelete(table, schema, pk));\n\n return { message: `Deleted row '${pk}' from table '${table}'` };\n }\n\n /**\n * Checks if a table exists\n */\n hasTable(table: string): boolean {\n return this.schemas.has(table);\n }\n\n /**\n * Gets the schema for a table\n */\n getTableSchema(table: string): TableSchema | undefined {\n return this.schemas.get(table);\n }\n\n /**\n * Updates the schemas map (after refresh)\n */\n setSchemas(schemas: Map<string, TableSchema>): void {\n this.schemas = schemas;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/operations/query-builder.ts
|
|
3
|
+
/**
|
|
4
|
+
* Builds a SELECT query string for a single row by primary key
|
|
5
|
+
*/
|
|
6
|
+
function buildSelectByPK(tableName, schema, pk) {
|
|
7
|
+
return `SELECT * FROM "${tableName}" WHERE "${schema.primaryKey[0] ?? "rowid"}" = '${escapeSQLString(pk)}'`;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Builds a SELECT query string for listing rows with optional limit and offset
|
|
11
|
+
*/
|
|
12
|
+
function buildSelectAll(tableName, options) {
|
|
13
|
+
let query = `SELECT * FROM "${tableName}"`;
|
|
14
|
+
if (options?.orderBy?.length) {
|
|
15
|
+
const orderClauses = options.orderBy.map(([col, dir]) => `"${col}" ${dir.toUpperCase()}`);
|
|
16
|
+
query += ` ORDER BY ${orderClauses.join(", ")}`;
|
|
17
|
+
}
|
|
18
|
+
if (options?.limit !== void 0) query += ` LIMIT ${options.limit}`;
|
|
19
|
+
if (options?.offset !== void 0) query += ` OFFSET ${options.offset}`;
|
|
20
|
+
return query;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Builds an INSERT query string from content object
|
|
24
|
+
*/
|
|
25
|
+
function buildInsert(tableName, schema, content) {
|
|
26
|
+
const validColumns = new Set(schema.columns.map((c) => c.name));
|
|
27
|
+
const entries = Object.entries(content).filter(([key]) => validColumns.has(key));
|
|
28
|
+
if (entries.length === 0) throw new Error(`No valid columns provided for INSERT into ${tableName}`);
|
|
29
|
+
return `INSERT INTO "${tableName}" (${entries.map(([key]) => `"${key}"`).join(", ")}) VALUES (${entries.map(([, value]) => formatValue(value)).join(", ")})`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Builds an UPDATE query string from content object
|
|
33
|
+
*/
|
|
34
|
+
function buildUpdate(tableName, schema, pk, content) {
|
|
35
|
+
const pkColumn = schema.primaryKey[0] ?? "rowid";
|
|
36
|
+
const validColumns = new Set(schema.columns.map((c) => c.name));
|
|
37
|
+
const entries = Object.entries(content).filter(([key]) => validColumns.has(key) && key !== pkColumn);
|
|
38
|
+
if (entries.length === 0) throw new Error(`No valid columns provided for UPDATE on ${tableName}`);
|
|
39
|
+
return `UPDATE "${tableName}" SET ${entries.map(([key, value]) => `"${key}" = ${formatValue(value)}`).join(", ")} WHERE "${pkColumn}" = '${escapeSQLString(pk)}'`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Builds a DELETE query string by primary key
|
|
43
|
+
*/
|
|
44
|
+
function buildDelete(tableName, schema, pk) {
|
|
45
|
+
return `DELETE FROM "${tableName}" WHERE "${schema.primaryKey[0] ?? "rowid"}" = '${escapeSQLString(pk)}'`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Formats a value for SQL insertion
|
|
49
|
+
*/
|
|
50
|
+
function formatValue(value) {
|
|
51
|
+
if (value === null || value === void 0) return "NULL";
|
|
52
|
+
if (typeof value === "number") return String(value);
|
|
53
|
+
if (typeof value === "boolean") return value ? "1" : "0";
|
|
54
|
+
if (value instanceof Date) return `'${value.toISOString()}'`;
|
|
55
|
+
if (typeof value === "object") return `'${escapeSQLString(JSON.stringify(value))}'`;
|
|
56
|
+
return `'${escapeSQLString(String(value))}'`;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Escapes a string for safe SQL insertion
|
|
60
|
+
*/
|
|
61
|
+
function escapeSQLString(str) {
|
|
62
|
+
return str.replace(/'/g, "''");
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Gets the last inserted rowid query string
|
|
66
|
+
*/
|
|
67
|
+
function buildGetLastRowId() {
|
|
68
|
+
return "SELECT last_insert_rowid() as id";
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
exports.buildDelete = buildDelete;
|
|
73
|
+
exports.buildGetLastRowId = buildGetLastRowId;
|
|
74
|
+
exports.buildInsert = buildInsert;
|
|
75
|
+
exports.buildSelectAll = buildSelectAll;
|
|
76
|
+
exports.buildSelectByPK = buildSelectByPK;
|
|
77
|
+
exports.buildUpdate = buildUpdate;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { TableSchema } from "../schema/types.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/operations/query-builder.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Builds a SELECT query string for a single row by primary key
|
|
6
|
+
*/
|
|
7
|
+
declare function buildSelectByPK(tableName: string, schema: TableSchema, pk: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Builds a SELECT query string for listing rows with optional limit and offset
|
|
10
|
+
*/
|
|
11
|
+
declare function buildSelectAll(tableName: string, options?: {
|
|
12
|
+
limit?: number;
|
|
13
|
+
offset?: number;
|
|
14
|
+
orderBy?: [string, "asc" | "desc"][];
|
|
15
|
+
}): string;
|
|
16
|
+
/**
|
|
17
|
+
* Builds an INSERT query string from content object
|
|
18
|
+
*/
|
|
19
|
+
declare function buildInsert(tableName: string, schema: TableSchema, content: Record<string, unknown>): string;
|
|
20
|
+
/**
|
|
21
|
+
* Builds an UPDATE query string from content object
|
|
22
|
+
*/
|
|
23
|
+
declare function buildUpdate(tableName: string, schema: TableSchema, pk: string, content: Record<string, unknown>): string;
|
|
24
|
+
/**
|
|
25
|
+
* Builds a DELETE query string by primary key
|
|
26
|
+
*/
|
|
27
|
+
declare function buildDelete(tableName: string, schema: TableSchema, pk: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Gets the last inserted rowid query string
|
|
30
|
+
*/
|
|
31
|
+
declare function buildGetLastRowId(): string;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { buildDelete, buildGetLastRowId, buildInsert, buildSelectAll, buildSelectByPK, buildUpdate };
|
|
34
|
+
//# sourceMappingURL=query-builder.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-builder.d.cts","names":[],"sources":["../../src/operations/query-builder.ts"],"mappings":";;;;AAKA;AAQA;iBARgB,eAAA,CAAA,SAAA,UAAA,MAAA,EAA2C,WAAA,EAAA,EAAA;AAAA;AAQ3D;AA6BA;AArC2D,iBAQ3C,cAAA,CAAA,SAAA,UAAA,OAAA;EAAA,KAAA;EAAA,MAAA;EAAA,OAAA;AAAA;AAAA;AA6BhB;AAsBA;AAnDgB,iBA6BA,WAAA,CAAA,SAAA,UAAA,MAAA,EAEN,WAAA,EAAA,OAAA,EACC,MAAA;AAAA;AAmBX;AA0BA;AA7CW,iBAmBK,WAAA,CAAA,SAAA,UAAA,MAAA,EAEN,WAAA,EAAA,EAAA,UAAA,OAAA,EAEC,MAAA;AAAA;AAsBX;AA0CA;AAhEW,iBAsBK,WAAA,CAAA,SAAA,UAAA,MAAA,EAAuC,WAAA,EAAA,EAAA;AAAA;AA0CvD;;AA1CuD,iBA0CvC,iBAAA,CAAA"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { TableSchema } from "../schema/types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/operations/query-builder.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Builds a SELECT query string for a single row by primary key
|
|
6
|
+
*/
|
|
7
|
+
declare function buildSelectByPK(tableName: string, schema: TableSchema, pk: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Builds a SELECT query string for listing rows with optional limit and offset
|
|
10
|
+
*/
|
|
11
|
+
declare function buildSelectAll(tableName: string, options?: {
|
|
12
|
+
limit?: number;
|
|
13
|
+
offset?: number;
|
|
14
|
+
orderBy?: [string, "asc" | "desc"][];
|
|
15
|
+
}): string;
|
|
16
|
+
/**
|
|
17
|
+
* Builds an INSERT query string from content object
|
|
18
|
+
*/
|
|
19
|
+
declare function buildInsert(tableName: string, schema: TableSchema, content: Record<string, unknown>): string;
|
|
20
|
+
/**
|
|
21
|
+
* Builds an UPDATE query string from content object
|
|
22
|
+
*/
|
|
23
|
+
declare function buildUpdate(tableName: string, schema: TableSchema, pk: string, content: Record<string, unknown>): string;
|
|
24
|
+
/**
|
|
25
|
+
* Builds a DELETE query string by primary key
|
|
26
|
+
*/
|
|
27
|
+
declare function buildDelete(tableName: string, schema: TableSchema, pk: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Gets the last inserted rowid query string
|
|
30
|
+
*/
|
|
31
|
+
declare function buildGetLastRowId(): string;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { buildDelete, buildGetLastRowId, buildInsert, buildSelectAll, buildSelectByPK, buildUpdate };
|
|
34
|
+
//# sourceMappingURL=query-builder.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-builder.d.mts","names":[],"sources":["../../src/operations/query-builder.ts"],"mappings":";;;;AAKA;AAQA;iBARgB,eAAA,CAAA,SAAA,UAAA,MAAA,EAA2C,WAAA,EAAA,EAAA;AAAA;AAQ3D;AA6BA;AArC2D,iBAQ3C,cAAA,CAAA,SAAA,UAAA,OAAA;EAAA,KAAA;EAAA,MAAA;EAAA,OAAA;AAAA;AAAA;AA6BhB;AAsBA;AAnDgB,iBA6BA,WAAA,CAAA,SAAA,UAAA,MAAA,EAEN,WAAA,EAAA,OAAA,EACC,MAAA;AAAA;AAmBX;AA0BA;AA7CW,iBAmBK,WAAA,CAAA,SAAA,UAAA,MAAA,EAEN,WAAA,EAAA,EAAA,UAAA,OAAA,EAEC,MAAA;AAAA;AAsBX;AA0CA;AAhEW,iBAsBK,WAAA,CAAA,SAAA,UAAA,MAAA,EAAuC,WAAA,EAAA,EAAA;AAAA;AA0CvD;;AA1CuD,iBA0CvC,iBAAA,CAAA"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
//#region src/operations/query-builder.ts
|
|
2
|
+
/**
|
|
3
|
+
* Builds a SELECT query string for a single row by primary key
|
|
4
|
+
*/
|
|
5
|
+
function buildSelectByPK(tableName, schema, pk) {
|
|
6
|
+
return `SELECT * FROM "${tableName}" WHERE "${schema.primaryKey[0] ?? "rowid"}" = '${escapeSQLString(pk)}'`;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Builds a SELECT query string for listing rows with optional limit and offset
|
|
10
|
+
*/
|
|
11
|
+
function buildSelectAll(tableName, options) {
|
|
12
|
+
let query = `SELECT * FROM "${tableName}"`;
|
|
13
|
+
if (options?.orderBy?.length) {
|
|
14
|
+
const orderClauses = options.orderBy.map(([col, dir]) => `"${col}" ${dir.toUpperCase()}`);
|
|
15
|
+
query += ` ORDER BY ${orderClauses.join(", ")}`;
|
|
16
|
+
}
|
|
17
|
+
if (options?.limit !== void 0) query += ` LIMIT ${options.limit}`;
|
|
18
|
+
if (options?.offset !== void 0) query += ` OFFSET ${options.offset}`;
|
|
19
|
+
return query;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Builds an INSERT query string from content object
|
|
23
|
+
*/
|
|
24
|
+
function buildInsert(tableName, schema, content) {
|
|
25
|
+
const validColumns = new Set(schema.columns.map((c) => c.name));
|
|
26
|
+
const entries = Object.entries(content).filter(([key]) => validColumns.has(key));
|
|
27
|
+
if (entries.length === 0) throw new Error(`No valid columns provided for INSERT into ${tableName}`);
|
|
28
|
+
return `INSERT INTO "${tableName}" (${entries.map(([key]) => `"${key}"`).join(", ")}) VALUES (${entries.map(([, value]) => formatValue(value)).join(", ")})`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Builds an UPDATE query string from content object
|
|
32
|
+
*/
|
|
33
|
+
function buildUpdate(tableName, schema, pk, content) {
|
|
34
|
+
const pkColumn = schema.primaryKey[0] ?? "rowid";
|
|
35
|
+
const validColumns = new Set(schema.columns.map((c) => c.name));
|
|
36
|
+
const entries = Object.entries(content).filter(([key]) => validColumns.has(key) && key !== pkColumn);
|
|
37
|
+
if (entries.length === 0) throw new Error(`No valid columns provided for UPDATE on ${tableName}`);
|
|
38
|
+
return `UPDATE "${tableName}" SET ${entries.map(([key, value]) => `"${key}" = ${formatValue(value)}`).join(", ")} WHERE "${pkColumn}" = '${escapeSQLString(pk)}'`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Builds a DELETE query string by primary key
|
|
42
|
+
*/
|
|
43
|
+
function buildDelete(tableName, schema, pk) {
|
|
44
|
+
return `DELETE FROM "${tableName}" WHERE "${schema.primaryKey[0] ?? "rowid"}" = '${escapeSQLString(pk)}'`;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Formats a value for SQL insertion
|
|
48
|
+
*/
|
|
49
|
+
function formatValue(value) {
|
|
50
|
+
if (value === null || value === void 0) return "NULL";
|
|
51
|
+
if (typeof value === "number") return String(value);
|
|
52
|
+
if (typeof value === "boolean") return value ? "1" : "0";
|
|
53
|
+
if (value instanceof Date) return `'${value.toISOString()}'`;
|
|
54
|
+
if (typeof value === "object") return `'${escapeSQLString(JSON.stringify(value))}'`;
|
|
55
|
+
return `'${escapeSQLString(String(value))}'`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Escapes a string for safe SQL insertion
|
|
59
|
+
*/
|
|
60
|
+
function escapeSQLString(str) {
|
|
61
|
+
return str.replace(/'/g, "''");
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Gets the last inserted rowid query string
|
|
65
|
+
*/
|
|
66
|
+
function buildGetLastRowId() {
|
|
67
|
+
return "SELECT last_insert_rowid() as id";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
export { buildDelete, buildGetLastRowId, buildInsert, buildSelectAll, buildSelectByPK, buildUpdate };
|
|
72
|
+
//# sourceMappingURL=query-builder.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-builder.mjs","names":[],"sources":["../../src/operations/query-builder.ts"],"sourcesContent":["import type { TableSchema } from \"../schema/types.js\";\n\n/**\n * Builds a SELECT query string for a single row by primary key\n */\nexport function buildSelectByPK(tableName: string, schema: TableSchema, pk: string): string {\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n return `SELECT * FROM \"${tableName}\" WHERE \"${pkColumn}\" = '${escapeSQLString(pk)}'`;\n}\n\n/**\n * Builds a SELECT query string for listing rows with optional limit and offset\n */\nexport function buildSelectAll(\n tableName: string,\n options?: {\n limit?: number;\n offset?: number;\n orderBy?: [string, \"asc\" | \"desc\"][];\n },\n): string {\n let query = `SELECT * FROM \"${tableName}\"`;\n\n if (options?.orderBy?.length) {\n const orderClauses = options.orderBy.map(([col, dir]) => `\"${col}\" ${dir.toUpperCase()}`);\n query += ` ORDER BY ${orderClauses.join(\", \")}`;\n }\n\n if (options?.limit !== undefined) {\n query += ` LIMIT ${options.limit}`;\n }\n\n if (options?.offset !== undefined) {\n query += ` OFFSET ${options.offset}`;\n }\n\n return query;\n}\n\n/**\n * Builds an INSERT query string from content object\n */\nexport function buildInsert(\n tableName: string,\n schema: TableSchema,\n content: Record<string, unknown>,\n): string {\n // Filter to only valid columns\n const validColumns = new Set(schema.columns.map((c) => c.name));\n const entries = Object.entries(content).filter(([key]) => validColumns.has(key));\n\n if (entries.length === 0) {\n throw new Error(`No valid columns provided for INSERT into ${tableName}`);\n }\n\n const columns = entries.map(([key]) => `\"${key}\"`).join(\", \");\n const values = entries.map(([, value]) => formatValue(value)).join(\", \");\n\n return `INSERT INTO \"${tableName}\" (${columns}) VALUES (${values})`;\n}\n\n/**\n * Builds an UPDATE query string from content object\n */\nexport function buildUpdate(\n tableName: string,\n schema: TableSchema,\n pk: string,\n content: Record<string, unknown>,\n): string {\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n\n // Filter to only valid columns, excluding PK\n const validColumns = new Set(schema.columns.map((c) => c.name));\n const entries = Object.entries(content).filter(\n ([key]) => validColumns.has(key) && key !== pkColumn,\n );\n\n if (entries.length === 0) {\n throw new Error(`No valid columns provided for UPDATE on ${tableName}`);\n }\n\n const setClauses = entries.map(([key, value]) => `\"${key}\" = ${formatValue(value)}`).join(\", \");\n\n return `UPDATE \"${tableName}\" SET ${setClauses} WHERE \"${pkColumn}\" = '${escapeSQLString(pk)}'`;\n}\n\n/**\n * Builds a DELETE query string by primary key\n */\nexport function buildDelete(tableName: string, schema: TableSchema, pk: string): string {\n const pkColumn = schema.primaryKey[0] ?? \"rowid\";\n return `DELETE FROM \"${tableName}\" WHERE \"${pkColumn}\" = '${escapeSQLString(pk)}'`;\n}\n\n/**\n * Formats a value for SQL insertion\n */\nexport function formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return \"NULL\";\n }\n\n if (typeof value === \"number\") {\n return String(value);\n }\n\n if (typeof value === \"boolean\") {\n return value ? \"1\" : \"0\";\n }\n\n if (value instanceof Date) {\n return `'${value.toISOString()}'`;\n }\n\n if (typeof value === \"object\") {\n return `'${escapeSQLString(JSON.stringify(value))}'`;\n }\n\n return `'${escapeSQLString(String(value))}'`;\n}\n\n/**\n * Escapes a string for safe SQL insertion\n */\nexport function escapeSQLString(str: string): string {\n return str.replace(/'/g, \"''\");\n}\n\n/**\n * Gets the last inserted rowid query string\n */\nexport function buildGetLastRowId(): string {\n return \"SELECT last_insert_rowid() as id\";\n}\n"],"mappings":";;;;AAKA,SAAgB,gBAAgB,WAAmB,QAAqB,IAAoB;AAE1F,QAAO,kBAAkB,UAAU,WADlB,OAAO,WAAW,MAAM,QACc,OAAO,gBAAgB,GAAG,CAAC;;;;;AAMpF,SAAgB,eACd,WACA,SAKQ;CACR,IAAI,QAAQ,kBAAkB,UAAU;AAExC,KAAI,SAAS,SAAS,QAAQ;EAC5B,MAAM,eAAe,QAAQ,QAAQ,KAAK,CAAC,KAAK,SAAS,IAAI,IAAI,IAAI,IAAI,aAAa,GAAG;AACzF,WAAS,aAAa,aAAa,KAAK,KAAK;;AAG/C,KAAI,SAAS,UAAU,OACrB,UAAS,UAAU,QAAQ;AAG7B,KAAI,SAAS,WAAW,OACtB,UAAS,WAAW,QAAQ;AAG9B,QAAO;;;;;AAMT,SAAgB,YACd,WACA,QACA,SACQ;CAER,MAAM,eAAe,IAAI,IAAI,OAAO,QAAQ,KAAK,MAAM,EAAE,KAAK,CAAC;CAC/D,MAAM,UAAU,OAAO,QAAQ,QAAQ,CAAC,QAAQ,CAAC,SAAS,aAAa,IAAI,IAAI,CAAC;AAEhF,KAAI,QAAQ,WAAW,EACrB,OAAM,IAAI,MAAM,6CAA6C,YAAY;AAM3E,QAAO,gBAAgB,UAAU,KAHjB,QAAQ,KAAK,CAAC,SAAS,IAAI,IAAI,GAAG,CAAC,KAAK,KAAK,CAGf,YAF/B,QAAQ,KAAK,GAAG,WAAW,YAAY,MAAM,CAAC,CAAC,KAAK,KAAK,CAEP;;;;;AAMnE,SAAgB,YACd,WACA,QACA,IACA,SACQ;CACR,MAAM,WAAW,OAAO,WAAW,MAAM;CAGzC,MAAM,eAAe,IAAI,IAAI,OAAO,QAAQ,KAAK,MAAM,EAAE,KAAK,CAAC;CAC/D,MAAM,UAAU,OAAO,QAAQ,QAAQ,CAAC,QACrC,CAAC,SAAS,aAAa,IAAI,IAAI,IAAI,QAAQ,SAC7C;AAED,KAAI,QAAQ,WAAW,EACrB,OAAM,IAAI,MAAM,2CAA2C,YAAY;AAKzE,QAAO,WAAW,UAAU,QAFT,QAAQ,KAAK,CAAC,KAAK,WAAW,IAAI,IAAI,MAAM,YAAY,MAAM,GAAG,CAAC,KAAK,KAAK,CAEhD,UAAU,SAAS,OAAO,gBAAgB,GAAG,CAAC;;;;;AAM/F,SAAgB,YAAY,WAAmB,QAAqB,IAAoB;AAEtF,QAAO,gBAAgB,UAAU,WADhB,OAAO,WAAW,MAAM,QACY,OAAO,gBAAgB,GAAG,CAAC;;;;;AAMlF,SAAgB,YAAY,OAAwB;AAClD,KAAI,UAAU,QAAQ,UAAU,OAC9B,QAAO;AAGT,KAAI,OAAO,UAAU,SACnB,QAAO,OAAO,MAAM;AAGtB,KAAI,OAAO,UAAU,UACnB,QAAO,QAAQ,MAAM;AAGvB,KAAI,iBAAiB,KACnB,QAAO,IAAI,MAAM,aAAa,CAAC;AAGjC,KAAI,OAAO,UAAU,SACnB,QAAO,IAAI,gBAAgB,KAAK,UAAU,MAAM,CAAC,CAAC;AAGpD,QAAO,IAAI,gBAAgB,OAAO,MAAM,CAAC,CAAC;;;;;AAM5C,SAAgB,gBAAgB,KAAqB;AACnD,QAAO,IAAI,QAAQ,MAAM,KAAK;;;;;AAMhC,SAAgB,oBAA4B;AAC1C,QAAO"}
|