diff --git a/Makefile b/Makefile index 792d4008..91ebe6c5 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,8 @@ EMFLAGS = \ -s EXPORTED_RUNTIME_METHODS=@src/exported_runtime_methods.json \ -s SINGLE_FILE=0 \ -s NODEJS_CATCH_EXIT=0 \ - -s NODEJS_CATCH_REJECTION=0 + -s NODEJS_CATCH_REJECTION=0 \ + -l nodefs.js EMFLAGS_ASM = \ -s WASM=0 diff --git a/src/api.js b/src/api.js index 6cb3de13..9d6cae64 100644 --- a/src/api.js +++ b/src/api.js @@ -176,10 +176,9 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() { "number", "number", "number", - "number", - "number", - "number", - "number" + + + ] ); var sqlite3_value_type = cwrap("sqlite3_value_type", "number", ["number"]); @@ -819,14 +818,21 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() { * @memberof module:SqlJs * Open a new database either by creating a new one or opening an existing * one stored in the byte array passed in first argument - * @param {Array} data An array of bytes representing + * @param {Array|string} data An array of bytes representing, + * or a string for mapped file name * an SQLite database file */ function Database(data) { - this.filename = "dbfile_" + (0xffffffff * Math.random() >>> 0); - if (data != null) { - FS.createDataFile("/", this.filename, data, true, true); + if (data != null && typeof data === "string") { + this.filename = data; + this.filetype = "FS"; + } else { + this.filename = "dbfile_" + (0xffffffff * Math.random() >>> 0); + if (data != null) { + FS.createDataFile("/", this.filename, data, true, true); + } } + this.handleError(sqlite3_open(this.filename, apiTemp)); this.db = getValue(apiTemp, "i32"); registerExtensionFunctions(this.db); @@ -1113,7 +1119,9 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() { Object.values(this.functions).forEach(removeFunction); this.functions = {}; this.handleError(sqlite3_close_v2(this.db)); - FS.unlink("/" + this.filename); + if (this.filetype !== "FS") { + FS.unlink("/" + this.filename); + } this.db = null; }; @@ -1250,6 +1258,27 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() { return this; }; + var vfs = Module["FS"]; + + /** Create database instance + @param {string} vdir directory name to mount for virtual fs + @param {string} osdir system directory to mount + */ + Module["mount"] = function mount(vdir, osdir) { + if (vfs.mayCreate(vdir)) { + vfs.mkdir(vdir); + } + vfs.mount(vfs.filesystems["NODEFS"], { root: osdir }, vdir); + }; + + var mountpoints = Module["mountpoints"]; + if (mountpoints) { + Array.prototype.forEach.call(Object.keys(mountpoints), + function mount(mp) { + Module["mount"](mp, mountpoints[mp]); + }); + } + /** Register a custom aggregate with SQLite @example Register a custom sum function db.create_aggregate("js_sum", { diff --git a/src/exported_runtime_methods.json b/src/exported_runtime_methods.json index 245d2078..001c21d3 100644 --- a/src/exported_runtime_methods.json +++ b/src/exported_runtime_methods.json @@ -3,7 +3,8 @@ "stackAlloc", "stackSave", "stackRestore", -"UTF8ToString", +"FS", +"UTF8ToString" "allocate", "ALLOC_NORMAL", diff --git a/test/test_nodefs.js b/test/test_nodefs.js new file mode 100644 index 00000000..4ecd189c --- /dev/null +++ b/test/test_nodefs.js @@ -0,0 +1,35 @@ +exports.test = function(SQL, assert) { + //Node filesystem module - You know that. + var fs = require('fs'); + + //Ditto, path module + var path = require('path'); + + SQL.mount('/nfs', __dirname); + + //Works + var db = new SQL.Database('/nfs/test.sqlite'); + + //[{"columns":["id","content"],"values":[["0","hello"],["1","world"]]}] + var res = db.exec("SELECT * FROM test WHERE id = 0"); + assert.deepEqual(res, + [{"columns":["id","content"],"values":[[0,"hello"]]}], + "One should be able to read the mounted file from disk"); + db.close(); +} + +if (module == require.main) { + const target_file = process.argv[2]; + const sql_loader = require('./load_sql_lib'); + sql_loader(target_file).then((sql)=>{ + require('test').run({ + 'test node file': function(assert){ + exports.test(sql, assert); + } + }); + }) + .catch((e)=>{ + console.error(e); + assert.fail(e); + }); +}