From 7702bb2e1dbef8d822b639f9ee1ae8867a60cd53 Mon Sep 17 00:00:00 2001 From: William Chargin Date: Thu, 20 Sep 2018 11:31:26 -0700 Subject: [PATCH] flow: simplify better-sqlite3 bound parameters (#869) Summary: The actual constraints for bound parameters are too complicated to express within Flow. This commit changes the type definitions from one approximation to another, simpler one. Neither approximation is likely to cause many problems in practice, either in terms of spurious errors or spurious lacks of error. (The failure mode for the new formulation is having multiple dictionaries of binding values, which would pass Flow but quickly raise a `TypeError` at runtime.) The reason for the change is that it makes the method definitions considerably simpler, in a way that is likely to avoid other problems with Flow. In particular, this removes method overloads and the need for parameter disambiguation. I fix a typo while in the area. Test Plan: Note that the following file typechecks: ```js // @flow import Database from "better-sqlite3"; const db = new Database(":memory:"); const stmt = db.prepare("BEGIN"); // SQL text doesn't matter stmt.run(); stmt.run(null, 2, "three", new Buffer(Array(4))); stmt.run(+false); stmt.run(1, {dos: 2}, 3); // the binding dictionary can go anywhere stmt.run({a: 1}, {b: 2}); // this will fail at runtime (TypeError) // $ExpectFlowError stmt.run(false); // booleans cannot be bound // $ExpectFlowError stmt.run({x: {y: "z"}}); // named parameters are not recursive ``` All but the last two success cases (lines 9 and 10) would also have passed before this change. wchargin-branch: flow-better-sqlite3-bound-parameters-simplify --- flow-typed/npm/better-sqlite3_vx.x.x.js | 57 ++++++++----------------- 1 file changed, 17 insertions(+), 40 deletions(-) diff --git a/flow-typed/npm/better-sqlite3_vx.x.x.js b/flow-typed/npm/better-sqlite3_vx.x.x.js index c667e84..97f934a 100644 --- a/flow-typed/npm/better-sqlite3_vx.x.x.js +++ b/flow-typed/npm/better-sqlite3_vx.x.x.js @@ -41,12 +41,13 @@ declare type bettersqlite3$Database$RegisterOptions = { +safeIntegers?: boolean }; -// For functions that accept bound parameters, we permit an optional -// binding dictionary, followed by zero or more bound values. In -// reality, better-sqlite3 is more flexible than this: the binding -// dictionary can go anywhere among the arguments. We can't express this -// type, though, and it is strange to use both named and numbered -// parameters at all, so we accept this concession. +// Functions that accept bound parameters take positional parameters, +// named parameters (passed as an object), or a combination of the two. +// The named parameters can be placed anywhere in the argument list, but +// must appear at most once. We can't express this constraint, so we +// permit any argument to be either a simple value or a dictionary of +// values. In the case that a user provides multiple binding +// dictionaries, better-sqlite3 will fail fast with a TypeError. // // Also note that better-sqlite3 permits binding `Integer.IntLike` from // npm/integer, not just `number`, but we don't have those typedefs. For @@ -55,6 +56,9 @@ declare type bettersqlite3$BoundValue = number | string | Buffer | null; declare type bettersqlite3$BindingDictionary = { +[string]: bettersqlite3$BoundValue }; +declare type bettersqlite3$BoundParameter = + | bettersqlite3$BoundValue + | bettersqlite3$BindingDictionary; declare class bettersqlite3$Statement { +memory: boolean; @@ -63,32 +67,12 @@ declare class bettersqlite3$Statement { +open: boolean; +inTransaction: boolean; - run(...params: bettersqlite3$BoundValue[]): bettersqlite3$RunResult; - run( - namedParams: bettersqlite3$BindingDictionary, - ...params: bettersqlite3$BoundValue[] - ): bettersqlite3$RunResult; - get(...params: bettersqlite3$BoundValue[]): any; - get( - namedParams: bettersqlite3$BindingDictionary, - ...params: bettersqlite3$BoundValue[] - ): any; - all(...params: bettersqlite3$BoundValue[]): any[]; - all( - namedParams: bettersqlite3$BindingDictionary, - ...params: bettersqlite3$BoundValue[] - ): any[]; - iterate(...params: bettersqlite3$BoundValue[]): Iterator; - iterate( - namedParams: bettersqlite3$BindingDictionary, - ...params: bettersqlite3$BoundValue[] - ): Iterator; + run(...params: bettersqlite3$BoundParameter[]): bettersqlite3$RunResult; + get(...params: bettersqlite3$BoundParameter[]): any; + all(...params: bettersqlite3$BoundParameter[]): any[]; + iterate(...params: bettersqlite3$BoundParameter[]): Iterator; pluck(toggleState?: boolean): this; - bind(...params: bettersqlite3$BoundValue[]): this; - bind( - namedParams: bettersqlite3$BindingDictionary, - ...params: bettersqlite3$BoundValue[] - ): this; + bind(...params: bettersqlite3$BoundParameter[]): this; safeIntegers(toggleState?: boolean): this; } @@ -98,15 +82,7 @@ declare class bettersqlite3$Transaction { constructor(db: bettersqlite3$Database, sources: string[]): void; run(...params: any[]): bettersqlite3$RunResult; - run( - namedParams: bettersqlite3$BindingDictionary, - ...params: bettersqlite3$BoundValue[] - ): bettersqlite3$RunResult; bind(...params: any[]): this; - bind( - namedParams: bettersqlite3$BindingDictionary, - ...params: bettersqlite3$BoundValue[] - ): this; safeIntegers(toggleState?: boolean): this; } @@ -128,7 +104,8 @@ declare module "better-sqlite3" { declare export type Database$ConstructorOptions = bettersqlite3$Database$ConstructorOptions; declare export type Database$RegisterOptions = bettersqlite3$Database$RegisterOptions; declare export type BoundValue = bettersqlite3$BoundValue; - declare export type BidningDictionary = bettersqlite3$BindingDictionary; + declare export type BindingDictionary = bettersqlite3$BindingDictionary; + declare export type BoundParameter = bettersqlite3$BoundParameter; declare export type Statement = bettersqlite3$Statement; declare export type Transaction = bettersqlite3$Transaction; declare export type RunResult = bettersqlite3$RunResult;