@photostructure/sqlite 0.0.1 → 0.2.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 +36 -2
- package/README.md +45 -484
- package/SECURITY.md +27 -84
- package/binding.gyp +69 -22
- package/dist/index.cjs +185 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +552 -100
- package/dist/index.d.mts +552 -100
- package/dist/index.d.ts +552 -100
- package/dist/index.mjs +183 -18
- package/dist/index.mjs.map +1 -1
- package/package.json +51 -41
- 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-x64/@photostructure+sqlite.glibc.node +0 -0
- package/src/aggregate_function.cpp +503 -235
- package/src/aggregate_function.h +57 -42
- package/src/binding.cpp +117 -14
- package/src/dirname.ts +1 -1
- package/src/index.ts +122 -332
- package/src/lru-cache.ts +84 -0
- package/src/shims/env-inl.h +6 -15
- package/src/shims/node_errors.h +4 -0
- package/src/shims/sqlite_errors.h +162 -0
- package/src/shims/util.h +29 -4
- package/src/sql-tag-store.ts +140 -0
- package/src/sqlite_exception.h +49 -0
- package/src/sqlite_impl.cpp +711 -127
- package/src/sqlite_impl.h +84 -6
- package/src/{stack_path.ts → stack-path.ts} +7 -1
- package/src/types/aggregate-options.ts +22 -0
- package/src/types/changeset-apply-options.ts +18 -0
- package/src/types/database-sync-instance.ts +203 -0
- package/src/types/database-sync-options.ts +69 -0
- package/src/types/session-options.ts +10 -0
- package/src/types/sql-tag-store-instance.ts +51 -0
- package/src/types/sqlite-authorization-actions.ts +77 -0
- package/src/types/sqlite-authorization-results.ts +15 -0
- package/src/types/sqlite-changeset-conflict-types.ts +19 -0
- package/src/types/sqlite-changeset-resolution.ts +15 -0
- package/src/types/sqlite-open-flags.ts +50 -0
- package/src/types/statement-sync-instance.ts +73 -0
- package/src/types/user-functions-options.ts +14 -0
- package/src/upstream/node_sqlite.cc +960 -259
- package/src/upstream/node_sqlite.h +127 -2
- package/src/upstream/sqlite.js +1 -14
- package/src/upstream/sqlite3.c +4510 -1411
- package/src/upstream/sqlite3.h +390 -195
- package/src/upstream/sqlite3ext.h +7 -0
- package/src/user_function.cpp +88 -36
- package/src/user_function.h +2 -1
package/src/index.ts
CHANGED
|
@@ -2,42 +2,53 @@
|
|
|
2
2
|
import nodeGypBuild from "node-gyp-build";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { _dirname } from "./dirname";
|
|
5
|
+
import { SQLTagStore } from "./sql-tag-store";
|
|
6
|
+
import { DatabaseSyncInstance } from "./types/database-sync-instance";
|
|
7
|
+
import { DatabaseSyncOptions } from "./types/database-sync-options";
|
|
8
|
+
import { SQLTagStoreInstance } from "./types/sql-tag-store-instance";
|
|
9
|
+
import { SqliteAuthorizationActions } from "./types/sqlite-authorization-actions";
|
|
10
|
+
import { SqliteAuthorizationResults } from "./types/sqlite-authorization-results";
|
|
11
|
+
import { SqliteChangesetConflictTypes } from "./types/sqlite-changeset-conflict-types";
|
|
12
|
+
import { SqliteChangesetResolution } from "./types/sqlite-changeset-resolution";
|
|
13
|
+
import { SqliteOpenFlags } from "./types/sqlite-open-flags";
|
|
14
|
+
import { StatementSyncInstance } from "./types/statement-sync-instance";
|
|
15
|
+
|
|
16
|
+
export type { AggregateOptions } from "./types/aggregate-options";
|
|
17
|
+
export type { ChangesetApplyOptions } from "./types/changeset-apply-options";
|
|
18
|
+
export type { DatabaseSyncInstance } from "./types/database-sync-instance";
|
|
19
|
+
export type { DatabaseSyncOptions } from "./types/database-sync-options";
|
|
20
|
+
export type { SessionOptions } from "./types/session-options";
|
|
21
|
+
export type { SQLTagStoreInstance } from "./types/sql-tag-store-instance";
|
|
22
|
+
export type { SqliteAuthorizationActions } from "./types/sqlite-authorization-actions";
|
|
23
|
+
export type { SqliteAuthorizationResults } from "./types/sqlite-authorization-results";
|
|
24
|
+
export type { SqliteChangesetConflictTypes } from "./types/sqlite-changeset-conflict-types";
|
|
25
|
+
export type { SqliteChangesetResolution } from "./types/sqlite-changeset-resolution";
|
|
26
|
+
export type { SqliteOpenFlags } from "./types/sqlite-open-flags";
|
|
27
|
+
export type { StatementSyncInstance } from "./types/statement-sync-instance";
|
|
28
|
+
export type { UserFunctionOptions } from "./types/user-functions-options";
|
|
5
29
|
|
|
6
30
|
// Use _dirname() helper that works in both CJS/ESM and Jest
|
|
7
31
|
const binding = nodeGypBuild(join(_dirname(), ".."));
|
|
8
32
|
|
|
9
33
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
34
|
+
* All SQLite constants exported by this module.
|
|
35
|
+
*
|
|
36
|
+
* This is a union of all constant category interfaces:
|
|
37
|
+
* - {@link SqliteOpenFlags} - Database open flags (extension beyond `node:sqlite`)
|
|
38
|
+
* - {@link SqliteChangesetResolution} - Changeset conflict resolution values
|
|
39
|
+
* - {@link SqliteChangesetConflictTypes} - Changeset conflict type codes
|
|
40
|
+
* - {@link SqliteAuthorizationResults} - Authorization return values
|
|
41
|
+
* - {@link SqliteAuthorizationActions} - Authorization action codes
|
|
42
|
+
*
|
|
43
|
+
* **Note:** The categorized interfaces (`SqliteOpenFlags`, etc.) are extensions
|
|
44
|
+
* provided by `@photostructure/sqlite`. The `node:sqlite` module exports only
|
|
45
|
+
* a flat `constants` object without these type categories.
|
|
12
46
|
*/
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
/** If true, foreign key constraints are enforced. @default true */
|
|
19
|
-
readonly enableForeignKeyConstraints?: boolean;
|
|
20
|
-
/**
|
|
21
|
-
* If true, double-quoted string literals are allowed.
|
|
22
|
-
*
|
|
23
|
-
* If enabled, double quotes can be misinterpreted as identifiers instead of
|
|
24
|
-
* string literals, leading to confusing errors.
|
|
25
|
-
*
|
|
26
|
-
* **The SQLite documentation strongly recommends avoiding double-quoted
|
|
27
|
-
* strings entirely.**
|
|
28
|
-
|
|
29
|
-
* @see https://sqlite.org/quirks.html#dblquote
|
|
30
|
-
* @default false
|
|
31
|
-
*/
|
|
32
|
-
readonly enableDoubleQuotedStringLiterals?: boolean;
|
|
33
|
-
/**
|
|
34
|
-
* Sets the busy timeout in milliseconds.
|
|
35
|
-
* @default 5000
|
|
36
|
-
*/
|
|
37
|
-
readonly timeout?: number;
|
|
38
|
-
/** If true, enables loading of SQLite extensions. @default false */
|
|
39
|
-
readonly allowExtension?: boolean;
|
|
40
|
-
}
|
|
47
|
+
export type SqliteConstants = SqliteOpenFlags &
|
|
48
|
+
SqliteChangesetResolution &
|
|
49
|
+
SqliteChangesetConflictTypes &
|
|
50
|
+
SqliteAuthorizationResults &
|
|
51
|
+
SqliteAuthorizationActions;
|
|
41
52
|
|
|
42
53
|
/**
|
|
43
54
|
* Options for creating a prepared statement.
|
|
@@ -49,110 +60,6 @@ export interface StatementOptions {
|
|
|
49
60
|
readonly anonymousParameters?: boolean;
|
|
50
61
|
}
|
|
51
62
|
|
|
52
|
-
/**
|
|
53
|
-
* A prepared SQL statement that can be executed multiple times with different parameters.
|
|
54
|
-
* This interface represents an instance of the StatementSync class.
|
|
55
|
-
*/
|
|
56
|
-
export interface StatementSyncInstance {
|
|
57
|
-
/** The original SQL source string. */
|
|
58
|
-
readonly sourceSQL: string;
|
|
59
|
-
/** The expanded SQL string with bound parameters, if expandedSQL option was set. */
|
|
60
|
-
readonly expandedSQL: string | undefined;
|
|
61
|
-
/**
|
|
62
|
-
* This method executes a prepared statement and returns an object.
|
|
63
|
-
* @param parameters Optional named and anonymous parameters to bind to the statement.
|
|
64
|
-
* @returns An object with the number of changes and the last insert rowid.
|
|
65
|
-
*/
|
|
66
|
-
run(...parameters: any[]): {
|
|
67
|
-
changes: number;
|
|
68
|
-
lastInsertRowid: number | bigint;
|
|
69
|
-
};
|
|
70
|
-
/**
|
|
71
|
-
* This method executes a prepared statement and returns the first result row.
|
|
72
|
-
* @param parameters Optional named and anonymous parameters to bind to the statement.
|
|
73
|
-
* @returns The first row from the query results, or undefined if no rows.
|
|
74
|
-
*/
|
|
75
|
-
get(...parameters: any[]): any;
|
|
76
|
-
/**
|
|
77
|
-
* This method executes a prepared statement and returns all results as an array.
|
|
78
|
-
* @param parameters Optional named and anonymous parameters to bind to the statement.
|
|
79
|
-
* @returns An array of row objects from the query results.
|
|
80
|
-
*/
|
|
81
|
-
all(...parameters: any[]): any[];
|
|
82
|
-
/**
|
|
83
|
-
* This method executes a prepared statement and returns an iterable iterator of objects.
|
|
84
|
-
* Each object represents a row from the query results.
|
|
85
|
-
* @param parameters Optional named and anonymous parameters to bind to the statement.
|
|
86
|
-
* @returns An iterable iterator of row objects.
|
|
87
|
-
*/
|
|
88
|
-
iterate(...parameters: any[]): IterableIterator<any>;
|
|
89
|
-
/**
|
|
90
|
-
* Set whether to read integer values as JavaScript BigInt.
|
|
91
|
-
* @param readBigInts If true, read integers as BigInts. @default false
|
|
92
|
-
*/
|
|
93
|
-
setReadBigInts(readBigInts: boolean): void;
|
|
94
|
-
/**
|
|
95
|
-
* Set whether to allow bare named parameters in SQL.
|
|
96
|
-
* @param allowBareNamedParameters If true, allows bare named parameters. @default false
|
|
97
|
-
*/
|
|
98
|
-
setAllowBareNamedParameters(allowBareNamedParameters: boolean): void;
|
|
99
|
-
/**
|
|
100
|
-
* Set whether to return results as arrays rather than objects.
|
|
101
|
-
* @param returnArrays If true, return results as arrays. @default false
|
|
102
|
-
*/
|
|
103
|
-
setReturnArrays(returnArrays: boolean): void;
|
|
104
|
-
/**
|
|
105
|
-
* Returns an array of objects, each representing a column in the statement's result set.
|
|
106
|
-
* Each object has a 'name' property for the column name and a 'type' property for the SQLite type.
|
|
107
|
-
* @returns Array of column metadata objects.
|
|
108
|
-
*/
|
|
109
|
-
columns(): Array<{ name: string; type?: string }>;
|
|
110
|
-
/**
|
|
111
|
-
* Finalizes the prepared statement and releases its resources.
|
|
112
|
-
* Called automatically by Symbol.dispose.
|
|
113
|
-
*/
|
|
114
|
-
finalize(): void;
|
|
115
|
-
/** Dispose of the statement resources using the explicit resource management protocol. */
|
|
116
|
-
[Symbol.dispose](): void;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
export interface UserFunctionOptions {
|
|
120
|
-
/** If `true`, sets the `SQLITE_DETERMINISTIC` flag. @default false */
|
|
121
|
-
readonly deterministic?: boolean;
|
|
122
|
-
/** If `true`, sets the `SQLITE_DIRECTONLY` flag. @default false */
|
|
123
|
-
readonly directOnly?: boolean;
|
|
124
|
-
/** If `true`, converts integer arguments to `BigInt`s. @default false */
|
|
125
|
-
readonly useBigIntArguments?: boolean;
|
|
126
|
-
/** If `true`, allows function to be invoked with variable arguments. @default false */
|
|
127
|
-
readonly varargs?: boolean;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export interface AggregateOptions {
|
|
131
|
-
/** The initial value for the aggregation. */
|
|
132
|
-
readonly start?: any;
|
|
133
|
-
/** Function called for each row to update the aggregate state. */
|
|
134
|
-
readonly step: (accumulator: any, ...args: any[]) => any;
|
|
135
|
-
/** Optional function for window function support to reverse a step. */
|
|
136
|
-
readonly inverse?: (accumulator: any, ...args: any[]) => any;
|
|
137
|
-
/** Optional function to compute the final result from the accumulator. */
|
|
138
|
-
readonly result?: (accumulator: any) => any;
|
|
139
|
-
/** If `true`, sets the `SQLITE_DETERMINISTIC` flag. @default false */
|
|
140
|
-
readonly deterministic?: boolean;
|
|
141
|
-
/** If `true`, sets the `SQLITE_DIRECTONLY` flag. @default false */
|
|
142
|
-
readonly directOnly?: boolean;
|
|
143
|
-
/** If `true`, converts integer arguments to `BigInt`s. @default false */
|
|
144
|
-
readonly useBigIntArguments?: boolean;
|
|
145
|
-
/** If `true`, allows function to be invoked with variable arguments. @default false */
|
|
146
|
-
readonly varargs?: boolean;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export interface SessionOptions {
|
|
150
|
-
/** The table to track changes for. If omitted, all tables are tracked. */
|
|
151
|
-
readonly table?: string;
|
|
152
|
-
/** The database name. @default "main" */
|
|
153
|
-
readonly db?: string;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
63
|
export interface Session {
|
|
157
64
|
/**
|
|
158
65
|
* Generate a changeset containing all changes recorded by the session.
|
|
@@ -170,153 +77,6 @@ export interface Session {
|
|
|
170
77
|
close(): void;
|
|
171
78
|
}
|
|
172
79
|
|
|
173
|
-
export interface ChangesetApplyOptions {
|
|
174
|
-
/**
|
|
175
|
-
* Function called when a conflict is detected during changeset application.
|
|
176
|
-
* @param conflictType The type of conflict (SQLITE_CHANGESET_CONFLICT, etc.)
|
|
177
|
-
* @returns One of SQLITE_CHANGESET_OMIT, SQLITE_CHANGESET_REPLACE, or SQLITE_CHANGESET_ABORT
|
|
178
|
-
*/
|
|
179
|
-
readonly onConflict?: (conflictType: number) => number;
|
|
180
|
-
/**
|
|
181
|
-
* Function called to filter which tables to apply changes to.
|
|
182
|
-
* @param tableName The name of the table
|
|
183
|
-
* @returns true to include the table, false to skip it
|
|
184
|
-
*/
|
|
185
|
-
readonly filter?: (tableName: string) => boolean;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Represents a SQLite database connection.
|
|
190
|
-
* This interface represents an instance of the DatabaseSync class.
|
|
191
|
-
*/
|
|
192
|
-
export interface DatabaseSyncInstance {
|
|
193
|
-
/** Indicates whether the database connection is open. */
|
|
194
|
-
readonly isOpen: boolean;
|
|
195
|
-
/** Indicates whether a transaction is currently active. */
|
|
196
|
-
readonly isTransaction: boolean;
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Opens a database connection. This method is called automatically when creating
|
|
200
|
-
* a DatabaseSync instance, so typically should not be called directly.
|
|
201
|
-
* @param configuration Optional configuration for opening the database.
|
|
202
|
-
*/
|
|
203
|
-
open(configuration?: DatabaseSyncOptions): void;
|
|
204
|
-
/**
|
|
205
|
-
* Closes the database connection. This method should be called to ensure that
|
|
206
|
-
* the database connection is properly cleaned up. Once a database is closed,
|
|
207
|
-
* it cannot be used again.
|
|
208
|
-
*/
|
|
209
|
-
close(): void;
|
|
210
|
-
/**
|
|
211
|
-
* Returns the location of the database file. For attached databases, you can specify
|
|
212
|
-
* the database name. Returns null for in-memory databases.
|
|
213
|
-
* @param dbName The name of the database. Defaults to 'main' (the primary database).
|
|
214
|
-
* @returns The file path of the database, or null for in-memory databases.
|
|
215
|
-
*/
|
|
216
|
-
location(dbName?: string): string | null;
|
|
217
|
-
/**
|
|
218
|
-
* Compiles an SQL statement and returns a StatementSyncInstance object.
|
|
219
|
-
* @param sql The SQL statement to prepare.
|
|
220
|
-
* @param options Optional configuration for the statement.
|
|
221
|
-
* @returns A StatementSyncInstance object that can be executed multiple times.
|
|
222
|
-
*/
|
|
223
|
-
prepare(sql: string, options?: StatementOptions): StatementSyncInstance;
|
|
224
|
-
/**
|
|
225
|
-
* This method allows one or more SQL statements to be executed without
|
|
226
|
-
* returning any results. This is useful for commands like CREATE TABLE,
|
|
227
|
-
* INSERT, UPDATE, or DELETE.
|
|
228
|
-
* @param sql The SQL statement(s) to execute.
|
|
229
|
-
*/
|
|
230
|
-
exec(sql: string): void;
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* This method creates SQLite user-defined functions, wrapping sqlite3_create_function_v2().
|
|
234
|
-
* @param name The name of the SQLite function to create.
|
|
235
|
-
* @param func The JavaScript function to call when the SQLite function is invoked.
|
|
236
|
-
*/
|
|
237
|
-
function(name: string, func: Function): void;
|
|
238
|
-
/**
|
|
239
|
-
* This method creates SQLite user-defined functions, wrapping sqlite3_create_function_v2().
|
|
240
|
-
* @param name The name of the SQLite function to create.
|
|
241
|
-
* @param options Optional configuration settings.
|
|
242
|
-
* @param func The JavaScript function to call when the SQLite function is invoked.
|
|
243
|
-
*/
|
|
244
|
-
function(name: string, options: UserFunctionOptions, func: Function): void;
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* This method creates SQLite aggregate functions, wrapping sqlite3_create_window_function().
|
|
248
|
-
* @param name The name of the SQLite aggregate function to create.
|
|
249
|
-
* @param options Configuration object containing step function and other settings.
|
|
250
|
-
*/
|
|
251
|
-
aggregate(name: string, options: AggregateOptions): void;
|
|
252
|
-
/**
|
|
253
|
-
* Create a new session to record database changes.
|
|
254
|
-
* @param options Optional configuration for the session.
|
|
255
|
-
* @returns A Session object for recording changes.
|
|
256
|
-
*/
|
|
257
|
-
createSession(options?: SessionOptions): Session;
|
|
258
|
-
/**
|
|
259
|
-
* Apply a changeset to the database.
|
|
260
|
-
* @param changeset The changeset data to apply.
|
|
261
|
-
* @param options Optional configuration for applying the changeset.
|
|
262
|
-
* @returns true if successful, false if aborted.
|
|
263
|
-
*/
|
|
264
|
-
applyChangeset(changeset: Buffer, options?: ChangesetApplyOptions): boolean;
|
|
265
|
-
/**
|
|
266
|
-
* Enables or disables the loading of SQLite extensions.
|
|
267
|
-
* @param enable If true, enables extension loading. If false, disables it.
|
|
268
|
-
*/
|
|
269
|
-
enableLoadExtension(enable: boolean): void;
|
|
270
|
-
/**
|
|
271
|
-
* Loads an SQLite extension from the specified file path.
|
|
272
|
-
* @param path The path to the extension library.
|
|
273
|
-
* @param entryPoint Optional entry point function name. If not provided, uses the default entry point.
|
|
274
|
-
*/
|
|
275
|
-
loadExtension(path: string, entryPoint?: string): void;
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Makes a backup of the database. This method abstracts the sqlite3_backup_init(),
|
|
279
|
-
* sqlite3_backup_step() and sqlite3_backup_finish() functions.
|
|
280
|
-
*
|
|
281
|
-
* The backed-up database can be used normally during the backup process. Mutations
|
|
282
|
-
* coming from the same connection will be reflected in the backup right away.
|
|
283
|
-
* However, mutations from other connections will cause the backup process to restart.
|
|
284
|
-
*
|
|
285
|
-
* @param path The path where the backup will be created. If the file already exists, the contents will be overwritten.
|
|
286
|
-
* @param options Optional configuration for the backup operation.
|
|
287
|
-
* @param options.rate Number of pages to be transmitted in each batch of the backup. @default 100
|
|
288
|
-
* @param options.source Name of the source database. This can be 'main' (the default primary database) or any other database that have been added with ATTACH DATABASE. @default 'main'
|
|
289
|
-
* @param options.target Name of the target database. This can be 'main' (the default primary database) or any other database that have been added with ATTACH DATABASE. @default 'main'
|
|
290
|
-
* @param options.progress Callback function that will be called with the number of pages copied and the total number of pages.
|
|
291
|
-
* @returns A promise that resolves when the backup is completed and rejects if an error occurs.
|
|
292
|
-
*
|
|
293
|
-
* @example
|
|
294
|
-
* // Basic backup
|
|
295
|
-
* await db.backup('./backup.db');
|
|
296
|
-
*
|
|
297
|
-
* @example
|
|
298
|
-
* // Backup with progress
|
|
299
|
-
* await db.backup('./backup.db', {
|
|
300
|
-
* rate: 10,
|
|
301
|
-
* progress: ({ totalPages, remainingPages }) => {
|
|
302
|
-
* console.log(`Progress: ${totalPages - remainingPages}/${totalPages}`);
|
|
303
|
-
* }
|
|
304
|
-
* });
|
|
305
|
-
*/
|
|
306
|
-
backup(
|
|
307
|
-
path: string | Buffer | URL,
|
|
308
|
-
options?: {
|
|
309
|
-
rate?: number;
|
|
310
|
-
source?: string;
|
|
311
|
-
target?: string;
|
|
312
|
-
progress?: (info: { totalPages: number; remainingPages: number }) => void;
|
|
313
|
-
},
|
|
314
|
-
): Promise<number>;
|
|
315
|
-
|
|
316
|
-
/** Dispose of the database resources using the explicit resource management protocol. */
|
|
317
|
-
[Symbol.dispose](): void;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
80
|
/**
|
|
321
81
|
* The main SQLite module interface.
|
|
322
82
|
*/
|
|
@@ -345,58 +105,16 @@ export interface SqliteModule {
|
|
|
345
105
|
Session: new () => Session;
|
|
346
106
|
/**
|
|
347
107
|
* SQLite constants for various operations and flags.
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
// Changeset constants
|
|
357
|
-
/** Skip conflicting changes. */
|
|
358
|
-
SQLITE_CHANGESET_OMIT: number;
|
|
359
|
-
/** Replace conflicting changes. */
|
|
360
|
-
SQLITE_CHANGESET_REPLACE: number;
|
|
361
|
-
/** Abort on conflict. */
|
|
362
|
-
SQLITE_CHANGESET_ABORT: number;
|
|
363
|
-
/** Data conflict type. */
|
|
364
|
-
SQLITE_CHANGESET_DATA: number;
|
|
365
|
-
/** Row not found conflict. */
|
|
366
|
-
SQLITE_CHANGESET_NOTFOUND: number;
|
|
367
|
-
/** General conflict. */
|
|
368
|
-
SQLITE_CHANGESET_CONFLICT: number;
|
|
369
|
-
/** Constraint violation. */
|
|
370
|
-
SQLITE_CHANGESET_CONSTRAINT: number;
|
|
371
|
-
/** Foreign key constraint violation. */
|
|
372
|
-
SQLITE_CHANGESET_FOREIGN_KEY: number;
|
|
373
|
-
// ... more constants
|
|
374
|
-
};
|
|
108
|
+
* @see {@link SqliteConstants} for the type definition
|
|
109
|
+
* @see {@link SqliteOpenFlags} for database open flags (extension beyond `node:sqlite`)
|
|
110
|
+
* @see {@link SqliteChangesetResolution} for changeset conflict resolution values
|
|
111
|
+
* @see {@link SqliteChangesetConflictTypes} for changeset conflict type codes
|
|
112
|
+
* @see {@link SqliteAuthorizationResults} for authorization return values
|
|
113
|
+
* @see {@link SqliteAuthorizationActions} for authorization action codes
|
|
114
|
+
*/
|
|
115
|
+
constants: SqliteConstants;
|
|
375
116
|
}
|
|
376
117
|
|
|
377
|
-
// Add Symbol.dispose to the native classes
|
|
378
|
-
if (binding.DatabaseSync && typeof Symbol.dispose !== "undefined") {
|
|
379
|
-
binding.DatabaseSync.prototype[Symbol.dispose] = function () {
|
|
380
|
-
try {
|
|
381
|
-
this.close();
|
|
382
|
-
} catch {
|
|
383
|
-
// Ignore errors during disposal
|
|
384
|
-
}
|
|
385
|
-
};
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
if (binding.StatementSync && typeof Symbol.dispose !== "undefined") {
|
|
389
|
-
binding.StatementSync.prototype[Symbol.dispose] = function () {
|
|
390
|
-
try {
|
|
391
|
-
this.finalize();
|
|
392
|
-
} catch {
|
|
393
|
-
// Ignore errors during disposal
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// Export the native binding with TypeScript types
|
|
399
|
-
|
|
400
118
|
/**
|
|
401
119
|
* The DatabaseSync class represents a synchronous connection to a SQLite database.
|
|
402
120
|
* All database operations are performed synchronously, blocking the thread until completion.
|
|
@@ -418,6 +136,18 @@ if (binding.StatementSync && typeof Symbol.dispose !== "undefined") {
|
|
|
418
136
|
export const DatabaseSync =
|
|
419
137
|
binding.DatabaseSync as SqliteModule["DatabaseSync"];
|
|
420
138
|
|
|
139
|
+
// node:sqlite implements createTagStore and SQLTagStore entirely in native C++.
|
|
140
|
+
// We use a TypeScript implementation instead, attached via prototype extension.
|
|
141
|
+
// This maintains API compatibility with node:sqlite while avoiding the complexity
|
|
142
|
+
// of a native LRU cache. Performance is equivalent since the real cost is SQLite
|
|
143
|
+
// execution, not cache lookups - V8's Map is highly optimized for string keys.
|
|
144
|
+
(DatabaseSync.prototype as DatabaseSyncInstance).createTagStore = function (
|
|
145
|
+
this: DatabaseSyncInstance,
|
|
146
|
+
capacity?: number,
|
|
147
|
+
): SQLTagStoreInstance {
|
|
148
|
+
return new SQLTagStore(this, capacity);
|
|
149
|
+
};
|
|
150
|
+
|
|
421
151
|
/**
|
|
422
152
|
* The StatementSync class represents a prepared SQL statement.
|
|
423
153
|
* This class should not be instantiated directly; use DatabaseSync.prepare() instead.
|
|
@@ -446,6 +176,19 @@ export const StatementSync =
|
|
|
446
176
|
*/
|
|
447
177
|
export const Session = binding.Session as SqliteModule["Session"];
|
|
448
178
|
|
|
179
|
+
/**
|
|
180
|
+
* The SQLTagStore class for cached prepared statements via tagged template syntax.
|
|
181
|
+
* This class should not be instantiated directly; use DatabaseSync.createTagStore() instead.
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* ```typescript
|
|
185
|
+
* const sql = db.createTagStore();
|
|
186
|
+
* sql.run`INSERT INTO users VALUES (${id}, ${name})`;
|
|
187
|
+
* const user = sql.get`SELECT * FROM users WHERE id = ${id}`;
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
export { SQLTagStore };
|
|
191
|
+
|
|
449
192
|
/**
|
|
450
193
|
* SQLite constants for various operations and flags.
|
|
451
194
|
*
|
|
@@ -459,7 +202,54 @@ export const Session = binding.Session as SqliteModule["Session"];
|
|
|
459
202
|
* });
|
|
460
203
|
* ```
|
|
461
204
|
*/
|
|
462
|
-
export const constants = binding.constants
|
|
205
|
+
export const constants: SqliteConstants = binding.constants;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Options for the backup() function.
|
|
209
|
+
*/
|
|
210
|
+
export interface BackupOptions {
|
|
211
|
+
/** Number of pages to be transmitted in each batch of the backup. @default 100 */
|
|
212
|
+
rate?: number;
|
|
213
|
+
/** Name of the source database. Can be 'main' or any attached database. @default 'main' */
|
|
214
|
+
source?: string;
|
|
215
|
+
/** Name of the target database. Can be 'main' or any attached database. @default 'main' */
|
|
216
|
+
target?: string;
|
|
217
|
+
/** Callback function that will be called with progress information. */
|
|
218
|
+
progress?: (info: { totalPages: number; remainingPages: number }) => void;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Standalone function to make a backup of a database.
|
|
223
|
+
*
|
|
224
|
+
* This function matches the Node.js `node:sqlite` module API which exports
|
|
225
|
+
* `backup()` as a standalone function in addition to the `db.backup()` method.
|
|
226
|
+
*
|
|
227
|
+
* @param sourceDb The database to backup from.
|
|
228
|
+
* @param destination The path where the backup will be created.
|
|
229
|
+
* @param options Optional configuration for the backup operation.
|
|
230
|
+
* @returns A promise that resolves when the backup is completed.
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```typescript
|
|
234
|
+
* import { DatabaseSync, backup } from '@photostructure/sqlite';
|
|
235
|
+
*
|
|
236
|
+
* const db = new DatabaseSync('./source.db');
|
|
237
|
+
* await backup(db, './backup.db');
|
|
238
|
+
*
|
|
239
|
+
* // With options
|
|
240
|
+
* await backup(db, './backup.db', {
|
|
241
|
+
* rate: 10,
|
|
242
|
+
* progress: ({ totalPages, remainingPages }) => {
|
|
243
|
+
* console.log(`Progress: ${totalPages - remainingPages}/${totalPages}`);
|
|
244
|
+
* }
|
|
245
|
+
* });
|
|
246
|
+
* ```
|
|
247
|
+
*/
|
|
248
|
+
export const backup: (
|
|
249
|
+
sourceDb: DatabaseSyncInstance,
|
|
250
|
+
destination: string | Buffer | URL,
|
|
251
|
+
options?: BackupOptions,
|
|
252
|
+
) => Promise<number> = binding.backup;
|
|
463
253
|
|
|
464
254
|
// Default export for CommonJS compatibility
|
|
465
255
|
export default binding as SqliteModule;
|
package/src/lru-cache.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple LRU (Least Recently Used) cache implementation.
|
|
3
|
+
* Uses Map's insertion order to track recency - first key is oldest.
|
|
4
|
+
*/
|
|
5
|
+
export class LRUCache<K, V> {
|
|
6
|
+
private cache = new Map<K, V>();
|
|
7
|
+
private readonly maxCapacity: number;
|
|
8
|
+
|
|
9
|
+
constructor(capacity: number) {
|
|
10
|
+
if (capacity < 1) {
|
|
11
|
+
throw new RangeError("LRU cache capacity must be at least 1");
|
|
12
|
+
}
|
|
13
|
+
this.maxCapacity = capacity;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get a value from the cache.
|
|
18
|
+
* If found, moves the entry to the end (most recently used).
|
|
19
|
+
*/
|
|
20
|
+
get(key: K): V | undefined {
|
|
21
|
+
const value = this.cache.get(key);
|
|
22
|
+
if (value !== undefined) {
|
|
23
|
+
// Move to end (most recently used) by reinserting
|
|
24
|
+
this.cache.delete(key);
|
|
25
|
+
this.cache.set(key, value);
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Set a value in the cache.
|
|
32
|
+
* If key exists, updates and moves to end.
|
|
33
|
+
* If at capacity, evicts the oldest entry first.
|
|
34
|
+
*/
|
|
35
|
+
set(key: K, value: V): void {
|
|
36
|
+
if (this.cache.has(key)) {
|
|
37
|
+
// Update existing - delete and reinsert at end
|
|
38
|
+
this.cache.delete(key);
|
|
39
|
+
} else if (this.cache.size >= this.maxCapacity) {
|
|
40
|
+
// Evict oldest (first key in Map iteration order)
|
|
41
|
+
const oldestKey = this.cache.keys().next().value;
|
|
42
|
+
if (oldestKey !== undefined) {
|
|
43
|
+
this.cache.delete(oldestKey);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
this.cache.set(key, value);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Delete an entry from the cache.
|
|
51
|
+
*/
|
|
52
|
+
delete(key: K): boolean {
|
|
53
|
+
return this.cache.delete(key);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if a key exists in the cache.
|
|
58
|
+
* Does NOT update recency.
|
|
59
|
+
*/
|
|
60
|
+
has(key: K): boolean {
|
|
61
|
+
return this.cache.has(key);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Clear all entries from the cache.
|
|
66
|
+
*/
|
|
67
|
+
clear(): void {
|
|
68
|
+
this.cache.clear();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get the current number of entries in the cache.
|
|
73
|
+
*/
|
|
74
|
+
size(): number {
|
|
75
|
+
return this.cache.size;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get the maximum capacity of the cache.
|
|
80
|
+
*/
|
|
81
|
+
capacity(): number {
|
|
82
|
+
return this.maxCapacity;
|
|
83
|
+
}
|
|
84
|
+
}
|
package/src/shims/env-inl.h
CHANGED
|
@@ -1,19 +1,10 @@
|
|
|
1
1
|
#ifndef SRC_SHIMS_ENV_INL_H_
|
|
2
2
|
#define SRC_SHIMS_ENV_INL_H_
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
// This header exists for Node.js source compatibility.
|
|
5
|
+
// src/upstream/node_sqlite.cc includes "env-inl.h", and we can't modify
|
|
6
|
+
// upstream files (they're auto-synced from Node.js). The actual Environment
|
|
7
|
+
// implementation is in util.h.
|
|
8
|
+
#include "util.h"
|
|
5
9
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
// Environment stubs
|
|
9
|
-
class Environment {
|
|
10
|
-
public:
|
|
11
|
-
static Environment *GetCurrent(Napi::Env env) {
|
|
12
|
-
static Environment instance;
|
|
13
|
-
return &instance;
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
} // namespace node
|
|
18
|
-
|
|
19
|
-
#endif // SRC_SHIMS_ENV_INL_H_
|
|
10
|
+
#endif // SRC_SHIMS_ENV_INL_H_
|
package/src/shims/node_errors.h
CHANGED
|
@@ -38,6 +38,10 @@ inline void THROW_ERR_SQLITE_ERROR(Napi::Env env,
|
|
|
38
38
|
Napi::Error::New(env, msg).ThrowAsJavaScriptException();
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
// Database-aware version available when sqlite_impl.h is included
|
|
42
|
+
// This will be specialized in sqlite_impl.cpp to avoid forward declaration
|
|
43
|
+
// issues
|
|
44
|
+
|
|
41
45
|
inline void THROW_ERR_CONSTRUCT_CALL_REQUIRED(Napi::Env env) {
|
|
42
46
|
Napi::TypeError::New(env, "Class constructor cannot be invoked without 'new'")
|
|
43
47
|
.ThrowAsJavaScriptException();
|