summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEuAndreh <eu@euandre.org>2023-11-16 15:48:12 -0300
committerEuAndreh <eu@euandre.org>2023-11-16 15:51:57 -0300
commitb2b5ba67c25705ddabb7f59baf725604eaf67c04 (patch)
tree96ffbd2b9455965a814cc55ec47b50fbbd213b68 /src
parentMakefile, mkdeps.sh: Enforce JS->native dependency (diff)
downloadpapod-b2b5ba67c25705ddabb7f59baf725604eaf67c04.tar.gz
papod-b2b5ba67c25705ddabb7f59baf725604eaf67c04.tar.xz
Add WIP non-async functions to napi-sqlite.c
Diffstat (limited to 'src')
-rw-r--r--src/db.js60
-rw-r--r--src/napi-sqlite.c807
-rw-r--r--src/sql/config.sql34
-rw-r--r--src/sql/migrations/2023-11-16T15:46:27-03:00-init-auth-data.sql0
-rw-r--r--src/utils.js13
5 files changed, 813 insertions, 101 deletions
diff --git a/src/db.js b/src/db.js
index e735ab1..88e43a4 100644
--- a/src/db.js
+++ b/src/db.js
@@ -1,43 +1,49 @@
-const fs = require("node:fs");
+const assert = require("node:assert/strict");
+const fs = require("node:fs");
+
const sqlite = require("./napi-sqlite.node");
+const { difference, log } = require("./utils");
-// const value = 8;
-// console.log(`${value} time 2 =`, sqlite.my_function(value));
-const CONFIG_FILE = __dirname + "/sql/config.sql";
const MIGRATIONS_DIR = __dirname + "/sql/migrations/";
+const MIGRATION_FILENAMES = fs.readdirSync(MIGRATIONS_DIR, "UTF-8");
let db = null;
-const init = async () => {
- console.log({
- sqlite,
- });
- console.log(`sqlite.myfn(2): ${sqlite.myfn(2)}`);
- console.log(`sqlite.open(2): ${sqlite.open(2)}`);
- /*
- const config = fs.readFileSync(CONFIG_FILE, "UTF-8");
- const migrations = fs.readdirSync(MIGRATIONS_DIR, "UTF-8");
-
- await exec(config);
- await exec(`
+const init = async (dbName = process.env.PAPO_DB_PATH) => {
+ assert(dbName);
+
+ db = await sqlite.open(dbName);
+ await db.exec(`
+ BEGIN TRANSACTION;
CREATE TABLE IF NOT EXISTS migrations (
filename TEXT PRIMARY KEY
);
- `);
- const done = await run(`
- SELECT filename FROM migrations;
+ COMMIT TRANSACTION;
`);
- // FIXME: sort
- const pending = new Set(migrations).difference(new Set(done));
+ const done = await db.all(`
+ SELECT filename FROM migrations;
+ `).map(row => row.filename);
+ const pending = difference(
+ new Set(MIGRATION_FILENAMES),
+ new Set(done)
+ );
+ const sortedPending = [...pending].sort((a, b) => a.localeCompare(b));
- await exec("BEGIN TRANSACTION;");
- for (const p of pending) {
- await exec(fs.readFileSync(MIGRATIONS_DIR + p, "UTF-8"));
- await exec(`INSERT INTO migrations (filename) VALUES (?)`, p);
+ await db.exec("BEGIN TRANSACTION;");
+ for (const filename of sortedPending) {
+ log({
+ log: "exec-migration",
+ filename,
+ });
+ const sql = fs.readFileSync(MIGRATIONS_DIR + filename, "UTF-8");
+ await db.exec(sql);
+ await db.run(
+ `INSERT INTO migrations (filename) VALUES ($filename);`,
+ { filename },
+ );
}
- await exec("COMMIT TRANSACTION;");
- */
+ await db.exec("COMMIT TRANSACTION;");
};
module.exports = {
diff --git a/src/napi-sqlite.c b/src/napi-sqlite.c
index df3b042..74ab340 100644
--- a/src/napi-sqlite.c
+++ b/src/napi-sqlite.c
@@ -1,74 +1,801 @@
+#include <assert.h>
#include <stdio.h>
+#include <stdlib.h>
#include <node/node_api.h>
+#include <sqlite3.h>
+
+
+static napi_value ffi_open(napi_env env, napi_callback_info info);
+static napi_value ffi_exec(napi_env env, napi_callback_info info);
+static napi_value ffi_all (napi_env env, napi_callback_info info);
+static napi_value ffi_run (napi_env env, napi_callback_info info);
+
+
+struct NAPIContext {
+ napi_env env;
+ napi_value value;
+ uint32_t index;
+};
+
+struct Fn {
+ const char *const label;
+ napi_value(*const handle)(napi_env env, napi_callback_info info);
+};
+
+static const struct Fn fns[] = {
+ { .label = "open", .handle = ffi_open, },
+ { NULL, NULL },
+};
+
+struct Fn methods[] = {
+ { .label = "exec", .handle = ffi_exec, },
+ { .label = "all", .handle = ffi_all, },
+ { .label = "run", .handle = ffi_run, },
+ { NULL, NULL },
+};
-/*
-FIXME
static const napi_type_tag SQLITE_DB_TYPE_TAG = {
0x0e9614d459f746cc, 0x88b814a5dc5c4cf7
};
-*/
+
+static const int
+SQLITE_OPEN_FLAGS =
+ /*
+ From https://www.sqlite.org/c3ref/open.html:
+
+ > The database is opened for reading and writing, and is created if
+ > it does not already exist. This is the behavior that is always
+ > used for sqlite3_open() and sqlite3_open16().
+ */
+ SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE |
+
+ /*
+ From https://www.sqlite.org/c3ref/open.html:
+
+ > The new database connection will use the "serialized" threading
+ > mode. This means the multiple threads can safely attempt to use
+ > the same database connection at the same time. (Mutexes will block
+ > any actual concurrency, but in this mode there is no harm in
+ > trying.)
+ */
+ SQLITE_OPEN_FULLMUTEX |
+
+ /*
+ From https://www.sqlite.org/c3ref/open.html:
+
+ > The database connection comes up in "extended result code mode".
+ > In other words, the database behaves has if
+ > sqlite3_extended_result_codes(db,1) where called on the database
+ > connection as soon as the connection is created. In addition to
+ > setting the extended result code mode, this flag also causes
+ > sqlite3_open_v2() to return an extended result code.
+
+ From https://www.sqlite.org/c3ref/extended_result_codes.html:
+
+ > The sqlite3_extended_result_codes() routine enables or disables the
+ > extended result codes feature of SQLite. The extended result codes
+ > are disabled by default for historical compatibility.
+ */
+ SQLITE_OPEN_EXRESCODE;
+
+
+static const char *const
+FIX_SQLITE_PRAGMAS =
+ /*
+ From https://research.cs.wisc.edu/adsl/Publications/alice-osdi14.pdf:
+
+ > Similarly, SQLite does not provide durability under the default
+ > journal-mode (we became aware of this only after interacting with
+ > developers), but its documentation seems misleading.
+ >
+ > (...)
+ >
+ > The developers suggest the SQLite vulnerability is actually not a
+ > behavior guaranteed by SQLite (specifically, that durability cannot
+ > be achieved under rollback journaling); we believe the
+ > documentation is misleading.
+ >
+ > (...)
+ >
+ > Unclear documentation of application guarantees contributes to the
+ > confusion about crash vulnerabilities. During discussions with
+ > developers about durability vulnerabilities, we found that SQLite,
+ > which proclaims itself as fully ACID-complaint, does not provide
+ > durability (even optionally) with the default storage engine,
+ > though the documentation suggests it does.
+ */
+ "PRAGMA journal_mode = WAL;\n"
+ "PRAGMA synchronous = EXTRA;\n"
+
+ /*
+ From https://www.sqlite.org/foreignkeys.html:
+
+ > Foreign key constraints are disabled by default (for backwards
+ > compatibility), so must be enabled separately for each database
+ > connection.
+ */
+ "PRAGMA foreign_keys = ON;\n"
+ ;
+
+
+// FIXME: make this async
+static napi_value
+ffi_exec(napi_env env, napi_callback_info info) {
+ size_t argc = 1;
+ napi_value argv[1];
+ int sqlite_rc;
+ napi_status napi_rc;
+ char *sql = NULL;
+ size_t sql_size1;
+ size_t sql_size2;
+ sqlite3 *db_handle = NULL;
+ char *error_msg = NULL;
+
+ napi_rc = napi_get_cb_info(
+ env,
+ info,
+ &argc,
+ argv,
+ NULL,
+ (void *)&db_handle
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "111TODO ERRCODE",
+ "Failed to parse arguments TODO i18n"
+ );
+ goto out;
+ }
+
+ napi_rc = napi_get_value_string_utf8(env, argv[0], NULL, 0, &sql_size1);
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "222TODO ERRCODE",
+ "Invalid number was passed as argument TODO i18n"
+ );
+ goto out;
+ }
+
+ if (sql_size1 == SIZE_MAX) {
+ napi_throw_error(
+ env,
+ "SQLITE_EOVERFLOW",
+ "TODO "
+ );
+ goto out;
+ }
+ sql_size1++; // include the NULL-terminator in size measurement
+
+ sql = malloc(sql_size1);
+ if (!sql) {
+ napi_throw_error(
+ env,
+ "SQLITE_ENOMEM",
+ "TODO i18n"
+ );
+ goto out;
+ }
+
+ napi_rc = napi_get_value_string_utf8(
+ env,
+ argv[0],
+ sql,
+ sql_size1,
+ &sql_size2
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ "Invalid number was passed as argument TODO i18n"
+ );
+ goto out;
+ }
+ assert(sql_size1 == sql_size2 + 1 &&
+ "Unstable behaviour from Node-API");
+ assert(sql);
+
+ sqlite_rc = sqlite3_exec(
+ db_handle,
+ sql,
+ NULL,
+ NULL,
+ &error_msg
+ );
+ if (sqlite_rc != SQLITE_OK) {
+ napi_throw_error(
+ env,
+ "3iii33TODO ERRCODE",
+ sqlite3_errstr(sqlite_rc)
+ );
+ goto out;
+ }
+
+out:
+ if (error_msg) {
+ sqlite3_free(error_msg);
+ }
+ if (sql) {
+ free(sql);
+ }
+ return NULL;
+}
+
+
+static int
+accumulate_all_results(
+ void *ctxptr,
+ int argc,
+ char **argv,
+ char **column_names
+) {
+ int rc = 0;
+
+ napi_status napi_rc;
+ napi_value row = NULL;
+
+ struct NAPIContext *ctx = ctxptr;
+ napi_env env = ctx->env;
+ napi_value results = ctx->value;
+ uint32_t index = ctx->index;
+
+ napi_rc = napi_create_object(env, &row);
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ "TODO i18n"
+ );
+ rc = -1;
+ goto out;
+ }
+
+ for (int i = 0; i < argc; i++) {
+ const char *const column_name = column_names[i];
+ const char *const column_value = argv[i];
+
+ // printf("column_name: %s\n", column_name);
+ // printf("column_value: %s\n", column_value);
+
+ napi_value str; // FIXME: dispatch on the type
+ napi_rc = napi_create_string_utf8(
+ env,
+ column_value,
+ NAPI_AUTO_LENGTH,
+ &str
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "SQLITE_MiiiETHOD_CREATE",
+ "TODO i18n"
+ );
+ rc = -1;
+ goto out;
+ }
+
+ napi_rc = napi_set_named_property(
+ env,
+ row,
+ column_name,
+ str
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "iSQLITE_MiETHOD_CREATE",
+ "TODO i18n"
+ );
+ rc = -1;
+ goto out;
+ }
+ }
+
+ napi_rc = napi_set_element(
+ env,
+ results,
+ index,
+ row
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ "TODO i18n"
+ );
+ rc = -1;
+ goto out;
+ }
+
+ ctx->index++;
+
+out:
+ return rc;
+}
static napi_value
-myfn(napi_env env, napi_callback_info info) {
+ffi_all(napi_env env, napi_callback_info info) {
napi_value ret = NULL;
- napi_status status;
size_t argc = 1;
- int number;
napi_value argv[1];
- napi_value my_number;
+ int sqlite_rc;
+ napi_status napi_rc;
+ char *sql = NULL;
+ size_t sql_size1;
+ size_t sql_size2;
+ sqlite3 *db_handle = NULL;
+ char *error_msg = NULL;
+ napi_value results_array = NULL;
+
+ napi_rc = napi_get_cb_info(
+ env,
+ info,
+ &argc,
+ argv,
+ NULL,
+ (void *)&db_handle
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "111TODO ERRCODE",
+ "Failed to parse arguments TODO i18n"
+ );
+ goto out;
+ }
+
+ napi_rc = napi_get_value_string_utf8(env, argv[0], NULL, 0, &sql_size1);
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "222TODO ERRCODE",
+ "Invalid number was passed as argument TODO i18n"
+ );
+ goto out;
+ }
- status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Failed to parse arguments FIXME i18n");
+ if (sql_size1 == SIZE_MAX) {
+ napi_throw_error(
+ env,
+ "SQLITE_EOVERFLOW",
+ "TODO "
+ );
goto out;
}
+ sql_size1++; // include the NULL-terminator in size measurement
- status = napi_get_value_int32(env, argv[0], &number);
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Invalid number was passed as argument FIXME i18n");
+ sql = malloc(sql_size1);
+ if (!sql) {
+ napi_throw_error(
+ env,
+ "SQLITE_ENOMEM",
+ "TODO i18n"
+ );
goto out;
}
- number = number * 2;
- status = napi_create_int32(env, number, &my_number);
- if (status != napi_ok) {
- napi_throw_error(env, NULL, "Unable to create return value FIXME i18n");
+ napi_rc = napi_get_value_string_utf8(
+ env,
+ argv[0],
+ sql,
+ sql_size1,
+ &sql_size2
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ "Invalid number was passed as argument TODO i18n"
+ );
goto out;
}
- ret = my_number;
+ assert(sql_size1 == sql_size2 + 1 &&
+ "Unstable behaviour from Node-API");
+ assert(sql);
+
+ napi_rc = napi_create_array(env, &results_array);
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ "Invalid number was passed as argument TODO i18n"
+ );
+ goto out;
+ }
+
+ struct NAPIContext ctx = {
+ .env = env,
+ .value = results_array,
+ .index = 0,
+ };
+ sqlite_rc = sqlite3_exec(
+ db_handle,
+ sql,
+ accumulate_all_results,
+ &ctx,
+ &error_msg
+ );
+ if (sqlite_rc != SQLITE_OK) {
+ napi_throw_error(
+ env,
+ "i3iiii33TODO ERRCODE",
+ sqlite3_errstr(sqlite_rc)
+ );
+ goto out;
+ }
+
+ ret = results_array;
out:
+ if (error_msg) {
+ sqlite3_free(error_msg);
+ }
+ if (sql) {
+ free(sql);
+ }
return ret;
}
static napi_value
-open(napi_env env, napi_callback_info info) {
- (void)env;
- (void)info;
- return NULL;
+ffi_run(napi_env env, napi_callback_info info) {
+ napi_value ret = NULL;
+
+ size_t argc = 1;
+ napi_value argv[1];
+ int sqlite_rc;
+ napi_status napi_rc;
+ char *sql = NULL;
+ size_t sql_size1;
+ size_t sql_size2;
+ sqlite3 *db_handle = NULL;
+ char *error_msg = NULL;
+ napi_value results_array = NULL;
+
+ napi_rc = napi_get_cb_info(
+ env,
+ info,
+ &argc,
+ argv,
+ NULL,
+ (void *)&db_handle
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "111TODO ERRCODE",
+ "Failed to parse arguments TODO i18n"
+ );
+ goto out;
+ }
+
+ napi_rc = napi_get_value_string_utf8(env, argv[0], NULL, 0, &sql_size1);
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "222TODO ERRCODE",
+ "Invalid number was passed as argument TODO i18n"
+ );
+ goto out;
+ }
+
+ if (sql_size1 == SIZE_MAX) {
+ napi_throw_error(
+ env,
+ "SQLITE_EOVERFLOW",
+ "TODO "
+ );
+ goto out;
+ }
+ sql_size1++; // include the NULL-terminator in size measurement
+
+ sql = malloc(sql_size1);
+ if (!sql) {
+ napi_throw_error(
+ env,
+ "SQLITE_ENOMEM",
+ "TODO i18n"
+ );
+ goto out;
+ }
+
+ napi_rc = napi_get_value_string_utf8(
+ env,
+ argv[0],
+ sql,
+ sql_size1,
+ &sql_size2
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ "Invalid number was passed as argument TODO i18n"
+ );
+ goto out;
+ }
+ assert(sql_size1 == sql_size2 + 1 &&
+ "Unstable behaviour from Node-API");
+ assert(sql);
+
+ napi_rc = napi_create_array(env, &results_array);
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ "Invalid number was passed as argument TODO i18n"
+ );
+ goto out;
+ }
+
+ struct NAPIContext ctx = {
+ .env = env,
+ .value = results_array,
+ .index = 0,
+ };
+ sqlite_rc = sqlite3_exec(
+ db_handle,
+ sql,
+ accumulate_all_results,
+ &ctx,
+ &error_msg
+ );
+ if (sqlite_rc != SQLITE_OK) {
+ napi_throw_error(
+ env,
+ "i3iiii33TODO ERRCODE",
+ sqlite3_errstr(sqlite_rc)
+ );
+ goto out;
+ }
+
+ ret = results_array;
+
+out:
+ if (error_msg) {
+ sqlite3_free(error_msg);
+ }
+ if (sql) {
+ free(sql);
+ }
+ return ret;
+}
+
+static void
+finalize_db_handle(napi_env env, void *finalize_data, void *finalize_hint) {
+ (void)finalize_hint;
+ sqlite3 *db_handle = finalize_data;
+ int sqlite_rc;
+
+ sqlite_rc = sqlite3_close(db_handle);
+ if (sqlite_rc != SQLITE_OK) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ sqlite3_errstr(sqlite_rc)
+ );
+ goto out;
+ }
+
+out:
+ return;
}
static napi_value
-close(napi_env env, napi_callback_info info) {
- (void)env;
- (void)info;
- return NULL;
+ffi_open(napi_env env, napi_callback_info info) {
+ napi_value ret = NULL;
+
+ size_t argc = 1;
+ napi_value argv[1];
+ int sqlite_rc;
+ napi_status napi_rc;
+ char *filename = NULL;
+ size_t filename_size1;
+ size_t filename_size2;
+ sqlite3 *db_handle = NULL;
+ napi_value wrapped_db_handle = NULL;
+ char *error_msg = NULL;
+
+ napi_rc = napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ "Failed to parse arguments TODO i18n"
+ );
+ goto out;
+ }
+
+ napi_rc = napi_get_value_string_utf8(
+ env,
+ argv[0],
+ NULL, // FIXME: what is this?
+ 0, // FIXME: what is this?
+ &filename_size1
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ "Invalid number was passed as argument TODO i18n"
+ );
+ goto out;
+ }
+
+ if (filename_size1 == SIZE_MAX) {
+ napi_throw_error(
+ env,
+ "SQLITE_EOVERFLOW",
+ "TODO "
+ );
+ goto out;
+ }
+ filename_size1++; // include the NULL-terminator in size measurement
+
+ filename = malloc(filename_size1);
+ if (!filename) {
+ napi_throw_error(
+ env,
+ "SQLITE_ENOMEM",
+ "TODO i18n"
+ );
+ goto out;
+ }
+
+ napi_rc = napi_get_value_string_utf8(
+ env,
+ argv[0],
+ filename,
+ filename_size1,
+ &filename_size2
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ "Invalid number was passed as argument TODO i18n"
+ );
+ goto out;
+ }
+ assert(filename_size1 == filename_size2 + 1 &&
+ "Unstable behaviour from Node-API");
+ assert(filename);
+
+ sqlite_rc = sqlite3_open_v2(
+ filename,
+ &db_handle,
+ SQLITE_OPEN_FLAGS,
+ NULL
+ );
+ if (sqlite_rc != SQLITE_OK) {
+ napi_throw_error(
+ env,
+ "3i33TODO ERRCODE",
+ sqlite3_errstr(sqlite_rc)
+ );
+ goto out;
+ }
+
+ sqlite_rc = sqlite3_exec(
+ db_handle,
+ FIX_SQLITE_PRAGMAS,
+ NULL,
+ NULL,
+ &error_msg
+ );
+ if (sqlite_rc != SQLITE_OK) {
+ napi_throw_error(
+ env,
+ "3ii33TODO ERRCODE",
+ sqlite3_errstr(sqlite_rc)
+ );
+ goto out;
+ }
+
+
+ // FIXME: setup the global error log:
+ // https://www.sqlite.org/errlog.html
+
+ napi_rc = napi_create_object(env, &wrapped_db_handle);
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ "TODO i18n"
+ );
+ goto out;
+ }
+
+ napi_rc = napi_type_tag_object(
+ env,
+ wrapped_db_handle,
+ &SQLITE_DB_TYPE_TAG
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ "TODO i18n"
+ );
+ goto out;
+ }
+
+ napi_rc = napi_wrap(
+ env,
+ wrapped_db_handle,
+ db_handle,
+ finalize_db_handle,
+ NULL,
+ NULL
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "TODO ERRCODE",
+ "TODO i18n"
+ );
+ goto out;
+ }
+
+ for (size_t i = 0; methods[i].label && methods[i].handle; i++) {
+ napi_value fn;
+ napi_rc = napi_create_function(
+ env,
+ methods[i].label,
+ NAPI_AUTO_LENGTH,
+ methods[i].handle,
+ db_handle,
+ &fn
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "SQLITE_MiiETHOD_CREATE",
+ "TODO i18n"
+ );
+ goto out;
+ }
+
+ napi_rc = napi_set_named_property(
+ env,
+ wrapped_db_handle,
+ methods[i].label,
+ fn
+ );
+ if (napi_rc != napi_ok) {
+ napi_throw_error(
+ env,
+ "SQLITE_METHOD_SETNAME",
+ "TODO i18n"
+ );
+ goto out;
+ }
+ }
+ ret = wrapped_db_handle;
+
+out:
+ if (error_msg) {
+ sqlite3_free(error_msg);
+ }
+ if (filename) {
+ free(filename);
+ }
+ if (!ret) {
+ if (db_handle) {
+ if (sqlite3_close(db_handle)) {
+ // logerr();
+ }
+ }
+ }
+ return ret;
}
-static const struct {
- const char *label;
- napi_value(*const handle)(napi_env env, napi_callback_info info);
-} fns[] = {
- { .label = "myfn", .handle = myfn, },
- { .label = "open", .handle = open, },
- { .label = "close", .handle = close, },
- { NULL, NULL },
-};
static napi_value
-init(napi_env env, napi_value exports) {
+ffi_init(napi_env env, napi_value exports) {
napi_value ret = exports;
napi_status status;
@@ -80,7 +807,7 @@ init(napi_env env, napi_value exports) {
fns[i].label,
NAPI_AUTO_LENGTH,
fns[i].handle,
- "xucrutes",
+ NULL,
&fn
);
if (status != napi_ok) {
@@ -88,7 +815,7 @@ init(napi_env env, napi_value exports) {
napi_throw_error(
env,
"SQLITE_FN_CREATE",
- "Unable to wrap native function FIXME i18n"
+ "Unable to wrap native function TODO i18n"
);
goto out;
}
@@ -104,7 +831,7 @@ init(napi_env env, napi_value exports) {
napi_throw_error(
env,
"SQLITE_FN_SETNAME",
- "Unable to populate exports FIXME i18n"
+ "Unable to populate exports TODO i18n"
);
goto out;
}
@@ -116,5 +843,5 @@ out:
NAPI_MODULE_INIT() {
- return init(env, exports);
+ return ffi_init(env, exports);
}
diff --git a/src/sql/config.sql b/src/sql/config.sql
deleted file mode 100644
index 53eb279..0000000
--- a/src/sql/config.sql
+++ /dev/null
@@ -1,34 +0,0 @@
-; "Litestream requires periodic but short write locks on the database when
-; checkpointing occurs":
-; https://litestream.io/tips/#busy-timeout
-PRAGMA busy_timeout = 5000;
-
-; "Litestream only works with the SQLite WAL journaling mode":
-; https://litestream.io/tips/#wal-journal-mode
-PRAGMA journal_mode = WAL;
-
-; "(...) change the synchronous mode to NORMAL (it typically defaults to FULL)":
-; https://litestream.io/tips/#synchronous-pragma
-; "WAL mode is safe from corruption with synchronous=NORMAL":
-; https://www.sqlite.org/pragma.html#pragma_synchronous
-PRAGMA synchronous = NORMAL;
-
-; "(...) can perform a checkpoint in between Litestream-initiated checkpoints
-; and cause Litestream to miss a WAL file":
-; https://litestream.io/tips/#disable-autocheckpoints-for-high-write-load-servers
-PRAGMA wal_autocheckpoint = 0;
-
-; "This pragma does a low-level formatting and consistency check of the
-; database":
-; https://www.sqlite.org/pragma.html#pragma_integrity_check
-PRAGMA integrity_check;
-
-; "The foreign_key_check pragma checks the database, or the table called
- \"table-name\", for foreign key constraints that are violated":
-; https://www.sqlite.org/pragma.html#pragma_foreign_key_check
-PRAGMA foreign_key_check;
-
-
-CREATE TABLE IF NO EXISTS migrations (
- name TEXT PRIMARY KEY
-);
diff --git a/src/sql/migrations/2023-11-16T15:46:27-03:00-init-auth-data.sql b/src/sql/migrations/2023-11-16T15:46:27-03:00-init-auth-data.sql
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/sql/migrations/2023-11-16T15:46:27-03:00-init-auth-data.sql
diff --git a/src/utils.js b/src/utils.js
index 2c3ea72..e1725ef 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -38,7 +38,20 @@ const keys = (ks, obj) =>
{},
);
+const difference = (a, b) => {
+ const diff = new Set(a);
+ for (const el of b) {
+ diff.delete(el);
+ }
+ return diff;
+};
+
+const log = o => console.error(JSON.stringify(o));
+
+
module.exports = {
eq,
keys,
+ difference,
+ log,
};