better-sqlite3-multiple-ciphers 7.4.6-beta.0 → 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 +14 -7
- package/deps/download.sh +111 -108
- package/deps/setup.ps1 +10 -12
- 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 -31
- package/test/50.misc.js +0 -44
package/src/util/macros.lzz
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
#define NODE_ARGUMENTS const v8::FunctionCallbackInfo<v8::Value>&
|
|
2
|
-
#define NODE_ARGUMENTS_POINTER const v8::FunctionCallbackInfo<v8::Value>*
|
|
3
|
-
#define NODE_METHOD(name) static void name(NODE_ARGUMENTS info)
|
|
4
|
-
#define NODE_GETTER(name) static void name(v8::Local<v8::String> _, const v8::PropertyCallbackInfo<v8::Value>& info)
|
|
5
|
-
#define INIT(name) static v8::Local<v8::Function> name(v8::Isolate* isolate, v8::Local<v8::External> data)
|
|
6
|
-
|
|
7
|
-
#define EasyIsolate v8::Isolate* isolate = v8::Isolate::GetCurrent()
|
|
8
|
-
#define OnlyIsolate info.GetIsolate()
|
|
9
|
-
#define OnlyContext isolate->GetCurrentContext()
|
|
10
|
-
#define OnlyAddon static_cast<Addon*>(info.Data().As<v8::External>()->Value())
|
|
11
|
-
#define UseIsolate v8::Isolate* isolate = OnlyIsolate
|
|
12
|
-
#define UseContext v8::Local<v8::Context> ctx = OnlyContext
|
|
13
|
-
#define UseAddon Addon* addon = OnlyAddon
|
|
14
|
-
#define Unwrap node::ObjectWrap::Unwrap
|
|
15
|
-
|
|
16
|
-
inline v8::Local<v8::String> StringFromUtf8(v8::Isolate* isolate, const char* data, int length) {
|
|
17
|
-
return v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kNormal, length).ToLocalChecked();
|
|
18
|
-
}
|
|
19
|
-
inline v8::Local<v8::String> InternalizedFromUtf8(v8::Isolate* isolate, const char* data, int length) {
|
|
20
|
-
return v8::String::NewFromUtf8(isolate, data, v8::NewStringType::kInternalized, length).ToLocalChecked();
|
|
21
|
-
}
|
|
22
|
-
inline v8::Local<v8::Value> InternalizedFromUtf8OrNull(v8::Isolate* isolate, const char* data, int length) {
|
|
23
|
-
if (data == NULL) return v8::Null(isolate);
|
|
24
|
-
return InternalizedFromUtf8(isolate, data, length);
|
|
25
|
-
}
|
|
26
|
-
inline v8::Local<v8::String> InternalizedFromLatin1(v8::Isolate* isolate, const char* str) {
|
|
27
|
-
return v8::String::NewFromOneByte(isolate, reinterpret_cast<const uint8_t*>(str), v8::NewStringType::kInternalized).ToLocalChecked();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
#hdr
|
|
31
|
-
template <class T> using CopyablePersistent = v8::Persistent<T, v8::CopyablePersistentTraits<T>>;
|
|
32
|
-
#end
|
|
33
|
-
inline void SetFrozen(v8::Isolate* isolate, v8::Local<v8::Context> ctx, v8::Local<v8::Object> obj, CopyablePersistent<v8::String>& key, v8::Local<v8::Value> value) {
|
|
34
|
-
obj->DefineOwnProperty(ctx, key.Get(isolate), value, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly)).FromJust();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
void ThrowError(const char* message) { EasyIsolate; isolate->ThrowException(v8::Exception::Error(StringFromUtf8(isolate, message, -1))); }
|
|
38
|
-
void ThrowTypeError(const char* message) { EasyIsolate; isolate->ThrowException(v8::Exception::TypeError(StringFromUtf8(isolate, message, -1))); }
|
|
39
|
-
void ThrowRangeError(const char* message) { EasyIsolate; isolate->ThrowException(v8::Exception::RangeError(StringFromUtf8(isolate, message, -1))); }
|
|
40
|
-
|
|
41
|
-
#define REQUIRE_ARGUMENT_ANY(at, var) \
|
|
42
|
-
if (info.Length() <= (at())) \
|
|
43
|
-
return ThrowTypeError("Expected a "#at" argument"); \
|
|
44
|
-
var = info[at()]
|
|
45
|
-
|
|
46
|
-
#define _REQUIRE_ARGUMENT(at, var, Type, message, ...) \
|
|
47
|
-
if (info.Length() <= (at()) || !info[at()]->Is##Type()) \
|
|
48
|
-
return ThrowTypeError("Expected "#at" argument to be "#message); \
|
|
49
|
-
var = (info[at()].As<v8::Type>())__VA_ARGS__
|
|
50
|
-
|
|
51
|
-
#define REQUIRE_ARGUMENT_INT32(at, var) \
|
|
52
|
-
_REQUIRE_ARGUMENT(at, var, Int32, a 32-bit signed integer, ->Value())
|
|
53
|
-
#define REQUIRE_ARGUMENT_BOOLEAN(at, var) \
|
|
54
|
-
_REQUIRE_ARGUMENT(at, var, Boolean, a boolean, ->Value())
|
|
55
|
-
#define REQUIRE_ARGUMENT_STRING(at, var) \
|
|
56
|
-
_REQUIRE_ARGUMENT(at, var, String, a string)
|
|
57
|
-
#define REQUIRE_ARGUMENT_OBJECT(at, var) \
|
|
58
|
-
_REQUIRE_ARGUMENT(at, var, Object, an object)
|
|
59
|
-
#define REQUIRE_ARGUMENT_FUNCTION(at, var) \
|
|
60
|
-
_REQUIRE_ARGUMENT(at, var, Function, a function)
|
|
61
|
-
|
|
62
|
-
#define REQUIRE_DATABASE_OPEN(db) \
|
|
63
|
-
if (!db->open) \
|
|
64
|
-
return ThrowTypeError("The database connection is not open")
|
|
65
|
-
#define REQUIRE_DATABASE_NOT_BUSY(db) \
|
|
66
|
-
if (db->busy) \
|
|
67
|
-
return ThrowTypeError("This database connection is busy executing a query")
|
|
68
|
-
#define REQUIRE_DATABASE_NO_ITERATORS(db) \
|
|
69
|
-
if (db->iterators) \
|
|
70
|
-
return ThrowTypeError("This database connection is busy executing a query")
|
|
71
|
-
#define REQUIRE_DATABASE_NO_ITERATORS_UNLESS_UNSAFE(db) \
|
|
72
|
-
if (!db->unsafe_mode) { \
|
|
73
|
-
REQUIRE_DATABASE_NO_ITERATORS(db); \
|
|
74
|
-
} ((void)0)
|
|
75
|
-
#define REQUIRE_STATEMENT_NOT_LOCKED(stmt) \
|
|
76
|
-
if (stmt->locked) \
|
|
77
|
-
return ThrowTypeError("This statement is busy executing a query")
|
|
78
|
-
|
|
79
|
-
#define first() 0
|
|
80
|
-
#define second() 1
|
|
81
|
-
#define third() 2
|
|
82
|
-
#define fourth() 3
|
|
83
|
-
#define fifth() 4
|
|
84
|
-
#define sixth() 5
|
|
85
|
-
#define seventh() 6
|
|
86
|
-
#define eighth() 7
|
|
87
|
-
#define ninth() 8
|
|
88
|
-
#define tenth() 9
|
|
89
|
-
|
|
90
|
-
// Determines whether to skip the given character at the start of an SQL string.
|
|
91
|
-
inline bool IS_SKIPPED(char c) {
|
|
92
|
-
return c == ' ' || c == ';' || (c >= '\t' && c <= '\r');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Allocates an empty array, without calling constructors/initializers.
|
|
96
|
-
template<class T> inline T* ALLOC_ARRAY(size_t count) {
|
|
97
|
-
return static_cast<T*>(::operator new[](count * sizeof(T)));
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// Deallocates an array, without calling destructors.
|
|
101
|
-
template<class T> inline void FREE_ARRAY(T* array_pointer) {
|
|
102
|
-
::operator delete[](array_pointer);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
v8::Local<v8::FunctionTemplate> NewConstructorTemplate(
|
|
106
|
-
v8::Isolate* isolate,
|
|
107
|
-
v8::Local<v8::External> data,
|
|
108
|
-
v8::FunctionCallback func,
|
|
109
|
-
const char* name
|
|
110
|
-
) {
|
|
111
|
-
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate, func, data);
|
|
112
|
-
t->InstanceTemplate()->SetInternalFieldCount(1);
|
|
113
|
-
t->SetClassName(InternalizedFromLatin1(isolate, name));
|
|
114
|
-
return t;
|
|
115
|
-
}
|
|
116
|
-
void SetPrototypeMethod(
|
|
117
|
-
v8::Isolate* isolate,
|
|
118
|
-
v8::Local<v8::External> data,
|
|
119
|
-
v8::Local<v8::FunctionTemplate> recv,
|
|
120
|
-
const char* name,
|
|
121
|
-
v8::FunctionCallback func
|
|
122
|
-
) {
|
|
123
|
-
v8::HandleScope scope(isolate);
|
|
124
|
-
recv->PrototypeTemplate()->Set(
|
|
125
|
-
InternalizedFromLatin1(isolate, name),
|
|
126
|
-
v8::FunctionTemplate::New(isolate, func, data, v8::Signature::New(isolate, recv))
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
void SetPrototypeSymbolMethod(
|
|
130
|
-
v8::Isolate* isolate,
|
|
131
|
-
v8::Local<v8::External> data,
|
|
132
|
-
v8::Local<v8::FunctionTemplate> recv,
|
|
133
|
-
v8::Local<v8::Symbol> symbol,
|
|
134
|
-
v8::FunctionCallback func
|
|
135
|
-
) {
|
|
136
|
-
v8::HandleScope scope(isolate);
|
|
137
|
-
recv->PrototypeTemplate()->Set(
|
|
138
|
-
symbol,
|
|
139
|
-
v8::FunctionTemplate::New(isolate, func, data, v8::Signature::New(isolate, recv))
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
void SetPrototypeGetter(
|
|
143
|
-
v8::Isolate* isolate,
|
|
144
|
-
v8::Local<v8::External> data,
|
|
145
|
-
v8::Local<v8::FunctionTemplate> recv,
|
|
146
|
-
const char* name,
|
|
147
|
-
v8::AccessorGetterCallback func
|
|
148
|
-
) {
|
|
149
|
-
v8::HandleScope scope(isolate);
|
|
150
|
-
recv->InstanceTemplate()->SetAccessor(
|
|
151
|
-
InternalizedFromLatin1(isolate, name),
|
|
152
|
-
func,
|
|
153
|
-
0,
|
|
154
|
-
data,
|
|
155
|
-
v8::AccessControl::DEFAULT,
|
|
156
|
-
v8::PropertyAttribute::None,
|
|
157
|
-
v8::AccessorSignature::New(isolate, recv)
|
|
158
|
-
);
|
|
159
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
#define STATEMENT_BIND(handle) \
|
|
2
|
-
Binder binder(handle); \
|
|
3
|
-
if (!binder.Bind(info, info.Length(), stmt)) { \
|
|
4
|
-
sqlite3_clear_bindings(handle); \
|
|
5
|
-
return; \
|
|
6
|
-
} ((void)0)
|
|
7
|
-
|
|
8
|
-
#define STATEMENT_THROW_LOGIC() \
|
|
9
|
-
db->ThrowDatabaseError(); \
|
|
10
|
-
if (!bound) { sqlite3_clear_bindings(handle); } \
|
|
11
|
-
return
|
|
12
|
-
|
|
13
|
-
#define STATEMENT_RETURN_LOGIC(return_value) \
|
|
14
|
-
info.GetReturnValue().Set(return_value); \
|
|
15
|
-
if (!bound) { sqlite3_clear_bindings(handle); } \
|
|
16
|
-
return
|
|
17
|
-
|
|
18
|
-
#define STATEMENT_START_LOGIC(RETURNS_DATA_CHECK, MUTATE_CHECK) \
|
|
19
|
-
Statement* stmt = Unwrap<Statement>(info.This()); \
|
|
20
|
-
RETURNS_DATA_CHECK(); \
|
|
21
|
-
sqlite3_stmt* handle = stmt->handle; \
|
|
22
|
-
Database* db = stmt->db; \
|
|
23
|
-
REQUIRE_DATABASE_OPEN(db->GetState()); \
|
|
24
|
-
REQUIRE_DATABASE_NOT_BUSY(db->GetState()); \
|
|
25
|
-
MUTATE_CHECK(); \
|
|
26
|
-
const bool bound = stmt->bound; \
|
|
27
|
-
if (!bound) { \
|
|
28
|
-
STATEMENT_BIND(handle); \
|
|
29
|
-
} else if (info.Length() > 0) { \
|
|
30
|
-
return ThrowTypeError("This statement already has bound parameters"); \
|
|
31
|
-
} ((void)0)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
#define STATEMENT_THROW() db->GetState()->busy = false; STATEMENT_THROW_LOGIC()
|
|
35
|
-
#define STATEMENT_RETURN(x) db->GetState()->busy = false; STATEMENT_RETURN_LOGIC(x)
|
|
36
|
-
#define STATEMENT_START(x, y) \
|
|
37
|
-
STATEMENT_START_LOGIC(x, y); \
|
|
38
|
-
db->GetState()->busy = true; \
|
|
39
|
-
UseIsolate; \
|
|
40
|
-
if (db->Log(isolate, handle)) { \
|
|
41
|
-
STATEMENT_THROW(); \
|
|
42
|
-
} ((void)0)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
#define DOES_NOT_MUTATE() REQUIRE_STATEMENT_NOT_LOCKED(stmt)
|
|
46
|
-
#define DOES_MUTATE() \
|
|
47
|
-
assert(!stmt->locked); \
|
|
48
|
-
REQUIRE_DATABASE_NO_ITERATORS_UNLESS_UNSAFE(db->GetState())
|
|
49
|
-
#define DOES_ADD_ITERATOR() \
|
|
50
|
-
DOES_NOT_MUTATE(); \
|
|
51
|
-
if (db->GetState()->iterators == USHRT_MAX) \
|
|
52
|
-
return ThrowRangeError("Too many active database iterators")
|
|
53
|
-
#define REQUIRE_STATEMENT_RETURNS_DATA() \
|
|
54
|
-
if (!stmt->returns_data) \
|
|
55
|
-
return ThrowTypeError("This statement does not return data. Use run() instead")
|
|
56
|
-
#define ALLOW_ANY_STATEMENT() \
|
|
57
|
-
((void)0)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
#define _FUNCTION_START(type) \
|
|
61
|
-
type* self = static_cast<type*>(sqlite3_user_data(invocation)); \
|
|
62
|
-
v8::Isolate* isolate = self->isolate; \
|
|
63
|
-
v8::HandleScope scope(isolate)
|
|
64
|
-
|
|
65
|
-
#define FUNCTION_START() \
|
|
66
|
-
_FUNCTION_START(CustomFunction)
|
|
67
|
-
|
|
68
|
-
#define AGGREGATE_START() \
|
|
69
|
-
_FUNCTION_START(CustomAggregate); \
|
|
70
|
-
Accumulator* acc = self->GetAccumulator(invocation); \
|
|
71
|
-
if (acc->value.IsEmpty()) return
|
package/test/00.setup.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const fs = require('fs-extra');
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const os = require('os');
|
|
5
|
-
const chai = require('chai');
|
|
6
|
-
|
|
7
|
-
const isWindows = os.platform().startsWith('win');
|
|
8
|
-
const tempDir = path.join(__dirname, '..', 'temp');
|
|
9
|
-
let dbId = 0;
|
|
10
|
-
|
|
11
|
-
global.expect = chai.expect;
|
|
12
|
-
global.util = {
|
|
13
|
-
current: () => path.join(tempDir, `${dbId}.db`),
|
|
14
|
-
next: () => (++dbId, global.util.current()),
|
|
15
|
-
itUnix: isWindows ? it.skip : it,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
before(function () {
|
|
19
|
-
fs.removeSync(tempDir);
|
|
20
|
-
fs.ensureDirSync(tempDir);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
after(function () {
|
|
24
|
-
fs.removeSync(tempDir);
|
|
25
|
-
});
|
package/test/01.sqlite-error.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const { expect } = require('chai');
|
|
3
|
-
const { SqliteError } = require('../.');
|
|
4
|
-
|
|
5
|
-
describe('SqliteError', function () {
|
|
6
|
-
it('should be a subclass of Error', function () {
|
|
7
|
-
expect(SqliteError).to.be.a('function');
|
|
8
|
-
expect(SqliteError).to.not.equal(Error);
|
|
9
|
-
expect(SqliteError.prototype).to.be.an.instanceof(Error);
|
|
10
|
-
expect(SqliteError('foo', 'bar')).to.be.an.instanceof(Error);
|
|
11
|
-
expect(new SqliteError('foo', 'bar')).to.be.an.instanceof(Error);
|
|
12
|
-
});
|
|
13
|
-
it('should have the correct name', function () {
|
|
14
|
-
expect(SqliteError.prototype.name).to.equal('SqliteError');
|
|
15
|
-
});
|
|
16
|
-
it('should accept two arguments for setting the message and error code', function () {
|
|
17
|
-
const err = SqliteError('foobar', 'baz');
|
|
18
|
-
expect(err.message).to.equal('foobar');
|
|
19
|
-
expect(err.code).to.equal('baz');
|
|
20
|
-
expect(SqliteError(123, 'baz').message).to.equal('123');
|
|
21
|
-
expect(() => SqliteError('foo')).to.throw(TypeError);
|
|
22
|
-
expect(() => SqliteError('foo', 123)).to.throw(TypeError);
|
|
23
|
-
});
|
|
24
|
-
it('should capture stack traces', function () {
|
|
25
|
-
expect(SqliteError(null, 'baz').stack).to.be.a('string');
|
|
26
|
-
});
|
|
27
|
-
});
|
package/test/10.database.open.js
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const { existsSync } = require('fs');
|
|
3
|
-
const Database = require('../.');
|
|
4
|
-
|
|
5
|
-
describe('new Database()', function () {
|
|
6
|
-
afterEach(function () {
|
|
7
|
-
if (this.db) this.db.close();
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
it('should throw when given invalid argument types', function () {
|
|
11
|
-
expect(() => (this.db = new Database('', ''))).to.throw(TypeError);
|
|
12
|
-
expect(() => (this.db = new Database({}, ''))).to.throw(TypeError);
|
|
13
|
-
expect(() => (this.db = new Database({}, {}))).to.throw(TypeError);
|
|
14
|
-
expect(() => (this.db = new Database({}))).to.throw(TypeError);
|
|
15
|
-
expect(() => (this.db = new Database(0))).to.throw(TypeError);
|
|
16
|
-
expect(() => (this.db = new Database(123))).to.throw(TypeError);
|
|
17
|
-
expect(() => (this.db = new Database(new String(util.next())))).to.throw(TypeError);
|
|
18
|
-
expect(() => (this.db = new Database(() => util.next()))).to.throw(TypeError);
|
|
19
|
-
expect(() => (this.db = new Database([util.next()]))).to.throw(TypeError);
|
|
20
|
-
});
|
|
21
|
-
it('should throw when boolean options are provided as non-booleans', function () {
|
|
22
|
-
expect(() => (this.db = new Database(util.next(), { readOnly: false }))).to.throw(TypeError);
|
|
23
|
-
expect(() => (this.db = new Database(util.next(), { readonly: undefined }))).to.throw(TypeError);
|
|
24
|
-
expect(() => (this.db = new Database(util.next(), { fileMustExist: undefined }))).to.throw(TypeError);
|
|
25
|
-
});
|
|
26
|
-
it('should allow anonymous temporary databases to be created', function () {
|
|
27
|
-
for (const args of [[''], [], [null], [undefined], ['', { timeout: 2000 }]]) {
|
|
28
|
-
const db = this.db = new Database(...args);
|
|
29
|
-
expect(db.name).to.equal('');
|
|
30
|
-
expect(db.memory).to.be.true;
|
|
31
|
-
expect(db.readonly).to.be.false;
|
|
32
|
-
expect(db.open).to.be.true;
|
|
33
|
-
expect(db.inTransaction).to.be.false;
|
|
34
|
-
expect(existsSync('')).to.be.false;
|
|
35
|
-
expect(existsSync('null')).to.be.false;
|
|
36
|
-
expect(existsSync('undefined')).to.be.false;
|
|
37
|
-
expect(existsSync('[object Object]')).to.be.false;
|
|
38
|
-
db.close();
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
it('should allow anonymous in-memory databases to be created', function () {
|
|
42
|
-
const db = this.db = new Database(':memory:');
|
|
43
|
-
expect(db.name).to.equal(':memory:');
|
|
44
|
-
expect(db.memory).to.be.true;
|
|
45
|
-
expect(db.readonly).to.be.false;
|
|
46
|
-
expect(db.open).to.be.true;
|
|
47
|
-
expect(db.inTransaction).to.be.false;
|
|
48
|
-
expect(existsSync(':memory:')).to.be.false;
|
|
49
|
-
});
|
|
50
|
-
it('should allow disk-bound databases to be created', function () {
|
|
51
|
-
expect(existsSync(util.next())).to.be.false;
|
|
52
|
-
const db = this.db = new Database(util.current());
|
|
53
|
-
expect(db.name).to.equal(util.current());
|
|
54
|
-
expect(db.memory).to.be.false;
|
|
55
|
-
expect(db.readonly).to.be.false;
|
|
56
|
-
expect(db.open).to.be.true;
|
|
57
|
-
expect(db.inTransaction).to.be.false;
|
|
58
|
-
expect(existsSync(util.current())).to.be.true;
|
|
59
|
-
});
|
|
60
|
-
it('should allow readonly database connections to be created', function () {
|
|
61
|
-
expect(existsSync(util.next())).to.be.false;
|
|
62
|
-
expect(() => (this.db = new Database(util.current(), { readonly: true }))).to.throw(Database.SqliteError).with.property('code', 'SQLITE_CANTOPEN');
|
|
63
|
-
(new Database(util.current())).close();
|
|
64
|
-
expect(existsSync(util.current())).to.be.true;
|
|
65
|
-
const db = this.db = new Database(util.current(), { readonly: true });
|
|
66
|
-
expect(db.name).to.equal(util.current());
|
|
67
|
-
expect(db.memory).to.be.false;
|
|
68
|
-
expect(db.readonly).to.be.true;
|
|
69
|
-
expect(db.open).to.be.true;
|
|
70
|
-
expect(db.inTransaction).to.be.false;
|
|
71
|
-
expect(existsSync(util.current())).to.be.true;
|
|
72
|
-
});
|
|
73
|
-
it('should not allow the "readonly" option for in-memory databases', function () {
|
|
74
|
-
expect(existsSync(util.next())).to.be.false;
|
|
75
|
-
expect(() => (this.db = new Database(':memory:', { readonly: true }))).to.throw(TypeError);
|
|
76
|
-
expect(() => (this.db = new Database('', { readonly: true }))).to.throw(TypeError);
|
|
77
|
-
expect(existsSync(util.current())).to.be.false;
|
|
78
|
-
});
|
|
79
|
-
it('should accept the "fileMustExist" option', function () {
|
|
80
|
-
expect(existsSync(util.next())).to.be.false;
|
|
81
|
-
expect(() => (this.db = new Database(util.current(), { fileMustExist: true }))).to.throw(Database.SqliteError).with.property('code', 'SQLITE_CANTOPEN');
|
|
82
|
-
(new Database(util.current())).close();
|
|
83
|
-
expect(existsSync(util.current())).to.be.true;
|
|
84
|
-
const db = this.db = new Database(util.current(), { fileMustExist: true });
|
|
85
|
-
expect(db.name).to.equal(util.current());
|
|
86
|
-
expect(db.memory).to.be.false;
|
|
87
|
-
expect(db.readonly).to.be.false;
|
|
88
|
-
expect(db.open).to.be.true;
|
|
89
|
-
expect(db.inTransaction).to.be.false;
|
|
90
|
-
expect(existsSync(util.current())).to.be.true;
|
|
91
|
-
});
|
|
92
|
-
util.itUnix('should accept the "timeout" option', function () {
|
|
93
|
-
this.slow(4000);
|
|
94
|
-
const testTimeout = (timeout) => {
|
|
95
|
-
const db = new Database(util.current(), { timeout });
|
|
96
|
-
try {
|
|
97
|
-
const start = Date.now();
|
|
98
|
-
expect(() => db.exec('BEGIN EXCLUSIVE')).to.throw(Database.SqliteError).with.property('code', 'SQLITE_BUSY');
|
|
99
|
-
const end = Date.now();
|
|
100
|
-
expect(end - start).to.be.closeTo(timeout, 200);
|
|
101
|
-
} finally {
|
|
102
|
-
db.close();
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
const blocker = this.db = new Database(util.next(), { timeout: 0x7fffffff });
|
|
106
|
-
blocker.exec('BEGIN EXCLUSIVE');
|
|
107
|
-
testTimeout(0);
|
|
108
|
-
testTimeout(1000);
|
|
109
|
-
blocker.close();
|
|
110
|
-
expect(() => (this.db = new Database(util.current(), { timeout: undefined }))).to.throw(TypeError);
|
|
111
|
-
expect(() => (this.db = new Database(util.current(), { timeout: null }))).to.throw(TypeError);
|
|
112
|
-
expect(() => (this.db = new Database(util.current(), { timeout: NaN }))).to.throw(TypeError);
|
|
113
|
-
expect(() => (this.db = new Database(util.current(), { timeout: '75' }))).to.throw(TypeError);
|
|
114
|
-
expect(() => (this.db = new Database(util.current(), { timeout: -1 }))).to.throw(TypeError);
|
|
115
|
-
expect(() => (this.db = new Database(util.current(), { timeout: 75.01 }))).to.throw(TypeError);
|
|
116
|
-
expect(() => (this.db = new Database(util.current(), { timeout: 0x80000000 }))).to.throw(RangeError);
|
|
117
|
-
});
|
|
118
|
-
it('should throw an Error if the directory does not exist', function () {
|
|
119
|
-
expect(existsSync(util.next())).to.be.false;
|
|
120
|
-
const filepath = `temp/nonexistent/abcfoobar123/${util.current()}`;
|
|
121
|
-
expect(() => (this.db = new Database(filepath))).to.throw(TypeError);
|
|
122
|
-
expect(existsSync(filepath)).to.be.false;
|
|
123
|
-
expect(existsSync(util.current())).to.be.false;
|
|
124
|
-
});
|
|
125
|
-
it('should have a proper prototype chain', function () {
|
|
126
|
-
const db = this.db = new Database(util.next());
|
|
127
|
-
expect(db).to.be.an.instanceof(Database);
|
|
128
|
-
expect(db.constructor).to.equal(Database);
|
|
129
|
-
expect(Database.prototype.constructor).to.equal(Database);
|
|
130
|
-
expect(Database.prototype.close).to.be.a('function');
|
|
131
|
-
expect(Database.prototype.close).to.equal(db.close);
|
|
132
|
-
expect(Database.prototype).to.equal(Object.getPrototypeOf(db));
|
|
133
|
-
});
|
|
134
|
-
it('should work properly when called as a function', function () {
|
|
135
|
-
const db = this.db = Database(util.next());
|
|
136
|
-
expect(db).to.be.an.instanceof(Database);
|
|
137
|
-
expect(db.constructor).to.equal(Database);
|
|
138
|
-
expect(Database.prototype.close).to.equal(db.close);
|
|
139
|
-
expect(Database.prototype).to.equal(Object.getPrototypeOf(db));
|
|
140
|
-
});
|
|
141
|
-
it('should work properly when subclassed', function () {
|
|
142
|
-
class MyDatabase extends Database {
|
|
143
|
-
foo() {
|
|
144
|
-
return 999;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
const db = this.db = new MyDatabase(util.next());
|
|
148
|
-
expect(db).to.be.an.instanceof(Database);
|
|
149
|
-
expect(db).to.be.an.instanceof(MyDatabase);
|
|
150
|
-
expect(db.constructor).to.equal(MyDatabase);
|
|
151
|
-
expect(Database.prototype.close).to.equal(db.close);
|
|
152
|
-
expect(MyDatabase.prototype.close).to.equal(db.close);
|
|
153
|
-
expect(Database.prototype.foo).to.be.undefined;
|
|
154
|
-
expect(MyDatabase.prototype.foo).to.equal(db.foo);
|
|
155
|
-
expect(Database.prototype).to.equal(Object.getPrototypeOf(MyDatabase.prototype));
|
|
156
|
-
expect(MyDatabase.prototype).to.equal(Object.getPrototypeOf(db));
|
|
157
|
-
expect(db.foo()).to.equal(999);
|
|
158
|
-
});
|
|
159
|
-
});
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const { existsSync } = require('fs');
|
|
3
|
-
const Database = require('../.');
|
|
4
|
-
|
|
5
|
-
describe('Database#close()', function () {
|
|
6
|
-
beforeEach(function () {
|
|
7
|
-
this.db = new Database(util.next());
|
|
8
|
-
});
|
|
9
|
-
afterEach(function () {
|
|
10
|
-
this.db.close();
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
it('should cause db.open to return false', function () {
|
|
14
|
-
expect(this.db.open).to.be.true;
|
|
15
|
-
this.db.close();
|
|
16
|
-
expect(this.db.open).to.be.false;
|
|
17
|
-
});
|
|
18
|
-
it('should return the database object', function () {
|
|
19
|
-
expect(this.db.open).to.be.true;
|
|
20
|
-
expect(this.db.close()).to.equal(this.db);
|
|
21
|
-
expect(this.db.open).to.be.false;
|
|
22
|
-
expect(this.db.close()).to.equal(this.db);
|
|
23
|
-
expect(this.db.open).to.be.false;
|
|
24
|
-
});
|
|
25
|
-
it('should prevent any further database operations', function () {
|
|
26
|
-
this.db.close();
|
|
27
|
-
expect(() => this.db.exec('CREATE TABLE people (name TEXT)')).to.throw(TypeError);
|
|
28
|
-
expect(() => this.db.prepare('CREATE TABLE cats (name TEXT)')).to.throw(TypeError);
|
|
29
|
-
expect(() => this.db.transaction(() => {})).to.throw(TypeError);
|
|
30
|
-
expect(() => this.db.pragma('cache_size')).to.throw(TypeError);
|
|
31
|
-
expect(() => this.db.function('foo', () => {})).to.throw(TypeError);
|
|
32
|
-
expect(() => this.db.aggregate('foo', { step: () => {} })).to.throw(TypeError);
|
|
33
|
-
expect(() => this.db.table('foo', () => {})).to.throw(TypeError);
|
|
34
|
-
});
|
|
35
|
-
it('should prevent any existing statements from running', function () {
|
|
36
|
-
this.db.prepare('CREATE TABLE people (name TEXT)').run();
|
|
37
|
-
const stmt1 = this.db.prepare('SELECT * FROM people');
|
|
38
|
-
const stmt2 = this.db.prepare("INSERT INTO people VALUES ('foobar')");
|
|
39
|
-
|
|
40
|
-
this.db.prepare('SELECT * FROM people').bind();
|
|
41
|
-
this.db.prepare("INSERT INTO people VALUES ('foobar')").bind();
|
|
42
|
-
this.db.prepare('SELECT * FROM people').get();
|
|
43
|
-
this.db.prepare('SELECT * FROM people').all();
|
|
44
|
-
this.db.prepare('SELECT * FROM people').iterate().return();
|
|
45
|
-
this.db.prepare("INSERT INTO people VALUES ('foobar')").run();
|
|
46
|
-
|
|
47
|
-
this.db.close();
|
|
48
|
-
|
|
49
|
-
expect(() => stmt1.bind()).to.throw(TypeError);
|
|
50
|
-
expect(() => stmt2.bind()).to.throw(TypeError);
|
|
51
|
-
expect(() => stmt1.get()).to.throw(TypeError);
|
|
52
|
-
expect(() => stmt1.all()).to.throw(TypeError);
|
|
53
|
-
expect(() => stmt1.iterate()).to.throw(TypeError);
|
|
54
|
-
expect(() => stmt2.run()).to.throw(TypeError);
|
|
55
|
-
});
|
|
56
|
-
it('should delete the database\'s associated temporary files', function () {
|
|
57
|
-
expect(existsSync(util.current())).to.be.true;
|
|
58
|
-
this.db.pragma('journal_mode = WAL');
|
|
59
|
-
this.db.prepare('CREATE TABLE people (name TEXT)').run();
|
|
60
|
-
this.db.prepare('INSERT INTO people VALUES (?)').run('foobar');
|
|
61
|
-
expect(existsSync(`${util.current()}-wal`)).to.be.true;
|
|
62
|
-
|
|
63
|
-
this.db.close();
|
|
64
|
-
|
|
65
|
-
expect(existsSync(util.current())).to.be.true;
|
|
66
|
-
expect(existsSync(`${util.current()}-wal`)).to.be.false;
|
|
67
|
-
});
|
|
68
|
-
});
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const Database = require('../.');
|
|
3
|
-
|
|
4
|
-
describe('Database#pragma()', function () {
|
|
5
|
-
beforeEach(function () {
|
|
6
|
-
this.db = new Database(util.next());
|
|
7
|
-
});
|
|
8
|
-
afterEach(function () {
|
|
9
|
-
this.db.close();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
it('should throw an exception if a string is not provided', function () {
|
|
13
|
-
expect(() => this.db.pragma(123)).to.throw(TypeError);
|
|
14
|
-
expect(() => this.db.pragma(0)).to.throw(TypeError);
|
|
15
|
-
expect(() => this.db.pragma(null)).to.throw(TypeError);
|
|
16
|
-
expect(() => this.db.pragma()).to.throw(TypeError);
|
|
17
|
-
expect(() => this.db.pragma(new String('cache_size'))).to.throw(TypeError);
|
|
18
|
-
});
|
|
19
|
-
it('should throw an exception if boolean options are provided as non-booleans', function () {
|
|
20
|
-
expect(() => this.db.pragma('cache_size', { simple: undefined })).to.throw(TypeError);
|
|
21
|
-
});
|
|
22
|
-
it('should throw an exception if invalid/redundant SQL is provided', function () {
|
|
23
|
-
expect(() => this.db.pragma('PRAGMA cache_size')).to.throw(Database.SqliteError).with.property('code', 'SQLITE_ERROR');
|
|
24
|
-
expect(() => this.db.pragma('cache_size; PRAGMA cache_size')).to.throw(RangeError);
|
|
25
|
-
});
|
|
26
|
-
it('should execute the pragma, returning rows of results', function () {
|
|
27
|
-
const rows = this.db.pragma('cache_size');
|
|
28
|
-
expect(rows).to.be.an('array');
|
|
29
|
-
expect(rows[0]).to.be.an('object');
|
|
30
|
-
expect(rows[0].cache_size).to.be.a('number');
|
|
31
|
-
expect(rows[0].cache_size).to.equal(-16000);
|
|
32
|
-
});
|
|
33
|
-
it('should optionally return simpler results', function () {
|
|
34
|
-
expect(this.db.pragma('cache_size', { simple: false })).to.be.an('array');
|
|
35
|
-
const cache_size = this.db.pragma('cache_size', { simple: true });
|
|
36
|
-
expect(cache_size).to.be.a('number');
|
|
37
|
-
expect(cache_size).to.equal(-16000);
|
|
38
|
-
expect(() => this.db.pragma('cache_size', true)).to.throw(TypeError);
|
|
39
|
-
expect(() => this.db.pragma('cache_size', 123)).to.throw(TypeError);
|
|
40
|
-
expect(() => this.db.pragma('cache_size', function () {})).to.throw(TypeError);
|
|
41
|
-
expect(() => this.db.pragma('cache_size', NaN)).to.throw(TypeError);
|
|
42
|
-
expect(() => this.db.pragma('cache_size', 'true')).to.throw(TypeError);
|
|
43
|
-
});
|
|
44
|
-
it('should obey PRAGMA changes', function () {
|
|
45
|
-
expect(this.db.pragma('cache_size', { simple: true })).to.equal(-16000);
|
|
46
|
-
this.db.pragma('cache_size = -8000');
|
|
47
|
-
expect(this.db.pragma('cache_size', { simple: true })).to.equal(-8000);
|
|
48
|
-
expect(this.db.pragma('journal_mode', { simple: true })).to.equal('delete');
|
|
49
|
-
this.db.pragma('journal_mode = wal');
|
|
50
|
-
expect(this.db.pragma('journal_mode', { simple: true })).to.equal('wal');
|
|
51
|
-
});
|
|
52
|
-
it('should respect readonly connections', function () {
|
|
53
|
-
this.db.close();
|
|
54
|
-
this.db = new Database(util.current(), { readonly: true, fileMustExist: true });
|
|
55
|
-
expect(this.db.pragma('cache_size', { simple: true })).to.equal(-16000);
|
|
56
|
-
this.db.pragma('cache_size = -8000');
|
|
57
|
-
expect(this.db.pragma('cache_size', { simple: true })).to.equal(-8000);
|
|
58
|
-
expect(this.db.pragma('journal_mode', { simple: true })).to.equal('delete');
|
|
59
|
-
expect(() => this.db.pragma('journal_mode = wal')).to.throw(Database.SqliteError).with.property('code', 'SQLITE_READONLY');
|
|
60
|
-
expect(this.db.pragma('journal_mode', { simple: true })).to.equal('delete');
|
|
61
|
-
});
|
|
62
|
-
it('should return undefined if no rows exist and simpler results are desired', function () {
|
|
63
|
-
expect(this.db.pragma('table_info', { simple: true })).to.be.undefined;
|
|
64
|
-
});
|
|
65
|
-
});
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
const Database = require('../.');
|
|
3
|
-
|
|
4
|
-
describe('Database#prepare()', function () {
|
|
5
|
-
beforeEach(function () {
|
|
6
|
-
this.db = new Database(util.next());
|
|
7
|
-
});
|
|
8
|
-
afterEach(function () {
|
|
9
|
-
this.db.close();
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
function assertStmt(stmt, source, db, reader, readonly) {
|
|
13
|
-
expect(stmt.source).to.equal(source);
|
|
14
|
-
expect(stmt.constructor.name).to.equal('Statement');
|
|
15
|
-
expect(stmt.database).to.equal(db);
|
|
16
|
-
expect(stmt.reader).to.equal(reader);
|
|
17
|
-
expect(stmt.readonly).to.equal(readonly);
|
|
18
|
-
expect(() => new stmt.constructor(source)).to.throw(TypeError);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
it('should throw an exception if a string is not provided', function () {
|
|
22
|
-
expect(() => this.db.prepare(123)).to.throw(TypeError);
|
|
23
|
-
expect(() => this.db.prepare(0)).to.throw(TypeError);
|
|
24
|
-
expect(() => this.db.prepare(null)).to.throw(TypeError);
|
|
25
|
-
expect(() => this.db.prepare()).to.throw(TypeError);
|
|
26
|
-
expect(() => this.db.prepare(new String('CREATE TABLE people (name TEXT)'))).to.throw(TypeError);
|
|
27
|
-
});
|
|
28
|
-
it('should throw an exception if invalid SQL is provided', function () {
|
|
29
|
-
expect(() => this.db.prepare('CREATE TABLE people (name TEXT')).to.throw(Database.SqliteError).with.property('code', 'SQLITE_ERROR');
|
|
30
|
-
expect(() => this.db.prepare('INSERT INTO people VALUES (?)')).to.throw(Database.SqliteError).with.property('code', 'SQLITE_ERROR');
|
|
31
|
-
});
|
|
32
|
-
it('should throw an exception if no statements are provided', function () {
|
|
33
|
-
expect(() => this.db.prepare('')).to.throw(RangeError);
|
|
34
|
-
expect(() => this.db.prepare(';')).to.throw(RangeError);
|
|
35
|
-
});
|
|
36
|
-
it('should throw an exception if more than one statement is provided', function () {
|
|
37
|
-
expect(() => this.db.prepare('CREATE TABLE people (name TEXT);CREATE TABLE animals (name TEXT)')).to.throw(RangeError);
|
|
38
|
-
expect(() => this.db.prepare('CREATE TABLE people (name TEXT);/')).to.throw(RangeError);
|
|
39
|
-
expect(() => this.db.prepare('CREATE TABLE people (name TEXT);-')).to.throw(RangeError);
|
|
40
|
-
});
|
|
41
|
-
it('should create a prepared Statement object', function () {
|
|
42
|
-
const stmt1 = this.db.prepare('CREATE TABLE people (name TEXT) ');
|
|
43
|
-
const stmt2 = this.db.prepare('CREATE TABLE people (name TEXT); ');
|
|
44
|
-
assertStmt(stmt1, 'CREATE TABLE people (name TEXT) ', this.db, false, false);
|
|
45
|
-
assertStmt(stmt2, 'CREATE TABLE people (name TEXT); ', this.db, false, false);
|
|
46
|
-
expect(stmt1).to.not.equal(stmt2);
|
|
47
|
-
expect(stmt1).to.not.equal(this.db.prepare('CREATE TABLE people (name TEXT) '));
|
|
48
|
-
});
|
|
49
|
-
it('should create a prepared Statement object with just an expression', function () {
|
|
50
|
-
const stmt = this.db.prepare('SELECT 555');
|
|
51
|
-
assertStmt(stmt, 'SELECT 555', this.db, true, true);
|
|
52
|
-
});
|
|
53
|
-
it('should set the correct values for "reader" and "readonly"', function () {
|
|
54
|
-
this.db.exec('CREATE TABLE data (value)');
|
|
55
|
-
assertStmt(this.db.prepare('SELECT 555'), 'SELECT 555', this.db, true, true);
|
|
56
|
-
assertStmt(this.db.prepare('BEGIN'), 'BEGIN', this.db, false, true);
|
|
57
|
-
assertStmt(this.db.prepare('BEGIN EXCLUSIVE'), 'BEGIN EXCLUSIVE', this.db, false, false);
|
|
58
|
-
assertStmt(this.db.prepare('DELETE FROM data RETURNING *'), 'DELETE FROM data RETURNING *', this.db, true, false);
|
|
59
|
-
});
|
|
60
|
-
});
|