diff --git a/README.md b/README.md index 421d19a0..0f18150a 100644 --- a/README.md +++ b/README.md @@ -342,6 +342,18 @@ select * from users select * from users where user_id = $1 ``` +### Dynamic fragments +Multiple fragments can be joined together with `sql.join` to create more complex dynamic queries: + +```js +// this could be built dynamically +let expressions = [sql`name is not null`, sql`age > 50`] +const separator = and ? sql` and ` : sql` or ` +sql`select * from from users where ${ + sql.join(separator, expressions) +}` +``` + ### SQL functions Using keywords or calling functions dynamically is also possible by using ``` sql`` ``` fragments. ```js diff --git a/src/index.js b/src/index.js index 0573e2bc..5e06ce49 100644 --- a/src/index.js +++ b/src/index.js @@ -98,6 +98,7 @@ function Postgres(a, b) { notify, array, json, + join, file }) @@ -318,6 +319,14 @@ function Postgres(a, b) { return new Parameter(x, 3802) } + function join(sep, xs) { + return xs.flatMap((x, i) => { + if (i === 0) return x + if (Array.isArray(x)) return [sep, ...x] + return [sep, x] + }) + } + function array(x, type) { if (!Array.isArray(x)) return array(Array.from(arguments)) diff --git a/tests/index.js b/tests/index.js index bf81b036..8dd191b7 100644 --- a/tests/index.js +++ b/tests/index.js @@ -2469,6 +2469,14 @@ t('Supports arrays of fragments', async() => { ] }) +t("Joins fragments with a separator", () => { + const fs = [sql`a = ${1}`, sql`b = ${"test"}`] + return [ + sql`select * from t where ${ sql.join(sql` and `, fs) }`.describe().string, + 'select * from t where a = $1 and b = $2' + ] +}); + t('Does not try rollback when commit errors', async() => { let notice = null const sql = postgres({ ...options, onnotice: x => notice = x }) diff --git a/types/index.d.ts b/types/index.d.ts index 8989ff47..29f09478 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -702,6 +702,7 @@ declare namespace postgres { file(path: string | Buffer | URL | number, options?: { cache?: boolean | undefined } | undefined): PendingQuery; file(path: string | Buffer | URL | number, args: (ParameterOrJSON)[], options?: { cache?: boolean | undefined } | undefined): PendingQuery; json(value: JSONValue): Parameter; + join(a: PendingQuery, p: PendingQuery): PendingQuery reserve(): Promise> }