@photostructure/sqlite 0.3.0 → 0.5.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/CHANGELOG.md +65 -16
- package/README.md +5 -10
- package/binding.gyp +2 -2
- package/dist/index.cjs +314 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +346 -89
- package/dist/index.d.mts +346 -89
- package/dist/index.d.ts +346 -89
- package/dist/index.mjs +311 -10
- package/dist/index.mjs.map +1 -1
- package/package.json +72 -63
- package/prebuilds/darwin-arm64/@photostructure+sqlite.glibc.node +0 -0
- package/prebuilds/darwin-x64/@photostructure+sqlite.glibc.node +0 -0
- package/prebuilds/linux-arm64/@photostructure+sqlite.glibc.node +0 -0
- package/prebuilds/linux-arm64/@photostructure+sqlite.musl.node +0 -0
- package/prebuilds/linux-x64/@photostructure+sqlite.glibc.node +0 -0
- package/prebuilds/linux-x64/@photostructure+sqlite.musl.node +0 -0
- package/prebuilds/test_extension.so +0 -0
- package/prebuilds/win32-arm64/@photostructure+sqlite.glibc.node +0 -0
- package/prebuilds/win32-x64/@photostructure+sqlite.glibc.node +0 -0
- package/src/aggregate_function.cpp +222 -114
- package/src/aggregate_function.h +5 -6
- package/src/binding.cpp +30 -21
- package/src/enhance.ts +552 -0
- package/src/index.ts +84 -9
- package/src/shims/node_errors.h +34 -15
- package/src/shims/sqlite_errors.h +34 -8
- package/src/sql-tag-store.ts +6 -9
- package/src/sqlite_impl.cpp +1044 -394
- package/src/sqlite_impl.h +46 -7
- package/src/transaction.ts +178 -0
- package/src/types/database-sync-instance.ts +6 -40
- package/src/types/pragma-options.ts +23 -0
- package/src/types/statement-sync-instance.ts +38 -12
- package/src/types/transaction.ts +72 -0
- package/src/upstream/node_sqlite.cc +143 -43
- package/src/upstream/node_sqlite.h +15 -11
- package/src/upstream/sqlite3.c +102 -58
- package/src/upstream/sqlite3.h +5 -5
- package/src/user_function.cpp +138 -141
- package/src/user_function.h +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,13 +2,60 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.5.0] (2026-02-06)
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Statement modes via `enhance()`**: `stmt.pluck()`, `stmt.raw()`, `stmt.expand()` for better-sqlite3 compatibility
|
|
10
|
+
- `.pluck()` returns only the first column value from queries
|
|
11
|
+
- `.raw()` returns rows as arrays instead of objects
|
|
12
|
+
- `.expand()` returns rows namespaced by table, correctly handling duplicate column names across JOINs
|
|
13
|
+
- All three modes are mutually exclusive, matching better-sqlite3's toggle semantics
|
|
14
|
+
- **`stmt.database`**: Back-reference from prepared statements to their parent database instance
|
|
15
|
+
- **`EnhancedStatementMethods` type**: TypeScript interface for `pluck()`, `raw()`, `expand()`, and `database`
|
|
16
|
+
|
|
17
|
+
## [0.4.0] (2026-02-04)
|
|
18
|
+
|
|
19
|
+
API compatible with `node:sqlite` from Node.js v25.6.1.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **`enhance()` function**: Adds better-sqlite3-style `.pragma()` and `.transaction()` methods to any compatible database instance
|
|
24
|
+
- **`isEnhanced()` type guard**: Check if a database has enhanced methods
|
|
25
|
+
- **Transaction helper**: Automatic BEGIN/COMMIT/ROLLBACK with savepoint support for nested transactions
|
|
26
|
+
- **Pragma convenience method**: Simple API for reading and setting SQLite pragmas with `simple` option
|
|
27
|
+
- **Node.js test sync script**: `npm run sync:tests` downloads and adapts upstream Node.js SQLite tests
|
|
28
|
+
- **Percentile extension**: `SQLITE_ENABLE_PERCENTILE` now enabled, adding `percentile()`, `median()`, `percentile_cont()`, `percentile_disc()` SQL functions (Node.js v25+)
|
|
29
|
+
- **Prepare options**: `db.prepare(sql, options)` now accepts per-statement options (`readBigInts`, `returnArrays`, `allowBareNamedParameters`, `allowUnknownNamedParameters`) to override database-level defaults. This is a Node.js v25+ feature; `node:sqlite` on v24 and earlier silently ignores these options.
|
|
30
|
+
- **StatementColumnMetadata type**: `stmt.columns()` now returns richer metadata including `column`, `database`, `table`, and `type` properties alongside `name`
|
|
31
|
+
- **SQLite 3.51.2**: Updated from 3.51.1
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- **BREAKING**: Removed API extensions to achieve exact parity with `node:sqlite`:
|
|
36
|
+
- Removed `stmt.finalize()` method (use database close for cleanup)
|
|
37
|
+
- Removed `stmt.finalized` property
|
|
38
|
+
- Removed `stmt[Symbol.dispose]` (still available on `DatabaseSync` and `Session`)
|
|
39
|
+
- Removed `db.backup()` instance method (use standalone `backup(db, path)` function instead)
|
|
40
|
+
- **BREAKING**: `Session.changeset()` and `Session.patchset()` now return `Uint8Array` instead of `Buffer` to match `node:sqlite` API
|
|
41
|
+
- **BREAKING**: Defensive mode now defaults to `true` instead of `false` to match Node.js v25+ behavior. Use `{ defensive: false }` to restore old behavior.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- **Alpine Linux / musl stability**: Fixed native crashes by removing N-API reference cleanup from destructors that corrupted V8 JIT state
|
|
46
|
+
- **Session lifecycle management**: Fixed use-after-free, double-free, and mutex deadlock when databases are garbage collected before their sessions
|
|
47
|
+
- **Worker thread stability**: Added cleanup hooks and exception handling for worker thread termination
|
|
48
|
+
- **Callback error preservation**: `applyChangeset()` now preserves the original error message when JavaScript callbacks throw
|
|
49
|
+
- `createTagStore()` now throws errors with `code: 'ERR_INVALID_STATE'` property when database is closed, matching Node.js error format
|
|
50
|
+
|
|
5
51
|
## [0.3.0] (2025-12-16)
|
|
6
52
|
|
|
7
53
|
### Changed
|
|
8
54
|
|
|
9
|
-
- **BREAKING**: `SQLTagStore.size` changed from method to getter for Node.js API parity (Node.js PR #60246)
|
|
55
|
+
- **BREAKING**: `SQLTagStore.size` changed from method to getter for Node.js API parity ([Node.js PR #60246](https://github.com/nodejs/node/pull/60246))
|
|
10
56
|
- Before: `sql.size()`
|
|
11
57
|
- After: `sql.size`
|
|
58
|
+
- **Note**: This change was merged into Node.js main on December 11, 2025 and will appear in a future Node.js release. Current Node.js v24.x still uses `sql.size()` as a method.
|
|
12
59
|
|
|
13
60
|
## [0.2.1] (2025-12-01)
|
|
14
61
|
|
|
@@ -30,11 +77,11 @@ All notable changes to this project will be documented in this file.
|
|
|
30
77
|
- **Defensive mode**: `enableDefensive()` method to prevent SQL from deliberately corrupting the database
|
|
31
78
|
- **Statement enhancements**: `setAllowUnknownNamedParameters()` method, `finalized` property
|
|
32
79
|
- **Type identification**: `sqlite-type` symbol property on DatabaseSync (Node.js PR #59405)
|
|
33
|
-
- **
|
|
80
|
+
- **SQLite error properties**: `sqliteCode`, `sqliteExtendedCode`, `code`, `sqliteErrorString`, `systemErrno`
|
|
34
81
|
- **ARM64 prebuilds**: macOS Apple Silicon and Windows ARM64 binaries
|
|
35
82
|
- **Tagged template literals**: `db.createTagStore()` for cached prepared statements (Node.js PR #58748)
|
|
36
83
|
- **Authorization API**: `db.setAuthorizer()` for security callbacks (Node.js PR #59928)
|
|
37
|
-
- **Standalone backup**: `backup(srcDb, destFile, options?)` for
|
|
84
|
+
- **Standalone backup**: `backup(srcDb, destFile, options?)` for database backups with progress callbacks
|
|
38
85
|
|
|
39
86
|
### Fixed
|
|
40
87
|
|
|
@@ -48,16 +95,16 @@ All notable changes to this project will be documented in this file.
|
|
|
48
95
|
|
|
49
96
|
### Added
|
|
50
97
|
|
|
51
|
-
- Initial release of `@photostructure/sqlite
|
|
52
|
-
-
|
|
98
|
+
- Initial release of `@photostructure/sqlite`, standalone SQLite for Node.js 20+
|
|
99
|
+
- Compatible with Node.js built-in SQLite module API
|
|
53
100
|
- Core SQLite operations with `DatabaseSync` and `StatementSync` classes
|
|
54
|
-
- User-defined scalar and aggregate functions with
|
|
55
|
-
- Database backup and restoration
|
|
101
|
+
- User-defined scalar and aggregate functions with window function support
|
|
102
|
+
- Database backup and restoration
|
|
56
103
|
- SQLite sessions and changesets for change tracking
|
|
57
|
-
- Extension loading
|
|
58
|
-
- TypeScript definitions
|
|
104
|
+
- Extension loading with automatic platform-specific file resolution
|
|
105
|
+
- TypeScript definitions
|
|
59
106
|
- Cross-platform prebuilt binaries for Windows, macOS, and Linux (x64, ARM64)
|
|
60
|
-
-
|
|
107
|
+
- Test suite with 89+ tests
|
|
61
108
|
- Memory safety validation with Valgrind and sanitizers
|
|
62
109
|
- Performance benchmarking suite comparing to better-sqlite3
|
|
63
110
|
- Automated synchronization from Node.js upstream SQLite implementation
|
|
@@ -65,15 +112,15 @@ All notable changes to this project will be documented in this file.
|
|
|
65
112
|
|
|
66
113
|
### Features
|
|
67
114
|
|
|
68
|
-
- **Synchronous API**:
|
|
69
|
-
- **Parameter binding**:
|
|
115
|
+
- **Synchronous API**: Blocking database operations for scripts and tools
|
|
116
|
+
- **Parameter binding**: All SQLite data types including BigInt
|
|
70
117
|
- **Error handling**: Detailed error messages with SQLite error codes
|
|
71
118
|
- **Resource limits**: Control memory usage and query complexity
|
|
72
119
|
- **Safe integer handling**: JavaScript-safe integer conversion with overflow detection
|
|
73
|
-
- **Multi-process support**:
|
|
74
|
-
- **Worker thread support**:
|
|
75
|
-
- **URI filename support**:
|
|
76
|
-
- **Strict tables**:
|
|
120
|
+
- **Multi-process support**: Concurrent access from multiple Node.js processes
|
|
121
|
+
- **Worker thread support**: Works in worker threads
|
|
122
|
+
- **URI filename support**: SQLite URI syntax for advanced database configuration
|
|
123
|
+
- **Strict tables**: SQLite strict table mode
|
|
77
124
|
- **Double-quoted strings**: Configurable SQL syntax compatibility
|
|
78
125
|
|
|
79
126
|
### Platform Support
|
|
@@ -83,6 +130,8 @@ All notable changes to this project will be documented in this file.
|
|
|
83
130
|
- macOS (x64, ARM64)
|
|
84
131
|
- Linux (x64, ARM64), (glibc 2.28+, musl)
|
|
85
132
|
|
|
133
|
+
[0.5.0]: https://github.com/PhotoStructure/node-sqlite/releases/tag/v0.5.0
|
|
134
|
+
[0.4.0]: https://github.com/PhotoStructure/node-sqlite/releases/tag/v0.4.0
|
|
86
135
|
[0.3.0]: https://github.com/PhotoStructure/node-sqlite/releases/tag/v0.3.0
|
|
87
136
|
[0.2.1]: https://github.com/PhotoStructure/node-sqlite/releases/tag/v0.2.1
|
|
88
137
|
[0.2.0]: https://github.com/PhotoStructure/node-sqlite/releases/tag/v0.2.0
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@photostructure/sqlite)
|
|
4
4
|
[](https://github.com/photostructure/node-sqlite/actions/workflows/build.yml)
|
|
5
5
|
|
|
6
|
-
Native SQLite for Node.js 20+ without the experimental flag. Drop-in replacement for `node:sqlite`.
|
|
6
|
+
Native SQLite for Node.js 20+ without the experimental flag. Drop-in replacement for `node:sqlite`. Synced with Node.js v25.6.1 for the latest features including native `Symbol.dispose` resource management.
|
|
7
7
|
|
|
8
8
|
## Installation
|
|
9
9
|
|
|
@@ -27,17 +27,18 @@ db.close();
|
|
|
27
27
|
|
|
28
28
|
## Features
|
|
29
29
|
|
|
30
|
-
- 100% compatible with Node.js v25 built-in `node:sqlite` module\*
|
|
30
|
+
- 100% compatible with Node.js v25.6.1 built-in `node:sqlite` module\*
|
|
31
31
|
- Zero dependencies - native SQLite implementation
|
|
32
32
|
- Synchronous API - no async overhead
|
|
33
|
-
- Performance
|
|
33
|
+
- Performance comparable to better-sqlite3
|
|
34
34
|
- Full SQLite feature set ([details](./doc/features.md))
|
|
35
35
|
- TypeScript support with complete type definitions
|
|
36
36
|
- Cross-platform prebuilt binaries (Windows/macOS/Linux, x64/ARM64)
|
|
37
37
|
- User-defined functions and aggregates
|
|
38
38
|
- Database backups and session/changeset support
|
|
39
39
|
- Session class exposed for advanced replication workflows
|
|
40
|
-
- Native Symbol.dispose for
|
|
40
|
+
- Native `Symbol.dispose` for resource management
|
|
41
|
+
- `enhance()` function for better-sqlite3 style `.pragma()` and `.transaction()` methods
|
|
41
42
|
- URI filename support for advanced configuration
|
|
42
43
|
- Worker thread safe
|
|
43
44
|
- [Compare with other libraries →](./doc/library-comparison.md)
|
|
@@ -69,12 +70,6 @@ db.close();
|
|
|
69
70
|
- [Build Flags & Configuration](./doc/build-flags.md)
|
|
70
71
|
- [Library Comparison](./doc/library-comparison.md)
|
|
71
72
|
|
|
72
|
-
## Support
|
|
73
|
-
|
|
74
|
-
- 🐛 [Issues](https://github.com/photostructure/node-sqlite/issues)
|
|
75
|
-
- 💬 [Discussions](https://github.com/photostructure/node-sqlite/discussions)
|
|
76
|
-
- 📧 [Security](./SECURITY.md)
|
|
77
|
-
|
|
78
73
|
## License
|
|
79
74
|
|
|
80
75
|
MIT - see [LICENSE](./LICENSE) for details.
|
package/binding.gyp
CHANGED
|
@@ -11,13 +11,12 @@
|
|
|
11
11
|
"src/upstream/sqlite3.c"
|
|
12
12
|
],
|
|
13
13
|
"include_dirs": [
|
|
14
|
-
"<!@(node -p \"require('node-addon-api').include\")",
|
|
15
14
|
"src",
|
|
16
15
|
"src/upstream",
|
|
17
16
|
"src/shims"
|
|
18
17
|
],
|
|
19
18
|
"dependencies": [
|
|
20
|
-
"<!(node -p \"require('node-addon-api').
|
|
19
|
+
"<!(node -p \"require('node-addon-api').targets + ':node_addon_api_except'\")"
|
|
21
20
|
],
|
|
22
21
|
# SQLite build flags - see doc/build-flags.md for comprehensive documentation
|
|
23
22
|
# including comparison with Node.js configuration and rationale for our choices
|
|
@@ -40,6 +39,7 @@
|
|
|
40
39
|
"SQLITE_ENABLE_JSON1",
|
|
41
40
|
"SQLITE_ENABLE_MATH_FUNCTIONS",
|
|
42
41
|
"SQLITE_ENABLE_NORMALIZE",
|
|
42
|
+
"SQLITE_ENABLE_PERCENTILE",
|
|
43
43
|
"SQLITE_ENABLE_PREUPDATE_HOOK",
|
|
44
44
|
"SQLITE_ENABLE_RBU",
|
|
45
45
|
"SQLITE_ENABLE_RTREE",
|
package/dist/index.cjs
CHANGED
|
@@ -36,7 +36,9 @@ __export(index_exports, {
|
|
|
36
36
|
StatementSync: () => StatementSync,
|
|
37
37
|
backup: () => backup,
|
|
38
38
|
constants: () => constants,
|
|
39
|
-
default: () => index_default
|
|
39
|
+
default: () => index_default,
|
|
40
|
+
enhance: () => enhance,
|
|
41
|
+
isEnhanced: () => isEnhanced
|
|
40
42
|
});
|
|
41
43
|
module.exports = __toCommonJS(index_exports);
|
|
42
44
|
var import_node_gyp_build = __toESM(require("node-gyp-build"));
|
|
@@ -187,7 +189,9 @@ var SQLTagStore = class {
|
|
|
187
189
|
maxCapacity;
|
|
188
190
|
constructor(db, capacity = DEFAULT_CAPACITY) {
|
|
189
191
|
if (!db.isOpen) {
|
|
190
|
-
|
|
192
|
+
const err = new Error("database is not open");
|
|
193
|
+
err.code = "ERR_INVALID_STATE";
|
|
194
|
+
throw err;
|
|
191
195
|
}
|
|
192
196
|
this.database = db;
|
|
193
197
|
this.maxCapacity = capacity;
|
|
@@ -248,19 +252,15 @@ var SQLTagStore = class {
|
|
|
248
252
|
}
|
|
249
253
|
/**
|
|
250
254
|
* Get a cached statement or prepare a new one.
|
|
251
|
-
* If a cached statement has been finalized, it's evicted and a new one is prepared.
|
|
252
255
|
*/
|
|
253
256
|
getOrPrepare(strings) {
|
|
254
257
|
if (!this.database.isOpen) {
|
|
255
|
-
throw new Error("
|
|
258
|
+
throw new Error("database is not open");
|
|
256
259
|
}
|
|
257
260
|
const sql = this.buildSQL(strings);
|
|
258
261
|
const cached = this.cache.get(sql);
|
|
259
262
|
if (cached) {
|
|
260
|
-
|
|
261
|
-
return cached;
|
|
262
|
-
}
|
|
263
|
-
this.cache.delete(sql);
|
|
263
|
+
return cached;
|
|
264
264
|
}
|
|
265
265
|
const stmt = this.database.prepare(sql);
|
|
266
266
|
this.cache.set(sql, stmt);
|
|
@@ -278,13 +278,314 @@ var SQLTagStore = class {
|
|
|
278
278
|
}
|
|
279
279
|
};
|
|
280
280
|
|
|
281
|
+
// src/transaction.ts
|
|
282
|
+
var savepointCounter = 0;
|
|
283
|
+
function createTransaction(db, fn) {
|
|
284
|
+
if (typeof fn !== "function") {
|
|
285
|
+
throw new TypeError("Expected first argument to be a function");
|
|
286
|
+
}
|
|
287
|
+
const variants = {
|
|
288
|
+
deferred: createVariant(db, fn, "deferred"),
|
|
289
|
+
immediate: createVariant(db, fn, "immediate"),
|
|
290
|
+
exclusive: createVariant(db, fn, "exclusive")
|
|
291
|
+
};
|
|
292
|
+
const defaultFn = variants.deferred;
|
|
293
|
+
for (const variant of Object.values(variants)) {
|
|
294
|
+
Object.defineProperties(variant, {
|
|
295
|
+
deferred: { value: variants.deferred, enumerable: true },
|
|
296
|
+
immediate: { value: variants.immediate, enumerable: true },
|
|
297
|
+
exclusive: { value: variants.exclusive, enumerable: true },
|
|
298
|
+
database: { value: db, enumerable: true }
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
return defaultFn;
|
|
302
|
+
}
|
|
303
|
+
function createVariant(db, fn, mode) {
|
|
304
|
+
const beginStatement = getBeginStatement(mode);
|
|
305
|
+
return function transactionWrapper(...args) {
|
|
306
|
+
const isNested = db.isTransaction;
|
|
307
|
+
let begin;
|
|
308
|
+
let commit;
|
|
309
|
+
let rollback;
|
|
310
|
+
if (isNested) {
|
|
311
|
+
const savepointName = `\`_txn_${++savepointCounter}\``;
|
|
312
|
+
begin = `SAVEPOINT ${savepointName}`;
|
|
313
|
+
commit = `RELEASE ${savepointName}`;
|
|
314
|
+
rollback = `ROLLBACK TO ${savepointName}`;
|
|
315
|
+
} else {
|
|
316
|
+
begin = beginStatement;
|
|
317
|
+
commit = "COMMIT";
|
|
318
|
+
rollback = "ROLLBACK";
|
|
319
|
+
}
|
|
320
|
+
db.exec(begin);
|
|
321
|
+
try {
|
|
322
|
+
const result = fn.apply(this, args);
|
|
323
|
+
if (result !== null && typeof result === "object" && "then" in result) {
|
|
324
|
+
throw new TypeError(
|
|
325
|
+
"Transaction function must not return a Promise. SQLite transactions are synchronous and cannot span across async operations. Use synchronous code within transactions."
|
|
326
|
+
);
|
|
327
|
+
}
|
|
328
|
+
db.exec(commit);
|
|
329
|
+
return result;
|
|
330
|
+
} catch (error) {
|
|
331
|
+
if (db.isTransaction) {
|
|
332
|
+
db.exec(rollback);
|
|
333
|
+
if (isNested) {
|
|
334
|
+
db.exec(commit);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
throw error;
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
function getBeginStatement(mode) {
|
|
342
|
+
switch (mode) {
|
|
343
|
+
case "deferred":
|
|
344
|
+
return "BEGIN DEFERRED";
|
|
345
|
+
case "immediate":
|
|
346
|
+
return "BEGIN IMMEDIATE";
|
|
347
|
+
case "exclusive":
|
|
348
|
+
return "BEGIN EXCLUSIVE";
|
|
349
|
+
default:
|
|
350
|
+
throw new Error(`Unknown transaction mode: ${mode}`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// src/enhance.ts
|
|
355
|
+
var ENHANCED_PREPARE = /* @__PURE__ */ Symbol.for("@photostructure/sqlite:enhancedPrepare");
|
|
356
|
+
function extractFirstColumn(row) {
|
|
357
|
+
if (row == null) return row;
|
|
358
|
+
if (Array.isArray(row)) return row[0];
|
|
359
|
+
const keys = Object.keys(row);
|
|
360
|
+
return keys.length > 0 ? row[keys[0]] : void 0;
|
|
361
|
+
}
|
|
362
|
+
function buildColumnTableMap(stmt) {
|
|
363
|
+
if (typeof stmt.columns !== "function") return void 0;
|
|
364
|
+
const cols = stmt.columns();
|
|
365
|
+
return cols.map((c) => ({
|
|
366
|
+
table: c.table ?? "$",
|
|
367
|
+
column: c.name
|
|
368
|
+
}));
|
|
369
|
+
}
|
|
370
|
+
function expandRowFromArray(row, columnMap) {
|
|
371
|
+
const result = {};
|
|
372
|
+
for (let i = 0; i < columnMap.length && i < row.length; i++) {
|
|
373
|
+
const { table, column } = columnMap[i];
|
|
374
|
+
result[table] ??= {};
|
|
375
|
+
result[table][column] = row[i];
|
|
376
|
+
}
|
|
377
|
+
return result;
|
|
378
|
+
}
|
|
379
|
+
function expandRowFromObject(row, columnMap) {
|
|
380
|
+
const result = {};
|
|
381
|
+
const keys = Object.keys(row);
|
|
382
|
+
for (let i = 0; i < keys.length && i < columnMap.length; i++) {
|
|
383
|
+
const { table, column } = columnMap[i];
|
|
384
|
+
result[table] ??= {};
|
|
385
|
+
result[table][column] = row[keys[i]];
|
|
386
|
+
}
|
|
387
|
+
return result;
|
|
388
|
+
}
|
|
389
|
+
function validateToggle(value) {
|
|
390
|
+
const use = value === void 0 ? true : value;
|
|
391
|
+
if (typeof use !== "boolean") {
|
|
392
|
+
throw new TypeError("Expected first argument to be a boolean");
|
|
393
|
+
}
|
|
394
|
+
return use;
|
|
395
|
+
}
|
|
396
|
+
function transformRow(row, mode, columnMap) {
|
|
397
|
+
if (row == null || mode === "flat") return row;
|
|
398
|
+
if (mode === "pluck") return extractFirstColumn(row);
|
|
399
|
+
if (mode === "expand") {
|
|
400
|
+
if (Array.isArray(row)) {
|
|
401
|
+
return expandRowFromArray(row, columnMap);
|
|
402
|
+
}
|
|
403
|
+
return expandRowFromObject(row, columnMap);
|
|
404
|
+
}
|
|
405
|
+
return row;
|
|
406
|
+
}
|
|
407
|
+
function enhanceStatement(stmt) {
|
|
408
|
+
if (typeof stmt.pluck === "function") {
|
|
409
|
+
return stmt;
|
|
410
|
+
}
|
|
411
|
+
let mode = "flat";
|
|
412
|
+
let columnMap;
|
|
413
|
+
const originalGet = typeof stmt.get === "function" ? stmt.get.bind(stmt) : void 0;
|
|
414
|
+
const originalAll = stmt.all.bind(stmt);
|
|
415
|
+
const originalIterate = typeof stmt.iterate === "function" ? stmt.iterate.bind(stmt) : void 0;
|
|
416
|
+
function setMode(target, use) {
|
|
417
|
+
if (use) {
|
|
418
|
+
mode = target;
|
|
419
|
+
if (target === "expand" && columnMap == null) {
|
|
420
|
+
columnMap = buildColumnTableMap(stmt);
|
|
421
|
+
if (columnMap == null) {
|
|
422
|
+
throw new TypeError(
|
|
423
|
+
"expand() requires the statement to have a columns() method"
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
} else if (mode === target) {
|
|
428
|
+
mode = "flat";
|
|
429
|
+
}
|
|
430
|
+
if (typeof stmt.setReturnArrays === "function") {
|
|
431
|
+
stmt.setReturnArrays(mode === "raw" || mode === "expand");
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
Object.defineProperty(stmt, "pluck", {
|
|
435
|
+
value: function pluck(toggle) {
|
|
436
|
+
setMode("pluck", validateToggle(toggle));
|
|
437
|
+
return stmt;
|
|
438
|
+
},
|
|
439
|
+
writable: true,
|
|
440
|
+
configurable: true,
|
|
441
|
+
enumerable: false
|
|
442
|
+
});
|
|
443
|
+
Object.defineProperty(stmt, "raw", {
|
|
444
|
+
value: function raw(toggle) {
|
|
445
|
+
setMode("raw", validateToggle(toggle));
|
|
446
|
+
return stmt;
|
|
447
|
+
},
|
|
448
|
+
writable: true,
|
|
449
|
+
configurable: true,
|
|
450
|
+
enumerable: false
|
|
451
|
+
});
|
|
452
|
+
Object.defineProperty(stmt, "expand", {
|
|
453
|
+
value: function expand(toggle) {
|
|
454
|
+
setMode("expand", validateToggle(toggle));
|
|
455
|
+
return stmt;
|
|
456
|
+
},
|
|
457
|
+
writable: true,
|
|
458
|
+
configurable: true,
|
|
459
|
+
enumerable: false
|
|
460
|
+
});
|
|
461
|
+
if (originalGet != null) {
|
|
462
|
+
Object.defineProperty(stmt, "get", {
|
|
463
|
+
value: (...params) => {
|
|
464
|
+
const row = originalGet(...params);
|
|
465
|
+
return transformRow(row, mode, columnMap);
|
|
466
|
+
},
|
|
467
|
+
writable: true,
|
|
468
|
+
configurable: true,
|
|
469
|
+
enumerable: false
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
Object.defineProperty(stmt, "all", {
|
|
473
|
+
value: (...params) => {
|
|
474
|
+
const rows = originalAll(...params);
|
|
475
|
+
if (mode === "flat" || mode === "raw") return rows;
|
|
476
|
+
return rows.map((row) => transformRow(row, mode, columnMap));
|
|
477
|
+
},
|
|
478
|
+
writable: true,
|
|
479
|
+
configurable: true,
|
|
480
|
+
enumerable: false
|
|
481
|
+
});
|
|
482
|
+
if (originalIterate != null) {
|
|
483
|
+
Object.defineProperty(stmt, "iterate", {
|
|
484
|
+
value: function* (...params) {
|
|
485
|
+
const iter = originalIterate(...params);
|
|
486
|
+
for (const row of iter) {
|
|
487
|
+
yield transformRow(row, mode, columnMap);
|
|
488
|
+
}
|
|
489
|
+
},
|
|
490
|
+
writable: true,
|
|
491
|
+
configurable: true,
|
|
492
|
+
enumerable: false
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
return stmt;
|
|
496
|
+
}
|
|
497
|
+
function pragmaImpl(source, options) {
|
|
498
|
+
if (typeof source !== "string") {
|
|
499
|
+
throw new TypeError("Expected first argument to be a string");
|
|
500
|
+
}
|
|
501
|
+
if (options != null && typeof options !== "object") {
|
|
502
|
+
throw new TypeError("Expected second argument to be an options object");
|
|
503
|
+
}
|
|
504
|
+
const simple = options?.simple === true;
|
|
505
|
+
if (options != null && "simple" in options && typeof options.simple !== "boolean") {
|
|
506
|
+
throw new TypeError('Expected the "simple" option to be a boolean');
|
|
507
|
+
}
|
|
508
|
+
const stmt = this.prepare(`PRAGMA ${source}`);
|
|
509
|
+
if (simple) {
|
|
510
|
+
return extractFirstColumn(stmt.all()[0]);
|
|
511
|
+
}
|
|
512
|
+
return stmt.all();
|
|
513
|
+
}
|
|
514
|
+
function transactionImpl(fn) {
|
|
515
|
+
return createTransaction(this, fn);
|
|
516
|
+
}
|
|
517
|
+
function hasEnhancedMethods(db) {
|
|
518
|
+
return typeof db.pragma === "function" && typeof db.transaction === "function";
|
|
519
|
+
}
|
|
520
|
+
function enhance(db) {
|
|
521
|
+
if (!hasEnhancedMethods(db)) {
|
|
522
|
+
Object.defineProperty(db, "pragma", {
|
|
523
|
+
value: pragmaImpl,
|
|
524
|
+
writable: true,
|
|
525
|
+
configurable: true,
|
|
526
|
+
enumerable: false
|
|
527
|
+
});
|
|
528
|
+
Object.defineProperty(db, "transaction", {
|
|
529
|
+
value: transactionImpl,
|
|
530
|
+
writable: true,
|
|
531
|
+
configurable: true,
|
|
532
|
+
enumerable: false
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
if (!db[ENHANCED_PREPARE]) {
|
|
536
|
+
const originalPrepare = db.prepare.bind(db);
|
|
537
|
+
Object.defineProperty(db, "prepare", {
|
|
538
|
+
value: (...args) => {
|
|
539
|
+
const stmt = originalPrepare(...args);
|
|
540
|
+
enhanceStatement(stmt);
|
|
541
|
+
Object.defineProperty(stmt, "database", {
|
|
542
|
+
value: db,
|
|
543
|
+
writable: false,
|
|
544
|
+
configurable: true,
|
|
545
|
+
enumerable: false
|
|
546
|
+
});
|
|
547
|
+
return stmt;
|
|
548
|
+
},
|
|
549
|
+
writable: true,
|
|
550
|
+
configurable: true,
|
|
551
|
+
enumerable: false
|
|
552
|
+
});
|
|
553
|
+
Object.defineProperty(db, ENHANCED_PREPARE, {
|
|
554
|
+
value: true,
|
|
555
|
+
writable: false,
|
|
556
|
+
configurable: false,
|
|
557
|
+
enumerable: false
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
return db;
|
|
561
|
+
}
|
|
562
|
+
function isEnhanced(db) {
|
|
563
|
+
return hasEnhancedMethods(db);
|
|
564
|
+
}
|
|
565
|
+
|
|
281
566
|
// src/index.ts
|
|
282
567
|
var binding = (0, import_node_gyp_build.default)((0, import_node_path2.join)(_dirname(), ".."));
|
|
283
|
-
var
|
|
568
|
+
var _DatabaseSync = binding.DatabaseSync;
|
|
569
|
+
var DatabaseSync = function DatabaseSync2(...args) {
|
|
570
|
+
if (!new.target) {
|
|
571
|
+
const err = new TypeError("Cannot call constructor without `new`");
|
|
572
|
+
err.code = "ERR_CONSTRUCT_CALL_REQUIRED";
|
|
573
|
+
throw err;
|
|
574
|
+
}
|
|
575
|
+
return Reflect.construct(_DatabaseSync, args, new.target);
|
|
576
|
+
};
|
|
577
|
+
Object.setPrototypeOf(DatabaseSync, _DatabaseSync);
|
|
578
|
+
DatabaseSync.prototype = _DatabaseSync.prototype;
|
|
284
579
|
DatabaseSync.prototype.createTagStore = function(capacity) {
|
|
285
580
|
return new SQLTagStore(this, capacity);
|
|
286
581
|
};
|
|
287
|
-
var
|
|
582
|
+
var _StatementSync = binding.StatementSync;
|
|
583
|
+
var StatementSync = function StatementSync2() {
|
|
584
|
+
const err = new TypeError("Illegal constructor");
|
|
585
|
+
err.code = "ERR_ILLEGAL_CONSTRUCTOR";
|
|
586
|
+
throw err;
|
|
587
|
+
};
|
|
588
|
+
StatementSync.prototype = _StatementSync.prototype;
|
|
288
589
|
var Session = binding.Session;
|
|
289
590
|
var constants = binding.constants;
|
|
290
591
|
var backup = binding.backup;
|
|
@@ -296,6 +597,8 @@ var index_default = binding;
|
|
|
296
597
|
Session,
|
|
297
598
|
StatementSync,
|
|
298
599
|
backup,
|
|
299
|
-
constants
|
|
600
|
+
constants,
|
|
601
|
+
enhance,
|
|
602
|
+
isEnhanced
|
|
300
603
|
});
|
|
301
604
|
//# sourceMappingURL=index.cjs.map
|