import sqlite3InitModule from "@sqlite.org/sqlite-wasm";
const log = console.log;
const err_log = console.error;
export class SQLiteError extends Error {
constructor(message, code) {
super(message);
this.code = code;
}
}
export class SQLite {
#module;
#sqlite3;
constructor(sqlite3) {
if (typeof sqlite3 === "undefined") {
throw new Error(
"`sqliteObject` must be defined before calling constructor",
);
}
this.sqlite3 = sqlite3;
}
static async init_module(opts) {
return await sqlite3InitModule({
print: log,
printErr: err_log,
...opts,
});
}
version() {
return this.sqlite3.version;
}
filename(db, name) {
return this.sqlite3.capi.sqlite3_db_filename(db, name);
}
extended_errcode(connection) {
return this.sqlite3.capi.sqlite3_extended_errcode(connection);
}
errstr(code) {
return this.sqlite3.capi.sqlite3_errstr(code);
}
errmsg(connection) {
return this.sqlite3.capi.sqlite3_errmsg(connection);
}
result_js(context, value) {
return this.sqlite3.capi.sqlite3_result_js(context, value);
}
result_text(context, value) {
return this.sqlite3.capi.sqlite3_result_text(context, value);
}
result_int(context, value) {
return this.sqlite3.capi.sqlite3_result_int(context, value);
}
result_int64(context, value) {
return this.sqlite3.capi.sqlite3_result_int64(context, value);
}
result_double(context, value) {
return this.sqlite3.capi.sqlite3_result_double(context, value);
}
result_blob(context, value) {
return this.sqlite3.capi.sqlite3_result_blob(context, value);
}
result_null(context) {
return this.sqlite3.capi.sqlite3_result_null(context);
}
bind_blob(stmt, i, value, len, flags) {
return this.sqlite3.capi.sqlite_bind_blob(stmt, i, value);
}
bind_text(stmt, i, value, len, flags) {
return this.sqlite3.capi.sqlite3_bind_text(stmt, i, value, len, flags);
}
bind_double(stmt, i, value) {
return this.sqlite3.capi.sqlite3_bind_double(stmt, i, value);
}
bind_int(stmt, i, value) {
return this.sqlite3.capi.sqlite3_bind_int(stmt, i, value);
}
bind_int64(stmt, i, value) {
return this.sqlite3.capi.sqlite3_bind_int64(stmt, i, value);
}
bind_null(stmt, i) {
this.sqlite3.capi.sqlite3_bind_null(stmt, i);
return this.sqlite3.capi.SQLITE_OK;
}
bind_parameter_count(stmt) {
return this.sqlite3.capi.sqlite3_bind_parameter_count(stmt);
}
bind_parameter_name(stmt, i) {
return this.sqlite3.capi.sqlite3_bind_paramater_name(stmt, it);
}
value_dup(pValue) {
return this.sqlite3.capi.sqlite3_value_dup(pValue);
}
value_blob(pValue) {
return this.sqlite3.capi.sqlite3_value_blob(pValue);
}
value_bytes(pValue) {
return this.sqlite3.capi.sqlite3_value_bytes(pValue);
}
value_double(pValue) {
return this.sqlite3.capi.sqlite3_value_double(pValue);
}
value_int(pValue) {
return this.sqlite3.capi.sqlite3_value_int(pValue);
}
value_int64(pValue) {
return this.sqlite3.capi.sqlite3_value_int64(pValue);
}
value_text(pValue) {
return this.sqlite3.capi.sqlite3_value_text(pValue);
}
value_type(pValue) {
return this.sqlite3.capi.sqlite3_value_type(pValue);
}
open(database_url, iflags) {
try {
let db;
if (database_url === ":memory:") {
db = new this.sqlite3.oo1.DB("transient_in_memory_db:");
console.log(`Created in-memory database`);
} else {
db = new this.sqlite3.oo1.OpfsDb(database_url);
console.log(`Created persistent database at ${db.filename}`);
}
return db;
} catch (error) {
console.log("OPFS open error", error);
throw error;
}
}
exec(db, query) {
try {
return db.exec(query, {
callback: (row) => {
log(`exec'd ${row}`);
},
});
} catch (error) {
throw error;
}
}
finalize(stmt) {
return this.sqlite3.capi.sqlite3_finalize(stmt);
}
changes(db) {
return this.sqlite3.capi.sqlite3_changes(db);
}
clear_bindings(stmt) {
return this.sqlite3.capi.sqlite3_clear_bindings(stmt);
}
reset(stmt) {
return this.sqlite3.capi.sqlite3_reset(stmt);
}
close(db) {
return this.sqlite3.capi.sqlite3_close_v2(db.pointer);
}
db_handle(stmt) {
return this.sqlite3.capi.sqlite3_db_handle(stmt);
}
prepare_v3(db, sql, nByte, prepFlags, ppStmt, pzTail) {
return this.sqlite3.capi.sqlite3_prepare_v3(
db.pointer,
sql,
nByte,
prepFlags,
ppStmt,
pzTail,
);
}
into_statement(pStmt) {
const BindTypes = {
null: 1,
number: 2,
string: 3,
boolean: 4,
blob: 5,
};
BindTypes["undefined"] == BindTypes.null;
if (wasm.bigIntEnabled) {
BindTypes.bigint = BindTypes.number;
}
new Stmt(this, pStmt, BindTypes);
}
step(stmt) {
return this.sqlite3.capi.sqlite3_step(stmt);
}
column_value(stmt, i) {
return this.sqlite3.capi.sqlite3_column_value(stmt, i);
}
column_name(stmt, idx) {
return this.sqlite3.capi.sqlite3_column_name(stmt, idx);
}
column_count(stmt) {
return this.sqlite3.capi.sqlite3_column_count(stmt);
}
create_function(
database,
functionName,
nArg,
textRep,
pApp,
xFunc,
xStep,
xFinal,
) {
try {
this.sqlite3.capi.sqlite3_create_function(
database,
functionName,
nArg,
textRep,
pApp, xFunc,
xStep,
xFinal,
);
console.log("create function");
} catch (error) {
console.log("create function err");
throw error;
}
}
register_diesel_sql_functions(database) {
try {
this.sqlite3.capi.sqlite3_create_function(
database,
"diesel_manage_updated_at",
1,
this.sqlite3.capi.SQLITE_UTF8,
0,
async (context, values) => {
const table_name = this.sqlite3.value_text(values[0]);
database.exec(
context,
`CREATE TRIGGER __diesel_manage_updated_at_${table_name}
AFTER UPDATE ON ${table_name}
FOR EACH ROW WHEN
old.updated_at IS NULL AND
new.updated_at IS NULL OR
old.updated_at == new.updated_at
BEGIN
UPDATE ${table_name}
SET updated_at = CURRENT_TIMESTAMP
WHERE ROWID = new.ROWID;
END`,
(row) => {
log(`------------------------------------`);
log(`Created trigger for ${table_name}`);
log(row);
log(`------------------------------------`);
},
);
},
);
} catch (error) {
console.log("error creating diesel trigger");
throw error;
}
}
value_free(value) {
return this.sqlite3.capi.sqlite3_value_free(value);
}
}