Skip to content

Commit d8d7c8d

Browse files
Initial implementation
0 parents  commit d8d7c8d

File tree

7 files changed

+273
-0
lines changed

7 files changed

+273
-0
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
*.log
2+
package-lock.json
3+
bun.lockb
4+
5+
.idea/
6+
dist/
7+
node_modules/

LICENSE.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2023 FAR.js contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in
13+
all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
[![CI](https://github.com/farjs/better-sqlite3-websql/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/farjs/better-sqlite3-websql/actions/workflows/ci.yml?query=workflow%3Aci+branch%3Amain)
3+
[![npm version](https://img.shields.io/npm/v/@farjs/better-sqlite3-websql)](https://www.npmjs.com/package/@farjs/better-sqlite3-websql)
4+
5+
## @farjs/better-sqlite3-websql
6+
7+
Cross-runtime implementation of [WebSql](https://www.npmjs.com/package/websql) api
8+
backed by [better-sqlite3](https://github.com/WiseLibs/better-sqlite3)
9+
and [bun:sqlite](https://bun.sh/docs/api/sqlite).

SQLiteDatabase.js

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
'use strict';
2+
3+
const Database = require("@farjs/better-sqlite3-wrapper");
4+
const SQLiteResult = require('@expo/websql/lib/sqlite/SQLiteResult');
5+
6+
const READ_ONLY_ERROR = new Error('could not prepare statement (23 not authorized)');
7+
8+
function SQLiteDatabase(name) {
9+
const db = new Database(name);
10+
db.pragma('journal_mode = WAL');
11+
db._lastInsertRowIdQuery = db.prepare("SELECT last_insert_rowid() AS id;");
12+
db._changesQuery = db.prepare("SELECT changes() AS changes;");
13+
this._db = db;
14+
}
15+
16+
function runSelect(db, sql, args, cb) {
17+
let err;
18+
let resultSet;
19+
try {
20+
const rows = db.prepare(sql).all(args);
21+
22+
const insertId = undefined;
23+
const rowsAffected = 0;
24+
resultSet = new SQLiteResult(null, insertId, rowsAffected, rows);
25+
}
26+
catch (e) {
27+
err = e;
28+
}
29+
30+
if (err) {
31+
return cb(new SQLiteResult(err));
32+
}
33+
cb(resultSet);
34+
}
35+
36+
function runNonSelect(db, sql, args, cb) {
37+
let err;
38+
let resultSet;
39+
try {
40+
db.prepare(sql).run(args);
41+
42+
const insertId = db._lastInsertRowIdQuery.get().id;
43+
const rowsAffected = db._changesQuery.get().changes;
44+
const rows = [];
45+
resultSet = new SQLiteResult(null, insertId, rowsAffected, rows);
46+
}
47+
catch (e) {
48+
err = e;
49+
}
50+
51+
if (err) {
52+
return cb(new SQLiteResult(err));
53+
}
54+
cb(resultSet);
55+
}
56+
57+
SQLiteDatabase.prototype.exec = function exec(queries, readOnly, callback) {
58+
const db = this._db;
59+
const len = queries.length;
60+
const results = new Array(len);
61+
62+
var i = 0;
63+
64+
function checkDone() {
65+
if (++i === len) {
66+
callback(null, results);
67+
} else {
68+
doNext();
69+
}
70+
}
71+
72+
function onQueryComplete(i) {
73+
return function (res) {
74+
results[i] = res;
75+
checkDone();
76+
};
77+
}
78+
79+
function doNext() {
80+
const query = queries[i];
81+
const sql = query.sql;
82+
const args = query.args;
83+
84+
// We try to sniff whether it's a SELECT query or not.
85+
// This is inherently error-prone, although it will probably work in the 99%
86+
// case.
87+
const isSelect = /^\s*SELECT\b/i.test(sql);
88+
89+
if (readOnly && !isSelect) {
90+
onQueryComplete(i)(new SQLiteResult(READ_ONLY_ERROR));
91+
} else if (isSelect) {
92+
runSelect(db, sql, args, onQueryComplete(i));
93+
} else {
94+
runNonSelect(db, sql, args, onQueryComplete(i));
95+
}
96+
}
97+
98+
doNext();
99+
};
100+
101+
module.exports = SQLiteDatabase;

index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
'use strict';
2+
3+
const customOpenDatabase = require('@expo/websql/custom');
4+
const SQLiteDatabase = require('./SQLiteDatabase.js');
5+
6+
const openDatabase = customOpenDatabase(SQLiteDatabase);
7+
8+
module.exports = openDatabase;

index.test.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
const openDatabase = require('./index');
2+
3+
const assert = require('assert').strict;
4+
const it = function() {
5+
return process['isBun'] ? test : require('node:test').it;
6+
}();
7+
8+
//given
9+
const db = openDatabase(":memory:", '1.0', 'description', 1);
10+
11+
it('should write to database', async () => {
12+
//when
13+
const result = await new Promise((resolve, reject) => {
14+
db.transaction((tx) => {
15+
tx.executeSql(`
16+
create table test(
17+
id integer primary key,
18+
name text not null
19+
);
20+
`, [], (tx, r) => {
21+
const insertSql = "insert into test (name) values (?);"
22+
tx.executeSql(insertSql, ["test1"], (tx, r) => {
23+
tx.executeSql(insertSql, ["test2"], (tx, r) => {
24+
resolve(r);
25+
}, (tx, e) => {
26+
reject(e);
27+
});
28+
}, (tx, e) => {
29+
reject(e);
30+
});
31+
}, (tx, e) => {
32+
reject(e);
33+
});
34+
});
35+
36+
});
37+
38+
//then
39+
assert.deepEqual(result.insertId, 2);
40+
assert.deepEqual(result.rowsAffected, 1);
41+
assert.deepEqual(result.rows._array, []);
42+
});
43+
44+
it('should read all records from database', async () => {
45+
//when
46+
const result = await new Promise((resolve, reject) => {
47+
db.readTransaction((tx) => {
48+
tx.executeSql("select * from test order by id;", [], (tx, r) => {
49+
resolve(r);
50+
}, (tx, e) => {
51+
reject(e);
52+
});
53+
});
54+
55+
});
56+
57+
//then
58+
assert.deepEqual(result.insertId, undefined);
59+
assert.deepEqual(result.rowsAffected, 0);
60+
assert.deepEqual(result.rows._array, [{
61+
id: 1,
62+
name: "test1"
63+
}, {
64+
id: 2,
65+
name: "test2"
66+
}]);
67+
});
68+
69+
it('should read record by id from database', async () => {
70+
//when
71+
const result = await new Promise((resolve, reject) => {
72+
db.readTransaction((tx) => {
73+
tx.executeSql("select * from test where id=?;", [2], (tx, r) => {
74+
resolve(r);
75+
}, (tx, e) => {
76+
reject(e);
77+
});
78+
});
79+
80+
});
81+
82+
//then
83+
assert.deepEqual(result.insertId, undefined);
84+
assert.deepEqual(result.rowsAffected, 0);
85+
assert.deepEqual(result.rows._array, [{
86+
id: 2,
87+
name: "test2"
88+
}]);
89+
});

package.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"name": "@farjs/better-sqlite3-websql",
3+
"version": "0.0.0",
4+
"repository": {
5+
"type": "git",
6+
"url": "git+https://github.com/farjs/better-sqlite3-websql.git"
7+
},
8+
"author": "viktor-podzigun",
9+
"private": false,
10+
"description": "Cross-runtime implementation of WebSql api backed by better-sqlite3 and bun:sqlite",
11+
"license": "MIT",
12+
"bugs": {
13+
"url": "https://github.com/farjs/better-sqlite3-websql/issues"
14+
},
15+
"homepage": "https://github.com/farjs/better-sqlite3-websql",
16+
"keywords": [
17+
"sqlite",
18+
"cross-runtime",
19+
"bun"
20+
],
21+
"files": [
22+
"index.js",
23+
"SQLiteDatabase.js",
24+
"LICENSE.txt",
25+
"README.md"
26+
],
27+
"main": "./index.js",
28+
"exports": "./index.js",
29+
"browserslist": "maintained node versions",
30+
"engines": {
31+
"node": ">=14.21.1",
32+
"bun": ">=0.5.8"
33+
},
34+
"dependencies": {
35+
"@expo/websql": "^1.0.1",
36+
"@farjs/better-sqlite3-wrapper": "../better-sqlite3-wrapper"
37+
}
38+
}

0 commit comments

Comments
 (0)