UNPKG

7.48 kBMarkdownView Raw
1<img align="right" src="https://cdn.rawgit.com/mikesamuel/template-tag-common/7f0159bda72d616af30645d49c3c9203c963c0a6/images/logo.png" alt="Sisyphus Logo">
2
3# Safe SQL Template Tag
4
5[![Build Status](https://travis-ci.org/mikesamuel/safesql.svg?branch=master)](https://travis-ci.org/mikesamuel/safesql)
6[![Dependencies Status](https://david-dm.org/mikesamuel/safesql/status.svg)](https://david-dm.org/mikesamuel/safesql)
7[![npm](https://img.shields.io/npm/v/safesql.svg)](https://www.npmjs.com/package/safesql)
8[![Coverage Status](https://coveralls.io/repos/github/mikesamuel/safesql/badge.svg?branch=master)](https://coveralls.io/github/mikesamuel/safesql?branch=master)
9[![Install Size](https://packagephobia.now.sh/badge?p=safesql)](https://packagephobia.now.sh/result?p=safesql)
10[![Known Vulnerabilities](https://snyk.io/test/github/mikesamuel/safesql/badge.svg?targetFile=package.json)](https://snyk.io/test/github/mikesamuel/safesql?targetFile=package.json)
11
12Provides a string template tag that makes it easy to compose
13[MySQL][mysql] and [PostgreSQL][pg] query strings from untrusted
14inputs by escaping dynamic values based on the context in which they
15appear.
16
17<!-- scripts/make-md-toc.pl replaces the below and test/check-markdown.js keeps this up-to-date. -->
18
19<!-- TOC -->
20
21* [Installation](#installation)
22* [Supported Databases](#supported)
23* [Usage By Example](#usage)
24 * [`mysql` returns a *SqlFragment*](#sql-returns-sqlfragment)
25 * [No excess quotes](#minimal-quotes)
26 * [Escaped backticks delimit SQL identifiers](#escaped-backticks)
27 * [Escape Sequences are Raw](#raw-escapes)
28* [API](#API)
29 * [mysql(options)](#mysql-options)
30 * [pgsql(options)](#pg-options)
31 * [mysql\`...\`](#mysql-as-tag)
32 * [pg\`...\`](#pg-as-tag)
33 * [SqlFragment](#class-SqlFragment)
34 * [SqlId](#class-SqlId)
35
36<!-- /TOC -->
37
38## Installation <a name="installation"></a>
39
40```bash
41$ npm install safesql
42```
43
44## Supported Databases <a name="supported"></a>
45
46**MySQL** via
47
48```js
49const { mysql } = require('safesql');
50```
51
52**PostgreSQL** via
53
54```js
55const { pg } = require('safesql');
56```
57
58
59## Usage By Example <a name="usage"></a>
60
61<!--
62
63This mirrors a testcase in ./test/example-test.js so if you modify this,
64be sure to reflect changes there.
65
66-->
67
68```js
69const { mysql, SqlId } = require('safesql');
70
71const table = 'table';
72const ids = [ 'x', 'y', 'z' ];
73const str = 'foo\'"bar';
74
75const query = mysql`SELECT * FROM \`${ table }\` WHERE id IN (${ ids }) AND s=${ str }`;
76
77console.log(query);
78// SELECT * FROM `table` WHERE id IN ('x', 'y', 'z') AND s='foo''"bar'
79```
80
81`mysql` functions as a template tag.
82
83Commas separate elements of arrays in the output.
84
85`mysql` treats a `${...}` between backticks (<tt>\\\`</tt>) as a SQL identifier.
86
87A `${...}` outside any quotes will be escaped and wrapped in appropriate quotes if necessary.
88
89----
90
91PostgreSQL differs from MySQL in important ways. Use `pg` for Postgres.
92
93```js
94const { pg, SqlId } = require('safesql');
95
96const table = 'table';
97const ids = [ 'x', 'y', 'z' ];
98const str = 'foo\'"bar';
99
100const query = pg`SELECT * FROM "${ table }" WHERE id IN (${ ids }) AND s=${ str }`;
101
102console.log(query);
103// SELECT * FROM "table" WHERE id IN ('x', 'y', 'z') AND s=e'foo''\"bar'
104```
105
106----
107
108You can pass in an object to relate columns to values as in a `SET` clause above.
109
110The output of <tt>mysql\`...\`</tt> has type *SqlFragment* so the
111`NOW()` function call is not re-escaped when used in `${data}`.
112
113```js
114const { mysql } = require('safesql');
115
116const column = 'users';
117const userId = 1;
118const data = {
119 email: 'foobar@example.com',
120 modified: mysql`NOW()`
121};
122const query = mysql`UPDATE \`${column}\` SET ${data} WHERE \`id\` = ${userId}`;
123
124console.log(query);
125// UPDATE `users` SET `email` = 'foobar@example.com', `modified` = NOW() WHERE `id` = 1
126```
127
128### `mysql` returns a *SqlFragment* <a name="sql-returns-sqlfragment"></a>
129
130Since `mysql` returns a *SqlFragment* you can chain uses:
131
132```js
133const { mysql } = require('safesql');
134
135const data = { a: 1 };
136const whereClause = mysql`WHERE ${data}`;
137console.log(mysql`SELECT * FROM TABLE ${whereClause}`);
138// SELECT * FROM TABLE WHERE `a` = 1
139```
140
141### No excess quotes <a name="minimal-quotes"></a>
142
143An interpolation in a quoted string will not insert excess quotes:
144
145```js
146const { mysql } = require('safesql')
147
148console.log(mysql`SELECT '${ 'foo' }' `)
149// SELECT 'foo'
150console.log(mysql`SELECT ${ 'foo' } `)
151// SELECT 'foo'
152```
153
154### Escaped backticks delimit SQL identifiers <a name="escaped-backticks"></a>
155
156Backticks end a template tag, so you need to escape backticks.
157
158```js
159const { mysql } = require('safesql')
160
161console.log(mysql`SELECT \`${ 'id' }\` FROM \`TABLE\``)
162// SELECT `id` FROM `TABLE`
163```
164
165### Escape Sequences are Raw <a name="raw-escapes"></a>
166
167Other escape sequences are raw.
168
169```js
170const { mysql } = require('safesql')
171
172console.log(mysql`SELECT "\n"`)
173// SELECT "\n"
174```
175
176## API <a name="API"></a>
177
178Assuming
179
180```js
181const { mysql, pg, SqlFragment, SqlId } = require('safesql')
182```
183
184### mysql(options) <a name="mysql-options"></a>
185### pgsql(options) <a name="pg-options"></a>
186
187When called with an options bundle instead of as a template tag,
188`mysql` and `pg` return a template tag that uses those options.
189
190The options object can contain any of
191`{ stringifyObjects, timeZone, forbidQualified }` which have the
192same meaning as when used with *[sqlstring][]*.
193
194```js
195const timeZone = 'GMT'
196const date = new Date(Date.UTC(2000, 0, 1))
197
198console.log(mysql({ timeZone })`SELECT ${date}`)
199// SELECT '2000-01-01 00:00:00.000'
200```
201
202### mysql\`...\` <a name="mysql-as-tag"></a>
203
204When used as a template tag, chooses an appropriate escaping
205convention for each `${...}` based on the context in which it appears.
206
207`mysql` handles `${...}` inside quoted strings as if the template
208matched the following grammar:
209
210[![Railroad Diagram][mysql-railroad-raw]][mysql-railroad]
211
212### pg\`...\` <a name="pg-as-tag"></a>
213
214When used as a template tag, chooses an appropriate escaping
215convention for each `${...}` based on the context in which it appears.
216
217`pg` handles `${...}` inside quoted strings as if the template
218matched the following grammar:
219
220[![Railroad Diagram][pg-railroad-raw]][pg-railroad]
221
222### SqlFragment <a name="class-SqlFragment"></a>
223
224*SqlFragment* is a [Mintable][] class that represents fragments of SQL
225that are safe to send to a database.
226
227See [minting][] for example on how to create instances, and why this is a
228tad more involved than just using `new`.
229
230### SqlId <a name="class-SqlId"></a>
231
232*SqlId* is a [Mintable][] class that represents a SQL identifier.
233
234See [minting][] for example on how to create instances, and why this is a
235tad more involved than just using `new`.
236
237A `SqlId`'s content must be the raw text of a SQL identifier and
238creators should not rely on case folding by the database client.
239
240
241[mysql]: https://www.npmjs.com/package/mysql
242[pg]: https://www.npmjs.com/package/pg
243[sqlstring]: https://www.npmjs.com/package/sqlstring
244[Mintable]: https://www.npmjs.com/package/node-sec-patterns
245[minting]: https://www.npmjs.com/package/node-sec-patterns#creating-mintable-values
246
247[mysql-railroad]: docs/mysql-railroad.svg
248[mysql-railroad-raw]: https://rawgit.com/mikesamuel/safesql/master/docs/mysql-railroad.svg
249[pg-railroad]: docs/pg-railroad.svg
250[pg-railroad-raw]: https://rawgit.com/mikesamuel/safesql/master/docs/pg-railroad.svg