js-bao 0.2.11 → 0.2.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +174 -0
- package/dist/BaseModel-5YQCROYE.js +17 -0
- package/dist/BaseModel-5YQCROYE.js.map +1 -0
- package/dist/BaseModel-FCNWDJBH.js +17 -0
- package/dist/BaseModel-FCNWDJBH.js.map +1 -0
- package/dist/BrowserDatabaseFactory-PXOTK2DQ.js +119 -0
- package/dist/BrowserDatabaseFactory-PXOTK2DQ.js.map +1 -0
- package/dist/BrowserDatabaseFactory-WD4VX2VZ.js +119 -0
- package/dist/BrowserDatabaseFactory-WD4VX2VZ.js.map +1 -0
- package/dist/IncludeResolver-RCKQGNPZ.js +385 -0
- package/dist/IncludeResolver-RCKQGNPZ.js.map +1 -0
- package/dist/IncludeResolver-WGSQDMS7.js +385 -0
- package/dist/IncludeResolver-WGSQDMS7.js.map +1 -0
- package/dist/NodeDatabaseFactory-J4Z36UF3.js +165 -0
- package/dist/NodeDatabaseFactory-J4Z36UF3.js.map +1 -0
- package/dist/NodeDatabaseFactory-QIEKAXBM.js +10 -0
- package/dist/NodeDatabaseFactory-QIEKAXBM.js.map +1 -0
- package/dist/NodeSqliteEngine-HJSAYE4E.js +383 -0
- package/dist/NodeSqliteEngine-HJSAYE4E.js.map +1 -0
- package/dist/NodeSqliteEngine-I5SLWLME.js +383 -0
- package/dist/NodeSqliteEngine-I5SLWLME.js.map +1 -0
- package/dist/browser.cjs +3779 -3370
- package/dist/browser.d.cts +18 -1
- package/dist/browser.d.ts +18 -1
- package/dist/browser.js +3750 -3341
- package/dist/chunk-3PZWHUZO.js +4153 -0
- package/dist/chunk-3PZWHUZO.js.map +1 -0
- package/dist/chunk-53MS4MN7.js +373 -0
- package/dist/chunk-53MS4MN7.js.map +1 -0
- package/dist/chunk-65G2P4GL.js +709 -0
- package/dist/chunk-65G2P4GL.js.map +1 -0
- package/dist/chunk-6UX3YSCW.js +4151 -0
- package/dist/chunk-6UX3YSCW.js.map +1 -0
- package/dist/chunk-DANSD6BE.js +709 -0
- package/dist/chunk-DANSD6BE.js.map +1 -0
- package/dist/chunk-DF3JEQXA.js +373 -0
- package/dist/chunk-DF3JEQXA.js.map +1 -0
- package/dist/chunk-GO3APTPX.js +61 -0
- package/dist/chunk-GO3APTPX.js.map +1 -0
- package/dist/chunk-ID4U6IQC.js +53 -0
- package/dist/chunk-ID4U6IQC.js.map +1 -0
- package/dist/chunk-RQVS3LVL.js +165 -0
- package/dist/chunk-RQVS3LVL.js.map +1 -0
- package/dist/client.cjs +837 -0
- package/dist/client.d.cts +1101 -0
- package/dist/client.d.ts +1101 -0
- package/dist/client.js +806 -0
- package/dist/cloudflare-do.cjs +3637 -0
- package/dist/cloudflare-do.d.cts +1366 -0
- package/dist/cloudflare-do.d.ts +1366 -0
- package/dist/cloudflare-do.js +3614 -0
- package/dist/cloudflare.cjs +1048 -0
- package/dist/cloudflare.d.cts +1381 -0
- package/dist/cloudflare.d.ts +1381 -0
- package/dist/cloudflare.js +1017 -0
- package/dist/codegen.cjs +260 -19
- package/dist/environment-TOTQICSE.js +17 -0
- package/dist/environment-TOTQICSE.js.map +1 -0
- package/dist/index.cjs +1905 -1492
- package/dist/index.d.cts +19 -2
- package/dist/index.d.ts +19 -2
- package/dist/index.js +1870 -1457
- package/dist/node.cjs +4779 -4366
- package/dist/node.d.cts +18 -1
- package/dist/node.d.ts +18 -1
- package/dist/node.js +4758 -4345
- package/package.json +42 -13
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Logger,
|
|
3
|
+
quoteIdentifier
|
|
4
|
+
} from "./chunk-3PZWHUZO.js";
|
|
5
|
+
|
|
6
|
+
// src/engines/node/NodeSqliteEngine.ts
|
|
7
|
+
import { Mutex } from "async-mutex";
|
|
8
|
+
var TransactionalNodeSqliteOperations = class {
|
|
9
|
+
db;
|
|
10
|
+
engine;
|
|
11
|
+
constructor(db, engine) {
|
|
12
|
+
this.db = db;
|
|
13
|
+
this.engine = engine;
|
|
14
|
+
}
|
|
15
|
+
async insert(modelName, data) {
|
|
16
|
+
const tableName = this.engine.getTableName(modelName);
|
|
17
|
+
const columns = Object.keys(data);
|
|
18
|
+
const placeholders = columns.map(() => "?").join(", ");
|
|
19
|
+
const values = Object.values(data).map((value) => {
|
|
20
|
+
if (typeof value === "boolean") {
|
|
21
|
+
return value ? 1 : 0;
|
|
22
|
+
}
|
|
23
|
+
return value;
|
|
24
|
+
});
|
|
25
|
+
const insertSQL = `INSERT OR REPLACE INTO ${tableName} (${columns.join(
|
|
26
|
+
", "
|
|
27
|
+
)}) VALUES (${placeholders})`;
|
|
28
|
+
const stmt = this.db.prepare(insertSQL);
|
|
29
|
+
stmt.run(...values);
|
|
30
|
+
}
|
|
31
|
+
async delete(modelName, id) {
|
|
32
|
+
const tableName = this.engine.getTableName(modelName);
|
|
33
|
+
const deleteSQL = `DELETE FROM ${tableName} WHERE id = ?`;
|
|
34
|
+
const stmt = this.db.prepare(deleteSQL);
|
|
35
|
+
stmt.run(id);
|
|
36
|
+
}
|
|
37
|
+
async query(sql, params) {
|
|
38
|
+
const stmt = this.db.prepare(sql);
|
|
39
|
+
const results = params ? stmt.all(...params) : stmt.all();
|
|
40
|
+
return results;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var NodeSqliteEngine = class {
|
|
44
|
+
db = null;
|
|
45
|
+
tableNames = /* @__PURE__ */ new Set();
|
|
46
|
+
mutex = new Mutex();
|
|
47
|
+
readyPromise;
|
|
48
|
+
betterSqlite3 = null;
|
|
49
|
+
numOpenTransactions = 0;
|
|
50
|
+
constructor(options) {
|
|
51
|
+
Logger.debug("[NodeSqliteEngine] Constructor called. Initializing...");
|
|
52
|
+
this.readyPromise = this.initialize(options);
|
|
53
|
+
}
|
|
54
|
+
async ensureReady() {
|
|
55
|
+
return this.readyPromise;
|
|
56
|
+
}
|
|
57
|
+
async initialize(options) {
|
|
58
|
+
Logger.info("[NodeSqliteEngine] Initializing Node.js SQLite engine...");
|
|
59
|
+
try {
|
|
60
|
+
const betterSqlite3Module = await import("better-sqlite3");
|
|
61
|
+
this.betterSqlite3 = betterSqlite3Module.default || betterSqlite3Module;
|
|
62
|
+
const filePath = options?.filePath || ":memory:";
|
|
63
|
+
const dbOptions = options?.options || {};
|
|
64
|
+
Logger.debug(
|
|
65
|
+
`[NodeSqliteEngine] Opening SQLite database at: ${filePath}`
|
|
66
|
+
);
|
|
67
|
+
this.db = new this.betterSqlite3(filePath, dbOptions);
|
|
68
|
+
if (!this.db) {
|
|
69
|
+
throw new Error("Failed to create SQLite database instance");
|
|
70
|
+
}
|
|
71
|
+
if (filePath !== ":memory:") {
|
|
72
|
+
this.db.exec("PRAGMA journal_mode = WAL");
|
|
73
|
+
}
|
|
74
|
+
Logger.info(
|
|
75
|
+
"[NodeSqliteEngine] SQLite database initialized successfully."
|
|
76
|
+
);
|
|
77
|
+
this.updateTableNames();
|
|
78
|
+
} catch (error) {
|
|
79
|
+
Logger.error(
|
|
80
|
+
"[NodeSqliteEngine] Error during SQLite initialization:",
|
|
81
|
+
error
|
|
82
|
+
);
|
|
83
|
+
throw new Error(
|
|
84
|
+
`Failed to initialize Node.js SQLite engine: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
updateTableNames() {
|
|
89
|
+
if (!this.db) return;
|
|
90
|
+
const stmt = this.db.prepare(
|
|
91
|
+
"SELECT name FROM sqlite_master WHERE type='table'"
|
|
92
|
+
);
|
|
93
|
+
const tables = stmt.all();
|
|
94
|
+
this.tableNames.clear();
|
|
95
|
+
tables.forEach((table) => this.tableNames.add(table.name));
|
|
96
|
+
Logger.debug(
|
|
97
|
+
"[NodeSqliteEngine] Updated table names:",
|
|
98
|
+
Array.from(this.tableNames)
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
getTableName(modelName) {
|
|
102
|
+
return `model_${modelName.toLowerCase()}`;
|
|
103
|
+
}
|
|
104
|
+
mapTypeToSQL(type) {
|
|
105
|
+
switch (type.toLowerCase()) {
|
|
106
|
+
case "string":
|
|
107
|
+
return "TEXT";
|
|
108
|
+
case "number":
|
|
109
|
+
return "REAL";
|
|
110
|
+
case "boolean":
|
|
111
|
+
return "INTEGER";
|
|
112
|
+
case "date":
|
|
113
|
+
return "TEXT";
|
|
114
|
+
default:
|
|
115
|
+
return "TEXT";
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async createTable(modelName, schema, _options) {
|
|
119
|
+
await this.ensureReady();
|
|
120
|
+
if (!this.db) throw new Error("SQLite not initialized for createTable");
|
|
121
|
+
const tableName = this.getTableName(modelName);
|
|
122
|
+
const quotedTableName = quoteIdentifier(tableName);
|
|
123
|
+
const idColumn = quoteIdentifier("id");
|
|
124
|
+
const typeColumn = quoteIdentifier("type");
|
|
125
|
+
if (this.tableNames.has(tableName)) {
|
|
126
|
+
Logger.debug(
|
|
127
|
+
`[NodeSqliteEngine] Table ${tableName} already exists, skipping creation.`
|
|
128
|
+
);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const columns = Array.from(schema.entries()).filter(([field]) => field !== "id" && field !== "type").map(
|
|
132
|
+
([field, fieldOptions]) => `${quoteIdentifier(field)} ${this.mapTypeToSQL(fieldOptions.type)}`
|
|
133
|
+
);
|
|
134
|
+
const metadataColumns = [
|
|
135
|
+
`${quoteIdentifier("_meta_doc_id")} TEXT`,
|
|
136
|
+
`${quoteIdentifier("_meta_permission_hint")} TEXT`
|
|
137
|
+
];
|
|
138
|
+
const createTableSQL = `CREATE TABLE IF NOT EXISTS ${quotedTableName} (
|
|
139
|
+
${idColumn} TEXT PRIMARY KEY,
|
|
140
|
+
${typeColumn} TEXT,
|
|
141
|
+
${columns.join(", ")}${columns.length > 0 ? ", " : ""}${metadataColumns.join(", ")}
|
|
142
|
+
)`;
|
|
143
|
+
Logger.debug(
|
|
144
|
+
`[NodeSqliteEngine] Creating table ${tableName}:`,
|
|
145
|
+
createTableSQL
|
|
146
|
+
);
|
|
147
|
+
this.db.exec(createTableSQL);
|
|
148
|
+
for (const [field, fieldOptions] of schema.entries()) {
|
|
149
|
+
if (fieldOptions && fieldOptions.indexed && field !== "id") {
|
|
150
|
+
const indexName = `idx_${tableName}_${field}`;
|
|
151
|
+
const quotedIndexName = quoteIdentifier(indexName);
|
|
152
|
+
const quotedField = quoteIdentifier(field);
|
|
153
|
+
const createIndexSQL = `CREATE INDEX IF NOT EXISTS ${quotedIndexName} ON ${quotedTableName} (${quotedField})`;
|
|
154
|
+
Logger.debug(`[NodeSqliteEngine] Creating index ${indexName}`);
|
|
155
|
+
this.db.exec(createIndexSQL);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
const docIdIndexName = `idx_${tableName}_meta_doc_id`;
|
|
159
|
+
const docIdIndexSQL = `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(
|
|
160
|
+
docIdIndexName
|
|
161
|
+
)} ON ${quotedTableName} (${quoteIdentifier("_meta_doc_id")})`;
|
|
162
|
+
this.db.exec(docIdIndexSQL);
|
|
163
|
+
this.updateTableNames();
|
|
164
|
+
Logger.info(`[NodeSqliteEngine] Table ${tableName} created successfully.`);
|
|
165
|
+
}
|
|
166
|
+
async createStringSetJunctionTable(modelName, fieldName) {
|
|
167
|
+
await this.ensureReady();
|
|
168
|
+
if (!this.db)
|
|
169
|
+
throw new Error(
|
|
170
|
+
"SQLite not initialized for createStringSetJunctionTable"
|
|
171
|
+
);
|
|
172
|
+
const junctionTableName = `${this.getTableName(modelName)}_${fieldName}`;
|
|
173
|
+
const quotedJunctionTable = quoteIdentifier(junctionTableName);
|
|
174
|
+
const foreignKeyColumn = `${modelName.toLowerCase()}_id`;
|
|
175
|
+
const quotedForeignKey = quoteIdentifier(foreignKeyColumn);
|
|
176
|
+
const quotedIdColumn = quoteIdentifier("id");
|
|
177
|
+
const quotedValueColumn = quoteIdentifier("value");
|
|
178
|
+
if (this.tableNames.has(junctionTableName)) {
|
|
179
|
+
Logger.debug(
|
|
180
|
+
`[NodeSqliteEngine] StringSet junction table ${junctionTableName} already exists, skipping creation.`
|
|
181
|
+
);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const createTableSQL = `CREATE TABLE IF NOT EXISTS ${quotedJunctionTable} (
|
|
185
|
+
${quotedIdColumn} TEXT PRIMARY KEY,
|
|
186
|
+
${quotedForeignKey} TEXT NOT NULL,
|
|
187
|
+
${quotedValueColumn} TEXT NOT NULL,
|
|
188
|
+
UNIQUE(${quotedForeignKey}, ${quotedValueColumn})
|
|
189
|
+
)`;
|
|
190
|
+
Logger.info(
|
|
191
|
+
`[NodeSqliteEngine] Creating StringSet junction table ${junctionTableName} for ${modelName}.${fieldName}`
|
|
192
|
+
);
|
|
193
|
+
this.db.exec(createTableSQL);
|
|
194
|
+
const indexName = `idx_${junctionTableName}_${modelName.toLowerCase()}_id`;
|
|
195
|
+
const indexSQL = `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(
|
|
196
|
+
indexName
|
|
197
|
+
)} ON ${quotedJunctionTable} (${quotedForeignKey})`;
|
|
198
|
+
this.db.exec(indexSQL);
|
|
199
|
+
this.updateTableNames();
|
|
200
|
+
Logger.info(
|
|
201
|
+
`[NodeSqliteEngine] StringSet junction table ${junctionTableName} created successfully.`
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
async insertStringSetValues(modelName, fieldName, recordId, values) {
|
|
205
|
+
await this.ensureReady();
|
|
206
|
+
if (!this.db)
|
|
207
|
+
throw new Error("SQLite not initialized for insertStringSetValues");
|
|
208
|
+
if (values.length === 0) return;
|
|
209
|
+
const junctionTableName = `${this.getTableName(modelName)}_${fieldName}`;
|
|
210
|
+
const quotedJunctionTable = quoteIdentifier(junctionTableName);
|
|
211
|
+
const quotedIdColumn = quoteIdentifier("id");
|
|
212
|
+
const quotedForeignKey = quoteIdentifier(`${modelName.toLowerCase()}_id`);
|
|
213
|
+
const quotedValueColumn = quoteIdentifier("value");
|
|
214
|
+
const insertSQL = `INSERT OR IGNORE INTO ${quotedJunctionTable} (${quotedIdColumn}, ${quotedForeignKey}, ${quotedValueColumn}) VALUES (?, ?, ?)`;
|
|
215
|
+
const stmt = this.db.prepare(insertSQL);
|
|
216
|
+
for (const value of values) {
|
|
217
|
+
const id = `${recordId}_${value}`;
|
|
218
|
+
stmt.run(id, recordId, value);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async removeStringSetValues(modelName, fieldName, recordId, values) {
|
|
222
|
+
await this.ensureReady();
|
|
223
|
+
if (!this.db)
|
|
224
|
+
throw new Error("SQLite not initialized for removeStringSetValues");
|
|
225
|
+
if (values.length === 0) return;
|
|
226
|
+
const junctionTableName = `${this.getTableName(modelName)}_${fieldName}`;
|
|
227
|
+
const quotedJunctionTable = quoteIdentifier(junctionTableName);
|
|
228
|
+
const quotedForeignKey = quoteIdentifier(`${modelName.toLowerCase()}_id`);
|
|
229
|
+
const quotedValueColumn = quoteIdentifier("value");
|
|
230
|
+
const deleteSQL = `DELETE FROM ${quotedJunctionTable} WHERE ${quotedForeignKey} = ? AND ${quotedValueColumn} = ?`;
|
|
231
|
+
const stmt = this.db.prepare(deleteSQL);
|
|
232
|
+
for (const value of values) {
|
|
233
|
+
stmt.run(recordId, value);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
async insert(modelName, data) {
|
|
237
|
+
await this.ensureReady();
|
|
238
|
+
if (!this.db) throw new Error("SQLite not initialized for insert");
|
|
239
|
+
const tableName = this.getTableName(modelName);
|
|
240
|
+
const quotedTableName = quoteIdentifier(tableName);
|
|
241
|
+
const columns = Object.keys(data);
|
|
242
|
+
const quotedColumns = columns.map((column) => quoteIdentifier(column));
|
|
243
|
+
const placeholders = columns.map(() => "?").join(", ");
|
|
244
|
+
const values = Object.values(data).map((value) => {
|
|
245
|
+
if (typeof value === "boolean") {
|
|
246
|
+
return value ? 1 : 0;
|
|
247
|
+
}
|
|
248
|
+
return value;
|
|
249
|
+
});
|
|
250
|
+
const insertSQL = `INSERT OR REPLACE INTO ${quotedTableName} (${quotedColumns.join(
|
|
251
|
+
", "
|
|
252
|
+
)}) VALUES (${placeholders})`;
|
|
253
|
+
const stmt = this.db.prepare(insertSQL);
|
|
254
|
+
stmt.run(...values);
|
|
255
|
+
}
|
|
256
|
+
async delete(modelName, id) {
|
|
257
|
+
await this.ensureReady();
|
|
258
|
+
if (!this.db) throw new Error("SQLite not initialized for delete");
|
|
259
|
+
const tableName = this.getTableName(modelName);
|
|
260
|
+
const deleteSQL = `DELETE FROM ${quoteIdentifier(
|
|
261
|
+
tableName
|
|
262
|
+
)} WHERE ${quoteIdentifier("id")} = ?`;
|
|
263
|
+
const stmt = this.db.prepare(deleteSQL);
|
|
264
|
+
stmt.run(id);
|
|
265
|
+
}
|
|
266
|
+
async deleteByDocumentId(modelName, docId) {
|
|
267
|
+
await this.ensureReady();
|
|
268
|
+
if (!this.db)
|
|
269
|
+
throw new Error("SQLite not initialized for deleteByDocumentId");
|
|
270
|
+
const tableName = this.getTableName(modelName);
|
|
271
|
+
const quotedTableName = quoteIdentifier(tableName);
|
|
272
|
+
if (!this.tableNames.has(tableName)) {
|
|
273
|
+
Logger.debug(
|
|
274
|
+
`[NodeSqliteEngine] Skipping deleteByDocumentId for ${tableName}; table does not exist.`
|
|
275
|
+
);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const deleteSQL = `DELETE FROM ${quotedTableName} WHERE ${quoteIdentifier(
|
|
279
|
+
"_meta_doc_id"
|
|
280
|
+
)} = ?`;
|
|
281
|
+
const stmt = this.db.prepare(deleteSQL);
|
|
282
|
+
stmt.run(docId);
|
|
283
|
+
for (const existingTableName of this.tableNames) {
|
|
284
|
+
if (existingTableName.startsWith(`${tableName}_`)) {
|
|
285
|
+
const quotedExistingTable = quoteIdentifier(existingTableName);
|
|
286
|
+
const quotedForeignKey = quoteIdentifier(`${modelName.toLowerCase()}_id`);
|
|
287
|
+
const junctionDeleteSQL = `DELETE FROM ${quotedExistingTable} WHERE ${quotedForeignKey} IN (
|
|
288
|
+
SELECT ${quoteIdentifier("id")} FROM ${quotedTableName} WHERE ${quoteIdentifier(
|
|
289
|
+
"_meta_doc_id"
|
|
290
|
+
)} = ?
|
|
291
|
+
)`;
|
|
292
|
+
try {
|
|
293
|
+
const junctionStmt = this.db.prepare(junctionDeleteSQL);
|
|
294
|
+
const result = junctionStmt.run(docId);
|
|
295
|
+
Logger.info(
|
|
296
|
+
`[NodeSqliteEngine] Cleared junction table ${existingTableName} for document ${docId}; removed ${result.changes} rows.`
|
|
297
|
+
);
|
|
298
|
+
} catch (error) {
|
|
299
|
+
console.warn(
|
|
300
|
+
`[NodeSqliteEngine] Warning: Could not clean up junction table ${existingTableName}:`,
|
|
301
|
+
error
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
async query(sql, params) {
|
|
308
|
+
await this.ensureReady();
|
|
309
|
+
if (!this.db) throw new Error("SQLite not initialized for query");
|
|
310
|
+
const stmt = this.db.prepare(sql);
|
|
311
|
+
const results = params ? stmt.all(...params) : stmt.all();
|
|
312
|
+
return results;
|
|
313
|
+
}
|
|
314
|
+
async withTransaction(callback) {
|
|
315
|
+
await this.ensureReady();
|
|
316
|
+
if (!this.db) throw new Error("SQLite not initialized for transaction");
|
|
317
|
+
let transactionStartedHere = false;
|
|
318
|
+
await this.mutex.runExclusive(async () => {
|
|
319
|
+
if (this.numOpenTransactions === 0) {
|
|
320
|
+
this.db.exec("BEGIN TRANSACTION");
|
|
321
|
+
transactionStartedHere = true;
|
|
322
|
+
}
|
|
323
|
+
this.numOpenTransactions++;
|
|
324
|
+
});
|
|
325
|
+
const transactionalOps = new TransactionalNodeSqliteOperations(
|
|
326
|
+
this.db,
|
|
327
|
+
this
|
|
328
|
+
);
|
|
329
|
+
try {
|
|
330
|
+
const result = await callback(transactionalOps);
|
|
331
|
+
await this.mutex.runExclusive(async () => {
|
|
332
|
+
this.numOpenTransactions--;
|
|
333
|
+
if (this.numOpenTransactions === 0) {
|
|
334
|
+
this.db.exec("COMMIT");
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
return result;
|
|
338
|
+
} catch (error) {
|
|
339
|
+
console.error(
|
|
340
|
+
"[NodeSqliteEngine] Error in transaction, rolling back:",
|
|
341
|
+
error
|
|
342
|
+
);
|
|
343
|
+
await this.mutex.runExclusive(async () => {
|
|
344
|
+
if (this.db && this.numOpenTransactions > 0 && transactionStartedHere) {
|
|
345
|
+
try {
|
|
346
|
+
this.db.exec("ROLLBACK");
|
|
347
|
+
} catch (rollbackError) {
|
|
348
|
+
console.error(
|
|
349
|
+
"[NodeSqliteEngine] Error during ROLLBACK:",
|
|
350
|
+
rollbackError
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
this.numOpenTransactions = 0;
|
|
355
|
+
});
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
async close() {
|
|
360
|
+
await this.readyPromise;
|
|
361
|
+
if (this.db) {
|
|
362
|
+
Logger.info("[NodeSqliteEngine] Closing SQLite database...");
|
|
363
|
+
this.db.close();
|
|
364
|
+
this.db = null;
|
|
365
|
+
Logger.info("[NodeSqliteEngine] SQLite database closed.");
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async destroy() {
|
|
369
|
+
await this.close();
|
|
370
|
+
this.tableNames.clear();
|
|
371
|
+
Logger.info("[NodeSqliteEngine] SQLite engine destroyed.");
|
|
372
|
+
}
|
|
373
|
+
async getTableSchema(_tableName) {
|
|
374
|
+
return {};
|
|
375
|
+
}
|
|
376
|
+
getLastErrorMessage() {
|
|
377
|
+
return void 0;
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
export {
|
|
381
|
+
NodeSqliteEngine
|
|
382
|
+
};
|
|
383
|
+
//# sourceMappingURL=NodeSqliteEngine-HJSAYE4E.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/engines/node/NodeSqliteEngine.ts"],"sourcesContent":["import {\n DatabaseEngine,\n ITransactionalDatabaseOperations,\n} from \"../DatabaseEngine\";\nimport { ModelOptions } from \"../../types/ormTypes\";\nimport { Logger } from \"../../models/BaseModel\";\nimport { Mutex } from \"async-mutex\";\nimport { quoteIdentifier } from \"../../utils/sql\";\n\n// Type definitions for better-sqlite3 (we'll use dynamic import to avoid bundling issues)\ninterface Database {\n exec(sql: string): this;\n prepare(sql: string): Statement;\n close(): this;\n inTransaction: boolean;\n transaction<T extends any[], R>(fn: (...args: T) => R): (...args: T) => R;\n}\n\ninterface Statement {\n run(...params: any[]): RunResult;\n get(...params: any[]): any;\n all(...params: any[]): any[];\n bind(...params: any[]): this;\n finalize(): this;\n}\n\ninterface RunResult {\n changes: number;\n lastInsertRowid: number | bigint;\n}\n\nexport interface NodeSqliteEngineOptions {\n /**\n * Path to the SQLite database file.\n * Use ':memory:' for in-memory database (default)\n */\n filePath?: string;\n\n /**\n * SQLite connection options\n */\n options?: {\n readonly?: boolean;\n fileMustExist?: boolean;\n timeout?: number;\n verbose?: (...args: any[]) => void;\n };\n}\n\nclass TransactionalNodeSqliteOperations\n implements ITransactionalDatabaseOperations\n{\n private db: Database;\n private engine: NodeSqliteEngine;\n\n constructor(db: Database, engine: NodeSqliteEngine) {\n this.db = db;\n this.engine = engine;\n }\n\n async insert(modelName: string, data: any): Promise<void> {\n const tableName = this.engine.getTableName(modelName);\n const columns = Object.keys(data);\n const placeholders = columns.map(() => \"?\").join(\", \");\n\n // Convert values for SQLite compatibility\n const values = Object.values(data).map((value) => {\n // Convert boolean to integer for SQLite\n if (typeof value === \"boolean\") {\n return value ? 1 : 0;\n }\n return value;\n });\n\n const insertSQL = `INSERT OR REPLACE INTO ${tableName} (${columns.join(\n \", \"\n )}) VALUES (${placeholders})`;\n\n const stmt = this.db.prepare(insertSQL);\n stmt.run(...values);\n }\n\n async delete(modelName: string, id: string): Promise<void> {\n const tableName = this.engine.getTableName(modelName);\n const deleteSQL = `DELETE FROM ${tableName} WHERE id = ?`;\n\n const stmt = this.db.prepare(deleteSQL);\n stmt.run(id);\n }\n\n async query<T extends Record<string, any>>(\n sql: string,\n params?: any[]\n ): Promise<T[]> {\n const stmt = this.db.prepare(sql);\n const results = params ? stmt.all(...params) : stmt.all();\n return results as T[];\n }\n}\n\nexport class NodeSqliteEngine implements DatabaseEngine {\n private db: Database | null = null;\n private tableNames: Set<string> = new Set();\n private mutex: Mutex = new Mutex();\n private readyPromise: Promise<void>;\n private betterSqlite3: any = null;\n private numOpenTransactions: number = 0;\n\n constructor(options?: NodeSqliteEngineOptions) {\n Logger.debug(\"[NodeSqliteEngine] Constructor called. Initializing...\");\n this.readyPromise = this.initialize(options);\n }\n\n public async ensureReady(): Promise<void> {\n return this.readyPromise;\n }\n\n private async initialize(options?: NodeSqliteEngineOptions): Promise<void> {\n Logger.info(\"[NodeSqliteEngine] Initializing Node.js SQLite engine...\");\n\n try {\n // Dynamic import to avoid bundling issues in browser builds\n // @ts-ignore - Optional dependency, may not be available\n const betterSqlite3Module = await import(\"better-sqlite3\");\n this.betterSqlite3 = betterSqlite3Module.default || betterSqlite3Module;\n\n const filePath = options?.filePath || \":memory:\";\n const dbOptions = options?.options || {};\n\n Logger.debug(\n `[NodeSqliteEngine] Opening SQLite database at: ${filePath}`\n );\n this.db = new this.betterSqlite3(filePath, dbOptions);\n\n if (!this.db) {\n throw new Error(\"Failed to create SQLite database instance\");\n }\n\n // Enable WAL mode for better performance and concurrency\n if (filePath !== \":memory:\") {\n this.db.exec(\"PRAGMA journal_mode = WAL\");\n }\n\n Logger.info(\n \"[NodeSqliteEngine] SQLite database initialized successfully.\"\n );\n this.updateTableNames();\n } catch (error) {\n Logger.error(\n \"[NodeSqliteEngine] Error during SQLite initialization:\",\n error\n );\n throw new Error(\n `Failed to initialize Node.js SQLite engine: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`\n );\n }\n }\n\n private updateTableNames(): void {\n if (!this.db) return;\n\n const stmt = this.db.prepare(\n \"SELECT name FROM sqlite_master WHERE type='table'\"\n );\n const tables = stmt.all() as { name: string }[];\n\n this.tableNames.clear();\n tables.forEach((table) => this.tableNames.add(table.name));\n\n Logger.debug(\n \"[NodeSqliteEngine] Updated table names:\",\n Array.from(this.tableNames)\n );\n }\n\n public getTableName(modelName: string): string {\n return `model_${modelName.toLowerCase()}`;\n }\n\n private mapTypeToSQL(type: string): string {\n switch (type.toLowerCase()) {\n case \"string\":\n return \"TEXT\";\n case \"number\":\n return \"REAL\";\n case \"boolean\":\n return \"INTEGER\";\n case \"date\":\n return \"TEXT\";\n default:\n return \"TEXT\";\n }\n }\n\n async createTable(\n modelName: string,\n schema: Map<string, any>,\n _options: ModelOptions\n ): Promise<void> {\n await this.ensureReady();\n if (!this.db) throw new Error(\"SQLite not initialized for createTable\");\n\n const tableName = this.getTableName(modelName);\n const quotedTableName = quoteIdentifier(tableName);\n const idColumn = quoteIdentifier(\"id\");\n const typeColumn = quoteIdentifier(\"type\");\n if (this.tableNames.has(tableName)) {\n Logger.debug(\n `[NodeSqliteEngine] Table ${tableName} already exists, skipping creation.`\n );\n return;\n }\n\n const columns = Array.from(schema.entries())\n .filter(([field]) => field !== \"id\" && field !== \"type\")\n .map(\n ([field, fieldOptions]) =>\n `${quoteIdentifier(field)} ${this.mapTypeToSQL(fieldOptions.type)}`\n );\n\n // Add metadata fields for multi-document support\n const metadataColumns = [\n `${quoteIdentifier(\"_meta_doc_id\")} TEXT`,\n `${quoteIdentifier(\"_meta_permission_hint\")} TEXT`,\n ];\n\n const createTableSQL = `CREATE TABLE IF NOT EXISTS ${quotedTableName} (\n ${idColumn} TEXT PRIMARY KEY,\n ${typeColumn} TEXT,\n ${columns.join(\", \")}${\n columns.length > 0 ? \", \" : \"\"\n }${metadataColumns.join(\", \")}\n )`;\n\n Logger.debug(\n `[NodeSqliteEngine] Creating table ${tableName}:`,\n createTableSQL\n );\n this.db.exec(createTableSQL);\n\n // Create indexes for fields marked as indexed: true\n for (const [field, fieldOptions] of schema.entries()) {\n if (fieldOptions && fieldOptions.indexed && field !== \"id\") {\n const indexName = `idx_${tableName}_${field}`;\n const quotedIndexName = quoteIdentifier(indexName);\n const quotedField = quoteIdentifier(field);\n const createIndexSQL = `CREATE INDEX IF NOT EXISTS ${quotedIndexName} ON ${quotedTableName} (${quotedField})`;\n Logger.debug(`[NodeSqliteEngine] Creating index ${indexName}`);\n this.db.exec(createIndexSQL);\n }\n }\n\n // Create index on _meta_doc_id for efficient document-based queries\n const docIdIndexName = `idx_${tableName}_meta_doc_id`;\n const docIdIndexSQL = `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(\n docIdIndexName\n )} ON ${quotedTableName} (${quoteIdentifier(\"_meta_doc_id\")})`;\n this.db.exec(docIdIndexSQL);\n\n this.updateTableNames();\n Logger.info(`[NodeSqliteEngine] Table ${tableName} created successfully.`);\n }\n\n async createStringSetJunctionTable(\n modelName: string,\n fieldName: string\n ): Promise<void> {\n await this.ensureReady();\n if (!this.db)\n throw new Error(\n \"SQLite not initialized for createStringSetJunctionTable\"\n );\n\n const junctionTableName = `${this.getTableName(modelName)}_${fieldName}`;\n const quotedJunctionTable = quoteIdentifier(junctionTableName);\n const foreignKeyColumn = `${modelName.toLowerCase()}_id`;\n const quotedForeignKey = quoteIdentifier(foreignKeyColumn);\n const quotedIdColumn = quoteIdentifier(\"id\");\n const quotedValueColumn = quoteIdentifier(\"value\");\n\n if (this.tableNames.has(junctionTableName)) {\n Logger.debug(\n `[NodeSqliteEngine] StringSet junction table ${junctionTableName} already exists, skipping creation.`\n );\n return; // Table already exists\n }\n\n const createTableSQL = `CREATE TABLE IF NOT EXISTS ${quotedJunctionTable} (\n ${quotedIdColumn} TEXT PRIMARY KEY,\n ${quotedForeignKey} TEXT NOT NULL,\n ${quotedValueColumn} TEXT NOT NULL,\n UNIQUE(${quotedForeignKey}, ${quotedValueColumn})\n )`;\n\n Logger.info(\n `[NodeSqliteEngine] Creating StringSet junction table ${junctionTableName} for ${modelName}.${fieldName}`\n );\n this.db.exec(createTableSQL);\n\n // Create index for faster lookups\n const indexName = `idx_${junctionTableName}_${modelName.toLowerCase()}_id`;\n const indexSQL = `CREATE INDEX IF NOT EXISTS ${quoteIdentifier(\n indexName\n )} ON ${quotedJunctionTable} (${quotedForeignKey})`;\n this.db.exec(indexSQL);\n\n this.updateTableNames();\n Logger.info(\n `[NodeSqliteEngine] StringSet junction table ${junctionTableName} created successfully.`\n );\n }\n\n async insertStringSetValues(\n modelName: string,\n fieldName: string,\n recordId: string,\n values: string[]\n ): Promise<void> {\n await this.ensureReady();\n if (!this.db)\n throw new Error(\"SQLite not initialized for insertStringSetValues\");\n\n if (values.length === 0) return;\n\n const junctionTableName = `${this.getTableName(modelName)}_${fieldName}`;\n const quotedJunctionTable = quoteIdentifier(junctionTableName);\n const quotedIdColumn = quoteIdentifier(\"id\");\n const quotedForeignKey = quoteIdentifier(`${modelName.toLowerCase()}_id`);\n const quotedValueColumn = quoteIdentifier(\"value\");\n const insertSQL = `INSERT OR IGNORE INTO ${quotedJunctionTable} (${quotedIdColumn}, ${quotedForeignKey}, ${quotedValueColumn}) VALUES (?, ?, ?)`;\n\n const stmt = this.db.prepare(insertSQL);\n\n for (const value of values) {\n const id = `${recordId}_${value}`;\n stmt.run(id, recordId, value);\n }\n }\n\n async removeStringSetValues(\n modelName: string,\n fieldName: string,\n recordId: string,\n values: string[]\n ): Promise<void> {\n await this.ensureReady();\n if (!this.db)\n throw new Error(\"SQLite not initialized for removeStringSetValues\");\n\n if (values.length === 0) return;\n\n const junctionTableName = `${this.getTableName(modelName)}_${fieldName}`;\n const quotedJunctionTable = quoteIdentifier(junctionTableName);\n const quotedForeignKey = quoteIdentifier(`${modelName.toLowerCase()}_id`);\n const quotedValueColumn = quoteIdentifier(\"value\");\n const deleteSQL = `DELETE FROM ${quotedJunctionTable} WHERE ${quotedForeignKey} = ? AND ${quotedValueColumn} = ?`;\n\n const stmt = this.db.prepare(deleteSQL);\n\n for (const value of values) {\n stmt.run(recordId, value);\n }\n }\n\n async insert(modelName: string, data: any): Promise<void> {\n await this.ensureReady();\n if (!this.db) throw new Error(\"SQLite not initialized for insert\");\n\n const tableName = this.getTableName(modelName);\n const quotedTableName = quoteIdentifier(tableName);\n const columns = Object.keys(data);\n const quotedColumns = columns.map((column) => quoteIdentifier(column));\n const placeholders = columns.map(() => \"?\").join(\", \");\n\n // Convert values for SQLite compatibility\n const values = Object.values(data).map((value) => {\n // Convert boolean to integer for SQLite\n if (typeof value === \"boolean\") {\n return value ? 1 : 0;\n }\n return value;\n });\n\n const insertSQL = `INSERT OR REPLACE INTO ${quotedTableName} (${quotedColumns.join(\n \", \"\n )}) VALUES (${placeholders})`;\n\n const stmt = this.db.prepare(insertSQL);\n stmt.run(...values);\n }\n\n async delete(modelName: string, id: string): Promise<void> {\n await this.ensureReady();\n if (!this.db) throw new Error(\"SQLite not initialized for delete\");\n\n const tableName = this.getTableName(modelName);\n const deleteSQL = `DELETE FROM ${quoteIdentifier(\n tableName\n )} WHERE ${quoteIdentifier(\"id\")} = ?`;\n\n const stmt = this.db.prepare(deleteSQL);\n stmt.run(id);\n }\n\n async deleteByDocumentId(modelName: string, docId: string): Promise<void> {\n await this.ensureReady();\n if (!this.db)\n throw new Error(\"SQLite not initialized for deleteByDocumentId\");\n\n const tableName = this.getTableName(modelName);\n const quotedTableName = quoteIdentifier(tableName);\n\n if (!this.tableNames.has(tableName)) {\n Logger.debug(\n `[NodeSqliteEngine] Skipping deleteByDocumentId for ${tableName}; table does not exist.`\n );\n return;\n }\n\n // Delete all records with the specified document ID\n const deleteSQL = `DELETE FROM ${quotedTableName} WHERE ${quoteIdentifier(\n \"_meta_doc_id\"\n )} = ?`;\n const stmt = this.db.prepare(deleteSQL);\n stmt.run(docId);\n\n // Also clean up StringSet junction tables\n for (const existingTableName of this.tableNames) {\n if (existingTableName.startsWith(`${tableName}_`)) {\n // This is likely a StringSet junction table\n const quotedExistingTable = quoteIdentifier(existingTableName);\n const quotedForeignKey = quoteIdentifier(`${modelName.toLowerCase()}_id`);\n const junctionDeleteSQL = `DELETE FROM ${quotedExistingTable} WHERE ${quotedForeignKey} IN (\n SELECT ${quoteIdentifier(\"id\")} FROM ${quotedTableName} WHERE ${quoteIdentifier(\n \"_meta_doc_id\"\n )} = ?\n )`;\n try {\n const junctionStmt = this.db.prepare(junctionDeleteSQL);\n const result = junctionStmt.run(docId);\n Logger.info(\n `[NodeSqliteEngine] Cleared junction table ${existingTableName} for document ${docId}; removed ${result.changes} rows.`\n );\n } catch (error) {\n console.warn(\n `[NodeSqliteEngine] Warning: Could not clean up junction table ${existingTableName}:`,\n error\n );\n }\n }\n }\n }\n\n async query<T extends Record<string, any>>(\n sql: string,\n params?: any[]\n ): Promise<T[]> {\n await this.ensureReady();\n if (!this.db) throw new Error(\"SQLite not initialized for query\");\n\n const stmt = this.db.prepare(sql);\n const results = params ? stmt.all(...params) : stmt.all();\n return results as T[];\n }\n\n async withTransaction<T>(\n callback: (operations: ITransactionalDatabaseOperations) => Promise<T>\n ): Promise<T> {\n await this.ensureReady();\n if (!this.db) throw new Error(\"SQLite not initialized for transaction\");\n\n let transactionStartedHere = false;\n await this.mutex.runExclusive(async () => {\n if (this.numOpenTransactions === 0) {\n this.db!.exec(\"BEGIN TRANSACTION\");\n transactionStartedHere = true;\n }\n this.numOpenTransactions++;\n });\n\n const transactionalOps = new TransactionalNodeSqliteOperations(\n this.db,\n this\n );\n\n try {\n const result = await callback(transactionalOps);\n await this.mutex.runExclusive(async () => {\n this.numOpenTransactions--;\n if (this.numOpenTransactions === 0) {\n this.db!.exec(\"COMMIT\");\n }\n });\n return result;\n } catch (error) {\n console.error(\n \"[NodeSqliteEngine] Error in transaction, rolling back:\",\n error\n );\n await this.mutex.runExclusive(async () => {\n if (this.db && this.numOpenTransactions > 0 && transactionStartedHere) {\n try {\n this.db.exec(\"ROLLBACK\");\n } catch (rollbackError) {\n console.error(\n \"[NodeSqliteEngine] Error during ROLLBACK:\",\n rollbackError\n );\n }\n }\n this.numOpenTransactions = 0;\n });\n throw error;\n }\n }\n\n async close(): Promise<void> {\n await this.readyPromise;\n if (this.db) {\n Logger.info(\"[NodeSqliteEngine] Closing SQLite database...\");\n this.db.close();\n this.db = null;\n Logger.info(\"[NodeSqliteEngine] SQLite database closed.\");\n }\n }\n\n async destroy(): Promise<void> {\n await this.close();\n this.tableNames.clear();\n Logger.info(\"[NodeSqliteEngine] SQLite engine destroyed.\");\n }\n\n async getTableSchema(_tableName: string): Promise<any> {\n // Implementation would return table schema information\n return {};\n }\n\n getLastErrorMessage(): string | undefined {\n // better-sqlite3 throws exceptions instead of setting error messages\n return undefined;\n }\n}\n"],"mappings":"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","names":[]}
|