From 0a783474bcfe1bb01defc5627688c30147f7631d Mon Sep 17 00:00:00 2001
From: Boyi <chenby@localhost>
Date: Mon, 1 Mar 2021 11:48:03 +0800
Subject: [PATCH 1/7] add nodefs to makefile

---
 Makefile                          |  3 ++-
 src/api.js                        | 18 ++++++++++++++++++
 src/exported_runtime_methods.json |  2 ++
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/Makefile b/Makefile
index 287de6fd..54e0b411 100644
--- a/Makefile
+++ b/Makefile
@@ -37,7 +37,8 @@ EMFLAGS = \
 	-s EXTRA_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 52bbab58..1b523ab6 100644
--- a/src/api.js
+++ b/src/api.js
@@ -800,6 +800,24 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
         this.functions = {};
     }
 
+    /** Create database instance
+    @param {string} fn filename for database file
+    @return {Database} the created database instance
+     */
+    Database.open = function(fn) {
+        var obj = Object.create(Database.prototype);
+        obj.filename = fn;
+        obj.handleError(sqlite3_open(obj.filename, apiTemp));
+        obj.db = getValue(apiTemp, "i32");
+        registerExtensionFunctions(obj.db);
+        // A list of all prepared statements of the database
+        obj.statements = {};
+        // A list of all user function of the database
+        // (created by create_function call)
+        obj.functions = {};
+        return obj;
+    }
+
     /** Execute an SQL query, ignoring the rows it returns.
     @param {string} sql a string containing some SQL text to execute
     @param {Statement.BindParams} [params] When the SQL statement contains
diff --git a/src/exported_runtime_methods.json b/src/exported_runtime_methods.json
index 13a8efb8..7a4dde89 100644
--- a/src/exported_runtime_methods.json
+++ b/src/exported_runtime_methods.json
@@ -3,5 +3,7 @@
 "stackAlloc",
 "stackSave",
 "stackRestore",
+"FS",
+"NODEFS",
 "UTF8ToString"
 ]

From e75de39dcb3d03aebb8bca0c24f4c4a186c94f4e Mon Sep 17 00:00:00 2001
From: Boyi <chenby@localhost>
Date: Mon, 1 Mar 2021 14:38:14 +0800
Subject: [PATCH 2/7] fix for closure compiler

---
 src/api.js                        | 15 ++++++++++++++-
 src/exported_runtime_methods.json |  1 -
 2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/api.js b/src/api.js
index 1b523ab6..81eaa716 100644
--- a/src/api.js
+++ b/src/api.js
@@ -804,7 +804,7 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
     @param {string} fn filename for database file
     @return {Database} the created database instance
      */
-    Database.open = function(fn) {
+    Database["open"] = function(fn) {
         var obj = Object.create(Database.prototype);
         obj.filename = fn;
         obj.handleError(sqlite3_open(obj.filename, apiTemp));
@@ -1216,6 +1216,19 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
         return this;
     };
 
+    var vfs = Module["FS"];
+
+    /** Create database instance
+    @param {string} fn filename for database file
+    @return {Database} the created database instance
+     */
+    Module["mount"] = function(vdir, osdir) {
+        if (vfs.mayCreate(vdir)) {
+            vfs.mkdir(vdir)
+        }
+        return vfs.mount(vfs.filesystems["NODEFS"], {root: osdir}, vdir);
+    }
+
     // export Database to Module
     Module.Database = Database;
 };
diff --git a/src/exported_runtime_methods.json b/src/exported_runtime_methods.json
index 7a4dde89..eb028ee6 100644
--- a/src/exported_runtime_methods.json
+++ b/src/exported_runtime_methods.json
@@ -4,6 +4,5 @@
 "stackSave",
 "stackRestore",
 "FS",
-"NODEFS",
 "UTF8ToString"
 ]

From df29c051a58181a05dc55133204c76d61859209c Mon Sep 17 00:00:00 2001
From: Boyi <chenby@localhost>
Date: Mon, 1 Mar 2021 18:44:37 +0800
Subject: [PATCH 3/7] nodefs db should not deleted; add test file

