@@ -27,15 +27,16 @@ const addon = bindings<{
27
27
persistent : boolean ,
28
28
pluck : boolean ,
29
29
bigint : boolean ,
30
+ paramNames : Array < string | null > ,
30
31
) : NativeStatement ;
31
32
statementRun < Options extends StatementOptions > (
32
33
stmt : NativeStatement ,
33
- params : StatementParameters < Options > | undefined ,
34
+ params : NativeParameters < Options > | undefined ,
34
35
result : [ number , number ] ,
35
36
) : void ;
36
37
statementStep < Options extends StatementOptions > (
37
38
stmt : NativeStatement ,
38
- params : StatementParameters < Options > | null | undefined ,
39
+ params : NativeParameters < Options > | null | undefined ,
39
40
cache : Array < SqliteValue < Options > > | undefined ,
40
41
isGet : boolean ,
41
42
) : Array < SqliteValue < Options > > ;
@@ -85,11 +86,15 @@ export type StatementOptions = Readonly<{
85
86
bigint ?: true ;
86
87
} > ;
87
88
89
+ export type NativeParameters < Options extends StatementOptions > = ReadonlyArray <
90
+ SqliteValue < Options >
91
+ > ;
92
+
88
93
/**
89
94
* Parameters accepted by `.run()`/`.get()`/`.all()` methods of the statement.
90
95
*/
91
96
export type StatementParameters < Options extends StatementOptions > =
92
- | ReadonlyArray < SqliteValue < Options > >
97
+ | NativeParameters < Options >
93
98
| Readonly < Record < string , SqliteValue < Options > > > ;
94
99
95
100
/**
@@ -119,6 +124,9 @@ class Statement<Options extends StatementOptions = object> {
119
124
120
125
#cache: Array < SqliteValue < Options > > | undefined ;
121
126
#createRow: undefined | ( ( result : unknown ) => RowType < Options > ) ;
127
+ #translateParams: (
128
+ params : StatementParameters < Options > ,
129
+ ) => NativeParameters < Options > ;
122
130
#native: NativeStatement | undefined ;
123
131
#onClose: ( ( ) => void ) | undefined ;
124
132
@@ -131,14 +139,47 @@ class Statement<Options extends StatementOptions = object> {
131
139
) {
132
140
this . #needsTranslation = persistent === true && ! pluck ;
133
141
142
+ const paramNames = new Array < string | null > ( ) ;
143
+
134
144
this . #native = addon . statementNew (
135
145
db ,
136
146
query ,
137
147
persistent === true ,
138
148
pluck === true ,
139
149
bigint === true ,
150
+ paramNames ,
140
151
) ;
141
152
153
+ const isArrayParams = paramNames . every ( ( name ) => name === null ) ;
154
+ const isObjectParams =
155
+ ! isArrayParams && paramNames . every ( ( name ) => typeof name === 'string' ) ;
156
+
157
+ if ( ! isArrayParams && ! isObjectParams ) {
158
+ throw new TypeError ( 'Cannot mix named and anonymous params in query' ) ;
159
+ }
160
+
161
+ if ( isArrayParams ) {
162
+ this . #translateParams = ( params ) => {
163
+ if ( ! Array . isArray ( params ) ) {
164
+ throw new TypeError ( 'Query requires an array of anonymous params' ) ;
165
+ }
166
+ return params ;
167
+ } ;
168
+ } else {
169
+ this . #translateParams = runInThisContext ( `
170
+ (function translateParams(params) {
171
+ if (Array.isArray(params)) {
172
+ throw new TypeError('Query requires an object of named params');
173
+ }
174
+ return [
175
+ ${ paramNames
176
+ . map ( ( name ) => `params[${ JSON . stringify ( name ) } ]` )
177
+ . join ( ',\n' ) }
178
+ ];
179
+ })
180
+ ` ) ;
181
+ }
182
+
142
183
this . #onClose = onClose ;
143
184
}
144
185
@@ -154,8 +195,8 @@ class Statement<Options extends StatementOptions = object> {
154
195
throw new Error ( 'Statement closed' ) ;
155
196
}
156
197
const result : [ number , number ] = [ 0 , 0 ] ;
157
- this . #checkParams( params ) ;
158
- addon . statementRun ( this . #native, params , result ) ;
198
+ const nativeParams = this . #checkParams( params ) ;
199
+ addon . statementRun ( this . #native, nativeParams , result ) ;
159
200
return { changes : result [ 0 ] , lastInsertRowid : result [ 1 ] } ;
160
201
}
161
202
@@ -174,8 +215,13 @@ class Statement<Options extends StatementOptions = object> {
174
215
if ( this . #native === undefined ) {
175
216
throw new Error ( 'Statement closed' ) ;
176
217
}
177
- this . #checkParams( params ) ;
178
- const result = addon . statementStep ( this . #native, params , this . #cache, true ) ;
218
+ const nativeParams = this . #checkParams( params ) ;
219
+ const result = addon . statementStep (
220
+ this . #native,
221
+ nativeParams ,
222
+ this . #cache,
223
+ true ,
224
+ ) ;
179
225
if ( result === undefined ) {
180
226
return undefined ;
181
227
}
@@ -202,9 +248,8 @@ class Statement<Options extends StatementOptions = object> {
202
248
throw new Error ( 'Statement closed' ) ;
203
249
}
204
250
const result = [ ] ;
205
- this . #checkParams( params ) ;
206
- let singleUseParams : StatementParameters < Options > | undefined | null =
207
- params ;
251
+ const nativeParams = this . #checkParams( params ) ;
252
+ let singleUseParams : typeof nativeParams | undefined | null = nativeParams ;
208
253
while ( true ) {
209
254
const single = addon . statementStep (
210
255
this . #native,
@@ -282,16 +327,19 @@ class Statement<Options extends StatementOptions = object> {
282
327
}
283
328
284
329
/** @internal */
285
- #checkParams( params : StatementParameters < Options > | undefined ) : void {
330
+ #checkParams(
331
+ params : StatementParameters < Options > | undefined ,
332
+ ) : NativeParameters < Options > | undefined {
286
333
if ( params === undefined ) {
287
- return ;
334
+ return undefined ;
288
335
}
289
336
if ( typeof params !== 'object' ) {
290
337
throw new TypeError ( 'Params must be either object or array' ) ;
291
338
}
292
339
if ( params === null ) {
293
340
throw new TypeError ( 'Params cannot be null' ) ;
294
341
}
342
+ return this . #translateParams( params ) ;
295
343
}
296
344
}
297
345
0 commit comments