Skip to content

Commit

Permalink
cleaned up interface
Browse files Browse the repository at this point in the history
  • Loading branch information
root committed Dec 19, 2022
1 parent 6277b15 commit a207052
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 89 deletions.
26 changes: 6 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const { Client } = require('pg')

...

const res = await client.query(sql`delete from options where id in (${obsoleteOptions}) returning *`);
const res = await client.query(sql`delete from options where id in (${sql.join(obsoleteOptions)}) returning *`);
```

The template recognizes the following argument types:
Expand All @@ -24,7 +24,7 @@ sql`${null}` == { text: 'NULL', values: []}
```
* strings wrapped with `sql.raw()` will be directly inserted into the query
```js
sql`${sql.raw('--\n')}` == { text: '--\n', values: []}
sql`${sql('--\n')}` == { text: '--\n', values: []}
```
* strings wrapped with `sql.id()` are wrapped in double quotes and properly escaped
```js
Expand All @@ -35,25 +35,11 @@ sql`${sql.id('long row name"')}` == { text: '"long row name """', values: []}
sql`select * from "table" where id=${1} and ${sql`status=${2}`}` ==
{ text: 'select * from "table" where "id"=$1 and "status"=$2', values: [1, 2]}
```
* an array will be evaluated itemwise and joined by comma
* use `sql.join()` to join array of values or templates into a new template
```js
sql`delete from options where id in (${[1,2,3]}) returning *` ==
{ text: 'delete from options where id in ($1,$2,$3) returning *', values: [1, 2, 3]}
```

### helper methods

* `sql.insertObjs(array)`: generates the column name and value arrays for an insert query. We assume that the objects are uniform (same keys in every object) and the array contains at least one object

```js
sql`insert into "table" ${sql.insertObjs([{key: 1, data: 2}, {key: 3, data: 4}])}` ==
{ text: 'insert into "table" ("key","value") values ($1,$2),($3,$4)', values: [1, 2, 3, 4]}
```
* `sql.updateObj(obj)`: generates the key=value pairs for an update query.
sql.join([1, sql`hello`, 2], ",") ==
{ text: '$1,hello,$2', values: [1, 2]}
```

```js
sql`update "table" set ${sql.updateObj({key: 1, data: 2})}` ==
{ text: 'update "table" set "key"=$1,"value"=$2', values: [1, 2]}
```
## tips
[^1]: you can also install `pg-minify` to make the outputted queries a bit nicer, no other config needed!
17 changes: 5 additions & 12 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
type JsonPrimitive = string | number | boolean | null;
type JsonObject = { [key: string]: JsonValue };
type JsonArray = JsonValue[];
type JsonValue = JsonPrimitive | JsonArray | JsonObject;

type TemplateValue = JsonValue | SqlQuery | TemplateValue[];
type TemplateValue = unknown | SqlQuery;

type SqlQuery = {
readonly text: string,
readonly values: JsonArray[]
readonly values: Array<unknown>
};

declare function sql(strings: TemplateStringsArray, ...v: TemplateValue[]): SqlQuery;
declare function sql(strings: TemplateStringsArray | string, ...v: TemplateValue[]): SqlQuery;
declare namespace sql {
function raw(s: string): string;
function id(s: string): string;
function insertObjs(s: JsonObject[]): SqlQuery;
function updateObj(s: JsonObject): SqlQuery;
function id(s: string): SqlQuery;
function join(s: TemplateValue[], separator?: string): SqlQuery;
}

export = sql;
28 changes: 7 additions & 21 deletions sql.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ try {
minify = a => a
}

const $raw = Symbol();
const $sql = Symbol();

function sql(strings, ...values) {
let compiled = null;
strings = strings || ['']
strings = Array.isArray(strings) ? strings : [strings]

const template = {
s: strings || [''],
s: strings,
v: values || []
}

Expand All @@ -34,12 +36,6 @@ function sql(strings, ...values) {
throw new Error(`undefined argument $${d} to query`, { template: template });
} else if (v === null) {
o.s += 'NULL'
} else if (Array.isArray(v)) {
const w = compile({ s: Array(v.length + 1).fill(',', 1, v.length), v })
o.s += w.s;
o.v = o.v.concat(w.v);
} else if (typeof v === 'object' && v[$raw]) {
o.s += v;
} else if (typeof v === 'object' && v[$sql]) {
const w = compile(v[$sql]);
o.s += w.s;
Expand Down Expand Up @@ -67,22 +63,12 @@ function sql(strings, ...values) {
};
}

sql.raw = function (s) {
const v = new String(s);
v[$raw] = true;
return v;
}

sql.id = function (s) {
return sql.raw(`"${s.replace(/"/g, '""')}"`);
}

sql.insertObjs = function (v) {
return sql`(${Object.keys(v[0]).map(sql.id)}) values ${v.map(o => sql`(${Object.values(o)})`)}`;
return sql([`"${s.replace(/"/g, '""')}"`]);
}

sql.setObj = function (v) {
return sql`${Object.entries(v).map(([k, v]) => sql`${sql.id(k)}=${v}`)}`;
sql.join = function (v, d = ', ') {
return sql(Array(v.length + 1).fill('').fill(d, 1, v.length), ...v);
}

module.exports = sql;
42 changes: 6 additions & 36 deletions test.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,8 @@ it('nested template', () => {
})
});

it('array', () => {
const objs = [
{ key: 1, value: 'a' },
{ key: "2", value: 'b' },
]

template = sql`insert into table (${ Object.keys(objs[0]).map(sql.id) }) values ${ objs.map(o => sql`(${Object.values(o)})`) }`;
assert.deepEqual(template, {
text: 'insert into table ("key","value") values ($1,$2),($3,$4)',
values: [1, "a", "2", "b"]
})
});

it('sql.raw', () => {
template = sql`test ${sql.raw('RAW')} test`;
it('sql raw', () => {
template = sql`test ${sql('RAW')} test`;
assert.deepEqual(template, {
text: 'test RAW test',
values: []
Expand All @@ -75,27 +62,10 @@ it('sql.id', () => {
})
});

it('sql.insertObjs', () => {
const objs = [
{ key: 1, value: 'a' },
{ key: 2, value: 'b' },
]

template = sql`insert into table ${sql.insertObjs(objs)}`;
it('sql.join', () => {
template = sql`${sql.join([1, sql`hello`, 2, 3], "-")}`;
assert.deepEqual(template, {
text: 'insert into table ("key","value") values ($1,$2),($3,$4)',
values: [1, "a", 2, "b"]
text: '$1-hello-$2-$3',
values: [1, 2, 3]
})
});

it('sql.setObj', () => {
template = sql`update table set ${sql.setObj({
status: 1,
text: 'correct'
})} `;

assert.deepEqual(template, {
text: 'update table set "status"=$1,"text"=$2',
values: [1, 'correct']
})
});

0 comments on commit a207052

Please sign in to comment.