---
 src/api.js          | 21 ++++++++++++---------
 test/test_nodefs.js | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 47 insertions(+), 9 deletions(-)
 create mode 100644 test/test_nodefs.js

diff --git a/src/api.js b/src/api.js
index 81eaa716..59a52766 100644
--- a/src/api.js
+++ b/src/api.js
@@ -804,8 +804,9 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
     @param {string} fn filename for database file
     @return {Database} the created database instance
      */
-    Database["open"] = function(fn) {
+    Database["open"] = function open(fn) {
         var obj = Object.create(Database.prototype);
+        obj.filetype = "FS";
         obj.filename = fn;
         obj.handleError(sqlite3_open(obj.filename, apiTemp));
         obj.db = getValue(apiTemp, "i32");
@@ -816,7 +817,7 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
         // (created by create_function call)
         obj.functions = {};
         return obj;
-    }
+    };
 
     /** Execute an SQL query, ignoring the rows it returns.
     @param {string} sql a string containing some SQL text to execute
@@ -1090,7 +1091,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;
     };
 
@@ -1219,15 +1222,15 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
     var vfs = Module["FS"];
 
     /** Create database instance
-    @param {string} fn filename for database file
-    @return {Database} the created database instance
+    @param {string} vdir directory name to mount for virtual fs
+    @param {string} osdir system directory to mount
      */
-    Module["mount"] = function(vdir, osdir) {
+    Module["mount"] = function mount(vdir, osdir) {
         if (vfs.mayCreate(vdir)) {
-            vfs.mkdir(vdir)
+            vfs.mkdir(vdir);
         }
-        return vfs.mount(vfs.filesystems["NODEFS"], {root: osdir}, vdir);
-    }
+        vfs.mount(vfs.filesystems["NODEFS"], { root: osdir }, vdir);
+    };
 
     // export Database to Module
     Module.Database = Database;
diff --git a/test/test_nodefs.js b/test/test_nodefs.js
new file mode 100644
index 00000000..0db6d4fb
--- /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 = SQL.Database.open('/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);
+  });
+}

From 8e3347c69ecdf1c2de60534821f1dc17d4c668e4 Mon Sep 17 00:00:00 2001
From: Boyi <chenby@localhost>
Date: Mon, 1 Mar 2021 18:51:43 +0800
Subject: [PATCH 4/7] fix lint

---
 src/api.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/api.js b/src/api.js
index 59a52766..2ba6361e 100644
--- a/src/api.js
+++ b/src/api.js
@@ -1091,7 +1091,7 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
         Object.values(this.functions).forEach(removeFunction);
         this.functions = {};
         this.handleError(sqlite3_close_v2(this.db));
