206 lines
7.8 KiB
Markdown
206 lines
7.8 KiB
Markdown
|
# sqlstring
|
||
|
|
||
|
[![NPM Version][npm-version-image]][npm-url]
|
||
|
[![NPM Downloads][npm-downloads-image]][npm-url]
|
||
|
[![Node.js Version][node-image]][node-url]
|
||
|
[![Build Status][github-actions-ci-image]][github-actions-ci-url]
|
||
|
[![Coverage Status][coveralls-image]][coveralls-url]
|
||
|
|
||
|
Simple SQL escape and format for MySQL
|
||
|
|
||
|
## Install
|
||
|
|
||
|
```sh
|
||
|
$ npm install sqlstring
|
||
|
```
|
||
|
|
||
|
## Usage
|
||
|
|
||
|
|
||
|
```js
|
||
|
var SqlString = require('sqlstring');
|
||
|
```
|
||
|
|
||
|
### Escaping query values
|
||
|
|
||
|
**Caution** These methods of escaping values only works when the
|
||
|
[NO_BACKSLASH_ESCAPES](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html#sqlmode_no_backslash_escapes)
|
||
|
SQL mode is disabled (which is the default state for MySQL servers).
|
||
|
|
||
|
In order to avoid SQL Injection attacks, you should always escape any user
|
||
|
provided data before using it inside a SQL query. You can do so using the
|
||
|
`SqlString.escape()` method:
|
||
|
|
||
|
```js
|
||
|
var userId = 'some user provided value';
|
||
|
var sql = 'SELECT * FROM users WHERE id = ' + SqlString.escape(userId);
|
||
|
console.log(sql); // SELECT * FROM users WHERE id = 'some user provided value'
|
||
|
```
|
||
|
|
||
|
Alternatively, you can use `?` characters as placeholders for values you would
|
||
|
like to have escaped like this:
|
||
|
|
||
|
```js
|
||
|
var userId = 1;
|
||
|
var sql = SqlString.format('SELECT * FROM users WHERE id = ?', [userId]);
|
||
|
console.log(sql); // SELECT * FROM users WHERE id = 1
|
||
|
```
|
||
|
|
||
|
Multiple placeholders are mapped to values in the same order as passed. For example,
|
||
|
in the following query `foo` equals `a`, `bar` equals `b`, `baz` equals `c`, and
|
||
|
`id` will be `userId`:
|
||
|
|
||
|
```js
|
||
|
var userId = 1;
|
||
|
var sql = SqlString.format('UPDATE users SET foo = ?, bar = ?, baz = ? WHERE id = ?',
|
||
|
['a', 'b', 'c', userId]);
|
||
|
console.log(sql); // UPDATE users SET foo = 'a', bar = 'b', baz = 'c' WHERE id = 1
|
||
|
```
|
||
|
|
||
|
This looks similar to prepared statements in MySQL, however it really just uses
|
||
|
the same `SqlString.escape()` method internally.
|
||
|
|
||
|
**Caution** This also differs from prepared statements in that all `?` are
|
||
|
replaced, even those contained in comments and strings.
|
||
|
|
||
|
Different value types are escaped differently, here is how:
|
||
|
|
||
|
* Numbers are left untouched
|
||
|
* Booleans are converted to `true` / `false`
|
||
|
* Date objects are converted to `'YYYY-mm-dd HH:ii:ss'` strings
|
||
|
* Buffers are converted to hex strings, e.g. `X'0fa5'`
|
||
|
* Strings are safely escaped
|
||
|
* Arrays are turned into list, e.g. `['a', 'b']` turns into `'a', 'b'`
|
||
|
* Nested arrays are turned into grouped lists (for bulk inserts), e.g. `[['a',
|
||
|
'b'], ['c', 'd']]` turns into `('a', 'b'), ('c', 'd')`
|
||
|
* Objects that have a `toSqlString` method will have `.toSqlString()` called
|
||
|
and the returned value is used as the raw SQL.
|
||
|
* Objects are turned into `key = 'val'` pairs for each enumerable property on
|
||
|
the object. If the property's value is a function, it is skipped; if the
|
||
|
property's value is an object, toString() is called on it and the returned
|
||
|
value is used.
|
||
|
* `undefined` / `null` are converted to `NULL`
|
||
|
* `NaN` / `Infinity` are left as-is. MySQL does not support these, and trying
|
||
|
to insert them as values will trigger MySQL errors until they implement
|
||
|
support.
|
||
|
|
||
|
You may have noticed that this escaping allows you to do neat things like this:
|
||
|
|
||
|
```js
|
||
|
var post = {id: 1, title: 'Hello MySQL'};
|
||
|
var sql = SqlString.format('INSERT INTO posts SET ?', post);
|
||
|
console.log(sql); // INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL'
|
||
|
```
|
||
|
|
||
|
And the `toSqlString` method allows you to form complex queries with functions:
|
||
|
|
||
|
```js
|
||
|
var CURRENT_TIMESTAMP = { toSqlString: function() { return 'CURRENT_TIMESTAMP()'; } };
|
||
|
var sql = SqlString.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]);
|
||
|
console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42
|
||
|
```
|
||
|
|
||
|
To generate objects with a `toSqlString` method, the `SqlString.raw()` method can
|
||
|
be used. This creates an object that will be left un-touched when using in a `?`
|
||
|
placeholder, useful for using functions as dynamic values:
|
||
|
|
||
|
**Caution** The string provided to `SqlString.raw()` will skip all escaping
|
||
|
functions when used, so be careful when passing in unvalidated input.
|
||
|
|
||
|
```js
|
||
|
var CURRENT_TIMESTAMP = SqlString.raw('CURRENT_TIMESTAMP()');
|
||
|
var sql = SqlString.format('UPDATE posts SET modified = ? WHERE id = ?', [CURRENT_TIMESTAMP, 42]);
|
||
|
console.log(sql); // UPDATE posts SET modified = CURRENT_TIMESTAMP() WHERE id = 42
|
||
|
```
|
||
|
|
||
|
If you feel the need to escape queries by yourself, you can also use the escaping
|
||
|
function directly:
|
||
|
|
||
|
```js
|
||
|
var sql = 'SELECT * FROM posts WHERE title=' + SqlString.escape('Hello MySQL');
|
||
|
console.log(sql); // SELECT * FROM posts WHERE title='Hello MySQL'
|
||
|
```
|
||
|
|
||
|
### Escaping query identifiers
|
||
|
|
||
|
If you can't trust an SQL identifier (database / table / column name) because it is
|
||
|
provided by a user, you should escape it with `SqlString.escapeId(identifier)` like this:
|
||
|
|
||
|
```js
|
||
|
var sorter = 'date';
|
||
|
var sql = 'SELECT * FROM posts ORDER BY ' + SqlString.escapeId(sorter);
|
||
|
console.log(sql); // SELECT * FROM posts ORDER BY `date`
|
||
|
```
|
||
|
|
||
|
It also supports adding qualified identifiers. It will escape both parts.
|
||
|
|
||
|
```js
|
||
|
var sorter = 'date';
|
||
|
var sql = 'SELECT * FROM posts ORDER BY ' + SqlString.escapeId('posts.' + sorter);
|
||
|
console.log(sql); // SELECT * FROM posts ORDER BY `posts`.`date`
|
||
|
```
|
||
|
|
||
|
If you do not want to treat `.` as qualified identifiers, you can set the second
|
||
|
argument to `true` in order to keep the string as a literal identifier:
|
||
|
|
||
|
```js
|
||
|
var sorter = 'date.2';
|
||
|
var sql = 'SELECT * FROM posts ORDER BY ' + SqlString.escapeId(sorter, true);
|
||
|
console.log(sql); // SELECT * FROM posts ORDER BY `date.2`
|
||
|
```
|
||
|
|
||
|
Alternatively, you can use `??` characters as placeholders for identifiers you would
|
||
|
like to have escaped like this:
|
||
|
|
||
|
```js
|
||
|
var userId = 1;
|
||
|
var columns = ['username', 'email'];
|
||
|
var sql = SqlString.format('SELECT ?? FROM ?? WHERE id = ?', [columns, 'users', userId]);
|
||
|
console.log(sql); // SELECT `username`, `email` FROM `users` WHERE id = 1
|
||
|
```
|
||
|
**Please note that this last character sequence is experimental and syntax might change**
|
||
|
|
||
|
When you pass an Object to `.escape()` or `.format()`, `.escapeId()` is used to avoid SQL injection in object keys.
|
||
|
|
||
|
### Formatting queries
|
||
|
|
||
|
You can use `SqlString.format` to prepare a query with multiple insertion points,
|
||
|
utilizing the proper escaping for ids and values. A simple example of this follows:
|
||
|
|
||
|
```js
|
||
|
var userId = 1;
|
||
|
var inserts = ['users', 'id', userId];
|
||
|
var sql = SqlString.format('SELECT * FROM ?? WHERE ?? = ?', inserts);
|
||
|
console.log(sql); // SELECT * FROM `users` WHERE `id` = 1
|
||
|
```
|
||
|
|
||
|
Following this you then have a valid, escaped query that you can then send to the database safely.
|
||
|
This is useful if you are looking to prepare the query before actually sending it to the database.
|
||
|
You also have the option (but are not required) to pass in `stringifyObject` and `timeZone`,
|
||
|
allowing you provide a custom means of turning objects into strings, as well as a
|
||
|
location-specific/timezone-aware `Date`.
|
||
|
|
||
|
This can be further combined with the `SqlString.raw()` helper to generate SQL
|
||
|
that includes MySQL functions as dynamic vales:
|
||
|
|
||
|
```js
|
||
|
var userId = 1;
|
||
|
var data = { email: 'foobar@example.com', modified: SqlString.raw('NOW()') };
|
||
|
var sql = SqlString.format('UPDATE ?? SET ? WHERE `id` = ?', ['users', data, userId]);
|
||
|
console.log(sql); // UPDATE `users` SET `email` = 'foobar@example.com', `modified` = NOW() WHERE `id` = 1
|
||
|
```
|
||
|
|
||
|
## License
|
||
|
|
||
|
[MIT](LICENSE)
|
||
|
|
||
|
[npm-version-image]: https://img.shields.io/npm/v/sqlstring.svg
|
||
|
[npm-downloads-image]: https://img.shields.io/npm/dm/sqlstring.svg
|
||
|
[npm-url]: https://npmjs.org/package/sqlstring
|
||
|
[coveralls-image]: https://img.shields.io/coveralls/mysqljs/sqlstring/master.svg
|
||
|
[coveralls-url]: https://coveralls.io/r/mysqljs/sqlstring?branch=master
|
||
|
[github-actions-ci-image]: https://img.shields.io/github/workflow/status/mysqljs/sqlstring/ci/master?label=build
|
||
|
[github-actions-ci-url]: https://github.com/mysqljs/sqlstring/actions/workflows/ci.yml
|
||
|
[node-image]: https://img.shields.io/node/v/sqlstring.svg
|
||
|
[node-url]: https://nodejs.org/en/download
|