@@ -27,15 +27,16 @@ const addon = bindings<{
2727 persistent : boolean ,
2828 pluck : boolean ,
2929 bigint : boolean ,
30+ paramNames : Array < string | null > ,
3031 ) : NativeStatement ;
3132 statementRun < Options extends StatementOptions > (
3233 stmt : NativeStatement ,
33- params : StatementParameters < Options > | undefined ,
34+ params : NativeParameters < Options > | undefined ,
3435 result : [ number , number ] ,
3536 ) : void ;
3637 statementStep < Options extends StatementOptions > (
3738 stmt : NativeStatement ,
38- params : StatementParameters < Options > | null | undefined ,
39+ params : NativeParameters < Options > | null | undefined ,
3940 cache : Array < SqliteValue < Options > > | undefined ,
4041 isGet : boolean ,
4142 ) : Array < SqliteValue < Options > > ;
@@ -85,11 +86,15 @@ export type StatementOptions = Readonly<{
8586 bigint ?: true ;
8687} > ;
8788
89+ export type NativeParameters < Options extends StatementOptions > = ReadonlyArray <
90+ SqliteValue < Options >
91+ > ;
92+
8893/**
8994 * Parameters accepted by `.run()`/`.get()`/`.all()` methods of the statement.
9095 */
9196export type StatementParameters < Options extends StatementOptions > =
92- | ReadonlyArray < SqliteValue < Options > >
97+ | NativeParameters < Options >
9398 | Readonly < Record < string , SqliteValue < Options > > > ;
9499
95100/**
@@ -119,6 +124,9 @@ class Statement<Options extends StatementOptions = object> {
119124
120125 #cache: Array < SqliteValue < Options > > | undefined ;
121126 #createRow: undefined | ( ( result : unknown ) => RowType < Options > ) ;
127+ #translateParams: (
128+ params : StatementParameters < Options > ,
129+ ) => NativeParameters < Options > ;
122130 #native: NativeStatement | undefined ;
123131 #onClose: ( ( ) => void ) | undefined ;
124132
@@ -131,14 +139,47 @@ class Statement<Options extends StatementOptions = object> {
131139 ) {
132140 this . #needsTranslation = persistent === true && ! pluck ;
133141
142+ const paramNames = new Array < string | null > ( ) ;
143+
134144 this . #native = addon . statementNew (
135145 db ,
136146 query ,
137147 persistent === true ,
138148 pluck === true ,
139149 bigint === true ,
150+ paramNames ,
140151 ) ;
141152
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+
142183 this . #onClose = onClose ;
143184 }
144185
@@ -154,8 +195,8 @@ class Statement<Options extends StatementOptions = object> {
154195 throw new Error ( 'Statement closed' ) ;
155196 }
156197 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 ) ;
159200 return { changes : result [ 0 ] , lastInsertRowid : result [ 1 ] } ;
160201 }
161202
@@ -174,8 +215,13 @@ class Statement<Options extends StatementOptions = object> {
174215 if ( this . #native === undefined ) {
175216 throw new Error ( 'Statement closed' ) ;
176217 }
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+ ) ;
179225 if ( result === undefined ) {
180226 return undefined ;
181227 }
@@ -202,9 +248,8 @@ class Statement<Options extends StatementOptions = object> {
202248 throw new Error ( 'Statement closed' ) ;
203249 }
204250 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 ;
208253 while ( true ) {
209254 const single = addon . statementStep (
210255 this . #native,
@@ -282,16 +327,19 @@ class Statement<Options extends StatementOptions = object> {
282327 }
283328
284329 /** @internal */
285- #checkParams( params : StatementParameters < Options > | undefined ) : void {
330+ #checkParams(
331+ params : StatementParameters < Options > | undefined ,
332+ ) : NativeParameters < Options > | undefined {
286333 if ( params === undefined ) {
287- return ;
334+ return undefined ;
288335 }
289336 if ( typeof params !== 'object' ) {
290337 throw new TypeError ( 'Params must be either object or array' ) ;
291338 }
292339 if ( params === null ) {
293340 throw new TypeError ( 'Params cannot be null' ) ;
294341 }
342+ return this . #translateParams( params ) ;
295343 }
296344}
297345
0 commit comments