-        if (this.filetype != "FS") {
+        if (this.filetype !== "FS") {
             FS.unlink("/" + this.filename);
         }
         this.db = null;

From 1886f1c8a695cd5de8b75d00554746357265fc72 Mon Sep 17 00:00:00 2001
From: Boyi <chenby@localhost>
Date: Tue, 2 Mar 2021 11:19:56 +0800
Subject: [PATCH 5/7] Make test run on debug first; add mountpoint support

---
 package.json |  2 +-
 src/api.js   | 40 +++++++++++++++++-----------------------
 2 files changed, 18 insertions(+), 24 deletions(-)

diff --git a/package.json b/package.json
index fac0370f..9bc9412f 100644
--- a/package.json
+++ b/package.json
@@ -21,7 +21,7 @@
 	"scripts": {
 		"build": "make",
 		"rebuild": "make clean && make",
-		"test": "npm run lint && npm run test-asm && npm run test-asm-debug && npm run test-wasm && npm run test-wasm-debug && npm run test-asm-memory-growth",
+		"test": "npm run lint && npm run test-asm-debug && npm run test-wasm-debug && npm run test-asm && npm run test-wasm && npm run test-asm-memory-growth",
 		"lint": "eslint .",
 		"prettify": "eslint . --fix",
 		"test-asm": "node test/all.js asm",
diff --git a/src/api.js b/src/api.js
index 2ba6361e..b43c80c5 100644
--- a/src/api.js
+++ b/src/api.js
@@ -782,14 +782,20 @@ 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 {number[]} data An array of bytes representing
+    * @param {number[]|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);
@@ -800,25 +806,6 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
         this.functions = {};
     }
 
-    /** Create database instance
-    @param {string} fn filename for database file
-    @return {Database} the created database instance
-     */
-    Database["open"] = function open(fn) {
-        var obj = Object.create(Database.prototype);
-        obj.filetype = "FS";
-        obj.filename = fn;
-        obj.handleError(sqlite3_open(obj.filename, apiTemp));
-        obj.db = getValue(apiTemp, "i32");
-        registerExtensionFunctions(obj.db);
-        // A list of all prepared statements of the database
-        obj.statements = {};
-        // A list of all user function of the database
-        // (created by create_function call)
-        obj.functions = {};
-        return obj;
-    };
-
     /** Execute an SQL query, ignoring the rows it returns.
     @param {string} sql a string containing some SQL text to execute
     @param {Statement.BindParams} [params] When the SQL statement contains
@@ -1232,6 +1219,13 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
         vfs.mount(vfs.filesystems["NODEFS"], { root: osdir }, vdir);
     };
 
+    var mountpoints = Module["fs"];
+    if (mountpoints) {
+        for (var mountpoint of Object.entries(mountpoints)) {
+            Module["mount"](mountpoint[0], mountpoint[1])
+        }
+    }
+
     // export Database to Module
     Module.Database = Database;
 };

From 4ea17ccca9409afe526cda78e7ad589885b775ad Mon Sep 17 00:00:00 2001
From: Boyi <chenby@localhost>
Date: Tue, 2 Mar 2021 11:25:18 +0800
Subject: [PATCH 6/7] fix test

---
 test/test_nodefs.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/test_nodefs.js b/test/test_nodefs.js
index 0db6d4fb..4ecd189c 100644
--- a/test/test_nodefs.js
+++ b/test/test_nodefs.js
@@ -8,7 +8,7 @@ exports.test = function(SQL, assert) {
 	SQL.mount('/nfs', __dirname);
 
 	//Works
-	var db = SQL.Database.open('/nfs/test.sqlite');
+	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");

From 9d579ff58ef40dc6a11cb0ee291bd4d2a576bd90 Mon Sep 17 00:00:00 2001
From: Boyi <chenby@localhost>
Date: Tue, 2 Mar 2021 13:55:35 +0800
Subject: [PATCH 7/7] fix for lint

---
 src/api.js | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/api.js b/src/api.js
index b43c80c5..66cf464d 100644
--- a/src/api.js
+++ b/src/api.js
@@ -782,11 +782,12 @@ 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 {number[]|string} data An array of bytes representing, or a string for mapped file name
+    * @param {number[]|string} data An array of bytes representing,
+    * or a string for mapped file name
     * an SQLite database file
     */
     function Database(data) {
-        if (data != null && typeof data === 'string') {
+        if (data != null && typeof data === "string") {
             this.filename = data;
             this.filetype = "FS";
         } else {
@@ -1219,11 +1220,12 @@ Module["onRuntimeInitialized"] = function onRuntimeInitialized() {
         vfs.mount(vfs.filesystems["NODEFS"], { root: osdir }, vdir);
     };
 
-    var mountpoints = Module["fs"];
+    var mountpoints = Module["mountpoints"];
     if (mountpoints) {
-        for (var mountpoint of Object.entries(mountpoints)) {
-            Module["mount"](mountpoint[0], mountpoint[1])
-        }
+        Array.prototype.forEach.call(Object.keys(mountpoints),
+            function mount(mp) {
+                Module["mount"](mp, mountpoints[mp]);
+            });
     }
 
     // export Database to Module