@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/src/shims/node_errors.h
CHANGED
|
@@ -11,25 +11,33 @@ namespace node {
|
|
|
11
11
|
inline void THROW_ERR_INVALID_STATE(Napi::Env env,
|
|
12
12
|
const char *message = nullptr) {
|
|
13
13
|
const char *msg = message ? message : "Invalid state";
|
|
14
|
-
Napi::Error::New(env, msg)
|
|
14
|
+
Napi::Error error = Napi::Error::New(env, msg);
|
|
15
|
+
error.Set("code", Napi::String::New(env, "ERR_INVALID_STATE"));
|
|
16
|
+
error.ThrowAsJavaScriptException();
|
|
15
17
|
}
|
|
16
18
|
|
|
17
19
|
inline void THROW_ERR_INVALID_ARG_TYPE(Napi::Env env,
|
|
18
20
|
const char *message = nullptr) {
|
|
19
21
|
const char *msg = message ? message : "Invalid argument type";
|
|
20
|
-
Napi::TypeError::New(env, msg)
|
|
22
|
+
Napi::TypeError error = Napi::TypeError::New(env, msg);
|
|
23
|
+
error.Set("code", Napi::String::New(env, "ERR_INVALID_ARG_TYPE"));
|
|
24
|
+
error.ThrowAsJavaScriptException();
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
inline void THROW_ERR_OUT_OF_RANGE(Napi::Env env,
|
|
24
28
|
const char *message = nullptr) {
|
|
25
29
|
const char *msg = message ? message : "Value out of range";
|
|
26
|
-
Napi::RangeError::New(env, msg)
|
|
30
|
+
Napi::RangeError error = Napi::RangeError::New(env, msg);
|
|
31
|
+
error.Set("code", Napi::String::New(env, "ERR_OUT_OF_RANGE"));
|
|
32
|
+
error.ThrowAsJavaScriptException();
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
inline void THROW_ERR_INVALID_ARG_VALUE(Napi::Env env,
|
|
30
36
|
const char *message = nullptr) {
|
|
31
37
|
const char *msg = message ? message : "Invalid argument value";
|
|
32
|
-
Napi::Error::New(env, msg)
|
|
38
|
+
Napi::Error error = Napi::Error::New(env, msg);
|
|
39
|
+
error.Set("code", Napi::String::New(env, "ERR_INVALID_ARG_VALUE"));
|
|
40
|
+
error.ThrowAsJavaScriptException();
|
|
33
41
|
}
|
|
34
42
|
|
|
35
43
|
inline void THROW_ERR_SQLITE_ERROR(Napi::Env env,
|
|
@@ -37,7 +45,9 @@ inline void THROW_ERR_SQLITE_ERROR(Napi::Env env,
|
|
|
37
45
|
// Check for both null and empty string - on Windows (MSVC),
|
|
38
46
|
// std::exception::what() can sometimes return an empty string
|
|
39
47
|
const char *msg = (message && message[0] != '\0') ? message : "SQLite error";
|
|
40
|
-
Napi::Error::New(env, msg)
|
|
48
|
+
Napi::Error error = Napi::Error::New(env, msg);
|
|
49
|
+
error.Set("code", Napi::String::New(env, "ERR_SQLITE_ERROR"));
|
|
50
|
+
error.ThrowAsJavaScriptException();
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
// Database-aware version available when sqlite_impl.h is included
|
|
@@ -45,24 +55,33 @@ inline void THROW_ERR_SQLITE_ERROR(Napi::Env env,
|
|
|
45
55
|
// issues
|
|
46
56
|
|
|
47
57
|
inline void THROW_ERR_CONSTRUCT_CALL_REQUIRED(Napi::Env env) {
|
|
48
|
-
Napi::TypeError::New(
|
|
49
|
-
|
|
58
|
+
Napi::TypeError error = Napi::TypeError::New(
|
|
59
|
+
env, "Class constructor cannot be invoked without 'new'");
|
|
60
|
+
error.Set("code", Napi::String::New(env, "ERR_CONSTRUCT_CALL_REQUIRED"));
|
|
61
|
+
error.ThrowAsJavaScriptException();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
inline void THROW_ERR_ILLEGAL_CONSTRUCTOR(Napi::Env env) {
|
|
65
|
+
Napi::TypeError error = Napi::TypeError::New(env, "Illegal constructor");
|
|
66
|
+
error.Set("code", Napi::String::New(env, "ERR_ILLEGAL_CONSTRUCTOR"));
|
|
67
|
+
error.ThrowAsJavaScriptException();
|
|
50
68
|
}
|
|
51
69
|
|
|
52
70
|
inline void THROW_ERR_INVALID_URL_SCHEME(Napi::Env env,
|
|
53
|
-
const char *scheme = nullptr) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
Napi::TypeError::New(env, msg).ThrowAsJavaScriptException();
|
|
71
|
+
const char * /*scheme*/ = nullptr) {
|
|
72
|
+
// Message must match Node.js exactly
|
|
73
|
+
Napi::TypeError error =
|
|
74
|
+
Napi::TypeError::New(env, "The URL must be of scheme file:");
|
|
75
|
+
error.Set("code", Napi::String::New(env, "ERR_INVALID_URL_SCHEME"));
|
|
76
|
+
error.ThrowAsJavaScriptException();
|
|
60
77
|
}
|
|
61
78
|
|
|
62
79
|
inline void THROW_ERR_LOAD_SQLITE_EXTENSION(Napi::Env env,
|
|
63
80
|
const char *message = nullptr) {
|
|
64
81
|
const char *msg = message ? message : "Failed to load SQLite extension";
|
|
65
|
-
Napi::Error::New(env, msg)
|
|
82
|
+
Napi::Error error = Napi::Error::New(env, msg);
|
|
83
|
+
error.Set("code", Napi::String::New(env, "ERR_LOAD_SQLITE_EXTENSION"));
|
|
84
|
+
error.ThrowAsJavaScriptException();
|
|
66
85
|
}
|
|
67
86
|
|
|
68
87
|
// Macro wrappers for compatibility (removed to avoid conflicts)
|
|
@@ -81,6 +81,14 @@ inline const char *GetSqliteErrorCodeName(int code) {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// Enhanced SQLite error that includes system errno information
|
|
84
|
+
// Error format matches Node.js node:sqlite for API compatibility:
|
|
85
|
+
// - code: 'ERR_SQLITE_ERROR' (constant, matches Node.js)
|
|
86
|
+
// - errcode: number (SQLite error code, matches Node.js)
|
|
87
|
+
// - errstr: string (SQLite error string, matches Node.js)
|
|
88
|
+
// We also add extra properties for enhanced debugging:
|
|
89
|
+
// - sqliteCode: number (same as errcode, for backward compat)
|
|
90
|
+
// - sqliteExtendedCode: number (extended SQLite error code)
|
|
91
|
+
// - sqliteErrorString: string (same as errstr, for backward compat)
|
|
84
92
|
inline void ThrowEnhancedSqliteError(Napi::Env env, sqlite3 *db,
|
|
85
93
|
int sqlite_code,
|
|
86
94
|
const std::string &message) {
|
|
@@ -89,7 +97,16 @@ inline void ThrowEnhancedSqliteError(Napi::Env env, sqlite3 *db,
|
|
|
89
97
|
// truncated or corrupted error messages
|
|
90
98
|
Napi::Error error = Napi::Error::New(env, message.c_str());
|
|
91
99
|
|
|
92
|
-
//
|
|
100
|
+
// Node.js compatible properties
|
|
101
|
+
error.Set("code", Napi::String::New(env, "ERR_SQLITE_ERROR"));
|
|
102
|
+
error.Set("errcode", Napi::Number::New(env, sqlite_code));
|
|
103
|
+
|
|
104
|
+
const char *err_str = sqlite3_errstr(sqlite_code);
|
|
105
|
+
if (err_str) {
|
|
106
|
+
error.Set("errstr", Napi::String::New(env, err_str));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Our enhanced properties (for backward compatibility and debugging)
|
|
93
110
|
error.Set("sqliteCode", Napi::Number::New(env, sqlite_code));
|
|
94
111
|
|
|
95
112
|
if (db) {
|
|
@@ -104,12 +121,11 @@ inline void ThrowEnhancedSqliteError(Napi::Env env, sqlite3 *db,
|
|
|
104
121
|
}
|
|
105
122
|
}
|
|
106
123
|
|
|
107
|
-
//
|
|
124
|
+
// Keep original code name as sqliteCodeName for debugging
|
|
108
125
|
const char *code_name = GetSqliteErrorCodeName(sqlite_code);
|
|
109
|
-
error.Set("
|
|
126
|
+
error.Set("sqliteCodeName", Napi::String::New(env, code_name));
|
|
110
127
|
|
|
111
128
|
// Also set the human-readable error string
|
|
112
|
-
const char *err_str = sqlite3_errstr(sqlite_code);
|
|
113
129
|
if (err_str) {
|
|
114
130
|
error.Set("sqliteErrorString", Napi::String::New(env, err_str));
|
|
115
131
|
}
|
|
@@ -126,7 +142,9 @@ inline void ThrowEnhancedSqliteError(Napi::Env env, sqlite3 *db,
|
|
|
126
142
|
inline void ThrowSqliteError(Napi::Env env, sqlite3 *db,
|
|
127
143
|
const std::string &message) {
|
|
128
144
|
if (db) {
|
|
129
|
-
|
|
145
|
+
// Use extended error code (e.g., 1555 for SQLITE_CONSTRAINT_PRIMARYKEY)
|
|
146
|
+
// instead of basic code (e.g., 19 for SQLITE_CONSTRAINT) to match Node.js
|
|
147
|
+
int errcode = sqlite3_extended_errcode(db);
|
|
130
148
|
ThrowEnhancedSqliteError(env, db, errcode, message);
|
|
131
149
|
} else {
|
|
132
150
|
// Fallback to simple error when no db handle available
|
|
@@ -136,12 +154,20 @@ inline void ThrowSqliteError(Napi::Env env, sqlite3 *db,
|
|
|
136
154
|
}
|
|
137
155
|
|
|
138
156
|
// Helper to throw from a SqliteException with captured error info
|
|
157
|
+
// Uses same format as ThrowEnhancedSqliteError for consistency
|
|
139
158
|
inline void
|
|
140
159
|
ThrowFromSqliteException(Napi::Env env,
|
|
141
160
|
const photostructure::sqlite::SqliteException &ex) {
|
|
142
161
|
Napi::Error error = Napi::Error::New(env, ex.what());
|
|
143
162
|
|
|
144
|
-
//
|
|
163
|
+
// Node.js compatible properties
|
|
164
|
+
error.Set("code", Napi::String::New(env, "ERR_SQLITE_ERROR"));
|
|
165
|
+
error.Set("errcode", Napi::Number::New(env, ex.sqlite_code()));
|
|
166
|
+
if (!ex.error_string().empty()) {
|
|
167
|
+
error.Set("errstr", Napi::String::New(env, ex.error_string().c_str()));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Our enhanced properties (for backward compatibility and debugging)
|
|
145
171
|
error.Set("sqliteCode", Napi::Number::New(env, ex.sqlite_code()));
|
|
146
172
|
error.Set("sqliteExtendedCode", Napi::Number::New(env, ex.extended_code()));
|
|
147
173
|
|
|
@@ -149,9 +175,9 @@ ThrowFromSqliteException(Napi::Env env,
|
|
|
149
175
|
error.Set("systemErrno", Napi::Number::New(env, ex.system_errno()));
|
|
150
176
|
}
|
|
151
177
|
|
|
152
|
-
//
|
|
178
|
+
// Keep original code name as sqliteCodeName for debugging
|
|
153
179
|
const char *code_name = GetSqliteErrorCodeName(ex.sqlite_code());
|
|
154
|
-
error.Set("
|
|
180
|
+
error.Set("sqliteCodeName", Napi::String::New(env, code_name));
|
|
155
181
|
|
|
156
182
|
// Also set the human-readable error string
|
|
157
183
|
// Use c_str() explicitly to avoid potential ABI issues on Windows ARM
|
package/src/sql-tag-store.ts
CHANGED
|
@@ -25,7 +25,9 @@ export class SQLTagStore {
|
|
|
25
25
|
|
|
26
26
|
constructor(db: DatabaseSyncInstance, capacity: number = DEFAULT_CAPACITY) {
|
|
27
27
|
if (!db.isOpen) {
|
|
28
|
-
|
|
28
|
+
const err = new Error("database is not open");
|
|
29
|
+
(err as NodeJS.ErrnoException).code = "ERR_INVALID_STATE";
|
|
30
|
+
throw err;
|
|
29
31
|
}
|
|
30
32
|
this.database = db;
|
|
31
33
|
this.maxCapacity = capacity;
|
|
@@ -101,23 +103,18 @@ export class SQLTagStore {
|
|
|
101
103
|
|
|
102
104
|
/**
|
|
103
105
|
* Get a cached statement or prepare a new one.
|
|
104
|
-
* If a cached statement has been finalized, it's evicted and a new one is prepared.
|
|
105
106
|
*/
|
|
106
107
|
private getOrPrepare(strings: TemplateStringsArray): StatementSyncInstance {
|
|
107
108
|
if (!this.database.isOpen) {
|
|
108
|
-
throw new Error("
|
|
109
|
+
throw new Error("database is not open");
|
|
109
110
|
}
|
|
110
111
|
|
|
111
112
|
const sql = this.buildSQL(strings);
|
|
112
113
|
|
|
113
|
-
// Check cache
|
|
114
|
+
// Check cache
|
|
114
115
|
const cached = this.cache.get(sql);
|
|
115
116
|
if (cached) {
|
|
116
|
-
|
|
117
|
-
return cached;
|
|
118
|
-
}
|
|
119
|
-
// Statement was finalized externally - remove from cache
|
|
120
|
-
this.cache.delete(sql);
|
|
117
|
+
return cached;
|
|
121
118
|
}
|
|
122
119
|
|
|
123
120
|
// Prepare new statement and cache it
|