Skip to content

Commit

Permalink
feat: add tagged template literal invocation syntax (fixes #3)
Browse files Browse the repository at this point in the history
  • Loading branch information
gajus committed May 1, 2017
1 parent 4e57b7e commit 1d9fce2
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 10 deletions.
11 changes: 10 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,14 @@
"canonical",
"canonical/flowtype"
],
"root": true
"root": true,
"rules": {
"no-restricted-syntax": 0,
"no-unused-expressions": [
2,
{
"allowTaggedTemplates": true
}
]
}
}
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ A PostgreSQL client with strict types and assertions.
* [A value set](#a-value-set)
* [Multiple value sets](#multiple-value-sets)
* [Named placeholders](#named-placeholders)
* [Template literals](#template-literals)
* [Query methods](#query-methods)
* [`any`](#any)
* [`insert`](#insert)
Expand Down Expand Up @@ -131,6 +132,20 @@ SELECT $1

```

### Template literals

Query methods can be executed using [tagged template literals](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals) syntax, e.g.

```js
connection.query`INSERT INTO reservation_ticket (reservation_id, ticket_id) VALUES ${values}`;

```

> Is it safe? Absolutely!
> `foo\`bar${baz}qux\`` is equivalent to `foo(['bar', 'qux'], baz)`.
>
> Mightyql recognises tagged template literal invocation and uses it to construct a query with anonymous value placeholders.
> Execution of the resulting query is delegated to the `pg` module.
## Query methods

Expand Down
19 changes: 10 additions & 9 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
NotFoundError
} from './errors';
import {
mapTaggedTemplateLiteralInvocation,
normalizeAnonymousValuePlaceholders,
normalizeNamedValuePlaceholders
} from './utilities';
Expand Down Expand Up @@ -187,10 +188,10 @@ const createConnection = async (

return ended;
},
many: many.bind(null, connection, clientConfiguration),
maybeOne: maybeOne.bind(null, connection, clientConfiguration),
one: one.bind(null, connection, clientConfiguration),
query: query.bind(null, connection)
many: mapTaggedTemplateLiteralInvocation(many).bind(null, connection, clientConfiguration),
maybeOne: mapTaggedTemplateLiteralInvocation(maybeOne).bind(null, connection, clientConfiguration),
one: mapTaggedTemplateLiteralInvocation(one).bind(null, connection, clientConfiguration),
query: mapTaggedTemplateLiteralInvocation(query).bind(null, connection)
};
};

Expand All @@ -201,11 +202,11 @@ const createPool = (
const pool = new pg.Pool(typeof connectionConfiguration === 'string' ? parseConnectionString(connectionConfiguration) : connectionConfiguration);

return {
any: any.bind(null, pool, clientConfiguration),
many: many.bind(null, pool, clientConfiguration),
maybeOne: maybeOne.bind(null, pool, clientConfiguration),
one: one.bind(null, pool, clientConfiguration),
query: query.bind(null, pool)
any: mapTaggedTemplateLiteralInvocation(any).bind(null, pool, clientConfiguration),
many: mapTaggedTemplateLiteralInvocation(many).bind(null, pool, clientConfiguration),
maybeOne: mapTaggedTemplateLiteralInvocation(maybeOne).bind(null, pool, clientConfiguration),
one: mapTaggedTemplateLiteralInvocation(one).bind(null, pool, clientConfiguration),
query: mapTaggedTemplateLiteralInvocation(query).bind(null, pool)
};
};

Expand Down
1 change: 1 addition & 0 deletions src/utilities/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @flow

export {default as mapTaggedTemplateLiteralInvocation} from './mapTaggedTemplateLiteralInvocation';
export {default as normalizeAnonymousValuePlaceholders} from './normalizeAnonymousValuePlaceholders';
export {default as normalizeNamedValuePlaceholders} from './normalizeNamedValuePlaceholders';
15 changes: 15 additions & 0 deletions src/utilities/mapTaggedTemplateLiteralInvocation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// @flow

// eslint-disable-next-line flowtype/no-weak-types
export default (targetMethod: Function) => {
// eslint-disable-next-line flowtype/no-weak-types
return (maybeQuery: string | Array<string>, ...args: any) => {
if (typeof maybeQuery === 'string') {
return targetMethod(maybeQuery, args[0]);
} else {
const strings = maybeQuery;

return targetMethod(strings.join('?'), args);
}
};
};
29 changes: 29 additions & 0 deletions test/utilities/mapTaggedTemplateLiteralInvocation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// @flow

import test from 'ava';
import sinon from 'sinon';
import {
mapTaggedTemplateLiteralInvocation
} from '../../src/utilities';

test('works with regular invocation', (t) => {
const spy = sinon.spy();

const method = mapTaggedTemplateLiteralInvocation(spy);

method('query', 'parameters');

t.true(spy.calledWith('query', 'parameters'));
});

test('works with tagged template literals', (t) => {
const spy = sinon.spy();

const method = mapTaggedTemplateLiteralInvocation(spy);

const bar = 'BAR';

method`foo${bar}baz`;

t.true(spy.calledWith('foo?baz', ['BAR']));
});

0 comments on commit 1d9fce2

Please sign in to comment.