@gjsify/sqlite 0.3.13 → 0.3.15
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/lib/esm/constants.js +49 -93
- package/lib/esm/data-model-reader.js +69 -73
- package/lib/esm/database-sync.js +374 -395
- package/lib/esm/errors.js +63 -69
- package/lib/esm/index.js +4 -7
- package/lib/esm/param-binding.js +103 -105
- package/lib/esm/statement-sync.js +291 -283
- package/package.json +6 -6
|
@@ -1,292 +1,300 @@
|
|
|
1
|
-
import Gda from "@girs/gda-6.0";
|
|
2
1
|
import { IllegalConstructorError, InvalidArgTypeError, InvalidArgValueError, SqliteError } from "./errors.js";
|
|
3
2
|
import { readAllRows, readFirstRow } from "./data-model-reader.js";
|
|
3
|
+
import Gda from "@girs/gda-6.0";
|
|
4
|
+
|
|
5
|
+
//#region src/statement-sync.ts
|
|
4
6
|
const MAX_INT64 = 9223372036854775807n;
|
|
5
7
|
const MIN_INT64 = -9223372036854775808n;
|
|
6
|
-
const INTERNAL =
|
|
8
|
+
const INTERNAL = Symbol("StatementSync.internal");
|
|
7
9
|
function validateBindValue(value, paramIndex) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
`Provided value cannot be bound to SQLite parameter ${paramIndex}.`
|
|
15
|
-
);
|
|
10
|
+
if (value === null) return;
|
|
11
|
+
const t = typeof value;
|
|
12
|
+
if (t === "number" || t === "bigint" || t === "string" || t === "boolean") return;
|
|
13
|
+
if (value instanceof Uint8Array || value instanceof ArrayBuffer) return;
|
|
14
|
+
if (ArrayBuffer.isView(value)) return;
|
|
15
|
+
throw new InvalidArgTypeError(`Provided value cannot be bound to SQLite parameter ${paramIndex}.`);
|
|
16
16
|
}
|
|
17
17
|
function sqlEscapeValue(value) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
class StatementSync {
|
|
42
|
-
#connection;
|
|
43
|
-
#sql;
|
|
44
|
-
#paramMap;
|
|
45
|
-
#readBigInts;
|
|
46
|
-
#returnArrays;
|
|
47
|
-
#allowBareNamedParameters;
|
|
48
|
-
#allowUnknownNamedParameters;
|
|
49
|
-
#parser;
|
|
50
|
-
constructor(sentinel, connection, sql, options, paramMap, parser) {
|
|
51
|
-
if (sentinel !== INTERNAL) {
|
|
52
|
-
throw new IllegalConstructorError();
|
|
53
|
-
}
|
|
54
|
-
this.#connection = connection;
|
|
55
|
-
this.#sql = sql;
|
|
56
|
-
this.#paramMap = paramMap;
|
|
57
|
-
this.#readBigInts = options.readBigInts ?? false;
|
|
58
|
-
this.#returnArrays = options.returnArrays ?? false;
|
|
59
|
-
this.#allowBareNamedParameters = options.allowBareNamedParameters ?? true;
|
|
60
|
-
this.#allowUnknownNamedParameters = options.allowUnknownNamedParameters ?? false;
|
|
61
|
-
this.#parser = parser;
|
|
62
|
-
}
|
|
63
|
-
/** @internal */
|
|
64
|
-
static _create(connection, sql, options, paramMap, parser) {
|
|
65
|
-
return new StatementSync(INTERNAL, connection, sql, options, paramMap, parser);
|
|
66
|
-
}
|
|
67
|
-
get sourceSQL() {
|
|
68
|
-
return this.#sql;
|
|
69
|
-
}
|
|
70
|
-
get expandedSQL() {
|
|
71
|
-
return this.#sql;
|
|
72
|
-
}
|
|
73
|
-
#getReadOptions() {
|
|
74
|
-
return {
|
|
75
|
-
readBigInts: this.#readBigInts,
|
|
76
|
-
returnArrays: this.#returnArrays
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
// Build the final SQL with parameter values substituted inline.
|
|
80
|
-
// Returns the SQL string ready for execution.
|
|
81
|
-
#buildSql(args) {
|
|
82
|
-
if (this.#paramMap.length === 0) {
|
|
83
|
-
if (args.length > 0) {
|
|
84
|
-
const hasNamedArg = args.length > 0 && args[0] !== null && typeof args[0] === "object" && !(args[0] instanceof Uint8Array) && !ArrayBuffer.isView(args[0]);
|
|
85
|
-
if (!hasNamedArg) {
|
|
86
|
-
throw new SqliteError("column index out of range", 25, "column index out of range");
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return this.#sql;
|
|
90
|
-
}
|
|
91
|
-
let namedArgs = null;
|
|
92
|
-
let positionalArgs = args;
|
|
93
|
-
if (args.length > 0 && args[0] !== null && typeof args[0] === "object" && !(args[0] instanceof Uint8Array) && !ArrayBuffer.isView(args[0])) {
|
|
94
|
-
namedArgs = args[0];
|
|
95
|
-
positionalArgs = args.slice(1);
|
|
96
|
-
}
|
|
97
|
-
const values = /* @__PURE__ */ new Map();
|
|
98
|
-
const positionalValues = {};
|
|
99
|
-
if (namedArgs) {
|
|
100
|
-
for (const param of this.#paramMap) {
|
|
101
|
-
if (param.position >= 0) continue;
|
|
102
|
-
const origName = param.originalName;
|
|
103
|
-
let value = void 0;
|
|
104
|
-
let found = false;
|
|
105
|
-
if (origName in namedArgs) {
|
|
106
|
-
value = namedArgs[origName];
|
|
107
|
-
found = true;
|
|
108
|
-
}
|
|
109
|
-
if (!found && this.#allowBareNamedParameters) {
|
|
110
|
-
const bareName = origName.replace(/^[\$:@]/, "");
|
|
111
|
-
if (bareName in namedArgs) {
|
|
112
|
-
value = namedArgs[bareName];
|
|
113
|
-
found = true;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
if (!found && !this.#allowBareNamedParameters) {
|
|
117
|
-
const bareName = origName.replace(/^[\$:@]/, "");
|
|
118
|
-
if (bareName in namedArgs) {
|
|
119
|
-
throw new SqliteError(`Unknown named parameter '${bareName}'`, 0, `Unknown named parameter '${bareName}'`);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
if (found) {
|
|
123
|
-
validateBindValue(value, this.#paramMap.indexOf(param) + 1);
|
|
124
|
-
values.set(param.originalName, sqlEscapeValue(value));
|
|
125
|
-
} else {
|
|
126
|
-
values.set(param.originalName, "NULL");
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
const positionalParams = this.#paramMap.filter((p) => p.position >= 0);
|
|
130
|
-
for (let i = 0; i < positionalArgs.length; i++) {
|
|
131
|
-
if (i >= positionalParams.length) {
|
|
132
|
-
throw new SqliteError("column index out of range", 25, "column index out of range");
|
|
133
|
-
}
|
|
134
|
-
validateBindValue(positionalArgs[i], i + 1);
|
|
135
|
-
positionalValues[positionalParams[i].position] = sqlEscapeValue(positionalArgs[i]);
|
|
136
|
-
}
|
|
137
|
-
} else {
|
|
138
|
-
const positionalParams = this.#paramMap.filter((p) => p.position >= 0);
|
|
139
|
-
if (positionalArgs.length > positionalParams.length && positionalParams.length > 0) {
|
|
140
|
-
throw new SqliteError("column index out of range", 25, "column index out of range");
|
|
141
|
-
}
|
|
142
|
-
for (let i = 0; i < positionalParams.length; i++) {
|
|
143
|
-
if (i < positionalArgs.length) {
|
|
144
|
-
validateBindValue(positionalArgs[i], i + 1);
|
|
145
|
-
positionalValues[positionalParams[i].position] = sqlEscapeValue(positionalArgs[i]);
|
|
146
|
-
} else {
|
|
147
|
-
positionalValues[positionalParams[i].position] = "NULL";
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
let result = this.#sql;
|
|
152
|
-
const namedParams = this.#paramMap.filter((p) => p.position < 0).sort((a, b) => b.originalName.length - a.originalName.length);
|
|
153
|
-
for (const param of namedParams) {
|
|
154
|
-
const escaped = values.get(param.originalName) ?? "NULL";
|
|
155
|
-
result = result.split(param.originalName).join(escaped);
|
|
156
|
-
}
|
|
157
|
-
if (Object.keys(positionalValues).length > 0) {
|
|
158
|
-
let out = "";
|
|
159
|
-
let pIdx = 0;
|
|
160
|
-
let i = 0;
|
|
161
|
-
while (i < result.length) {
|
|
162
|
-
if (result[i] === "'") {
|
|
163
|
-
const start = i;
|
|
164
|
-
i++;
|
|
165
|
-
while (i < result.length && result[i] !== "'") {
|
|
166
|
-
if (result[i] === "'" && result[i + 1] === "'") {
|
|
167
|
-
i += 2;
|
|
168
|
-
continue;
|
|
169
|
-
}
|
|
170
|
-
i++;
|
|
171
|
-
}
|
|
172
|
-
if (i < result.length) i++;
|
|
173
|
-
out += result.substring(start, i);
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
if (result[i] === "?") {
|
|
177
|
-
i++;
|
|
178
|
-
let numStr = "";
|
|
179
|
-
while (i < result.length && result[i] >= "0" && result[i] <= "9") {
|
|
180
|
-
numStr += result[i];
|
|
181
|
-
i++;
|
|
182
|
-
}
|
|
183
|
-
const pos = numStr ? parseInt(numStr, 10) - 1 : pIdx;
|
|
184
|
-
pIdx = numStr ? pIdx : pIdx + 1;
|
|
185
|
-
out += pos in positionalValues ? positionalValues[pos] : "NULL";
|
|
186
|
-
continue;
|
|
187
|
-
}
|
|
188
|
-
out += result[i];
|
|
189
|
-
i++;
|
|
190
|
-
}
|
|
191
|
-
result = out;
|
|
192
|
-
}
|
|
193
|
-
return result;
|
|
194
|
-
}
|
|
195
|
-
#executeSql(sql) {
|
|
196
|
-
const [stmt] = this.#parser.parse_string(sql);
|
|
197
|
-
if (!stmt) {
|
|
198
|
-
throw new SqliteError("Failed to parse SQL statement");
|
|
199
|
-
}
|
|
200
|
-
const stmtType = stmt.get_statement_type();
|
|
201
|
-
if (stmtType === Gda.SqlStatementType.SELECT) {
|
|
202
|
-
return { model: this.#connection.statement_execute_select(stmt, null), isSelect: true };
|
|
203
|
-
}
|
|
204
|
-
try {
|
|
205
|
-
this.#connection.statement_execute_non_select(stmt, null);
|
|
206
|
-
return { model: null, isSelect: false };
|
|
207
|
-
} catch {
|
|
208
|
-
const model = this.#connection.statement_execute_select(stmt, null);
|
|
209
|
-
return { model, isSelect: true };
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
run(...args) {
|
|
213
|
-
const sql = this.#buildSql(args);
|
|
214
|
-
this.#executeSql(sql);
|
|
215
|
-
let changes = 0;
|
|
216
|
-
let lastInsertRowid = 0;
|
|
217
|
-
try {
|
|
218
|
-
const chModel = this.#connection.execute_select_command("SELECT changes()");
|
|
219
|
-
if (chModel && chModel.get_n_rows() > 0) {
|
|
220
|
-
changes = chModel.get_value_at(0, 0);
|
|
221
|
-
}
|
|
222
|
-
} catch {
|
|
223
|
-
}
|
|
224
|
-
try {
|
|
225
|
-
const ridModel = this.#connection.execute_select_command("SELECT last_insert_rowid()");
|
|
226
|
-
if (ridModel && ridModel.get_n_rows() > 0) {
|
|
227
|
-
lastInsertRowid = ridModel.get_value_at(0, 0);
|
|
228
|
-
}
|
|
229
|
-
} catch {
|
|
230
|
-
}
|
|
231
|
-
if (this.#readBigInts) {
|
|
232
|
-
changes = BigInt(changes);
|
|
233
|
-
lastInsertRowid = BigInt(lastInsertRowid);
|
|
234
|
-
}
|
|
235
|
-
return { changes, lastInsertRowid };
|
|
236
|
-
}
|
|
237
|
-
get(...args) {
|
|
238
|
-
const sql = this.#buildSql(args);
|
|
239
|
-
try {
|
|
240
|
-
const { model } = this.#executeSql(sql);
|
|
241
|
-
if (!model || model.get_n_rows() === 0) {
|
|
242
|
-
return void 0;
|
|
243
|
-
}
|
|
244
|
-
return readFirstRow(model, this.#getReadOptions());
|
|
245
|
-
} catch {
|
|
246
|
-
return void 0;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
all(...args) {
|
|
250
|
-
const sql = this.#buildSql(args);
|
|
251
|
-
try {
|
|
252
|
-
const { model } = this.#executeSql(sql);
|
|
253
|
-
if (!model) {
|
|
254
|
-
return [];
|
|
255
|
-
}
|
|
256
|
-
return readAllRows(model, this.#getReadOptions());
|
|
257
|
-
} catch {
|
|
258
|
-
return [];
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
setReadBigInts(enabled) {
|
|
262
|
-
if (typeof enabled !== "boolean") {
|
|
263
|
-
throw new InvalidArgTypeError('The "readBigInts" argument must be a boolean.');
|
|
264
|
-
}
|
|
265
|
-
this.#readBigInts = enabled;
|
|
266
|
-
return void 0;
|
|
267
|
-
}
|
|
268
|
-
setReturnArrays(enabled) {
|
|
269
|
-
if (typeof enabled !== "boolean") {
|
|
270
|
-
throw new InvalidArgTypeError('The "returnArrays" argument must be a boolean.');
|
|
271
|
-
}
|
|
272
|
-
this.#returnArrays = enabled;
|
|
273
|
-
return void 0;
|
|
274
|
-
}
|
|
275
|
-
setAllowBareNamedParameters(enabled) {
|
|
276
|
-
if (typeof enabled !== "boolean") {
|
|
277
|
-
throw new InvalidArgTypeError('The "allowBareNamedParameters" argument must be a boolean.');
|
|
278
|
-
}
|
|
279
|
-
this.#allowBareNamedParameters = enabled;
|
|
280
|
-
return void 0;
|
|
281
|
-
}
|
|
282
|
-
setAllowUnknownNamedParameters(enabled) {
|
|
283
|
-
if (typeof enabled !== "boolean") {
|
|
284
|
-
throw new InvalidArgTypeError('The "allowUnknownNamedParameters" argument must be a boolean.');
|
|
285
|
-
}
|
|
286
|
-
this.#allowUnknownNamedParameters = enabled;
|
|
287
|
-
return void 0;
|
|
288
|
-
}
|
|
18
|
+
if (value === null) return "NULL";
|
|
19
|
+
if (value === undefined) return "NULL";
|
|
20
|
+
if (typeof value === "number") return String(value);
|
|
21
|
+
if (typeof value === "boolean") return value ? "1" : "0";
|
|
22
|
+
if (typeof value === "bigint") {
|
|
23
|
+
if (value > MAX_INT64 || value < MIN_INT64) {
|
|
24
|
+
throw new InvalidArgValueError("BigInt value is too large to bind.");
|
|
25
|
+
}
|
|
26
|
+
return String(value);
|
|
27
|
+
}
|
|
28
|
+
if (typeof value === "string") return "'" + value.replace(/'/g, "''") + "'";
|
|
29
|
+
if (value instanceof Uint8Array) {
|
|
30
|
+
let hex = "";
|
|
31
|
+
for (let i = 0; i < value.length; i++) {
|
|
32
|
+
hex += value[i].toString(16).padStart(2, "0");
|
|
33
|
+
}
|
|
34
|
+
return "X'" + hex + "'";
|
|
35
|
+
}
|
|
36
|
+
if (ArrayBuffer.isView(value)) {
|
|
37
|
+
return sqlEscapeValue(new Uint8Array(value.buffer));
|
|
38
|
+
}
|
|
39
|
+
return "NULL";
|
|
289
40
|
}
|
|
290
|
-
|
|
291
|
-
|
|
41
|
+
var StatementSync = class StatementSync {
|
|
42
|
+
#connection;
|
|
43
|
+
#sql;
|
|
44
|
+
#paramMap;
|
|
45
|
+
#readBigInts;
|
|
46
|
+
#returnArrays;
|
|
47
|
+
#allowBareNamedParameters;
|
|
48
|
+
#allowUnknownNamedParameters;
|
|
49
|
+
#parser;
|
|
50
|
+
constructor(sentinel, connection, sql, options, paramMap, parser) {
|
|
51
|
+
if (sentinel !== INTERNAL) {
|
|
52
|
+
throw new IllegalConstructorError();
|
|
53
|
+
}
|
|
54
|
+
this.#connection = connection;
|
|
55
|
+
this.#sql = sql;
|
|
56
|
+
this.#paramMap = paramMap;
|
|
57
|
+
this.#readBigInts = options.readBigInts ?? false;
|
|
58
|
+
this.#returnArrays = options.returnArrays ?? false;
|
|
59
|
+
this.#allowBareNamedParameters = options.allowBareNamedParameters ?? true;
|
|
60
|
+
this.#allowUnknownNamedParameters = options.allowUnknownNamedParameters ?? false;
|
|
61
|
+
this.#parser = parser;
|
|
62
|
+
}
|
|
63
|
+
/** @internal */
|
|
64
|
+
static _create(connection, sql, options, paramMap, parser) {
|
|
65
|
+
return new StatementSync(INTERNAL, connection, sql, options, paramMap, parser);
|
|
66
|
+
}
|
|
67
|
+
get sourceSQL() {
|
|
68
|
+
return this.#sql;
|
|
69
|
+
}
|
|
70
|
+
get expandedSQL() {
|
|
71
|
+
return this.#sql;
|
|
72
|
+
}
|
|
73
|
+
#getReadOptions() {
|
|
74
|
+
return {
|
|
75
|
+
readBigInts: this.#readBigInts,
|
|
76
|
+
returnArrays: this.#returnArrays
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
#buildSql(args) {
|
|
80
|
+
if (this.#paramMap.length === 0) {
|
|
81
|
+
if (args.length > 0) {
|
|
82
|
+
const hasNamedArg = args.length > 0 && args[0] !== null && typeof args[0] === "object" && !(args[0] instanceof Uint8Array) && !ArrayBuffer.isView(args[0]);
|
|
83
|
+
if (!hasNamedArg) {
|
|
84
|
+
throw new SqliteError("column index out of range", 25, "column index out of range");
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return this.#sql;
|
|
88
|
+
}
|
|
89
|
+
let namedArgs = null;
|
|
90
|
+
let positionalArgs = args;
|
|
91
|
+
if (args.length > 0 && args[0] !== null && typeof args[0] === "object" && !(args[0] instanceof Uint8Array) && !ArrayBuffer.isView(args[0])) {
|
|
92
|
+
namedArgs = args[0];
|
|
93
|
+
positionalArgs = args.slice(1);
|
|
94
|
+
}
|
|
95
|
+
const values = new Map();
|
|
96
|
+
const positionalValues = {};
|
|
97
|
+
if (namedArgs) {
|
|
98
|
+
for (const param of this.#paramMap) {
|
|
99
|
+
if (param.position >= 0) continue;
|
|
100
|
+
const origName = param.originalName;
|
|
101
|
+
let value = undefined;
|
|
102
|
+
let found = false;
|
|
103
|
+
if (origName in namedArgs) {
|
|
104
|
+
value = namedArgs[origName];
|
|
105
|
+
found = true;
|
|
106
|
+
}
|
|
107
|
+
if (!found && this.#allowBareNamedParameters) {
|
|
108
|
+
const bareName = origName.replace(/^[\$:@]/, "");
|
|
109
|
+
if (bareName in namedArgs) {
|
|
110
|
+
value = namedArgs[bareName];
|
|
111
|
+
found = true;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (!found && !this.#allowBareNamedParameters) {
|
|
115
|
+
const bareName = origName.replace(/^[\$:@]/, "");
|
|
116
|
+
if (bareName in namedArgs) {
|
|
117
|
+
throw new SqliteError(`Unknown named parameter '${bareName}'`, 0, `Unknown named parameter '${bareName}'`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (found) {
|
|
121
|
+
validateBindValue(value, this.#paramMap.indexOf(param) + 1);
|
|
122
|
+
values.set(param.originalName, sqlEscapeValue(value));
|
|
123
|
+
} else {
|
|
124
|
+
values.set(param.originalName, "NULL");
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const positionalParams = this.#paramMap.filter((p) => p.position >= 0);
|
|
128
|
+
for (let i = 0; i < positionalArgs.length; i++) {
|
|
129
|
+
if (i >= positionalParams.length) {
|
|
130
|
+
throw new SqliteError("column index out of range", 25, "column index out of range");
|
|
131
|
+
}
|
|
132
|
+
validateBindValue(positionalArgs[i], i + 1);
|
|
133
|
+
positionalValues[positionalParams[i].position] = sqlEscapeValue(positionalArgs[i]);
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
const positionalParams = this.#paramMap.filter((p) => p.position >= 0);
|
|
137
|
+
if (positionalArgs.length > positionalParams.length && positionalParams.length > 0) {
|
|
138
|
+
throw new SqliteError("column index out of range", 25, "column index out of range");
|
|
139
|
+
}
|
|
140
|
+
for (let i = 0; i < positionalParams.length; i++) {
|
|
141
|
+
if (i < positionalArgs.length) {
|
|
142
|
+
validateBindValue(positionalArgs[i], i + 1);
|
|
143
|
+
positionalValues[positionalParams[i].position] = sqlEscapeValue(positionalArgs[i]);
|
|
144
|
+
} else {
|
|
145
|
+
positionalValues[positionalParams[i].position] = "NULL";
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
let result = this.#sql;
|
|
150
|
+
const namedParams = this.#paramMap.filter((p) => p.position < 0).sort((a, b) => b.originalName.length - a.originalName.length);
|
|
151
|
+
for (const param of namedParams) {
|
|
152
|
+
const escaped = values.get(param.originalName) ?? "NULL";
|
|
153
|
+
result = result.split(param.originalName).join(escaped);
|
|
154
|
+
}
|
|
155
|
+
if (Object.keys(positionalValues).length > 0) {
|
|
156
|
+
let out = "";
|
|
157
|
+
let pIdx = 0;
|
|
158
|
+
let i = 0;
|
|
159
|
+
while (i < result.length) {
|
|
160
|
+
if (result[i] === "'") {
|
|
161
|
+
const start = i;
|
|
162
|
+
i++;
|
|
163
|
+
while (i < result.length && result[i] !== "'") {
|
|
164
|
+
if (result[i] === "'" && result[i + 1] === "'") {
|
|
165
|
+
i += 2;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
i++;
|
|
169
|
+
}
|
|
170
|
+
if (i < result.length) i++;
|
|
171
|
+
out += result.substring(start, i);
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (result[i] === "?") {
|
|
175
|
+
i++;
|
|
176
|
+
let numStr = "";
|
|
177
|
+
while (i < result.length && result[i] >= "0" && result[i] <= "9") {
|
|
178
|
+
numStr += result[i];
|
|
179
|
+
i++;
|
|
180
|
+
}
|
|
181
|
+
const pos = numStr ? parseInt(numStr, 10) - 1 : pIdx;
|
|
182
|
+
pIdx = numStr ? pIdx : pIdx + 1;
|
|
183
|
+
out += pos in positionalValues ? positionalValues[pos] : "NULL";
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
out += result[i];
|
|
187
|
+
i++;
|
|
188
|
+
}
|
|
189
|
+
result = out;
|
|
190
|
+
}
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
#executeSql(sql) {
|
|
194
|
+
const [stmt] = this.#parser.parse_string(sql);
|
|
195
|
+
if (!stmt) {
|
|
196
|
+
throw new SqliteError("Failed to parse SQL statement");
|
|
197
|
+
}
|
|
198
|
+
const stmtType = stmt.get_statement_type();
|
|
199
|
+
if (stmtType === Gda.SqlStatementType.SELECT) {
|
|
200
|
+
return {
|
|
201
|
+
model: this.#connection.statement_execute_select(stmt, null),
|
|
202
|
+
isSelect: true
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
this.#connection.statement_execute_non_select(stmt, null);
|
|
207
|
+
return {
|
|
208
|
+
model: null,
|
|
209
|
+
isSelect: false
|
|
210
|
+
};
|
|
211
|
+
} catch {
|
|
212
|
+
const model = this.#connection.statement_execute_select(stmt, null);
|
|
213
|
+
return {
|
|
214
|
+
model,
|
|
215
|
+
isSelect: true
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
run(...args) {
|
|
220
|
+
const sql = this.#buildSql(args);
|
|
221
|
+
this.#executeSql(sql);
|
|
222
|
+
let changes = 0;
|
|
223
|
+
let lastInsertRowid = 0;
|
|
224
|
+
try {
|
|
225
|
+
const chModel = this.#connection.execute_select_command("SELECT changes()");
|
|
226
|
+
if (chModel && chModel.get_n_rows() > 0) {
|
|
227
|
+
changes = chModel.get_value_at(0, 0);
|
|
228
|
+
}
|
|
229
|
+
} catch {}
|
|
230
|
+
try {
|
|
231
|
+
const ridModel = this.#connection.execute_select_command("SELECT last_insert_rowid()");
|
|
232
|
+
if (ridModel && ridModel.get_n_rows() > 0) {
|
|
233
|
+
lastInsertRowid = ridModel.get_value_at(0, 0);
|
|
234
|
+
}
|
|
235
|
+
} catch {}
|
|
236
|
+
if (this.#readBigInts) {
|
|
237
|
+
changes = BigInt(changes);
|
|
238
|
+
lastInsertRowid = BigInt(lastInsertRowid);
|
|
239
|
+
}
|
|
240
|
+
return {
|
|
241
|
+
changes,
|
|
242
|
+
lastInsertRowid
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
get(...args) {
|
|
246
|
+
const sql = this.#buildSql(args);
|
|
247
|
+
try {
|
|
248
|
+
const { model } = this.#executeSql(sql);
|
|
249
|
+
if (!model || model.get_n_rows() === 0) {
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
252
|
+
return readFirstRow(model, this.#getReadOptions());
|
|
253
|
+
} catch {
|
|
254
|
+
return undefined;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
all(...args) {
|
|
258
|
+
const sql = this.#buildSql(args);
|
|
259
|
+
try {
|
|
260
|
+
const { model } = this.#executeSql(sql);
|
|
261
|
+
if (!model) {
|
|
262
|
+
return [];
|
|
263
|
+
}
|
|
264
|
+
return readAllRows(model, this.#getReadOptions());
|
|
265
|
+
} catch {
|
|
266
|
+
return [];
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
setReadBigInts(enabled) {
|
|
270
|
+
if (typeof enabled !== "boolean") {
|
|
271
|
+
throw new InvalidArgTypeError("The \"readBigInts\" argument must be a boolean.");
|
|
272
|
+
}
|
|
273
|
+
this.#readBigInts = enabled;
|
|
274
|
+
return undefined;
|
|
275
|
+
}
|
|
276
|
+
setReturnArrays(enabled) {
|
|
277
|
+
if (typeof enabled !== "boolean") {
|
|
278
|
+
throw new InvalidArgTypeError("The \"returnArrays\" argument must be a boolean.");
|
|
279
|
+
}
|
|
280
|
+
this.#returnArrays = enabled;
|
|
281
|
+
return undefined;
|
|
282
|
+
}
|
|
283
|
+
setAllowBareNamedParameters(enabled) {
|
|
284
|
+
if (typeof enabled !== "boolean") {
|
|
285
|
+
throw new InvalidArgTypeError("The \"allowBareNamedParameters\" argument must be a boolean.");
|
|
286
|
+
}
|
|
287
|
+
this.#allowBareNamedParameters = enabled;
|
|
288
|
+
return undefined;
|
|
289
|
+
}
|
|
290
|
+
setAllowUnknownNamedParameters(enabled) {
|
|
291
|
+
if (typeof enabled !== "boolean") {
|
|
292
|
+
throw new InvalidArgTypeError("The \"allowUnknownNamedParameters\" argument must be a boolean.");
|
|
293
|
+
}
|
|
294
|
+
this.#allowUnknownNamedParameters = enabled;
|
|
295
|
+
return undefined;
|
|
296
|
+
}
|
|
292
297
|
};
|
|
298
|
+
|
|
299
|
+
//#endregion
|
|
300
|
+
export { StatementSync };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/sqlite",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.15",
|
|
4
4
|
"description": "Node.js sqlite module for Gjs using libgda",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "lib/esm/index.js",
|
|
@@ -31,14 +31,14 @@
|
|
|
31
31
|
"libgda"
|
|
32
32
|
],
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@gjsify/cli": "^0.3.
|
|
35
|
-
"@gjsify/unit": "^0.3.
|
|
34
|
+
"@gjsify/cli": "^0.3.15",
|
|
35
|
+
"@gjsify/unit": "^0.3.15",
|
|
36
36
|
"@types/node": "^25.6.0",
|
|
37
37
|
"typescript": "^6.0.3"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@girs/gda-6.0": "
|
|
41
|
-
"@girs/glib-2.0": "
|
|
42
|
-
"@girs/gobject-2.0": "
|
|
40
|
+
"@girs/gda-6.0": "6.0.0-4.0.0-rc.9",
|
|
41
|
+
"@girs/glib-2.0": "2.88.0-4.0.0-rc.9",
|
|
42
|
+
"@girs/gobject-2.0": "2.88.0-4.0.0-rc.9"
|
|
43
43
|
}
|
|
44
44
|
}
|