better-sqlite3-multiple-ciphers 7.4.7-beta.1 → 7.5.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/deps/download.sh +111 -108
- package/deps/setup.ps1 +9 -11
- package/deps/sqlite3/sqlite3.c +272560 -0
- package/deps/sqlite3/sqlite3.h +12770 -0
- package/deps/sqlite3/sqlite3ext.h +675 -0
- package/deps/sqlite3.gyp +13 -7
- package/deps/symlink.js +7 -4
- package/lib/database.js +17 -6
- package/lib/sqlite-error.js +1 -2
- package/package.json +10 -4
- package/src/better_sqlite3.cpp +46 -35
- package/src/better_sqlite3.hpp +40 -38
- package/.gitattributes +0 -1
- package/.github/workflows/prebuild.yml +0 -49
- package/.github/workflows/test.yml +0 -59
- package/benchmark/benchmark.js +0 -31
- package/benchmark/drivers.js +0 -21
- package/benchmark/index.js +0 -83
- package/benchmark/seed.js +0 -47
- package/benchmark/trials.js +0 -65
- package/benchmark/types/insert.js +0 -16
- package/benchmark/types/select-all.js +0 -14
- package/benchmark/types/select-iterate.js +0 -23
- package/benchmark/types/select.js +0 -14
- package/benchmark/types/transaction.js +0 -40
- package/deps/extract.js +0 -16
- package/deps/sqlite3.tar.gz +0 -0
- package/docs/api.md +0 -645
- package/docs/benchmark.md +0 -38
- package/docs/compilation.md +0 -76
- package/docs/integer.md +0 -79
- package/docs/performance.md +0 -39
- package/docs/threads.md +0 -97
- package/docs/tips.md +0 -35
- package/docs/troubleshooting.md +0 -23
- package/docs/unsafe.md +0 -16
- package/src/better_sqlite3.lzz +0 -88
- package/src/objects/backup.lzz +0 -138
- package/src/objects/database.lzz +0 -468
- package/src/objects/statement-iterator.lzz +0 -138
- package/src/objects/statement.lzz +0 -323
- package/src/util/bind-map.lzz +0 -73
- package/src/util/binder.lzz +0 -190
- package/src/util/constants.lzz +0 -151
- package/src/util/custom-aggregate.lzz +0 -121
- package/src/util/custom-function.lzz +0 -59
- package/src/util/custom-table.lzz +0 -397
- package/src/util/data-converter.lzz +0 -17
- package/src/util/data.lzz +0 -145
- package/src/util/macros.lzz +0 -159
- package/src/util/query-macros.lzz +0 -71
- package/test/00.setup.js +0 -25
- package/test/01.sqlite-error.js +0 -27
- package/test/10.database.open.js +0 -159
- package/test/11.database.close.js +0 -68
- package/test/12.database.pragma.js +0 -65
- package/test/13.database.prepare.js +0 -60
- package/test/14.database.exec.js +0 -46
- package/test/20.statement.run.js +0 -170
- package/test/21.statement.get.js +0 -109
- package/test/22.statement.all.js +0 -129
- package/test/23.statement.iterate.js +0 -223
- package/test/24.statement.bind.js +0 -107
- package/test/25.statement.columns.js +0 -46
- package/test/30.database.transaction.js +0 -157
- package/test/31.database.checkpoint.js +0 -62
- package/test/32.database.function.js +0 -211
- package/test/33.database.aggregate.js +0 -603
- package/test/34.database.table.js +0 -671
- package/test/35.database.load-extension.js +0 -75
- package/test/36.database.backup.js +0 -240
- package/test/37.database.serialize.js +0 -81
- package/test/40.bigints.js +0 -145
- package/test/41.at-exit.js +0 -52
- package/test/42.integrity.js +0 -531
- package/test/43.verbose.js +0 -100
- package/test/44.worker-threads.js +0 -66
- package/test/45.unsafe-mode.js +0 -52
- package/test/46.encryption.js +0 -69
- package/test/50.misc.js +0 -44
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const fs = require('fs');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const Database = require('../.');
|
|
5
|
-
|
|
6
|
-
describe('Database#loadExtension()', function () {
|
|
7
|
-
let filepath;
|
|
8
|
-
before(function () {
|
|
9
|
-
const releaseFilepath = path.join(__dirname, '..', 'build', 'Release', 'test_extension.node');
|
|
10
|
-
const debugFilepath = path.join(__dirname, '..', 'build', 'Debug', 'test_extension.node');
|
|
11
|
-
try {
|
|
12
|
-
fs.accessSync(releaseFilepath);
|
|
13
|
-
filepath = releaseFilepath;
|
|
14
|
-
} catch (_) {
|
|
15
|
-
fs.accessSync(debugFilepath);
|
|
16
|
-
filepath = debugFilepath;
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
beforeEach(function () {
|
|
20
|
-
this.db = new Database(util.next());
|
|
21
|
-
});
|
|
22
|
-
afterEach(function () {
|
|
23
|
-
this.db.close();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('should throw an exception if a string argument is not given', function () {
|
|
27
|
-
expect(() => this.db.loadExtension()).to.throw(TypeError);
|
|
28
|
-
expect(() => this.db.loadExtension(undefined)).to.throw(TypeError);
|
|
29
|
-
expect(() => this.db.loadExtension(null)).to.throw(TypeError);
|
|
30
|
-
expect(() => this.db.loadExtension(123)).to.throw(TypeError);
|
|
31
|
-
expect(() => this.db.loadExtension(new String(filepath))).to.throw(TypeError);
|
|
32
|
-
expect(() => this.db.loadExtension([filepath])).to.throw(TypeError);
|
|
33
|
-
});
|
|
34
|
-
it('should throw an exception if the database is busy', function () {
|
|
35
|
-
let invoked = false;
|
|
36
|
-
for (const value of this.db.prepare('select 555').pluck().iterate()) {
|
|
37
|
-
expect(value).to.equal(555);
|
|
38
|
-
expect(() => this.db.loadExtension(filepath)).to.throw(TypeError);
|
|
39
|
-
invoked = true;
|
|
40
|
-
}
|
|
41
|
-
expect(invoked).to.be.true;
|
|
42
|
-
});
|
|
43
|
-
it('should throw an exception if the extension is not found', function () {
|
|
44
|
-
try {
|
|
45
|
-
this.db.loadExtension(filepath + 'x');
|
|
46
|
-
} catch (err) {
|
|
47
|
-
expect(err).to.be.an.instanceof(Database.SqliteError);
|
|
48
|
-
expect(err.message).to.be.a('string');
|
|
49
|
-
expect(err.message.length).to.be.above(0);
|
|
50
|
-
expect(err.message).to.not.equal('not an error');
|
|
51
|
-
expect(err.code).to.equal('SQLITE_ERROR');
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
throw new Error('This code should not have been reached');
|
|
55
|
-
});
|
|
56
|
-
it('should register the specified extension', function () {
|
|
57
|
-
expect(this.db.loadExtension(filepath)).to.equal(this.db);
|
|
58
|
-
expect(this.db.prepare('SELECT testExtensionFunction(NULL, 123, 99, 2)').pluck().get()).to.equal(4);
|
|
59
|
-
expect(this.db.prepare('SELECT testExtensionFunction(NULL, 2)').pluck().get()).to.equal(2);
|
|
60
|
-
});
|
|
61
|
-
it('should not allow registering extensions with SQL', function () {
|
|
62
|
-
expect(() => this.db.prepare('SELECT load_extension(?)').get(filepath)).to.throw(Database.SqliteError);
|
|
63
|
-
expect(this.db.loadExtension(filepath)).to.equal(this.db);
|
|
64
|
-
expect(() => this.db.prepare('SELECT load_extension(?)').get(filepath)).to.throw(Database.SqliteError);
|
|
65
|
-
this.db.close();
|
|
66
|
-
this.db = new Database(util.next());
|
|
67
|
-
try {
|
|
68
|
-
this.db.loadExtension(filepath + 'x');
|
|
69
|
-
} catch (err) {
|
|
70
|
-
expect(() => this.db.prepare('SELECT load_extension(?)').get(filepath)).to.throw(Database.SqliteError);
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
throw new Error('This code should not have been reached');
|
|
74
|
-
});
|
|
75
|
-
});
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const { existsSync, writeFileSync, readFileSync } = require('fs');
|
|
3
|
-
const Database = require('../.');
|
|
4
|
-
|
|
5
|
-
describe('Database#backup()', function () {
|
|
6
|
-
beforeEach(function () {
|
|
7
|
-
this.db = new Database(util.next());
|
|
8
|
-
this.db.prepare("CREATE TABLE entries (a TEXT, b INTEGER, c REAL, d BLOB, e TEXT)").run();
|
|
9
|
-
this.db.prepare("INSERT INTO entries WITH RECURSIVE temp(a, b, c, d, e) AS (SELECT 'foo', 1, 3.14, x'dddddddd', NULL UNION ALL SELECT a, b + 1, c, d, e FROM temp LIMIT 5) SELECT * FROM temp").run();
|
|
10
|
-
});
|
|
11
|
-
afterEach(function () {
|
|
12
|
-
this.db.close();
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
const fulfillsWith = (value, p) => p.then(v => void expect(v).to.deep.equal(value));
|
|
16
|
-
const rejectsWith = (type, p) => {
|
|
17
|
-
const shouldReject = () => { throw new Error('Promise should have been rejected') };
|
|
18
|
-
const reasonIs = (reason) => { if (!(reason instanceof type)) throw reason; }
|
|
19
|
-
return p.then(shouldReject, reasonIs);
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
it('should be rejected when destination is not a string', async function () {
|
|
23
|
-
await rejectsWith(TypeError, this.db.backup());
|
|
24
|
-
await rejectsWith(TypeError, this.db.backup(null));
|
|
25
|
-
await rejectsWith(TypeError, this.db.backup(0));
|
|
26
|
-
await rejectsWith(TypeError, this.db.backup(123));
|
|
27
|
-
await rejectsWith(TypeError, this.db.backup(new String(util.next())));
|
|
28
|
-
await rejectsWith(TypeError, this.db.backup(() => util.next()));
|
|
29
|
-
await rejectsWith(TypeError, this.db.backup([util.next()]));
|
|
30
|
-
});
|
|
31
|
-
it('should not allow an empty destination string', async function () {
|
|
32
|
-
await rejectsWith(TypeError, this.db.backup(''));
|
|
33
|
-
await rejectsWith(TypeError, this.db.backup(' \t\n '));
|
|
34
|
-
});
|
|
35
|
-
it('should not allow a :memory: destination', async function () {
|
|
36
|
-
await rejectsWith(TypeError, this.db.backup(':memory:'));
|
|
37
|
-
expect(existsSync(':memory:')).to.be.false;
|
|
38
|
-
});
|
|
39
|
-
it('should backup the database and fulfill the returned promise', async function () {
|
|
40
|
-
expect(existsSync(this.db.name)).to.be.true;
|
|
41
|
-
expect(existsSync(util.next())).to.be.false;
|
|
42
|
-
const promise = this.db.backup(util.current());
|
|
43
|
-
expect(existsSync(util.current())).to.be.false;
|
|
44
|
-
await fulfillsWith({ totalPages: 2, remainingPages: 0 }, promise);
|
|
45
|
-
expect(existsSync(this.db.name)).to.be.true;
|
|
46
|
-
expect(existsSync(util.current())).to.be.true;
|
|
47
|
-
const rows = this.db.prepare('SELECT * FROM entries').all();
|
|
48
|
-
this.db.close();
|
|
49
|
-
this.db = new Database(util.current());
|
|
50
|
-
expect(this.db.prepare('SELECT * FROM entries').all()).to.deep.equal(rows);
|
|
51
|
-
});
|
|
52
|
-
it('should be rejected if the directory does not exist', async function () {
|
|
53
|
-
expect(existsSync(util.next())).to.be.false;
|
|
54
|
-
const filepath = `temp/nonexistent/abcfoobar123/${util.current()}`;
|
|
55
|
-
await rejectsWith(TypeError, this.db.backup(filepath));
|
|
56
|
-
expect(existsSync(filepath)).to.be.false;
|
|
57
|
-
expect(existsSync(util.current())).to.be.false;
|
|
58
|
-
});
|
|
59
|
-
it('should be rejected if a database cannot be opened at the destination', async function () {
|
|
60
|
-
writeFileSync(util.next(), 'not a database file');
|
|
61
|
-
await rejectsWith(Database.SqliteError, this.db.backup(util.current()));
|
|
62
|
-
expect(readFileSync(util.current(), 'utf8')).to.equal('not a database file');
|
|
63
|
-
});
|
|
64
|
-
it('should accept the "attached" option', async function () {
|
|
65
|
-
const source = this.db.name;
|
|
66
|
-
const destination = util.next();
|
|
67
|
-
let promise;
|
|
68
|
-
this.db.close();
|
|
69
|
-
this.db = new Database(':memory:');
|
|
70
|
-
this.db.prepare('ATTACH ? AS cool_db').run(source);
|
|
71
|
-
expect(existsSync(source)).to.be.true;
|
|
72
|
-
expect(existsSync(destination)).to.be.false;
|
|
73
|
-
await fulfillsWith({ totalPages: 2, remainingPages: 0 },
|
|
74
|
-
this.db.backup(destination, { attached: 'cool_db' }));
|
|
75
|
-
expect(existsSync(source)).to.be.true;
|
|
76
|
-
expect(existsSync(destination)).to.be.true;
|
|
77
|
-
const rows = this.db.prepare('SELECT * FROM cool_db.entries').all();
|
|
78
|
-
this.db.close();
|
|
79
|
-
this.db = new Database(destination);
|
|
80
|
-
expect(this.db.prepare('SELECT * FROM main.entries').all()).to.deep.equal(rows);
|
|
81
|
-
});
|
|
82
|
-
it('should accept the "progress" option', async function () {
|
|
83
|
-
expect(existsSync(this.db.name)).to.be.true;
|
|
84
|
-
expect(existsSync(util.next())).to.be.false;
|
|
85
|
-
const calls = [];
|
|
86
|
-
const promise = this.db.backup(util.current(), { progress(...args) {
|
|
87
|
-
calls.push([this, ...args]);
|
|
88
|
-
} });
|
|
89
|
-
expect(existsSync(util.current())).to.be.false;
|
|
90
|
-
await fulfillsWith({ totalPages: 2, remainingPages: 0 }, promise);
|
|
91
|
-
expect(existsSync(this.db.name)).to.be.true;
|
|
92
|
-
expect(existsSync(util.current())).to.be.true;
|
|
93
|
-
const rows = this.db.prepare('SELECT * FROM entries').all();
|
|
94
|
-
this.db.close();
|
|
95
|
-
this.db = new Database(util.current());
|
|
96
|
-
expect(this.db.prepare('SELECT * FROM entries').all()).to.deep.equal(rows);
|
|
97
|
-
expect(calls).to.deep.equal([[undefined, { totalPages: 2, remainingPages: 2 }]]);
|
|
98
|
-
});
|
|
99
|
-
it('should allow control over transfer sizes via the progress callback', async function () {
|
|
100
|
-
let transferSize = 0;
|
|
101
|
-
const expected = [];
|
|
102
|
-
const actual = [];
|
|
103
|
-
const promise = this.db.backup(util.next(), { progress(state) {
|
|
104
|
-
actual.push(state);
|
|
105
|
-
return transferSize;
|
|
106
|
-
} });
|
|
107
|
-
promise.catch(() => {});
|
|
108
|
-
expect(actual).to.deep.equal(expected);
|
|
109
|
-
while (!actual.length) await new Promise(setImmediate);
|
|
110
|
-
expected.push({ totalPages: 2, remainingPages: 2 });
|
|
111
|
-
expect(actual).to.deep.equal(expected);
|
|
112
|
-
await new Promise(setImmediate);
|
|
113
|
-
transferSize = 1;
|
|
114
|
-
await new Promise(setImmediate);
|
|
115
|
-
expected.push({ totalPages: 2, remainingPages: 2 });
|
|
116
|
-
expected.push({ totalPages: 2, remainingPages: 2 });
|
|
117
|
-
expect(actual).to.deep.equal(expected);
|
|
118
|
-
await new Promise(setImmediate);
|
|
119
|
-
expected.push({ totalPages: 2, remainingPages: 1 });
|
|
120
|
-
expect(actual).to.deep.equal(expected);
|
|
121
|
-
const payload = Buffer.alloc(4096 * 5).fill(0x7a).toString();
|
|
122
|
-
this.db.prepare('INSERT INTO entries (a, b) VALUES (?, 999)').run(payload);
|
|
123
|
-
transferSize = Infinity;
|
|
124
|
-
await new Promise(setImmediate);
|
|
125
|
-
expected.push({ totalPages: 7, remainingPages: 5 });
|
|
126
|
-
expect(actual).to.deep.equal(expected);
|
|
127
|
-
await new Promise(setImmediate);
|
|
128
|
-
expect(actual).to.deep.equal(expected);
|
|
129
|
-
await fulfillsWith({ totalPages: 7, remainingPages: 0 }, promise);
|
|
130
|
-
this.db.close();
|
|
131
|
-
this.db = new Database(util.current());
|
|
132
|
-
expect(this.db.prepare('SELECT a FROM entries WHERE b = 999').pluck().get()).to.deep.equal(payload);
|
|
133
|
-
});
|
|
134
|
-
it('should be aborted if an error is thrown inside the progress callback', async function () {
|
|
135
|
-
const promise = this.db.backup(util.next(), { progress: () => { throw new SyntaxError('foo'); } });
|
|
136
|
-
await rejectsWith(SyntaxError, promise);
|
|
137
|
-
});
|
|
138
|
-
it('should be aborted if the progress callback returns a non-number', async function () {
|
|
139
|
-
const backup = x => this.db.backup(util.next(), { progress: () => x });
|
|
140
|
-
await rejectsWith(TypeError, backup(null));
|
|
141
|
-
await rejectsWith(TypeError, backup(new Number(1)));
|
|
142
|
-
await rejectsWith(TypeError, backup(() => 1));
|
|
143
|
-
await rejectsWith(TypeError, backup([1]));
|
|
144
|
-
await rejectsWith(TypeError, backup('1'));
|
|
145
|
-
});
|
|
146
|
-
it('should rollback an aborted backup file if it was not newly created', async function () {
|
|
147
|
-
const otherDb = new Database(util.next());
|
|
148
|
-
try {
|
|
149
|
-
otherDb.prepare('CREATE TABLE foo (bar)').run()
|
|
150
|
-
otherDb.prepare('INSERT INTO foo VALUES (2), (8)').run();
|
|
151
|
-
} finally {
|
|
152
|
-
otherDb.close();
|
|
153
|
-
}
|
|
154
|
-
let error;
|
|
155
|
-
let transferSize = 0;
|
|
156
|
-
const expected = [];
|
|
157
|
-
const actual = [];
|
|
158
|
-
const promise = this.db.backup(util.current(), { progress(state) {
|
|
159
|
-
actual.push(state);
|
|
160
|
-
if (error) throw error;
|
|
161
|
-
return transferSize;
|
|
162
|
-
} });
|
|
163
|
-
promise.catch(() => {});
|
|
164
|
-
expect(actual).to.deep.equal(expected);
|
|
165
|
-
while (!actual.length) await new Promise(setImmediate);
|
|
166
|
-
expected.push({ totalPages: 2, remainingPages: 2 });
|
|
167
|
-
expect(actual).to.deep.equal(expected);
|
|
168
|
-
transferSize = 1;
|
|
169
|
-
await new Promise(setImmediate);
|
|
170
|
-
expected.push({ totalPages: 2, remainingPages: 2 });
|
|
171
|
-
expect(actual).to.deep.equal(expected);
|
|
172
|
-
transferSize = 0;
|
|
173
|
-
await new Promise(setImmediate);
|
|
174
|
-
expected.push({ totalPages: 2, remainingPages: 1 });
|
|
175
|
-
expect(actual).to.deep.equal(expected);
|
|
176
|
-
error = new SyntaxError('foo');
|
|
177
|
-
await new Promise(setImmediate);
|
|
178
|
-
expected.push({ totalPages: 2, remainingPages: 1 });
|
|
179
|
-
expect(actual).to.deep.equal(expected);
|
|
180
|
-
await rejectsWith(SyntaxError, promise);
|
|
181
|
-
expect(actual).to.deep.equal(expected);
|
|
182
|
-
expect(existsSync(util.current())).to.be.true;
|
|
183
|
-
this.db.close();
|
|
184
|
-
this.db = new Database(util.current());
|
|
185
|
-
expect(this.db.prepare('SELECT bar FROM foo').pluck().all()).to.deep.equal([2, 8]);
|
|
186
|
-
});
|
|
187
|
-
it('should delete an aborted backup file if it was newly created', async function () {
|
|
188
|
-
let error;
|
|
189
|
-
let transferSize = 0;
|
|
190
|
-
const expected = [];
|
|
191
|
-
const actual = [];
|
|
192
|
-
const promise = this.db.backup(util.next(), { progress(state) {
|
|
193
|
-
actual.push(state);
|
|
194
|
-
if (error) throw error;
|
|
195
|
-
return transferSize;
|
|
196
|
-
} });
|
|
197
|
-
promise.catch(() => {});
|
|
198
|
-
expect(actual).to.deep.equal(expected);
|
|
199
|
-
while (!actual.length) await new Promise(setImmediate);
|
|
200
|
-
expected.push({ totalPages: 2, remainingPages: 2 });
|
|
201
|
-
expect(actual).to.deep.equal(expected);
|
|
202
|
-
transferSize = 1;
|
|
203
|
-
await new Promise(setImmediate);
|
|
204
|
-
expected.push({ totalPages: 2, remainingPages: 2 });
|
|
205
|
-
expect(actual).to.deep.equal(expected);
|
|
206
|
-
transferSize = 0;
|
|
207
|
-
await new Promise(setImmediate);
|
|
208
|
-
expected.push({ totalPages: 2, remainingPages: 1 });
|
|
209
|
-
expect(actual).to.deep.equal(expected);
|
|
210
|
-
error = new SyntaxError('foo');
|
|
211
|
-
await new Promise(setImmediate);
|
|
212
|
-
expected.push({ totalPages: 2, remainingPages: 1 });
|
|
213
|
-
expect(actual).to.deep.equal(expected);
|
|
214
|
-
await rejectsWith(SyntaxError, promise);
|
|
215
|
-
expect(actual).to.deep.equal(expected);
|
|
216
|
-
expect(existsSync(util.current())).to.be.false;
|
|
217
|
-
});
|
|
218
|
-
it('should be aborted if the connection is closed during a backup', async function () {
|
|
219
|
-
let transferSize = 0;
|
|
220
|
-
const calls = [];
|
|
221
|
-
const promise = this.db.backup(util.next(), { progress(state) {
|
|
222
|
-
calls.push(state);
|
|
223
|
-
return transferSize;
|
|
224
|
-
} });
|
|
225
|
-
promise.catch(() => {});
|
|
226
|
-
while (!calls.length) await new Promise(setImmediate);
|
|
227
|
-
transferSize = 1;
|
|
228
|
-
await new Promise(setImmediate);
|
|
229
|
-
await new Promise(setImmediate);
|
|
230
|
-
this.db.close();
|
|
231
|
-
expect(this.db.open).to.be.false;
|
|
232
|
-
await rejectsWith(TypeError, promise);
|
|
233
|
-
expect(calls).to.deep.equal([
|
|
234
|
-
{ totalPages: 2, remainingPages: 2 },
|
|
235
|
-
{ totalPages: 2, remainingPages: 2 },
|
|
236
|
-
{ totalPages: 2, remainingPages: 1 },
|
|
237
|
-
]);
|
|
238
|
-
expect(existsSync(util.current())).to.be.false;
|
|
239
|
-
});
|
|
240
|
-
});
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const Database = require('../.');
|
|
3
|
-
|
|
4
|
-
describe('Database#serialize()', function () {
|
|
5
|
-
beforeEach(function () {
|
|
6
|
-
this.db = new Database(util.next());
|
|
7
|
-
this.db.prepare("CREATE TABLE entries (a TEXT, b INTEGER, c REAL, d BLOB, e TEXT)").run();
|
|
8
|
-
this.seed = () => {
|
|
9
|
-
this.db.prepare("INSERT INTO entries WITH RECURSIVE temp(a, b, c, d, e) AS (SELECT 'foo', 1, 3.14, x'dddddddd', NULL UNION ALL SELECT a, b + 1, c, d, e FROM temp LIMIT 1000) SELECT * FROM temp").run();
|
|
10
|
-
};
|
|
11
|
-
});
|
|
12
|
-
afterEach(function () {
|
|
13
|
-
this.db.close();
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
it('should serialize the database and return a buffer', async function () {
|
|
17
|
-
let buffer = this.db.serialize();
|
|
18
|
-
expect(buffer).to.be.an.instanceof(Buffer);
|
|
19
|
-
expect(buffer.length).to.be.above(1000);
|
|
20
|
-
const lengthBefore = buffer.length;
|
|
21
|
-
this.seed();
|
|
22
|
-
buffer = this.db.serialize();
|
|
23
|
-
expect(buffer).to.be.an.instanceof(Buffer);
|
|
24
|
-
expect(buffer.length).to.be.above(lengthBefore);
|
|
25
|
-
});
|
|
26
|
-
it('should return a buffer that can be used by the Database constructor', async function () {
|
|
27
|
-
this.seed();
|
|
28
|
-
const buffer = this.db.serialize();
|
|
29
|
-
expect(buffer).to.be.an.instanceof(Buffer);
|
|
30
|
-
expect(buffer.length).to.be.above(1000);
|
|
31
|
-
this.db.prepare('delete from entries').run();
|
|
32
|
-
this.db.close();
|
|
33
|
-
this.db = new Database(buffer);
|
|
34
|
-
const bufferCopy = this.db.serialize();
|
|
35
|
-
expect(buffer.length).to.equal(bufferCopy.length);
|
|
36
|
-
expect(buffer).to.deep.equal(bufferCopy);
|
|
37
|
-
this.db.prepare('insert into entries (rowid, a, b) values (?, ?, ?)').run(0, 'bar', -999);
|
|
38
|
-
expect(this.db.prepare('select a, b from entries order by rowid limit 2').all())
|
|
39
|
-
.to.deep.equal([{ a: 'bar', b: -999 }, { a: 'foo', b: 1 }]);
|
|
40
|
-
});
|
|
41
|
-
it('should accept the "attached" option', async function () {
|
|
42
|
-
const smallBuffer = this.db.serialize();
|
|
43
|
-
this.seed();
|
|
44
|
-
const bigBuffer = this.db.serialize();
|
|
45
|
-
this.db.close();
|
|
46
|
-
this.db = new Database();
|
|
47
|
-
this.db.prepare('attach ? as other').run(util.current());
|
|
48
|
-
const smallBuffer2 = this.db.serialize();
|
|
49
|
-
const bigBuffer2 = this.db.serialize({ attached: 'other' });
|
|
50
|
-
expect(bigBuffer.length === bigBuffer2.length);
|
|
51
|
-
expect(bigBuffer).to.deep.equal(bigBuffer2);
|
|
52
|
-
expect(smallBuffer.length < bigBuffer.length);
|
|
53
|
-
expect(smallBuffer2.length < bigBuffer.length);
|
|
54
|
-
expect(smallBuffer).to.not.deep.equal(smallBuffer2);
|
|
55
|
-
});
|
|
56
|
-
it('should return a buffer that can be opened with the "readonly" option', async function () {
|
|
57
|
-
this.seed();
|
|
58
|
-
const buffer = this.db.serialize();
|
|
59
|
-
expect(buffer).to.be.an.instanceof(Buffer);
|
|
60
|
-
expect(buffer.length).to.be.above(1000);
|
|
61
|
-
this.db.close();
|
|
62
|
-
this.db = new Database(buffer, { readonly: true });
|
|
63
|
-
expect(() => this.db.prepare('insert into entries (rowid, a, b) values (?, ?, ?)').run(0, 'bar', -999))
|
|
64
|
-
.to.throw(Database.SqliteError);
|
|
65
|
-
expect(this.db.prepare('select a, b from entries order by rowid limit 2').all())
|
|
66
|
-
.to.deep.equal([{ a: 'foo', b: 1 }, { a: 'foo', b: 2 }]);
|
|
67
|
-
const bufferCopy = this.db.serialize();
|
|
68
|
-
expect(buffer.length).to.equal(bufferCopy.length);
|
|
69
|
-
expect(buffer).to.deep.equal(bufferCopy);
|
|
70
|
-
});
|
|
71
|
-
it('should work with an empty database', async function () {
|
|
72
|
-
this.db.close();
|
|
73
|
-
this.db = new Database();
|
|
74
|
-
const buffer = this.db.serialize();
|
|
75
|
-
expect(buffer).to.be.an.instanceof(Buffer);
|
|
76
|
-
expect(buffer.length).to.equal(0);
|
|
77
|
-
this.db.close();
|
|
78
|
-
this.db = new Database(buffer);
|
|
79
|
-
expect(this.db.serialize().length).to.equal(0);
|
|
80
|
-
});
|
|
81
|
-
});
|
package/test/40.bigints.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const Database = require('../.');
|
|
3
|
-
|
|
4
|
-
describe('BigInts', function () {
|
|
5
|
-
beforeEach(function () {
|
|
6
|
-
this.db = new Database(util.next());
|
|
7
|
-
this.db.prepare('CREATE TABLE entries (a INTEGER, b REAL, c TEXT)').run();
|
|
8
|
-
});
|
|
9
|
-
afterEach(function () {
|
|
10
|
-
this.db.close();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('should bind to prepared statements', function () {
|
|
14
|
-
const int = BigInt('1006028374637854687');
|
|
15
|
-
this.db.prepare('INSERT INTO entries VALUES (?, ?, ?)').run(int, int, int);
|
|
16
|
-
this.db.prepare('INSERT INTO entries VALUES (?, ?, ?)').bind(int, int, int).run();
|
|
17
|
-
|
|
18
|
-
const db2 = new Database(util.next());
|
|
19
|
-
try {
|
|
20
|
-
db2.prepare('CREATE TABLE entries (a INTEGER, b REAL, c TEXT)').run();
|
|
21
|
-
db2.prepare('INSERT INTO entries VALUES (?, ?, ?)').run(int, int, int);
|
|
22
|
-
db2.prepare('INSERT INTO entries VALUES (?, ?, ?)').bind(int, int, int).run();
|
|
23
|
-
} finally {
|
|
24
|
-
db2.close();
|
|
25
|
-
}
|
|
26
|
-
});
|
|
27
|
-
it('should be allowed as a return value in user-defined functions', function () {
|
|
28
|
-
this.db.function('returnsInteger', a => BigInt(a + a));
|
|
29
|
-
expect(this.db.prepare('SELECT returnsInteger(?)').pluck().get(42)).to.equal(84);
|
|
30
|
-
});
|
|
31
|
-
it('should get returned by operations after setting .safeIntegers()', function () {
|
|
32
|
-
const int = BigInt('1006028374637854687');
|
|
33
|
-
this.db.prepare('INSERT INTO entries VALUES (?, ?, ?)').run(int, int, int);
|
|
34
|
-
this.db.prepare('INSERT INTO entries VALUES (?, ?, ?)').run(int, int, int);
|
|
35
|
-
|
|
36
|
-
let stmt = this.db.prepare('SELECT a FROM entries').pluck();
|
|
37
|
-
expect(stmt.get()).to.equal(1006028374637854700);
|
|
38
|
-
expect(stmt.safeIntegers().get()).to.deep.equal(int);
|
|
39
|
-
expect(stmt.get()).to.deep.equal(int);
|
|
40
|
-
expect(stmt.safeIntegers(false).get()).to.equal(1006028374637854700);
|
|
41
|
-
expect(stmt.get()).to.equal(1006028374637854700);
|
|
42
|
-
expect(stmt.safeIntegers(true).get()).to.deep.equal(int);
|
|
43
|
-
expect(stmt.get()).to.deep.equal(int);
|
|
44
|
-
|
|
45
|
-
stmt = this.db.prepare('SELECT b FROM entries').pluck();
|
|
46
|
-
expect(stmt.get()).to.equal(1006028374637854700);
|
|
47
|
-
expect(stmt.safeIntegers().get()).to.equal(1006028374637854700);
|
|
48
|
-
|
|
49
|
-
stmt = this.db.prepare('SELECT c FROM entries').pluck();
|
|
50
|
-
expect(stmt.get()).to.equal('1006028374637854687');
|
|
51
|
-
expect(stmt.safeIntegers().get()).to.equal('1006028374637854687');
|
|
52
|
-
|
|
53
|
-
let lastRowid = this.db.prepare('SELECT rowid FROM entries ORDER BY rowid DESC').pluck().get();
|
|
54
|
-
stmt = this.db.prepare('INSERT INTO entries VALUES (?, ?, ?)');
|
|
55
|
-
expect(stmt.run(int, int, int).lastInsertRowid).to.equal(++lastRowid);
|
|
56
|
-
expect(stmt.safeIntegers().run(int, int, int).lastInsertRowid).to.deep.equal(BigInt(++lastRowid));
|
|
57
|
-
expect(stmt.run(int, int, int).lastInsertRowid).to.deep.equal(BigInt(++lastRowid));
|
|
58
|
-
expect(stmt.safeIntegers(false).run(int, int, int).lastInsertRowid).to.equal(++lastRowid);
|
|
59
|
-
});
|
|
60
|
-
it('should get passed to functions defined with the "safeIntegers" option', function () {
|
|
61
|
-
this.db.function('customfunc', { safeIntegers: true }, (a) => { return (typeof a) + a; });
|
|
62
|
-
expect(this.db.prepare('SELECT customfunc(?)').pluck().get(2)).to.equal('number2');
|
|
63
|
-
expect(this.db.prepare('SELECT customfunc(?)').pluck().get(BigInt(2))).to.equal('bigint2');
|
|
64
|
-
});
|
|
65
|
-
it('should get passed to aggregates defined with the "safeIntegers" option', function () {
|
|
66
|
-
this.db.aggregate('customagg', { safeIntegers: true, step: (_, a) => { return (typeof a) + a; } });
|
|
67
|
-
expect(this.db.prepare('SELECT customagg(?)').pluck().get(2)).to.equal('number2');
|
|
68
|
-
expect(this.db.prepare('SELECT customagg(?)').pluck().get(BigInt(2))).to.equal('bigint2');
|
|
69
|
-
});
|
|
70
|
-
it('should get passed to virtual tables defined with the "safeIntegers" option', function () {
|
|
71
|
-
this.db.table('customvtab', { safeIntegers: true, columns: ['x'], *rows(a) { yield [(typeof a) + a]; } });
|
|
72
|
-
expect(this.db.prepare('SELECT * FROM customvtab(?)').pluck().get(2)).to.equal('number2');
|
|
73
|
-
expect(this.db.prepare('SELECT * FROM customvtab(?)').pluck().get(BigInt(2))).to.equal('bigint2');
|
|
74
|
-
});
|
|
75
|
-
it('should respect the default setting on the database', function () {
|
|
76
|
-
let arg;
|
|
77
|
-
const int = BigInt('1006028374637854687');
|
|
78
|
-
const customFunctionArg = (name, options, dontDefine) => {
|
|
79
|
-
dontDefine || this.db.function(name, options, (a) => { arg = a; });
|
|
80
|
-
this.db.prepare(`SELECT ${name}(?)`).get(int);
|
|
81
|
-
return arg;
|
|
82
|
-
};
|
|
83
|
-
const customAggregateArg = (name, options, dontDefine) => {
|
|
84
|
-
dontDefine || this.db.aggregate(name, { ...options, step: (_, a) => { arg = a; } });
|
|
85
|
-
this.db.prepare(`SELECT ${name}(?)`).get(int);
|
|
86
|
-
return arg;
|
|
87
|
-
};
|
|
88
|
-
const customTableArg = (name, options, dontDefine) => {
|
|
89
|
-
dontDefine || this.db.table(name, { ...options, columns: ['x'], *rows(a) { arg = a; } });
|
|
90
|
-
this.db.prepare(`SELECT * FROM ${name}(?)`).get(int);
|
|
91
|
-
return arg;
|
|
92
|
-
};
|
|
93
|
-
this.db.prepare('INSERT INTO entries VALUES (?, ?, ?)').run(int, int, int);
|
|
94
|
-
this.db.defaultSafeIntegers(true);
|
|
95
|
-
|
|
96
|
-
const stmt = this.db.prepare('SELECT a FROM entries').pluck();
|
|
97
|
-
expect(stmt.get()).to.deep.equal(int);
|
|
98
|
-
expect(stmt.safeIntegers(false).get()).to.equal(1006028374637854700);
|
|
99
|
-
expect(customFunctionArg('a1')).to.deep.equal(int);
|
|
100
|
-
expect(customFunctionArg('a2', { safeIntegers: false })).to.equal(1006028374637854700);
|
|
101
|
-
expect(customAggregateArg('a1')).to.deep.equal(int);
|
|
102
|
-
expect(customAggregateArg('a2', { safeIntegers: false })).to.equal(1006028374637854700);
|
|
103
|
-
expect(customTableArg('a1')).to.deep.equal(int);
|
|
104
|
-
expect(customTableArg('a2', { safeIntegers: false })).to.equal(1006028374637854700);
|
|
105
|
-
|
|
106
|
-
this.db.defaultSafeIntegers(false);
|
|
107
|
-
|
|
108
|
-
const stmt2 = this.db.prepare('SELECT a FROM entries').pluck();
|
|
109
|
-
expect(stmt2.get()).to.equal(1006028374637854700);
|
|
110
|
-
expect(stmt2.safeIntegers().get()).to.deep.equal(int);
|
|
111
|
-
expect(customFunctionArg('a3')).to.equal(1006028374637854700);
|
|
112
|
-
expect(customFunctionArg('a4', { safeIntegers: true })).to.deep.equal(int);
|
|
113
|
-
expect(customAggregateArg('a3')).to.equal(1006028374637854700);
|
|
114
|
-
expect(customAggregateArg('a4', { safeIntegers: true })).to.deep.equal(int);
|
|
115
|
-
expect(customTableArg('a3')).to.equal(1006028374637854700);
|
|
116
|
-
expect(customTableArg('a4', { safeIntegers: true })).to.deep.equal(int);
|
|
117
|
-
|
|
118
|
-
this.db.defaultSafeIntegers();
|
|
119
|
-
|
|
120
|
-
expect(stmt.get()).to.equal(1006028374637854700);
|
|
121
|
-
expect(stmt2.get()).to.deep.equal(int);
|
|
122
|
-
expect(customFunctionArg('a1', {}, true)).to.deep.equal(int);
|
|
123
|
-
expect(customFunctionArg('a2', {}, true)).to.equal(1006028374637854700);
|
|
124
|
-
expect(customFunctionArg('a3', {}, true)).to.equal(1006028374637854700);
|
|
125
|
-
expect(customFunctionArg('a4', {}, true)).to.deep.equal(int);
|
|
126
|
-
expect(customAggregateArg('a1', {}, true)).to.deep.equal(int);
|
|
127
|
-
expect(customAggregateArg('a2', {}, true)).to.equal(1006028374637854700);
|
|
128
|
-
expect(customAggregateArg('a3', {}, true)).to.equal(1006028374637854700);
|
|
129
|
-
expect(customAggregateArg('a4', {}, true)).to.deep.equal(int);
|
|
130
|
-
expect(customTableArg('a1', {}, true)).to.deep.equal(int);
|
|
131
|
-
expect(customTableArg('a2', {}, true)).to.equal(1006028374637854700);
|
|
132
|
-
expect(customTableArg('a3', {}, true)).to.equal(1006028374637854700);
|
|
133
|
-
expect(customTableArg('a4', {}, true)).to.deep.equal(int);
|
|
134
|
-
|
|
135
|
-
const stmt3 = this.db.prepare('SELECT a FROM entries').pluck();
|
|
136
|
-
expect(stmt3.get()).to.deep.equal(int);
|
|
137
|
-
expect(stmt3.safeIntegers(false).get()).to.equal(1006028374637854700);
|
|
138
|
-
expect(customFunctionArg('a5')).to.deep.equal(int);
|
|
139
|
-
expect(customFunctionArg('a6', { safeIntegers: false })).to.equal(1006028374637854700);
|
|
140
|
-
expect(customAggregateArg('a5')).to.deep.equal(int);
|
|
141
|
-
expect(customAggregateArg('a6', { safeIntegers: false })).to.equal(1006028374637854700);
|
|
142
|
-
expect(customTableArg('a5')).to.deep.equal(int);
|
|
143
|
-
expect(customTableArg('a6', { safeIntegers: false })).to.equal(1006028374637854700);
|
|
144
|
-
});
|
|
145
|
-
});
|
package/test/41.at-exit.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const { existsSync, writeFileSync } = require('fs');
|
|
3
|
-
const { fork } = require('child_process');
|
|
4
|
-
|
|
5
|
-
describe('node::AtExit()', function () {
|
|
6
|
-
this.slow(500);
|
|
7
|
-
|
|
8
|
-
const source = (filename1, filename2) => `
|
|
9
|
-
'use strict';
|
|
10
|
-
const Database = require('../.');
|
|
11
|
-
const db1 = new Database('${filename1.replace(/(?=\W)/g, '\\')}');
|
|
12
|
-
const db2 = new Database('${filename2.replace(/(?=\W)/g, '\\')}');
|
|
13
|
-
for (const db of [db1, db2]) {
|
|
14
|
-
db.pragma('journal_mode = WAL');
|
|
15
|
-
db.prepare('CREATE TABLE people (name TEXT)').run();
|
|
16
|
-
db.prepare('INSERT INTO people VALUES (\\'foobar\\')').run();
|
|
17
|
-
}
|
|
18
|
-
const interval = setInterval(() => {}, 60000);
|
|
19
|
-
const messageHandler = (message) => {
|
|
20
|
-
if (message !== 'bar') return;
|
|
21
|
-
clearInterval(interval);
|
|
22
|
-
process.removeListener('message', messageHandler);
|
|
23
|
-
};
|
|
24
|
-
process.on('message', messageHandler);
|
|
25
|
-
process.send('foo');
|
|
26
|
-
`;
|
|
27
|
-
|
|
28
|
-
it('should close all databases when the process exits gracefully', async function () {
|
|
29
|
-
const filename1 = util.next();
|
|
30
|
-
const filename2 = util.next();
|
|
31
|
-
const jsFile = filename1 + '.js';
|
|
32
|
-
writeFileSync(jsFile, source(filename1, filename2));
|
|
33
|
-
await new Promise((resolve, reject) => {
|
|
34
|
-
const child = fork(jsFile);
|
|
35
|
-
child.on('error', reject);
|
|
36
|
-
child.on('close', () => reject(new Error('Child process was closed prematurely')));
|
|
37
|
-
child.on('message', (message) => {
|
|
38
|
-
if (message !== 'foo') return;
|
|
39
|
-
expect(existsSync(filename1)).to.be.true;
|
|
40
|
-
expect(existsSync(filename1 + '-wal')).to.be.true;
|
|
41
|
-
expect(existsSync(filename2)).to.be.true;
|
|
42
|
-
expect(existsSync(filename2 + '-wal')).to.be.true;
|
|
43
|
-
child.on('exit', resolve);
|
|
44
|
-
child.send('bar');
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
expect(existsSync(filename1)).to.be.true;
|
|
48
|
-
expect(existsSync(filename1 + '-wal')).to.be.false;
|
|
49
|
-
expect(existsSync(filename2)).to.be.true;
|
|
50
|
-
expect(existsSync(filename2 + '-wal')).to.be.false;
|
|
51
|
-
});
|
|
52
|
-
});
|