Socket
Socket
Sign inDemoInstall

slonik

Package Overview
Dependencies
Maintainers
1
Versions
395
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

slonik - npm Package Compare versions

Comparing version 7.0.3 to 8.0.0

dist/binders/bindIsolatedPoolConnection.js

631

dist/index.js

@@ -6,73 +6,20 @@ "use strict";

});
Object.defineProperty(exports, "CheckIntegrityConstraintViolationError", {
Object.defineProperty(exports, "createConnection", {
enumerable: true,
get: function () {
return _errors.CheckIntegrityConstraintViolationError;
return _factories.createConnection;
}
});
Object.defineProperty(exports, "DataIntegrityError", {
Object.defineProperty(exports, "createPool", {
enumerable: true,
get: function () {
return _errors.DataIntegrityError;
return _factories.createPool;
}
});
Object.defineProperty(exports, "ForeignKeyIntegrityConstraintViolationError", {
enumerable: true,
get: function () {
return _errors.ForeignKeyIntegrityConstraintViolationError;
}
});
Object.defineProperty(exports, "NotFoundError", {
enumerable: true,
get: function () {
return _errors.NotFoundError;
}
});
Object.defineProperty(exports, "NotNullIntegrityConstraintViolationError", {
enumerable: true,
get: function () {
return _errors.NotNullIntegrityConstraintViolationError;
}
});
Object.defineProperty(exports, "SlonikError", {
enumerable: true,
get: function () {
return _errors.SlonikError;
}
});
Object.defineProperty(exports, "UniqueIntegrityConstraintViolationError", {
enumerable: true,
get: function () {
return _errors.UniqueIntegrityConstraintViolationError;
}
});
exports.createPool = exports.createConnection = exports.transaction = exports.anyFirst = exports.any = exports.manyFirst = exports.many = exports.maybeOneFirst = exports.oneFirst = exports.maybeOne = exports.one = exports.query = exports.sql = void 0;
var _pg = _interopRequireWildcard(require("pg"));
var _pg = require("pg");
var _pgConnectionString = require("pg-connection-string");
var _factories = require("./factories");
var _getStackTrace = require("get-stack-trace");
var _serializeError = _interopRequireDefault(require("serialize-error"));
var _prettyHrtime = _interopRequireDefault(require("pretty-hrtime"));
var _ulid = require("ulid");
var _errors = require("./errors");
var _utilities = require("./utilities");
var _Logger = _interopRequireDefault(require("./Logger"));
var _config = require("./config");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
// @see https://github.com/facebook/flow/issues/2977#issuecomment-390613203
const defaultClientConfiguration = Object.freeze({}); // eslint-disable-next-line id-match
// eslint-disable-next-line id-match
const INT8_OID = 20;

@@ -93,566 +40,2 @@ const TIMESTAMPTZ_OID = 1184;

});
const log = _Logger.default.child({
namespace: 'slonik'
});
const ulid = (0, _ulid.factory)((0, _ulid.detectPrng)(true));
const sql = (parts, ...values) => {
let raw = '';
const bindings = [];
let index = 0;
for (const part of parts) {
const value = values[index++];
raw += part;
if (index >= parts.length) {
// eslint-disable-next-line no-continue
continue;
}
if (value && Array.isArray(value.names) && value.type === 'IDENTIFIER') {
raw += value.names.map(identifierName => {
if (typeof identifierName !== 'string') {
throw new TypeError('Identifier name must be a string.');
}
return (0, _utilities.escapeIdentifier)(identifierName);
}).join('.'); // eslint-disable-next-line no-continue
continue;
} else {
raw += '?';
bindings.push(value);
}
}
return {
sql: raw,
values: bindings
};
};
exports.sql = sql;
sql.identifier = names => {
// @todo Replace `type` with a symbol once Flow adds symbol support
// @see https://github.com/facebook/flow/issues/810
return {
names,
type: 'IDENTIFIER'
};
};
// eslint-disable-next-line complexity
const query = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
let stackTrace;
if (_config.SLONIK_LOG_STACK_TRACE) {
const callSites = await (0, _getStackTrace.getStackTrace)();
stackTrace = callSites.map(callSite => {
return (callSite.fileName || '') + ':' + callSite.lineNumber + ':' + callSite.columnNumber;
});
}
const strippedSql = (0, _utilities.stripComments)(rawSql);
let rowCount = null;
let normalized;
const start = process.hrtime();
const interceptors = clientConfiguration && clientConfiguration.interceptors || [];
try {
let result;
for (const interceptor of interceptors) {
if (interceptor.beforeQuery) {
const maybeResult = await interceptor.beforeQuery({
sql: rawSql,
values
});
if (maybeResult) {
return maybeResult;
}
}
}
if (Array.isArray(values)) {
normalized = (0, _utilities.normalizeAnonymousValuePlaceholders)(strippedSql, values);
} else if (values) {
normalized = (0, _utilities.normalizeNamedValuePlaceholders)(strippedSql, values);
}
if (normalized) {
result = connection.query(normalized.sql, normalized.values);
} else {
result = connection.query(strippedSql);
}
result = await result;
for (const interceptor of interceptors) {
if (interceptor.afterQuery) {
await interceptor.afterQuery({
sql: rawSql,
values
}, result);
}
} // @todo Use rowCount only if the query is UPDATE/ INSERT.
if (result.rowCount) {
rowCount = result.rowCount;
} else if (Array.isArray(result)) {
rowCount = result.length;
}
return result;
} catch (error) {
log.error({
error: (0, _serializeError.default)(error),
queryId
}, 'query produced an error');
if (error.code === '23502') {
throw new _errors.NotNullIntegrityConstraintViolationError(error.constraint);
}
if (error.code === '23503') {
throw new _errors.ForeignKeyIntegrityConstraintViolationError(error.constraint);
}
if (error.code === '23505') {
throw new _errors.UniqueIntegrityConstraintViolationError(error.constraint);
}
if (error.code === '23514') {
throw new _errors.CheckIntegrityConstraintViolationError(error.constraint);
}
throw error;
} finally {
const end = process.hrtime(start); // eslint-disable-next-line flowtype/no-weak-types
const payload = {
executionTime: (0, _prettyHrtime.default)(end),
queryId,
rowCount,
sql: strippedSql
};
if (_config.SLONIK_LOG_STACK_TRACE) {
payload.stackTrace = stackTrace;
}
if (_config.SLONIK_LOG_VALUES) {
payload.values = values;
}
if (_config.SLONIK_LOG_NORMALISED) {
payload.normalized = normalized;
}
log.debug(payload, 'query');
}
};
/**
* Makes a query and expects exactly one result.
*
* @throws NotFoundError If query returns no rows.
* @throws DataIntegrityError If query returns multiple rows.
*/
exports.query = query;
const one = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
const {
rows
} = await query(connection, clientConfiguration, rawSql, values, queryId);
if (rows.length === 0) {
log.error({
queryId
}, 'NotFoundError');
throw new _errors.NotFoundError();
}
if (rows.length > 1) {
log.error({
queryId
}, 'DataIntegrityError');
throw new _errors.DataIntegrityError();
}
return rows[0];
};
/**
* Makes a query and expects exactly one result.
*
* @throws DataIntegrityError If query returns multiple rows.
*/
exports.one = one;
const maybeOne = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
const {
rows
} = await query(connection, clientConfiguration, rawSql, values, queryId);
if (rows.length === 0) {
return null;
}
if (rows.length > 1) {
log.error({
queryId
}, 'DataIntegrityError');
throw new _errors.DataIntegrityError();
}
return rows[0];
};
/**
* Makes a query and expects exactly one result.
* Returns value of the first column.
*
* @throws NotFoundError If query returns no rows.
* @throws DataIntegrityError If query returns multiple rows.
*/
exports.maybeOne = maybeOne;
const oneFirst = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
const row = await one(connection, clientConfiguration, rawSql, values, queryId);
const keys = Object.keys(row);
if (keys.length !== 1) {
log.error({
queryId
}, 'DataIntegrityError');
throw new _errors.DataIntegrityError();
}
return row[keys[0]];
};
/**
* Makes a query and expects exactly one result.
* Returns value of the first column.
*
* @throws DataIntegrityError If query returns multiple rows.
*/
exports.oneFirst = oneFirst;
const maybeOneFirst = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
const row = await maybeOne(connection, clientConfiguration, rawSql, values, queryId);
if (!row) {
return null;
}
const keys = Object.keys(row);
if (keys.length !== 1) {
log.error({
queryId
}, 'DataIntegrityError');
throw new _errors.DataIntegrityError();
}
return row[keys[0]];
};
/**
* Makes a query and expects at least 1 result.
*
* @throws NotFoundError If query returns no rows.
*/
exports.maybeOneFirst = maybeOneFirst;
const many = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
const {
rows
} = await query(connection, clientConfiguration, rawSql, values, queryId);
if (rows.length === 0) {
log.error({
queryId
}, 'NotFoundError');
throw new _errors.NotFoundError();
}
return rows;
};
exports.many = many;
const manyFirst = async (connection, clientConfigurationType, rawSql, values, queryId = ulid()) => {
const rows = await many(connection, clientConfigurationType, rawSql, values, queryId);
if (rows.length === 0) {
log.error({
queryId
}, 'DataIntegrityError');
throw new _errors.DataIntegrityError();
}
const keys = Object.keys(rows[0]);
if (keys.length !== 1) {
log.error({
queryId
}, 'DataIntegrityError');
throw new _errors.DataIntegrityError();
}
const firstColumnName = keys[0];
if (typeof firstColumnName !== 'string') {
log.error({
queryId
}, 'DataIntegrityError');
throw new _errors.DataIntegrityError();
}
return rows.map(row => {
return row[firstColumnName];
});
};
/**
* Makes a query and expects any number of results.
*/
exports.manyFirst = manyFirst;
const any = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
const {
rows
} = await query(connection, clientConfiguration, rawSql, values, queryId);
return rows;
};
exports.any = any;
const anyFirst = async (connection, clientConfigurationType, rawSql, values, queryId = ulid()) => {
const rows = await any(connection, clientConfigurationType, rawSql, values, queryId);
if (rows.length === 0) {
return [];
}
const keys = Object.keys(rows[0]);
if (keys.length !== 1) {
log.error({
queryId
}, 'DataIntegrityError');
throw new _errors.DataIntegrityError();
}
const firstColumnName = keys[0];
if (typeof firstColumnName !== 'string') {
log.error({
queryId
}, 'DataIntegrityError');
throw new _errors.DataIntegrityError();
}
return rows.map(row => {
return row[firstColumnName];
});
};
exports.anyFirst = anyFirst;
const transaction = async (connection, handler) => {
await connection.query('START TRANSACTION');
try {
const result = await handler(connection);
await connection.query('COMMIT');
return result;
} catch (error) {
await connection.query('ROLLBACK');
log.error({
error: (0, _serializeError.default)(error)
}, 'rolling back transaction due to an error');
throw error;
}
};
exports.transaction = transaction;
const createConnection = async (connectionConfiguration, clientConfiguration = defaultClientConfiguration) => {
const pool = new _pg.default.Pool(typeof connectionConfiguration === 'string' ? (0, _pgConnectionString.parse)(connectionConfiguration) : connectionConfiguration);
pool.on('error', error => {
log.error({
error: (0, _serializeError.default)(error)
}, 'client connection error');
});
pool.on('connect', client => {
log.info({
processId: client.processID,
stats: {
idleConnectionCount: pool.idleCount,
totalConnectionCount: pool.totalCount,
waitingRequestCount: pool.waitingCount
}
}, 'created a new client connection');
});
pool.on('acquire', client => {
log.info({
processId: client.processID,
stats: {
idleConnectionCount: pool.idleCount,
totalConnectionCount: pool.totalCount,
waitingRequestCount: pool.waitingCount
}
}, 'client is checked out from the pool');
});
pool.on('remove', client => {
log.info({
processId: client.processID,
stats: {
idleConnectionCount: pool.idleCount,
totalConnectionCount: pool.totalCount,
waitingRequestCount: pool.waitingCount
}
}, 'client connection is closed and removed from the client pool');
});
const connection = await pool.connect();
connection.on('notice', notice => {
log.info({
notice
}, 'notice message');
});
let ended = false;
const bindConnection = {
any: (0, _utilities.mapTaggedTemplateLiteralInvocation)(any.bind(null, connection, clientConfiguration)),
anyFirst: (0, _utilities.mapTaggedTemplateLiteralInvocation)(anyFirst.bind(null, connection, clientConfiguration)),
end: async () => {
if (ended) {
return ended;
}
await connection.release();
ended = pool.end();
return ended;
},
many: (0, _utilities.mapTaggedTemplateLiteralInvocation)(many.bind(null, connection, clientConfiguration)),
manyFirst: (0, _utilities.mapTaggedTemplateLiteralInvocation)(manyFirst.bind(null, connection, clientConfiguration)),
maybeOne: (0, _utilities.mapTaggedTemplateLiteralInvocation)(maybeOne.bind(null, connection, clientConfiguration)),
maybeOneFirst: (0, _utilities.mapTaggedTemplateLiteralInvocation)(maybeOneFirst.bind(null, connection, clientConfiguration)),
one: (0, _utilities.mapTaggedTemplateLiteralInvocation)(one.bind(null, connection, clientConfiguration)),
oneFirst: (0, _utilities.mapTaggedTemplateLiteralInvocation)(oneFirst.bind(null, connection, clientConfiguration)),
query: (0, _utilities.mapTaggedTemplateLiteralInvocation)(query.bind(null, connection, clientConfiguration)),
transaction: handler => {
return transaction(bindConnection, handler);
}
};
return bindConnection;
};
exports.createConnection = createConnection;
const createPool = (connectionConfiguration, clientConfiguration = defaultClientConfiguration) => {
const pool = new _pg.default.Pool(typeof connectionConfiguration === 'string' ? (0, _pgConnectionString.parse)(connectionConfiguration) : connectionConfiguration);
pool.on('error', error => {
log.error({
error: (0, _serializeError.default)(error)
}, 'client connection error');
});
pool.on('connect', client => {
log.info({
processId: client.processID,
stats: {
idleConnectionCount: pool.idleCount,
totalConnectionCount: pool.totalCount,
waitingRequestCount: pool.waitingCount
}
}, 'created a new client connection');
});
pool.on('acquire', client => {
log.info({
processId: client.processID,
stats: {
idleConnectionCount: pool.idleCount,
totalConnectionCount: pool.totalCount,
waitingRequestCount: pool.waitingCount
}
}, 'client is checked out from the pool');
});
pool.on('remove', client => {
log.info({
processId: client.processID,
stats: {
idleConnectionCount: pool.idleCount,
totalConnectionCount: pool.totalCount,
waitingRequestCount: pool.waitingCount
}
}, 'client connection is closed and removed from the client pool');
});
const connect = async () => {
const connection = await pool.connect();
connection.on('notice', notice => {
log.info({
notice
}, 'notice message');
});
const bindConnection = {
any: (0, _utilities.mapTaggedTemplateLiteralInvocation)(any.bind(null, connection, clientConfiguration)),
anyFirst: (0, _utilities.mapTaggedTemplateLiteralInvocation)(anyFirst.bind(null, connection, clientConfiguration)),
many: (0, _utilities.mapTaggedTemplateLiteralInvocation)(many.bind(null, connection, clientConfiguration)),
manyFirst: (0, _utilities.mapTaggedTemplateLiteralInvocation)(manyFirst.bind(null, connection, clientConfiguration)),
maybeOne: (0, _utilities.mapTaggedTemplateLiteralInvocation)(maybeOne.bind(null, connection, clientConfiguration)),
maybeOneFirst: (0, _utilities.mapTaggedTemplateLiteralInvocation)(maybeOneFirst.bind(null, connection, clientConfiguration)),
one: (0, _utilities.mapTaggedTemplateLiteralInvocation)(one.bind(null, connection, clientConfiguration)),
oneFirst: (0, _utilities.mapTaggedTemplateLiteralInvocation)(oneFirst.bind(null, connection, clientConfiguration)),
query: (0, _utilities.mapTaggedTemplateLiteralInvocation)(query.bind(null, connection, clientConfiguration)),
release: connection.release.bind(connection),
transaction: handler => {
return transaction(bindConnection, handler);
}
};
return bindConnection;
};
return {
any: (0, _utilities.mapTaggedTemplateLiteralInvocation)(any.bind(null, pool, clientConfiguration)),
anyFirst: (0, _utilities.mapTaggedTemplateLiteralInvocation)(anyFirst.bind(null, pool, clientConfiguration)),
connect,
many: (0, _utilities.mapTaggedTemplateLiteralInvocation)(many.bind(null, pool, clientConfiguration)),
manyFirst: (0, _utilities.mapTaggedTemplateLiteralInvocation)(manyFirst.bind(null, pool, clientConfiguration)),
maybeOne: (0, _utilities.mapTaggedTemplateLiteralInvocation)(maybeOne.bind(null, pool, clientConfiguration)),
maybeOneFirst: (0, _utilities.mapTaggedTemplateLiteralInvocation)(maybeOneFirst.bind(null, pool, clientConfiguration)),
one: (0, _utilities.mapTaggedTemplateLiteralInvocation)(one.bind(null, pool, clientConfiguration)),
oneFirst: (0, _utilities.mapTaggedTemplateLiteralInvocation)(oneFirst.bind(null, pool, clientConfiguration)),
query: (0, _utilities.mapTaggedTemplateLiteralInvocation)(query.bind(null, pool, clientConfiguration)),
transaction: async handler => {
log.debug('allocating a new connection to execute the transaction');
const connection = await connect();
let result;
try {
result = await connection.transaction(handler);
} finally {
log.debug('releasing the connection that was earlier secured to execute a transaction');
await connection.release();
}
return result;
}
};
};
exports.createPool = createPool;
//# sourceMappingURL=index.js.map

