@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.
Files changed (95) hide show
  1. package/LICENSE.md +17 -84
  2. package/README.md +0 -3
  3. package/dist/actions/built-in.cjs +142 -0
  4. package/dist/actions/built-in.d.cts +10 -0
  5. package/dist/actions/built-in.d.cts.map +1 -0
  6. package/dist/actions/built-in.d.mts +10 -0
  7. package/dist/actions/built-in.d.mts.map +1 -0
  8. package/dist/actions/built-in.mjs +143 -0
  9. package/dist/actions/built-in.mjs.map +1 -0
  10. package/dist/actions/registry.cjs +91 -0
  11. package/dist/actions/registry.d.cts +54 -0
  12. package/dist/actions/registry.d.cts.map +1 -0
  13. package/dist/actions/registry.d.mts +54 -0
  14. package/dist/actions/registry.d.mts.map +1 -0
  15. package/dist/actions/registry.mjs +91 -0
  16. package/dist/actions/registry.mjs.map +1 -0
  17. package/dist/actions/types.d.cts +56 -0
  18. package/dist/actions/types.d.cts.map +1 -0
  19. package/dist/actions/types.d.mts +56 -0
  20. package/dist/actions/types.d.mts.map +1 -0
  21. package/dist/config.cjs +27 -0
  22. package/dist/config.d.cts +81 -0
  23. package/dist/config.d.cts.map +1 -0
  24. package/dist/config.d.mts +81 -0
  25. package/dist/config.d.mts.map +1 -0
  26. package/dist/config.mjs +28 -0
  27. package/dist/config.mjs.map +1 -0
  28. package/dist/index.cjs +38 -1324
  29. package/dist/index.d.cts +14 -758
  30. package/dist/index.d.mts +14 -758
  31. package/dist/index.mjs +12 -1299
  32. package/dist/node/builder.cjs +179 -0
  33. package/dist/node/builder.d.cts +48 -0
  34. package/dist/node/builder.d.cts.map +1 -0
  35. package/dist/node/builder.d.mts +48 -0
  36. package/dist/node/builder.d.mts.map +1 -0
  37. package/dist/node/builder.mjs +172 -0
  38. package/dist/node/builder.mjs.map +1 -0
  39. package/dist/operations/crud.cjs +176 -0
  40. package/dist/operations/crud.d.cts +69 -0
  41. package/dist/operations/crud.d.cts.map +1 -0
  42. package/dist/operations/crud.d.mts +69 -0
  43. package/dist/operations/crud.d.mts.map +1 -0
  44. package/dist/operations/crud.mjs +177 -0
  45. package/dist/operations/crud.mjs.map +1 -0
  46. package/dist/operations/query-builder.cjs +77 -0
  47. package/dist/operations/query-builder.d.cts +34 -0
  48. package/dist/operations/query-builder.d.cts.map +1 -0
  49. package/dist/operations/query-builder.d.mts +34 -0
  50. package/dist/operations/query-builder.d.mts.map +1 -0
  51. package/dist/operations/query-builder.mjs +72 -0
  52. package/dist/operations/query-builder.mjs.map +1 -0
  53. package/dist/operations/search.cjs +141 -0
  54. package/dist/operations/search.d.cts +79 -0
  55. package/dist/operations/search.d.cts.map +1 -0
  56. package/dist/operations/search.d.mts +79 -0
  57. package/dist/operations/search.d.mts.map +1 -0
  58. package/dist/operations/search.mjs +141 -0
  59. package/dist/operations/search.mjs.map +1 -0
  60. package/dist/router/path-router.cjs +79 -0
  61. package/dist/router/path-router.d.cts +42 -0
  62. package/dist/router/path-router.d.cts.map +1 -0
  63. package/dist/router/path-router.d.mts +42 -0
  64. package/dist/router/path-router.d.mts.map +1 -0
  65. package/dist/router/path-router.mjs +76 -0
  66. package/dist/router/path-router.mjs.map +1 -0
  67. package/dist/router/types.d.cts +34 -0
  68. package/dist/router/types.d.cts.map +1 -0
  69. package/dist/router/types.d.mts +34 -0
  70. package/dist/router/types.d.mts.map +1 -0
  71. package/dist/schema/introspector.cjs +160 -0
  72. package/dist/schema/introspector.d.cts +49 -0
  73. package/dist/schema/introspector.d.cts.map +1 -0
  74. package/dist/schema/introspector.d.mts +49 -0
  75. package/dist/schema/introspector.d.mts.map +1 -0
  76. package/dist/schema/introspector.mjs +161 -0
  77. package/dist/schema/introspector.mjs.map +1 -0
  78. package/dist/schema/types.cjs +15 -0
  79. package/dist/schema/types.d.cts +104 -0
  80. package/dist/schema/types.d.cts.map +1 -0
  81. package/dist/schema/types.d.mts +104 -0
  82. package/dist/schema/types.d.mts.map +1 -0
  83. package/dist/schema/types.mjs +15 -0
  84. package/dist/schema/types.mjs.map +1 -0
  85. package/dist/sqlite-afs.cjs +264 -0
  86. package/dist/sqlite-afs.d.cts +152 -0
  87. package/dist/sqlite-afs.d.cts.map +1 -0
  88. package/dist/sqlite-afs.d.mts +152 -0
  89. package/dist/sqlite-afs.d.mts.map +1 -0
  90. package/dist/sqlite-afs.mjs +265 -0
  91. package/dist/sqlite-afs.mjs.map +1 -0
  92. package/package.json +3 -3
  93. package/dist/index.d.cts.map +0 -1
  94. package/dist/index.d.mts.map +0 -1
  95. 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"}