dbx-native 0.1.2-beta → 0.2.0-beta
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 +88 -88
- package/artifacts/node-binary-macos-latest/index.node +0 -0
- package/artifacts/node-binary-ubuntu-latest/index.node +0 -0
- package/artifacts/node-binary-windows-latest/index.node +0 -0
- package/benchmarks/auto_batch_benchmark.js +98 -98
- package/benchmarks/benchmark.js +162 -162
- package/benchmarks/benchmark_batch.js +166 -166
- package/benchmarks/benchmark_sql.js +162 -162
- package/benchmarks/ffi_benchmark.js +72 -72
- package/benchmarks/zero_copy_benchmark.js +109 -109
- package/dbx-native-0.2.0-beta.tgz +0 -0
- package/examples/basic.js +34 -34
- package/index.js +2 -2
- package/package.json +46 -46
- package/smart_database.js +184 -184
- package/test/test_sql_insert.js +72 -72
- package/dbx-native-0.1.2-beta.tgz +0 -0
package/smart_database.js
CHANGED
|
@@ -1,184 +1,184 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SmartDatabase - Auto-batching wrapper for DBX
|
|
3
|
-
*
|
|
4
|
-
* Automatically batches multiple get() calls into a single getBatch() call
|
|
5
|
-
* using request coalescing pattern.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* const smartDb = new SmartDatabase(db);
|
|
9
|
-
* const results = await Promise.all([
|
|
10
|
-
* smartDb.get('table', key1),
|
|
11
|
-
* smartDb.get('table', key2),
|
|
12
|
-
* smartDb.get('table', key3),
|
|
13
|
-
* ]);
|
|
14
|
-
* // → Internally calls getBatch() once instead of get() three times
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
class SmartDatabase {
|
|
18
|
-
constructor(db) {
|
|
19
|
-
this._db = db;
|
|
20
|
-
this._pendingGets = new Map(); // table → [{ key, resolve, reject }]
|
|
21
|
-
this._batchScheduled = false;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Get a value by key (auto-batched)
|
|
26
|
-
* @param {string} table - Table name
|
|
27
|
-
* @param {Buffer} key - Key to get
|
|
28
|
-
* @returns {Promise<Buffer|null>} Value or null if not found
|
|
29
|
-
*/
|
|
30
|
-
get(table, key) {
|
|
31
|
-
return new Promise((resolve, reject) => {
|
|
32
|
-
// Add request to pending queue
|
|
33
|
-
if (!this._pendingGets.has(table)) {
|
|
34
|
-
this._pendingGets.set(table, []);
|
|
35
|
-
}
|
|
36
|
-
this._pendingGets.get(table).push({ key, resolve, reject });
|
|
37
|
-
|
|
38
|
-
// Schedule batch flush if not already scheduled
|
|
39
|
-
if (!this._batchScheduled) {
|
|
40
|
-
this._batchScheduled = true;
|
|
41
|
-
// Execute on next event loop tick
|
|
42
|
-
setImmediate(() => this._flushBatch());
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Flush all pending get requests as batches
|
|
49
|
-
* @private
|
|
50
|
-
*/
|
|
51
|
-
_flushBatch() {
|
|
52
|
-
this._batchScheduled = false;
|
|
53
|
-
|
|
54
|
-
for (const [table, requests] of this._pendingGets) {
|
|
55
|
-
const keys = requests.map(r => r.key);
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
// Execute batch get (synchronous)
|
|
59
|
-
const results = this._db.getBatch(table, keys);
|
|
60
|
-
|
|
61
|
-
// Resolve each request with its result
|
|
62
|
-
results.forEach((result, i) => {
|
|
63
|
-
requests[i].resolve(result);
|
|
64
|
-
});
|
|
65
|
-
} catch (err) {
|
|
66
|
-
// Reject all requests on error
|
|
67
|
-
requests.forEach(r => r.reject(err));
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
this._pendingGets.clear();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Proxy all other methods to the underlying database
|
|
75
|
-
insert(table, key, value) {
|
|
76
|
-
return this._db.insert(table, key, value);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
delete(table, key) {
|
|
80
|
-
return this._db.delete(table, key);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
scan(table) {
|
|
84
|
-
return this._db.scan(table);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
scanZeroCopy(table) {
|
|
88
|
-
return this._db.scanZeroCopy(table);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
insertBatch(table, rows) {
|
|
92
|
-
return this._db.insertBatch(table, rows);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
deleteBatch(table, keys) {
|
|
96
|
-
return this._db.deleteBatch(table, keys);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
range(table, startKey, endKey) {
|
|
100
|
-
return this._db.range(table, startKey, endKey);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
count(table) {
|
|
104
|
-
return this._db.count(table);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
flush() {
|
|
108
|
-
return this._db.flush();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
tableNames() {
|
|
112
|
-
return this._db.tableNames();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
gc() {
|
|
116
|
-
return this._db.gc();
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
isEncrypted() {
|
|
120
|
-
return this._db.isEncrypted();
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
executeSql(sql) {
|
|
124
|
-
return this._db.executeSql(sql);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
createIndex(table, column) {
|
|
128
|
-
return this._db.createIndex(table, column);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
dropIndex(table, column) {
|
|
132
|
-
return this._db.dropIndex(table, column);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
hasIndex(table, column) {
|
|
136
|
-
return this._db.hasIndex(table, column);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
saveToFile(path) {
|
|
140
|
-
return this._db.saveToFile(path);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
currentTimestamp() {
|
|
144
|
-
return this._db.currentTimestamp();
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
allocateCommitTs() {
|
|
148
|
-
return this._db.allocateCommitTs();
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
insertVersioned(table, key, value, commitTs) {
|
|
152
|
-
return this._db.insertVersioned(table, key, value, commitTs);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
getSnapshot(table, key, readTs) {
|
|
156
|
-
return this._db.getSnapshot(table, key, readTs);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
beginTransaction() {
|
|
160
|
-
return this._db.beginTransaction();
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
close() {
|
|
164
|
-
return this._db.close();
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// Static factory methods
|
|
168
|
-
static openInMemory() {
|
|
169
|
-
const { Database } = require('./');
|
|
170
|
-
return new SmartDatabase(Database.openInMemory());
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
static open(path) {
|
|
174
|
-
const { Database } = require('./');
|
|
175
|
-
return new SmartDatabase(Database.open(path));
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
static loadFromFile(path) {
|
|
179
|
-
const { Database } = require('./');
|
|
180
|
-
return new SmartDatabase(Database.loadFromFile(path));
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
module.exports = { SmartDatabase };
|
|
1
|
+
/**
|
|
2
|
+
* SmartDatabase - Auto-batching wrapper for DBX
|
|
3
|
+
*
|
|
4
|
+
* Automatically batches multiple get() calls into a single getBatch() call
|
|
5
|
+
* using request coalescing pattern.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const smartDb = new SmartDatabase(db);
|
|
9
|
+
* const results = await Promise.all([
|
|
10
|
+
* smartDb.get('table', key1),
|
|
11
|
+
* smartDb.get('table', key2),
|
|
12
|
+
* smartDb.get('table', key3),
|
|
13
|
+
* ]);
|
|
14
|
+
* // → Internally calls getBatch() once instead of get() three times
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
class SmartDatabase {
|
|
18
|
+
constructor(db) {
|
|
19
|
+
this._db = db;
|
|
20
|
+
this._pendingGets = new Map(); // table → [{ key, resolve, reject }]
|
|
21
|
+
this._batchScheduled = false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get a value by key (auto-batched)
|
|
26
|
+
* @param {string} table - Table name
|
|
27
|
+
* @param {Buffer} key - Key to get
|
|
28
|
+
* @returns {Promise<Buffer|null>} Value or null if not found
|
|
29
|
+
*/
|
|
30
|
+
get(table, key) {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
// Add request to pending queue
|
|
33
|
+
if (!this._pendingGets.has(table)) {
|
|
34
|
+
this._pendingGets.set(table, []);
|
|
35
|
+
}
|
|
36
|
+
this._pendingGets.get(table).push({ key, resolve, reject });
|
|
37
|
+
|
|
38
|
+
// Schedule batch flush if not already scheduled
|
|
39
|
+
if (!this._batchScheduled) {
|
|
40
|
+
this._batchScheduled = true;
|
|
41
|
+
// Execute on next event loop tick
|
|
42
|
+
setImmediate(() => this._flushBatch());
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Flush all pending get requests as batches
|
|
49
|
+
* @private
|
|
50
|
+
*/
|
|
51
|
+
_flushBatch() {
|
|
52
|
+
this._batchScheduled = false;
|
|
53
|
+
|
|
54
|
+
for (const [table, requests] of this._pendingGets) {
|
|
55
|
+
const keys = requests.map(r => r.key);
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
// Execute batch get (synchronous)
|
|
59
|
+
const results = this._db.getBatch(table, keys);
|
|
60
|
+
|
|
61
|
+
// Resolve each request with its result
|
|
62
|
+
results.forEach((result, i) => {
|
|
63
|
+
requests[i].resolve(result);
|
|
64
|
+
});
|
|
65
|
+
} catch (err) {
|
|
66
|
+
// Reject all requests on error
|
|
67
|
+
requests.forEach(r => r.reject(err));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
this._pendingGets.clear();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Proxy all other methods to the underlying database
|
|
75
|
+
insert(table, key, value) {
|
|
76
|
+
return this._db.insert(table, key, value);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
delete(table, key) {
|
|
80
|
+
return this._db.delete(table, key);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
scan(table) {
|
|
84
|
+
return this._db.scan(table);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
scanZeroCopy(table) {
|
|
88
|
+
return this._db.scanZeroCopy(table);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
insertBatch(table, rows) {
|
|
92
|
+
return this._db.insertBatch(table, rows);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
deleteBatch(table, keys) {
|
|
96
|
+
return this._db.deleteBatch(table, keys);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
range(table, startKey, endKey) {
|
|
100
|
+
return this._db.range(table, startKey, endKey);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
count(table) {
|
|
104
|
+
return this._db.count(table);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
flush() {
|
|
108
|
+
return this._db.flush();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
tableNames() {
|
|
112
|
+
return this._db.tableNames();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
gc() {
|
|
116
|
+
return this._db.gc();
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
isEncrypted() {
|
|
120
|
+
return this._db.isEncrypted();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
executeSql(sql) {
|
|
124
|
+
return this._db.executeSql(sql);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
createIndex(table, column) {
|
|
128
|
+
return this._db.createIndex(table, column);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
dropIndex(table, column) {
|
|
132
|
+
return this._db.dropIndex(table, column);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
hasIndex(table, column) {
|
|
136
|
+
return this._db.hasIndex(table, column);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
saveToFile(path) {
|
|
140
|
+
return this._db.saveToFile(path);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
currentTimestamp() {
|
|
144
|
+
return this._db.currentTimestamp();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
allocateCommitTs() {
|
|
148
|
+
return this._db.allocateCommitTs();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
insertVersioned(table, key, value, commitTs) {
|
|
152
|
+
return this._db.insertVersioned(table, key, value, commitTs);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
getSnapshot(table, key, readTs) {
|
|
156
|
+
return this._db.getSnapshot(table, key, readTs);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
beginTransaction() {
|
|
160
|
+
return this._db.beginTransaction();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
close() {
|
|
164
|
+
return this._db.close();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Static factory methods
|
|
168
|
+
static openInMemory() {
|
|
169
|
+
const { Database } = require('./');
|
|
170
|
+
return new SmartDatabase(Database.openInMemory());
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
static open(path) {
|
|
174
|
+
const { Database } = require('./');
|
|
175
|
+
return new SmartDatabase(Database.open(path));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
static loadFromFile(path) {
|
|
179
|
+
const { Database } = require('./');
|
|
180
|
+
return new SmartDatabase(Database.loadFromFile(path));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
module.exports = { SmartDatabase };
|
package/test/test_sql_insert.js
CHANGED
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SQL INSERT Test for DBX
|
|
3
|
-
*
|
|
4
|
-
* Tests SQL INSERT functionality via Node.js bindings
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
const { Database } = require('../index');
|
|
8
|
-
|
|
9
|
-
async function testSqlInsert() {
|
|
10
|
-
console.log('=== SQL INSERT Test ===\n');
|
|
11
|
-
|
|
12
|
-
// Create in-memory database
|
|
13
|
-
const db = Database.openInMemory();
|
|
14
|
-
console.log('✓ Database opened');
|
|
15
|
-
|
|
16
|
-
try {
|
|
17
|
-
// Test 1: Single row INSERT
|
|
18
|
-
console.log('\n1. Testing single-row INSERT...');
|
|
19
|
-
const tx1 = db.beginTransaction();
|
|
20
|
-
const result1 = tx1.execute("INSERT INTO users (id, name) VALUES (1, 'Alice')");
|
|
21
|
-
console.log(` Rows inserted: ${result1}`);
|
|
22
|
-
tx1.commit();
|
|
23
|
-
console.log(' ✓ Single-row INSERT successful');
|
|
24
|
-
|
|
25
|
-
// Test 2: Multi-row INSERT
|
|
26
|
-
console.log('\n2. Testing multi-row INSERT...');
|
|
27
|
-
const tx2 = db.beginTransaction();
|
|
28
|
-
const result2 = tx2.execute("INSERT INTO users (id, name) VALUES (2, 'Bob'), (3, 'Charlie')");
|
|
29
|
-
console.log(` Rows inserted: ${result2}`);
|
|
30
|
-
tx2.commit();
|
|
31
|
-
console.log(' ✓ Multi-row INSERT successful');
|
|
32
|
-
|
|
33
|
-
// Test 3: Different data types
|
|
34
|
-
console.log('\n3. Testing different data types...');
|
|
35
|
-
const tx3 = db.beginTransaction();
|
|
36
|
-
const result3 = tx3.execute("INSERT INTO data (id, value, flag) VALUES (42, 3.14, true)");
|
|
37
|
-
console.log(` Rows inserted: ${result3}`);
|
|
38
|
-
tx3.commit();
|
|
39
|
-
console.log(' ✓ Different data types INSERT successful');
|
|
40
|
-
|
|
41
|
-
// Test 4: Verify data via KV API
|
|
42
|
-
console.log('\n4. Verifying inserted data via KV API...');
|
|
43
|
-
const value1 = db.get('users', Buffer.from('1'));
|
|
44
|
-
if (value1) {
|
|
45
|
-
console.log(` Retrieved value for key '1': ${value1.toString()}`);
|
|
46
|
-
console.log(' ✓ Data verification successful');
|
|
47
|
-
} else {
|
|
48
|
-
console.log(' ⚠ Warning: Could not retrieve inserted data');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
console.log('\n=== All SQL INSERT tests passed! ===');
|
|
52
|
-
return true;
|
|
53
|
-
|
|
54
|
-
} catch (error) {
|
|
55
|
-
console.error('\n❌ Test failed:', error.message);
|
|
56
|
-
console.error('Stack:', error.stack);
|
|
57
|
-
return false;
|
|
58
|
-
} finally {
|
|
59
|
-
db.close();
|
|
60
|
-
console.log('\nDatabase closed');
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Run tests
|
|
65
|
-
testSqlInsert()
|
|
66
|
-
.then(success => {
|
|
67
|
-
process.exit(success ? 0 : 1);
|
|
68
|
-
})
|
|
69
|
-
.catch(error => {
|
|
70
|
-
console.error('Unexpected error:', error);
|
|
71
|
-
process.exit(1);
|
|
72
|
-
});
|
|
1
|
+
/**
|
|
2
|
+
* SQL INSERT Test for DBX
|
|
3
|
+
*
|
|
4
|
+
* Tests SQL INSERT functionality via Node.js bindings
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { Database } = require('../index');
|
|
8
|
+
|
|
9
|
+
async function testSqlInsert() {
|
|
10
|
+
console.log('=== SQL INSERT Test ===\n');
|
|
11
|
+
|
|
12
|
+
// Create in-memory database
|
|
13
|
+
const db = Database.openInMemory();
|
|
14
|
+
console.log('✓ Database opened');
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// Test 1: Single row INSERT
|
|
18
|
+
console.log('\n1. Testing single-row INSERT...');
|
|
19
|
+
const tx1 = db.beginTransaction();
|
|
20
|
+
const result1 = tx1.execute("INSERT INTO users (id, name) VALUES (1, 'Alice')");
|
|
21
|
+
console.log(` Rows inserted: ${result1}`);
|
|
22
|
+
tx1.commit();
|
|
23
|
+
console.log(' ✓ Single-row INSERT successful');
|
|
24
|
+
|
|
25
|
+
// Test 2: Multi-row INSERT
|
|
26
|
+
console.log('\n2. Testing multi-row INSERT...');
|
|
27
|
+
const tx2 = db.beginTransaction();
|
|
28
|
+
const result2 = tx2.execute("INSERT INTO users (id, name) VALUES (2, 'Bob'), (3, 'Charlie')");
|
|
29
|
+
console.log(` Rows inserted: ${result2}`);
|
|
30
|
+
tx2.commit();
|
|
31
|
+
console.log(' ✓ Multi-row INSERT successful');
|
|
32
|
+
|
|
33
|
+
// Test 3: Different data types
|
|
34
|
+
console.log('\n3. Testing different data types...');
|
|
35
|
+
const tx3 = db.beginTransaction();
|
|
36
|
+
const result3 = tx3.execute("INSERT INTO data (id, value, flag) VALUES (42, 3.14, true)");
|
|
37
|
+
console.log(` Rows inserted: ${result3}`);
|
|
38
|
+
tx3.commit();
|
|
39
|
+
console.log(' ✓ Different data types INSERT successful');
|
|
40
|
+
|
|
41
|
+
// Test 4: Verify data via KV API
|
|
42
|
+
console.log('\n4. Verifying inserted data via KV API...');
|
|
43
|
+
const value1 = db.get('users', Buffer.from('1'));
|
|
44
|
+
if (value1) {
|
|
45
|
+
console.log(` Retrieved value for key '1': ${value1.toString()}`);
|
|
46
|
+
console.log(' ✓ Data verification successful');
|
|
47
|
+
} else {
|
|
48
|
+
console.log(' ⚠ Warning: Could not retrieve inserted data');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
console.log('\n=== All SQL INSERT tests passed! ===');
|
|
52
|
+
return true;
|
|
53
|
+
|
|
54
|
+
} catch (error) {
|
|
55
|
+
console.error('\n❌ Test failed:', error.message);
|
|
56
|
+
console.error('Stack:', error.stack);
|
|
57
|
+
return false;
|
|
58
|
+
} finally {
|
|
59
|
+
db.close();
|
|
60
|
+
console.log('\nDatabase closed');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Run tests
|
|
65
|
+
testSqlInsert()
|
|
66
|
+
.then(success => {
|
|
67
|
+
process.exit(success ? 0 : 1);
|
|
68
|
+
})
|
|
69
|
+
.catch(error => {
|
|
70
|
+
console.error('Unexpected error:', error);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
});
|
|
Binary file
|