@@ -6,2 +6,14 @@ "use strict";

});
Object.defineProperty(exports, "createQueryId", {
enumerable: true,
get: function () {
return _createQueryId.default;
}
});
Object.defineProperty(exports, "createUlid", {
enumerable: true,
get: function () {
return _createUlid.default;
}
});
Object.defineProperty(exports, "escapeIdentifier", {

@@ -38,2 +50,6 @@ enumerable: true,

var _createQueryId = _interopRequireDefault(require("./createQueryId"));
var _createUlid = _interopRequireDefault(require("./createUlid"));
var _escapeIdentifier = _interopRequireDefault(require("./escapeIdentifier"));

@@ -40,0 +56,0 @@

@@ -13,3 +13,3 @@ {

"dependencies": {
"ajv": "^6.5.4",
"ajv": "^6.5.5",
"array-flatten": "^2.1.1",

@@ -19,6 +19,6 @@ "boolean": "^0.2.0",

"get-stack-trace": "^2.0.1",
"pg": "^7.6.0",
"pg": "^7.6.1",
"pg-connection-string": "^2.0.0",
"pretty-hrtime": "^1.0.3",
"roarr": "^2.11.6",
"roarr": "^2.11.8",
"serialize-error": "^3.0.0",

@@ -29,20 +29,20 @@ "ulid": "^2.3.0"

"devDependencies": {
"@babel/cli": "^7.1.2",
"@babel/core": "^7.1.2",
"@babel/plugin-transform-flow-strip-types": "^7.0.0",
"@babel/preset-env": "^7.1.0",
"@babel/cli": "^7.1.5",
"@babel/core": "^7.1.6",
"@babel/plugin-transform-flow-strip-types": "^7.1.6",
"@babel/preset-env": "^7.1.6",
"@babel/register": "^7.0.0",
"ava": "^1.0.0-rc.1",
"ava": "^1.0.0-rc.2",
"babel-plugin-istanbul": "^5.1.0",
"babel-plugin-transform-export-default-name": "^2.0.4",
"coveralls": "^3.0.2",
"eslint": "^5.8.0",
"eslint": "^5.9.0",
"eslint-config-canonical": "^13.0.0",
"flow-bin": "^0.85.0",
"flow-bin": "^0.86.0",
"flow-copy-source": "^2.0.2",
"gitdown": "^2.5.5",
"husky": "^1.1.2",
"husky": "^1.1.4",
"nyc": "^13.1.0",
"semantic-release": "^15.10.6",
"sinon": "^7.1.0"
"semantic-release": "^15.12.0",
"sinon": "^7.1.1"
},

@@ -96,3 +96,3 @@ "engines": {

},
"version": "7.0.3"
"version": "8.0.0"
}

@@ -12,3 +12,24 @@ <a name="slonik"></a>

<a name="slonik-features"></a>
## Features
* [Convenience methods](#slonik-query-methods) with built-in assertions
* Anonymous, named and tagged template literal [value placeholders](#slonik-value-placeholders)
* [Middleware](#slonik-interceptors) support
* [Syntax highlighting](#slonik-syntax-highlighting) (Atom plugin compatible with Slonik)
* [SQL injection guarding](https://github.com/gajus/eslint-plugin-sql) (ESLint plugin compatible with Slonik)
* Detail [logging](#slonik-debugging)
* Built-in [asynchronous stack trace resolution](#log-stack-trace)
* [Flow types](#types)
* [Mapped errors](#error-handling)
* [Transactions](#transactions)
---
<a name="slonik-documentation"></a>
## Documentation
* [Slonik](#slonik)
* [Features](#slonik-features)
* [Documentation](#slonik-documentation)
* [Usage](#slonik-usage)

@@ -23,2 +44,3 @@ * [Configuration](#slonik-usage-configuration)

* [Value placeholders](#slonik-value-placeholders)
* [Anonymous placeholders](#slonik-value-placeholders-anonymous-placeholders)
* [A value set](#slonik-value-placeholders-a-value-set)

@@ -63,17 +85,2 @@ * [Multiple value sets](#slonik-value-placeholders-multiple-value-sets)

Example:
```js
import {
createPool
} from 'slonik';
const connection = createPool({
host: '127.0.0.1'
});
await connection.query('SELECT 1');
```
The API of the query method is equivalent to that of [`pg`](https://travis-ci.org/brianc/node-postgres).

@@ -112,3 +119,16 @@

Example:
```js
import {
createPool
} from 'slonik';
const connection = createPool('postgres://localhost');
await connection.query(sql`SELECT 1`);
```
<a name="slonik-interceptors"></a>

@@ -183,3 +203,3 @@ ## Interceptors

// Do not do this
connection.query(`INSERT INTO foo (bar) VALUES ('\n')`);
connection.query(sql`INSERT INTO foo (bar) VALUES ('\n')`);

@@ -191,5 +211,3 @@ ```

```sql
connection.query(`INSERT INTO foo (bar) VALUES (?)`, [
'\n'
]);
connection.query(sql`INSERT INTO foo (bar) VALUES (${'\n'})`);

@@ -201,2 +219,5 @@ ```

<a name="slonik-value-placeholders-anonymous-placeholders"></a>
### Anonymous placeholders
Slonik enables use of question mark (`?`) value placeholders, e.g.

@@ -217,3 +238,3 @@

> Do not mix question mark and positional value placeholders in a single query.
Note: Mixing anonymous and position placeholders in a single query will result in an error.

@@ -302,3 +323,6 @@ <a name="slonik-value-placeholders-a-value-set"></a>

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

@@ -310,3 +334,6 @@ ```

```js
connection.query('INSERT INTO reservation_ticket (reservation_id, ticket_id) VALUES ?', [
connection.query(sql`
INSERT INTO reservation_ticket (reservation_id, ticket_id)
VALUES ?
`, [
values

@@ -323,3 +350,6 @@ ]);

```js
sql`SELECT ${'foo'} FROM ${sql.identifier(['bar', 'baz'])}`;
sql`
SELECT ${'foo'}
FROM ${sql.identifier(['bar', 'baz'])
}`;

@@ -343,3 +373,6 @@ // {

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

@@ -351,3 +384,6 @@ ```

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

@@ -369,11 +405,11 @@ ```

> Similar to `#query` except that it returns rows without fields information.
Example:
```js
const rows = await connection.any('SELECT foo');
const rows = await connection.any(sql`SELECT foo`);
```
`#any` is similar to `#query` except that it returns rows without fields information.
<a name="slonik-query-methods-anyfirst"></a>

@@ -389,3 +425,3 @@ ### <code>anyFirst</code>

```js
const fooValues = await connection.anyFirst('SELECT foo');
const fooValues = await connection.anyFirst(sql`SELECT foo`);

@@ -397,7 +433,4 @@ ```

Designed to use when inserting 1 row.
Used when inserting 1 row.
> The reason for using this method over `#query` is to leverage the strict types.
> `#insert` method result type is `InsertResultType`.
Example:

@@ -408,6 +441,8 @@

insertId
} = await connection.insert('INSERT INTO foo SET bar="baz"');
} = await connection.insert(sql`INSERT INTO foo SET bar='baz'`);
```
The reason for using this method over `#query` is to leverage the strict types. `#insert` method result type is `InsertResultType`.
<a name="slonik-query-methods-many"></a>

@@ -423,3 +458,3 @@ ### <code>many</code>

```js
const rows = await connection.many('SELECT foo');
const rows = await connection.many(sql`SELECT foo`);

@@ -439,3 +474,3 @@ ```

```js
const fooValues = await connection.many('SELECT foo');
const fooValues = await connection.many(sql`SELECT foo`);

@@ -455,3 +490,3 @@ ```

```js
const row = await connection.maybeOne('SELECT foo');
const row = await connection.maybeOne(sql`SELECT foo`);

@@ -474,3 +509,3 @@ // row.foo is the result of the `foo` column value of the first row.

```js
const foo = await connection.maybeOneFirst('SELECT foo');
const foo = await connection.maybeOneFirst(sql`SELECT foo`);

@@ -492,3 +527,3 @@ // foo is the result of the `foo` column value of the first row.

```js
const row = await connection.one('SELECT foo');
const row = await connection.one(sql`SELECT foo`);

@@ -501,6 +536,6 @@ // row.foo is the result of the `foo` column value of the first row.

>
> I've got asked "How is this different from [knex.js](http://knexjs.org/) `knex('foo').limit(1)`".
> I've been asked "What makes this different from [knex.js](http://knexjs.org/) `knex('foo').limit(1)`?".
> `knex('foo').limit(1)` simply generates "SELECT * FROM foo LIMIT 1" query.
> `knex` is a query builder; it does not assert the value of the result.
> Slonik `one` adds assertions about the result of the query.
> Slonik `#one` adds assertions about the result of the query.

@@ -519,3 +554,3 @@ <a name="slonik-query-methods-onefirst"></a>

```js
const foo = await connection.oneFirst('SELECT foo');
const foo = await connection.oneFirst(sql`SELECT foo`);

@@ -540,4 +575,4 @@ // foo is the result of the `foo` column value of the first row.

const result = await connection.transaction(async (transactionConnection) => {
transactionConnection.query(`INSERT INTO foo (bar) VALUES ('baz')`);
transactionConnection.query(`INSERT INTO qux (quux) VALUES ('quuz')`);
await transactionConnection.query(sql`INSERT INTO foo (bar) VALUES ('baz')`);
await transactionConnection.query(sql`INSERT INTO qux (quux) VALUES ('quuz')`);

@@ -585,3 +620,3 @@ return 'FOO';

try {
row = await connection.one('SELECT foo');
row = await connection.one(sql`SELECT foo`);
} catch (error) {

@@ -612,3 +647,3 @@ if (!(error instanceof NotFoundError)) {

try {
row = await connection.one('SELECT foo');
row = await connection.one(sql`SELECT foo`);
} catch (error) {

@@ -670,8 +705,9 @@ if (error instanceof DataIntegrityError) {

): Promise<number> => {
const row = await connection
.one('SELECT id FROM country WHERE code = ? LIMIT 2', [
code
]);
const countryId = await connection.oneFirst(sql`
SELECT id
FROM country
WHERE code = ${code}
`);
return Number(row.id);
return countryId;
};

@@ -710,24 +746,13 @@

```
[2018-05-19T20:10:37.681Z] DEBUG (20) (@slonik) (#slonik): query
executionTime: 52 ms
queryId: 01CDX0D15XWEHJ0TWNQA97VC7G
rowCount: null
sql: INSERT INTO cinema_movie_name ( cinema_id, name, url, description_blob ) VALUES ( ?, ?, ?, ? ) RETURNING id
stackTrace:
- /node_modules/slonik/dist/index.js:85:38
- /node_modules/slonik/dist/index.js:173:13
- /node_modules/slonik/dist/index.js:231:21
- /node_modules/slonik/dist/utilities/mapTaggedTemplateLiteralInvocation.js:17:14
- /src/queries/insertCinemaMovieName.js:11:31
- /src/routines/uploadData.js:101:68
values:
- 1000104
- Solo: A Star Wars Story
- null
- null
```json
{"context":{"package":"slonik","namespace":"slonik","logLevel":20,"executionTime":"357 ms","queryId":"01CV2V5S4H57KCYFFBS0BJ8K7E","rowCount":1,"sql":"SELECT schedule_cinema_data_task();","stackTrace":["/Users/gajus/Documents/dev/applaudience/data-management-program/node_modules/slonik/dist:162:28","/Users/gajus/Documents/dev/applaudience/data-management-program/node_modules/slonik/dist:314:12","/Users/gajus/Documents/dev/applaudience/data-management-program/node_modules/slonik/dist:361:20","/Users/gajus/Documents/dev/applaudience/data-management-program/node_modules/slonik/dist/utilities:17:13","/Users/gajus/Documents/dev/applaudience/data-management-program/src/bin/commands/do-cinema-data-tasks.js:59:21","/Users/gajus/Documents/dev/applaudience/data-management-program/src/bin/commands/do-cinema-data-tasks.js:590:45","internal/process/next_tick.js:68:7"],"values":[]},"message":"query","sequence":4,"time":1540915127833,"version":"1.0.0"}
{"context":{"package":"slonik","namespace":"slonik","logLevel":20,"executionTime":"66 ms","queryId":"01CV2V5SGS0WHJX4GJN09Z3MTB","rowCount":1,"sql":"SELECT cinema_id \"cinemaId\", target_data \"targetData\" FROM cinema_data_task WHERE id = ?","stackTrace":["/Users/gajus/Documents/dev/applaudience/data-management-program/node_modules/slonik/dist:162:28","/Users/gajus/Documents/dev/applaudience/data-management-program/node_modules/slonik/dist:285:12","/Users/gajus/Documents/dev/applaudience/data-management-program/node_modules/slonik/dist/utilities:17:13","/Users/gajus/Documents/dev/applaudience/data-management-program/src/bin/commands/do-cinema-data-tasks.js:603:26","internal/process/next_tick.js:68:7"],"values":[17953947]},"message":"query","sequence":5,"time":1540915127902,"version":"1.0.0"}
```
Use [`@roarr/cli`](https://github.com/gajus/roarr-cli) to pretty-print the output.
![Log Roarr pretty-print output.](./.README/log-roarr-pretty-print-output.png)
<a name="slonik-syntax-highlighting"></a>

@@ -734,0 +759,0 @@ ## Syntax highlighting

// @flow
import pg, {
import {
types
} from 'pg';
import {
parse as parseConnectionString
} from 'pg-connection-string';
import {
getStackTrace
} from 'get-stack-trace';
import serializeError from 'serialize-error';
import prettyHrtime from 'pretty-hrtime';
import {
factory as ulidFactory,
detectPrng
} from 'ulid';
import {
CheckIntegrityConstraintViolationError,
DataIntegrityError,
ForeignKeyIntegrityConstraintViolationError,
NotFoundError,
NotNullIntegrityConstraintViolationError,
SlonikError,
UniqueIntegrityConstraintViolationError
} from './errors';
import {
escapeIdentifier,
mapTaggedTemplateLiteralInvocation,
normalizeAnonymousValuePlaceholders,
normalizeNamedValuePlaceholders,
stripComments
} from './utilities';
import type {
AnonymouseValuePlaceholderValueType,
ClientConfigurationType,
DatabaseConfigurationType,
DatabasePoolType,
DatabaseSingleConnectionType,
InternalQueryAnyFirstFunctionType,
InternalQueryAnyFunctionType,
InternalQueryFunctionType,
InternalQueryManyFirstFunctionType,
InternalQueryManyFunctionType,
InternalQueryMaybeOneFirstFunctionType,
InternalQueryMaybeOneFunctionType,
InternalQueryOneFirstFunctionType,
InternalQueryOneFunctionType,
InternalTransactionFunctionType,
QueryIdentifierType,
TaggledTemplateLiteralInvocationType
} from './types';
import Logger from './Logger';
import {
SLONIK_LOG_NORMALISED,
SLONIK_LOG_STACK_TRACE,
SLONIK_LOG_VALUES
} from './config';
// @see https://github.com/facebook/flow/issues/2977#issuecomment-390613203
const defaultClientConfiguration = Object.freeze({});
// eslint-disable-next-line id-match

@@ -80,60 +24,2 @@ const INT8_OID = 20;

const log = Logger.child({
namespace: 'slonik'
});
const ulid = ulidFactory(detectPrng(true));
const sql = (parts: $ReadOnlyArray<string>, ...values: $ReadOnlyArray<AnonymouseValuePlaceholderValueType>): TaggledTemplateLiteralInvocationType => {
let raw = '';
const bindings = [];
let index = 0;
for (const part of parts) {
const value = values[index++];
raw += part;
if (index >= parts.length) {
// eslint-disable-next-line no-continue
continue;
}
if (value && Array.isArray(value.names) && value.type === 'IDENTIFIER') {
raw += value.names
.map((identifierName) => {
if (typeof identifierName !== 'string') {
throw new TypeError('Identifier name must be a string.');
}
return escapeIdentifier(identifierName);
})
.join('.');
// eslint-disable-next-line no-continue
continue;
} else {
raw += '?';
bindings.push(value);
}
}
return {
sql: raw,
values: bindings
};
};
sql.identifier = (names: $ReadOnlyArray<string>): QueryIdentifierType => {
// @todo Replace `type` with a symbol once Flow adds symbol support
// @see https://github.com/facebook/flow/issues/810
return {
names,
type: 'IDENTIFIER'
};
};
export type {

@@ -148,541 +34,4 @@ DatabaseConnectionType,

export {
CheckIntegrityConstraintViolationError,
DataIntegrityError,
ForeignKeyIntegrityConstraintViolationError,
NotFoundError,
NotNullIntegrityConstraintViolationError,
SlonikError,
sql,
UniqueIntegrityConstraintViolationError
};
// eslint-disable-next-line complexity
export const query: InternalQueryFunctionType<*> = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
let stackTrace;
if (SLONIK_LOG_STACK_TRACE) {
const callSites = await getStackTrace();
stackTrace = callSites
.map((callSite) => {
return (callSite.fileName || '') + ':' + callSite.lineNumber + ':' + callSite.columnNumber;
});
}
const strippedSql = stripComments(rawSql);
let rowCount: number | null = null;
let normalized;
const start = process.hrtime();
const interceptors = clientConfiguration && clientConfiguration.interceptors || [];
try {
let result;
for (const interceptor of interceptors) {
if (interceptor.beforeQuery) {
const maybeResult = await interceptor.beforeQuery({
sql: rawSql,
values
});
if (maybeResult) {
return maybeResult;
}
}
}
if (Array.isArray(values)) {
normalized = normalizeAnonymousValuePlaceholders(strippedSql, values);
} else if (values) {
normalized = normalizeNamedValuePlaceholders(strippedSql, values);
}
if (normalized) {
result = connection.query(normalized.sql, normalized.values);
} else {
result = connection.query(strippedSql);
}
result = await result;
for (const interceptor of interceptors) {
if (interceptor.afterQuery) {
await interceptor.afterQuery({
sql: rawSql,
values
}, result);
}
}
// @todo Use rowCount only if the query is UPDATE/ INSERT.
if (result.rowCount) {
rowCount = result.rowCount;
} else if (Array.isArray(result)) {
rowCount = result.length;
}
return result;
} catch (error) {
log.error({
error: serializeError(error),
queryId
}, 'query produced an error');
if (error.code === '23502') {
throw new NotNullIntegrityConstraintViolationError(error.constraint);
}
if (error.code === '23503') {
throw new ForeignKeyIntegrityConstraintViolationError(error.constraint);
}
if (error.code === '23505') {
throw new UniqueIntegrityConstraintViolationError(error.constraint);
}
if (error.code === '23514') {
throw new CheckIntegrityConstraintViolationError(error.constraint);
}
throw error;
} finally {
const end = process.hrtime(start);
// eslint-disable-next-line flowtype/no-weak-types
const payload: Object = {
executionTime: prettyHrtime(end),
queryId,
rowCount,
sql: strippedSql
};
if (SLONIK_LOG_STACK_TRACE) {
payload.stackTrace = stackTrace;
}
if (SLONIK_LOG_VALUES) {
payload.values = values;
}
if (SLONIK_LOG_NORMALISED) {
payload.normalized = normalized;
}
log.debug(payload, 'query');
}
};
/**
* Makes a query and expects exactly one result.
*
* @throws NotFoundError If query returns no rows.
* @throws DataIntegrityError If query returns multiple rows.
*/
export const one: InternalQueryOneFunctionType = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
const {
rows
} = await query(connection, clientConfiguration, rawSql, values, queryId);
if (rows.length === 0) {
log.error({
queryId
}, 'NotFoundError');
throw new NotFoundError();
}
if (rows.length > 1) {
log.error({
queryId
}, 'DataIntegrityError');
throw new DataIntegrityError();
}
return rows[0];
};
/**
* Makes a query and expects exactly one result.
*
* @throws DataIntegrityError If query returns multiple rows.
*/
export const maybeOne: InternalQueryMaybeOneFunctionType = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
const {
rows
} = await query(connection, clientConfiguration, rawSql, values, queryId);
if (rows.length === 0) {
return null;
}
if (rows.length > 1) {
log.error({
queryId
}, 'DataIntegrityError');
throw new DataIntegrityError();
}
return rows[0];
};
/**
* Makes a query and expects exactly one result.
* Returns value of the first column.
*
* @throws NotFoundError If query returns no rows.
* @throws DataIntegrityError If query returns multiple rows.
*/
export const oneFirst: InternalQueryOneFirstFunctionType = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
const row = await one(connection, clientConfiguration, rawSql, values, queryId);
const keys = Object.keys(row);
if (keys.length !== 1) {
log.error({
queryId
}, 'DataIntegrityError');
throw new DataIntegrityError();
}
return row[keys[0]];
};
/**
* Makes a query and expects exactly one result.
* Returns value of the first column.
*
* @throws DataIntegrityError If query returns multiple rows.
*/
export const maybeOneFirst: InternalQueryMaybeOneFirstFunctionType = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
const row = await maybeOne(connection, clientConfiguration, rawSql, values, queryId);
if (!row) {
return null;
}
const keys = Object.keys(row);
if (keys.length !== 1) {
log.error({
queryId
}, 'DataIntegrityError');
throw new DataIntegrityError();
}
return row[keys[0]];
};
/**
* Makes a query and expects at least 1 result.
*
* @throws NotFoundError If query returns no rows.
*/
export const many: InternalQueryManyFunctionType = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
const {
rows
} = await query(connection, clientConfiguration, rawSql, values, queryId);
if (rows.length === 0) {
log.error({
queryId
}, 'NotFoundError');
throw new NotFoundError();
}
return rows;
};
export const manyFirst: InternalQueryManyFirstFunctionType = async (connection, clientConfigurationType, rawSql, values, queryId = ulid()) => {
const rows = await many(connection, clientConfigurationType, rawSql, values, queryId);
if (rows.length === 0) {
log.error({
queryId
}, 'DataIntegrityError');
throw new DataIntegrityError();
}
const keys = Object.keys(rows[0]);
if (keys.length !== 1) {
log.error({
queryId
}, 'DataIntegrityError');
throw new DataIntegrityError();
}
const firstColumnName = keys[0];
if (typeof firstColumnName !== 'string') {
log.error({
queryId
}, 'DataIntegrityError');
throw new DataIntegrityError();
}
return rows.map((row) => {
return row[firstColumnName];
});
};
/**
* Makes a query and expects any number of results.
*/
export const any: InternalQueryAnyFunctionType = async (connection, clientConfiguration, rawSql, values, queryId = ulid()) => {
const {
rows
} = await query(connection, clientConfiguration, rawSql, values, queryId);
return rows;
};
export const anyFirst: InternalQueryAnyFirstFunctionType = async (connection, clientConfigurationType, rawSql, values, queryId = ulid()) => {
const rows = await any(connection, clientConfigurationType, rawSql, values, queryId);
if (rows.length === 0) {
return [];
}
const keys = Object.keys(rows[0]);
if (keys.length !== 1) {
log.error({
queryId
}, 'DataIntegrityError');
throw new DataIntegrityError();
}
const firstColumnName = keys[0];
if (typeof firstColumnName !== 'string') {
log.error({
queryId
}, 'DataIntegrityError');
throw new DataIntegrityError();
}
return rows.map((row) => {
return row[firstColumnName];
});
};
export const transaction: InternalTransactionFunctionType = async (connection, handler) => {
await connection.query('START TRANSACTION');
try {
const result = await handler(connection);
await connection.query('COMMIT');
return result;
} catch (error) {
await connection.query('ROLLBACK');
log.error({
error: serializeError(error)
}, 'rolling back transaction due to an error');
throw error;
}
};
export const createConnection = async (
connectionConfiguration: DatabaseConfigurationType,
clientConfiguration: ClientConfigurationType = defaultClientConfiguration
): Promise<DatabaseSingleConnectionType> => {
const pool = new pg.Pool(typeof connectionConfiguration === 'string' ? parseConnectionString(connectionConfiguration) : connectionConfiguration);
pool.on('error', (error) => {
log.error({
error: serializeError(error)
}, 'client connection error');
});
pool.on('connect', (client) => {
log.info({
processId: client.processID,
stats: {
idleConnectionCount: pool.idleCount,
totalConnectionCount: pool.totalCount,
waitingRequestCount: pool.waitingCount
}
}, 'created a new client connection');
});
pool.on('acquire', (client) => {
log.info({
processId: client.processID,
stats: {
idleConnectionCount: pool.idleCount,
totalConnectionCount: pool.totalCount,
waitingRequestCount: pool.waitingCount
}
}, 'client is checked out from the pool');
});
pool.on('remove', (client) => {
log.info({
processId: client.processID,
stats: {
idleConnectionCount: pool.idleCount,
totalConnectionCount: pool.totalCount,
waitingRequestCount: pool.waitingCount
}
}, 'client connection is closed and removed from the client pool');
});
const connection = await pool.connect();
connection.on('notice', (notice) => {
log.info({
notice
}, 'notice message');
});
let ended = false;
const bindConnection = {
any: mapTaggedTemplateLiteralInvocation(any.bind(null, connection, clientConfiguration)),
anyFirst: mapTaggedTemplateLiteralInvocation(anyFirst.bind(null, connection, clientConfiguration)),
end: async () => {
if (ended) {
return ended;
}
await connection.release();
ended = pool.end();
return ended;
},
many: mapTaggedTemplateLiteralInvocation(many.bind(null, connection, clientConfiguration)),
manyFirst: mapTaggedTemplateLiteralInvocation(manyFirst.bind(null, connection, clientConfiguration)),
maybeOne: mapTaggedTemplateLiteralInvocation(maybeOne.bind(null, connection, clientConfiguration)),
maybeOneFirst: mapTaggedTemplateLiteralInvocation(maybeOneFirst.bind(null, connection, clientConfiguration)),
one: mapTaggedTemplateLiteralInvocation(one.bind(null, connection, clientConfiguration)),
oneFirst: mapTaggedTemplateLiteralInvocation(oneFirst.bind(null, connection, clientConfiguration)),
query: mapTaggedTemplateLiteralInvocation(query.bind(null, connection, clientConfiguration)),
transaction: (handler) => {
return transaction(bindConnection, handler);
}
};
return bindConnection;
};
export const createPool = (
connectionConfiguration: DatabaseConfigurationType,
clientConfiguration: ClientConfigurationType = defaultClientConfiguration
): DatabasePoolType => {
const pool = new pg.Pool(typeof connectionConfiguration === 'string' ? parseConnectionString(connectionConfiguration) : connectionConfiguration);
pool.on('error', (error) => {
log.error({
error: serializeError(error)
}, 'client connection error');
});
pool.on('connect', (client) => {
log.info({
processId: client.processID,
stats: {
idleConnectionCount: pool.idleCount,
totalConnectionCount: pool.totalCount,
waitingRequestCount: pool.waitingCount
}
}, 'created a new client connection');
});
pool.on('acquire', (client) => {
log.info({
processId: client.processID,
stats: {
idleConnectionCount: pool.idleCount,
totalConnectionCount: pool.totalCount,
waitingRequestCount: pool.waitingCount
}
}, 'client is checked out from the pool');
});
pool.on('remove', (client) => {
log.info({
processId: client.processID,
stats: {
idleConnectionCount: pool.idleCount,
totalConnectionCount: pool.totalCount,
waitingRequestCount: pool.waitingCount
}
}, 'client connection is closed and removed from the client pool');
});
const connect = async () => {
const connection = await pool.connect();
connection.on('notice', (notice) => {
log.info({
notice
}, 'notice message');
});
const bindConnection = {
any: mapTaggedTemplateLiteralInvocation(any.bind(null, connection, clientConfiguration)),
anyFirst: mapTaggedTemplateLiteralInvocation(anyFirst.bind(null, connection, clientConfiguration)),
many: mapTaggedTemplateLiteralInvocation(many.bind(null, connection, clientConfiguration)),
manyFirst: mapTaggedTemplateLiteralInvocation(manyFirst.bind(null, connection, clientConfiguration)),
maybeOne: mapTaggedTemplateLiteralInvocation(maybeOne.bind(null, connection, clientConfiguration)),
maybeOneFirst: mapTaggedTemplateLiteralInvocation(maybeOneFirst.bind(null, connection, clientConfiguration)),
one: mapTaggedTemplateLiteralInvocation(one.bind(null, connection, clientConfiguration)),
oneFirst: mapTaggedTemplateLiteralInvocation(oneFirst.bind(null, connection, clientConfiguration)),
query: mapTaggedTemplateLiteralInvocation(query.bind(null, connection, clientConfiguration)),
release: connection.release.bind(connection),
transaction: (handler) => {
return transaction(bindConnection, handler);
}
};
return bindConnection;
};
return {
any: mapTaggedTemplateLiteralInvocation(any.bind(null, pool, clientConfiguration)),
anyFirst: mapTaggedTemplateLiteralInvocation(anyFirst.bind(null, pool, clientConfiguration)),
connect,
many: mapTaggedTemplateLiteralInvocation(many.bind(null, pool, clientConfiguration)),
manyFirst: mapTaggedTemplateLiteralInvocation(manyFirst.bind(null, pool, clientConfiguration)),
maybeOne: mapTaggedTemplateLiteralInvocation(maybeOne.bind(null, pool, clientConfiguration)),
maybeOneFirst: mapTaggedTemplateLiteralInvocation(maybeOneFirst.bind(null, pool, clientConfiguration)),
one: mapTaggedTemplateLiteralInvocation(one.bind(null, pool, clientConfiguration)),
oneFirst: mapTaggedTemplateLiteralInvocation(oneFirst.bind(null, pool, clientConfiguration)),
query: mapTaggedTemplateLiteralInvocation(query.bind(null, pool, clientConfiguration)),
transaction: async (handler) => {
log.debug('allocating a new connection to execute the transaction');
const connection = await connect();
let result;
try {
result = await connection.transaction(handler);
} finally {
log.debug('releasing the connection that was earlier secured to execute a transaction');
await connection.release();
}
return result;
}
};
};
createConnection,
createPool
} from './factories';
// @flow
/* eslint-disable no-use-before-define, import/exports-last */
/* eslint-disable no-use-before-define, import/exports-last, flowtype/require-types-at-top */
type FieldType = {
import type {
LoggerType
} from 'roarr';
export type {
LoggerType
};
export opaque type QueryIdType = string;
type FieldType = {|
+columnID: number,

@@ -13,5 +23,5 @@ +dataTypeID: number,

+tableID: number
};
|};
type QueryResultType<T> = {
type QueryResultType<T> = {|
+command: 'DELETE' | 'INSERT' | 'SELECT' | 'UPDATE',

@@ -23,7 +33,10 @@ +fields: $ReadOnlyArray<FieldType>,

+rows: $ReadOnlyArray<T>
};
|};
// eslint-disable-next-line flowtype/no-weak-types
type InternalDatabaseConnectionType = any;
export type InternalDatabasePoolType = any;
// eslint-disable-next-line flowtype/no-weak-types
export type InternalDatabaseConnectionType = any;
export type ClientConfigurationType = {|

@@ -47,3 +60,3 @@ +interceptors?: $ReadOnlyArray<InterceptorType>

export type DatabaseConnectionType = {
export type DatabaseConnectionType = {|
+any: QueryAnyFunctionType<*>,

@@ -57,18 +70,39 @@ +anyFirst: QueryAnyFirstFunctionType<*>,

+oneFirst: QueryOneFirstFunctionType<*>,
+query: QueryFunctionType<*>,
+transaction: TransactionFunctionType
};
+query: QueryFunctionType<*>
|};
export type DatabaseSingleConnectionType = {
end: () => Promise<void>
} & DatabaseConnectionType;
export type DatabaseTransactionConnectionType = {|
...DatabaseConnectionType
|};
export type DatabasePoolConnectionType = DatabaseConnectionType & {
+release: () => Promise<void>
};
export type TransactionFunctionType = (connection: DatabaseTransactionConnectionType) => Promise<*>;
export type DatabasePoolType = DatabaseConnectionType & {
+connect: () => Promise<DatabasePoolConnectionType>
};
export type DatabaseSingleConnectionType = {|
...DatabaseConnectionType,
+end: () => Promise<void>,
+transaction: (handler: TransactionFunctionType) => Promise<*>
|};
export type DatabasePoolConnectionType = {|
...DatabaseConnectionType,
+release: () => Promise<void>,
+transaction: (handler: TransactionFunctionType) => Promise<*>
|};
export type DatabaseIsolatedPoolConnectionType = {|
...DatabaseConnectionType,
+transaction: (handler: TransactionFunctionType) => Promise<*>
|};
// @todo Document `((connection: DatabaseIsolatedPoolConnectionType) => Promise<void>) => Promise<void>` API.
type DataPoolConnectMethodType =
() => Promise<DatabasePoolConnectionType> &
((connection: DatabaseIsolatedPoolConnectionType) => Promise<void>) => Promise<void>;
export type DatabasePoolType = {|
...DatabaseConnectionType,
+connect: DataPoolConnectMethodType,
+transaction: (handler: TransactionFunctionType) => Promise<*>
|};
type QueryResultRowColumnType = string | number;

@@ -113,8 +147,9 @@

export type TaggledTemplateLiteralInvocationType = {
export type TaggledTemplateLiteralInvocationType = {|
sql: string,
values: $ReadOnlyArray<AnonymouseValuePlaceholderValueType>
};
|};
export type InternalQueryAnyFunctionType = (
export type InternalQueryMethodType<R> = (
log: LoggerType,
connection: InternalDatabaseConnectionType,

@@ -124,78 +159,37 @@ clientConfiguration: ClientConfigurationType,

values?: DatabaseQueryValuesType,
queryId?: string
) => Promise<$ReadOnlyArray<QueryResultRowType>>;
queryId?: QueryIdType
) => Promise<R>;
export type InternalQueryAnyFirstFunctionType = (
connection: InternalDatabaseConnectionType,
clientConfiguration: ClientConfigurationType,
sql: string,
values?: DatabaseQueryValuesType,
queryId?: string
) => Promise<$ReadOnlyArray<QueryResultRowColumnType>>;
export type InternalQueryAnyFirstFunctionType = InternalQueryMethodType<$ReadOnlyArray<QueryResultRowColumnType>>;
export type InternalQueryAnyFunctionType = InternalQueryMethodType<$ReadOnlyArray<QueryResultRowType>>;
export type InternalQueryFunctionType<T: QueryResultRowType> = InternalQueryMethodType<QueryResultType<T>>;
export type InternalQueryManyFirstFunctionType = InternalQueryMethodType<$ReadOnlyArray<QueryResultRowColumnType>>;
export type InternalQueryManyFunctionType = InternalQueryMethodType<$ReadOnlyArray<QueryResultRowType>>;
export type InternalQueryMaybeOneFirstFunctionType = InternalQueryMethodType<QueryResultRowColumnType | null>;
export type InternalQueryMaybeOneFunctionType = InternalQueryMethodType<QueryResultRowType | null>;
export type InternalQueryOneFirstFunctionType = InternalQueryMethodType<QueryResultRowColumnType>;
export type InternalQueryOneFunctionType = InternalQueryMethodType<QueryResultRowType>;
export type InternalQueryManyFunctionType = (
export type InternalTransactionFunctionType = (
log: LoggerType,
connection: InternalDatabaseConnectionType,
clientConfiguration: ClientConfigurationType,
sql: string,
values?: DatabaseQueryValuesType,
queryId?: string
) => Promise<$ReadOnlyArray<QueryResultRowType>>;
handler: TransactionFunctionType
) => Promise<*>;
export type InternalQueryManyFirstFunctionType = (
connection: InternalDatabaseConnectionType,
clientConfiguration: ClientConfigurationType,
sql: string,
values?: DatabaseQueryValuesType,
queryId?: string
) => Promise<$ReadOnlyArray<QueryResultRowColumnType>>;
type QueryMethodType<R> = (
sql: string | TaggledTemplateLiteralInvocationType,
values?: DatabaseQueryValuesType
) => Promise<R>;
export type InternalQueryMaybeOneFirstFunctionType = (
connection: InternalDatabaseConnectionType,
clientConfiguration: ClientConfigurationType,
sql: string,
values?: DatabaseQueryValuesType,
queryId?: string
) => Promise<QueryResultRowColumnType | null>;
export type QueryAnyFirstFunctionType<T: QueryResultRowColumnType> = QueryMethodType<$ReadOnlyArray<T>>;
export type QueryAnyFunctionType<T: QueryResultRowType> = QueryMethodType<$ReadOnlyArray<T>>;
export type QueryFunctionType<T: QueryResultRowType> = QueryMethodType<T>;
export type QueryManyFirstFunctionType<T: QueryResultRowColumnType> = QueryMethodType<$ReadOnlyArray<T>>;
export type QueryManyFunctionType<T: QueryResultRowType> = QueryMethodType<$ReadOnlyArray<T>>;
export type QueryMaybeOneFirstFunctionType<T: QueryResultRowColumnType> = QueryMethodType<T>;
export type QueryMaybeOneFunctionType<T: QueryResultRowType | null> = QueryMethodType<T>;
export type QueryOneFirstFunctionType<T: QueryResultRowColumnType> = QueryMethodType<T>;
export type QueryOneFunctionType<T: QueryResultRowType> = QueryMethodType<T>;
export type InternalQueryMaybeOneFunctionType = (
connection: InternalDatabaseConnectionType,
clientConfiguration: ClientConfigurationType,
sql: string,
values?: DatabaseQueryValuesType,
queryId?: string
) => Promise<QueryResultRowType | null>;
export type InternalQueryOneFirstFunctionType = (
connection: InternalDatabaseConnectionType,
clientConfiguration: ClientConfigurationType,
sql: string,
values?: DatabaseQueryValuesType,
queryId?: string
) => Promise<QueryResultRowColumnType>;
export type InternalQueryOneFunctionType = (
connection: InternalDatabaseConnectionType,
clientConfiguration: ClientConfigurationType,
sql: string,
values?: DatabaseQueryValuesType,
queryId?: string
) => Promise<QueryResultRowType>;
export type TransactionHandlerType = (connection: DatabaseConnectionType) => Promise<*>;
export type InternalTransactionFunctionType = (connection: InternalDatabaseConnectionType, handler: TransactionHandlerType) => Promise<*>;
export type InternalQueryFunctionType<T: QueryResultRowType> = (connection: InternalDatabaseConnectionType, clientConfiguration: ClientConfigurationType, sql: string, values?: DatabaseQueryValuesType, queryId?: string) => Promise<QueryResultType<T>>;
export type QueryAnyFirstFunctionType<T: QueryResultRowColumnType> = (sql: string | TaggledTemplateLiteralInvocationType, values?: DatabaseQueryValuesType) => Promise<$ReadOnlyArray<T>>;
export type QueryAnyFunctionType<T: QueryResultRowType> = (sql: string | TaggledTemplateLiteralInvocationType, values?: DatabaseQueryValuesType) => Promise<$ReadOnlyArray<T>>;
export type QueryManyFirstFunctionType<T: QueryResultRowColumnType> = (sql: string | TaggledTemplateLiteralInvocationType, values?: DatabaseQueryValuesType) => Promise<$ReadOnlyArray<T>>;
export type QueryManyFunctionType<T: QueryResultRowType> = (sql: string | TaggledTemplateLiteralInvocationType, values?: DatabaseQueryValuesType) => Promise<$ReadOnlyArray<T>>;
export type QueryMaybeOneFirstFunctionType<T: QueryResultRowColumnType> = (sql: string | TaggledTemplateLiteralInvocationType, values?: DatabaseQueryValuesType) => Promise<T>;
export type QueryMaybeOneFunctionType<T: QueryResultRowType | null> = (sql: string | TaggledTemplateLiteralInvocationType, values?: DatabaseQueryValuesType) => Promise<T>;
export type QueryOneFirstFunctionType<T: QueryResultRowColumnType> = (sql: string | TaggledTemplateLiteralInvocationType, values?: DatabaseQueryValuesType) => Promise<T>;
export type QueryOneFunctionType<T: QueryResultRowType> = (sql: string | TaggledTemplateLiteralInvocationType, values?: DatabaseQueryValuesType) => Promise<T>;
export type QueryFunctionType<T: QueryResultRowType> = (sql: string | TaggledTemplateLiteralInvocationType, values?: DatabaseQueryValuesType) => Promise<QueryResultType<T>>;
export type TransactionFunctionType = (handler: TransactionHandlerType) => Promise<*>;
export type InterceptorType = {|

@@ -202,0 +196,0 @@ +beforeQuery?: (query: QueryType) => Promise<QueryResultType<QueryResultRowType>> | Promise<void> | QueryResultType<QueryResultRowType> | void,

// @flow
export {default as createQueryId} from './createQueryId';
export {default as createUlid} from './createUlid';
export {default as escapeIdentifier} from './escapeIdentifier';

@@ -4,0 +6,0 @@ export {default as mapTaggedTemplateLiteralInvocation} from './mapTaggedTemplateLiteralInvocation';

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc