Comparing version 13.1.0 to 13.1.1
@@ -40,6 +40,6 @@ { | ||
"eslint": "^5.13.0", | ||
"eslint-config-canonical": "^16.0.0", | ||
"eslint-config-canonical": "^16.1.0", | ||
"flow-bin": "^0.92.1", | ||
"flow-copy-source": "^2.0.2", | ||
"gitdown": "^2.5.5", | ||
"gitdown": "^2.5.7", | ||
"husky": "^1.3.1", | ||
@@ -97,3 +97,3 @@ "nyc": "^13.2.0", | ||
}, | ||
"version": "13.1.0" | ||
"version": "13.1.1" | ||
} |
321
README.md
@@ -10,3 +10,3 @@ <a name="slonik"></a> | ||
A PostgreSQL client with strict types, detail logging and assertions. | ||
A [battle-tested](#battled-tested) PostgreSQL client with strict types, detail logging and assertions. | ||
@@ -49,7 +49,37 @@ <a name="slonik-features"></a> | ||
* [Using `sql.raw` to generate dynamic queries](#slonik-recipes-using-sql-raw-to-generate-dynamic-queries) | ||
* [Logs query parameter values](#logs-query-parameter-values) | ||
* [Conventions](#logs-query-parameter-values-conventions) | ||
* [No multiline values](#logs-query-parameter-values-conventions-no-multiline-values) | ||
* [Syntax highlighting](#logs-query-parameter-values-syntax-highlighting) | ||
* [Atom](#logs-query-parameter-values-syntax-highlighting-atom) | ||
* [Battle-Tested](#slonik-battle-tested) | ||
* [Origin of the name](#slonik-origin-of-the-name) | ||
* [Conventions](#slonik-conventions) | ||
* [No multiline values](#slonik-conventions-no-multiline-values) | ||
* [Value placeholders](#slonik-value-placeholders) | ||
* [Tagged template literals](#slonik-value-placeholders-tagged-template-literals) | ||
* [`sql.set`](#slonik-value-placeholders-sql-set) | ||
* [`sql.multiset`](#slonik-value-placeholders-sql-multiset) | ||
* [`sql.identifier`](#slonik-value-placeholders-sql-identifier) | ||
* [`sql.raw`](#slonik-value-placeholders-sql-raw) | ||
* [Query methods](#slonik-query-methods) | ||
* [`any`](#slonik-query-methods-any) | ||
* [`anyFirst`](#slonik-query-methods-anyfirst) | ||
* [`insert`](#slonik-query-methods-insert) | ||
* [`many`](#slonik-query-methods-many) | ||
* [`manyFirst`](#slonik-query-methods-manyfirst) | ||
* [`maybeOne`](#slonik-query-methods-maybeone) | ||
* [`maybeOneFirst`](#slonik-query-methods-maybeonefirst) | ||
* [`one`](#slonik-query-methods-one) | ||
* [`oneFirst`](#slonik-query-methods-onefirst) | ||
* [`query`](#slonik-query-methods-query) | ||
* [`transaction`](#slonik-query-methods-transaction) | ||
* [Error handling](#slonik-error-handling) | ||
* [Handling `NotFoundError`](#slonik-error-handling-handling-notfounderror) | ||
* [Handling `DataIntegrityError`](#slonik-error-handling-handling-dataintegrityerror) | ||
* [Handling `NotNullIntegrityConstraintViolationError`](#slonik-error-handling-handling-notnullintegrityconstraintviolationerror) | ||
* [Handling `ForeignKeyIntegrityConstraintViolationError`](#slonik-error-handling-handling-foreignkeyintegrityconstraintviolationerror) | ||
* [Handling `UniqueIntegrityConstraintViolationError`](#slonik-error-handling-handling-uniqueintegrityconstraintviolationerror) | ||
* [Handling `CheckIntegrityConstraintViolationError`](#slonik-error-handling-handling-checkintegrityconstraintviolationerror) | ||
* [Types](#slonik-types) | ||
* [Debugging](#slonik-debugging) | ||
* [Logging](#slonik-debugging-logging) | ||
* [Log stack trace](#slonik-debugging-log-stack-trace) | ||
* [Syntax highlighting](#slonik-syntax-highlighting) | ||
* [Atom](#slonik-syntax-highlighting-atom) | ||
@@ -97,3 +127,6 @@ | ||
```js | ||
createPool(connectionConfiguration: DatabaseConfigurationType, clientConfiguration: ClientConfigurationType): DatabasePoolType; | ||
createPool( | ||
connectionConfiguration: DatabaseConfigurationType, | ||
clientConfiguration: ClientConfigurationType | ||
): DatabasePoolType; | ||
@@ -139,3 +172,3 @@ type DatabaseConnectionUriType = string; | ||
Slonik only allows to check out a connection for the duration of the promise routine supplied to the `connect()` method. | ||
Slonik only allows to check out a connection for the duration of the promise routine supplied to the `pool#connect()` method. | ||
@@ -205,7 +238,27 @@ ```js | ||
Functionality can be added to Slonik client by adding interceptors. | ||
Functionality can be added to Slonik client by adding interceptors (middleware). | ||
Each interceptor can implement several functions which can be used to change the behaviour of the database client. | ||
Interceptors are configured using [client configuration](#slonik-usage-configuration), e.g. | ||
```js | ||
import { | ||
createPool | ||
} from 'slonik'; | ||
const interceptors = []; | ||
const connection = createPool('postgres://', { | ||
interceptors | ||
}); | ||
``` | ||
Interceptors are executed in the order they are added. | ||
<a name="slonik-interceptors-interceptor-methods"></a> | ||
### Interceptor methods | ||
Interceptors implement methods that are used to change the behaviour of the database client at different stages of the connection life-cycle: | ||
```js | ||
type InterceptorType = {| | ||
@@ -231,26 +284,6 @@ +afterPoolConnection?: (connection: DatabasePoolConnectionType) => MaybePromiseType<void>, | ||
Interceptors are configured using [client configuration](#slonik-usage-configuration), e.g. | ||
```js | ||
import { | ||
createPool | ||
} from 'slonik'; | ||
const interceptors = []; | ||
const connection = createPool('postgres://', { | ||
interceptors | ||
}); | ||
``` | ||
Interceptors are executed in the order they are added. | ||
<a name="slonik-interceptors-interceptor-methods"></a> | ||
### Interceptor methods | ||
<a name="slonik-interceptors-interceptor-methods-afterpoolconnection"></a> | ||
#### <code>afterPoolConnection</code> | ||
Executed after a connection is , e.g. | ||
Executed after a connection is acquired from the connection pool (or a new connection is created), e.g. | ||
@@ -500,6 +533,64 @@ ```js | ||
.map((column) => { | ||
return column + ' = | ||
return column + ' = $' + placeholderIndex++; | ||
}) | ||
.join(' AND '); | ||
}) | ||
.join(' OR '); | ||
const values = []; | ||
for (const pairValues of uniquePairs) { | ||
values.push(...pairValues); | ||
} | ||
const query = sql` | ||
SELECT | ||
id | ||
FROM foo | ||
WHERE | ||
${sql.raw(whereConditionSql, values)} | ||
`; | ||
await connection.any(query); | ||
``` | ||
In the above example, `query` is: | ||
```js | ||
{ | ||
sql: 'SELECT id FROM foo WHERE (a = $1 AND b = $2) OR (a = $3 AND b = $4)', | ||
values: [ | ||
'a', | ||
1, | ||
'b', | ||
2 | ||
] | ||
} | ||
``` | ||
Multiple `sql.raw` fragments can be used to create a query. | ||
<a name="slonik-battle-tested"></a> | ||
## Battle-Tested | ||
Slonik began as a collection of utilities designed for working with [`node-postgres`](https://github.com/brianc/node-postgres). We continue to use `node-postgres` as it provides a robust foundation for interacting with PostgreSQL. However, what once was a collection of utilities has since grown into a framework that abstracts repeating code patterns, protects against unsafe connection handling and value interpolation, and provides rich debugging experience. | ||
Slonik has been [battle-tested](https://medium.com/@gajus/lessons-learned-scaling-postgresql-database-to-1-2bn-records-month-edc5449b3067) with large data volumes and queries ranging from simple CRUD operations to data-warehousing needs. | ||
<a name="slonik-origin-of-the-name"></a> | ||
## Origin of the name | ||
![Slonik](./.README/postgresql-elephant.png) | ||
The name of the elephant depicted in the official PostgreSQL logo is Slonik. The name itself is derived from the Russian word for "little elephant". | ||
Read: [The History of Slonik, the PostgreSQL Elephant Logo](https://www.vertabelo.com/blog/notes-from-the-lab/the-history-of-slonik-the-postgresql-elephant-logo) | ||
<a name="slonik-conventions"></a> | ||
## Conventions | ||
<a name="slonik-conventions-no-multiline-values"></a> | ||
### No multiline values | ||
@@ -526,4 +617,6 @@ | ||
<a name="slonik-value-placeholders"></a> | ||
## Value placeholders | ||
<a name="slonik-value-placeholders-tagged-template-literals"></a> | ||
### Tagged template literals | ||
@@ -557,3 +650,4 @@ | ||
### `sql.set` | ||
<a name="slonik-value-placeholders-sql-set"></a> | ||
### <code>sql.set</code> | ||
@@ -588,3 +682,4 @@ ```js | ||
### `sql.multiset` | ||
<a name="slonik-value-placeholders-sql-multiset"></a> | ||
### <code>sql.multiset</code> | ||
@@ -625,3 +720,4 @@ ```js | ||
### `sql.identifier` | ||
<a name="slonik-value-placeholders-sql-identifier"></a> | ||
### <code>sql.identifier</code> | ||
@@ -653,3 +749,4 @@ ```js | ||
### `sql.raw` | ||
<a name="slonik-value-placeholders-sql-raw"></a> | ||
### <code>sql.raw</code> | ||
@@ -703,5 +800,7 @@ ```js | ||
<a name="slonik-query-methods"></a> | ||
## Query methods | ||
### `any` | ||
<a name="slonik-query-methods-any"></a> | ||
### <code>any</code> | ||
@@ -719,3 +818,4 @@ Returns result rows. | ||
### `anyFirst` | ||
<a name="slonik-query-methods-anyfirst"></a> | ||
### <code>anyFirst</code> | ||
@@ -733,3 +833,4 @@ Returns value of the first column of every row in the result set. | ||
### `insert` | ||
<a name="slonik-query-methods-insert"></a> | ||
### <code>insert</code> | ||
@@ -749,3 +850,4 @@ Used when inserting 1 row. | ||
### `many` | ||
<a name="slonik-query-methods-many"></a> | ||
### <code>many</code> | ||
@@ -763,3 +865,4 @@ Returns result rows. | ||
### `manyFirst` | ||
<a name="slonik-query-methods-manyfirst"></a> | ||
### <code>manyFirst</code> | ||
@@ -778,3 +881,4 @@ Returns value of the first column of every row in the result set. | ||
### `maybeOne` | ||
<a name="slonik-query-methods-maybeone"></a> | ||
### <code>maybeOne</code> | ||
@@ -795,3 +899,4 @@ Selects the first row from the result. | ||
### `maybeOneFirst` | ||
<a name="slonik-query-methods-maybeonefirst"></a> | ||
### <code>maybeOneFirst</code> | ||
@@ -813,3 +918,4 @@ Returns value of the first column from the first row. | ||
### `one` | ||
<a name="slonik-query-methods-one"></a> | ||
### <code>one</code> | ||
@@ -837,3 +943,4 @@ Selects the first row from the result. | ||
### `oneFirst` | ||
<a name="slonik-query-methods-onefirst"></a> | ||
### <code>oneFirst</code> | ||
@@ -855,7 +962,9 @@ Returns value of the first column from the first row. | ||
### `query` | ||
<a name="slonik-query-methods-query"></a> | ||
### <code>query</code> | ||
API and the result shape are equivalent to [`pg#query`](https://github.com/brianc/node-postgres). | ||
### `transaction` | ||
<a name="slonik-query-methods-transaction"></a> | ||
### <code>transaction</code> | ||
@@ -879,2 +988,3 @@ `transaction` method is used wrap execution of queries in `START TRANSACTION` and `COMMIT` or `ROLLBACK`. `COMMIT` is called if the transaction handler returns a promise that resolves; `ROLLBACK` is called otherwise. | ||
<a name="slonik-error-handling"></a> | ||
## Error handling | ||
@@ -899,3 +1009,4 @@ | ||
### Handling `NotFoundError` | ||
<a name="slonik-error-handling-handling-notfounderror"></a> | ||
### Handling <code>NotFoundError</code> | ||
@@ -925,3 +1036,4 @@ To handle the case where query returns less than one row, catch `NotFoundError` error. | ||
### Handling `DataIntegrityError` | ||
<a name="slonik-error-handling-handling-dataintegrityerror"></a> | ||
### Handling <code>DataIntegrityError</code> | ||
@@ -949,18 +1061,23 @@ To handle the case where the data result does not match the expectations, catch `DataIntegrityError` error. | ||
### Handling `NotNullIntegrityConstraintViolationError` | ||
<a name="slonik-error-handling-handling-notnullintegrityconstraintviolationerror"></a> | ||
### Handling <code>NotNullIntegrityConstraintViolationError</code> | ||
`NotNullIntegrityConstraintViolationError` is thrown when Postgres responds with [`unique_violation`](https://www.postgresql.org/docs/9.4/static/errcodes-appendix.html) (`23502`) error. | ||
### Handling `ForeignKeyIntegrityConstraintViolationError` | ||
<a name="slonik-error-handling-handling-foreignkeyintegrityconstraintviolationerror"></a> | ||
### Handling <code>ForeignKeyIntegrityConstraintViolationError</code> | ||
`ForeignKeyIntegrityConstraintViolationError` is thrown when Postgres responds with [`unique_violation`](https://www.postgresql.org/docs/9.4/static/errcodes-appendix.html) (`23503`) error. | ||
### Handling `UniqueIntegrityConstraintViolationError` | ||
<a name="slonik-error-handling-handling-uniqueintegrityconstraintviolationerror"></a> | ||
### Handling <code>UniqueIntegrityConstraintViolationError</code> | ||
`UniqueIntegrityConstraintViolationError` is thrown when Postgres responds with [`unique_violation`](https://www.postgresql.org/docs/9.4/static/errcodes-appendix.html) (`23505`) error. | ||
### Handling `CheckIntegrityConstraintViolationError` | ||
<a name="slonik-error-handling-handling-checkintegrityconstraintviolationerror"></a> | ||
### Handling <code>CheckIntegrityConstraintViolationError</code> | ||
`CheckIntegrityConstraintViolationError` is thrown when Postgres responds with [`unique_violation`](https://www.postgresql.org/docs/9.4/static/errcodes-appendix.html) (`23514`) error. | ||
<a name="slonik-types"></a> | ||
## Types | ||
@@ -1003,4 +1120,6 @@ | ||
<a name="slonik-debugging"></a> | ||
## Debugging | ||
<a name="slonik-debugging-logging"></a> | ||
### Logging | ||
@@ -1017,3 +1136,2 @@ | ||
```bash | ||
<a name="logs-query-parameter-values"></a> | ||
# Logs query parameter values | ||
@@ -1024,2 +1142,3 @@ export SLONIK_LOG_VALUES=true | ||
<a name="slonik-debugging-log-stack-trace"></a> | ||
### Log stack trace | ||
@@ -1040,4 +1159,6 @@ | ||
<a name="slonik-syntax-highlighting"></a> | ||
## Syntax highlighting | ||
<a name="slonik-syntax-highlighting-atom"></a> | ||
### Atom | ||
@@ -1056,93 +1177,1 @@ | ||
For more information, refer to the [JavaScript Tagged Template Literal Grammar Extensions](https://github.com/gandm/language-babel#javascript-tagged-template-literal-grammar-extensions) documentation of `language-babel` package. | ||
+ placeholderIndex++; | ||
}) | ||
.join(' AND '); | ||
}) | ||
.join(' OR '); | ||
const values = []; | ||
for (const pairValues of uniquePairs) { | ||
values.push(...pairValues); | ||
} | ||
const query = sql` | ||
SELECT | ||
id | ||
FROM foo | ||
WHERE | ||
${sql.raw(whereConditionSql, values)} | ||
`; | ||
await connection.any(query); | ||
``` | ||
In the above example, `query` is: | ||
```js | ||
{ | ||
sql: 'SELECT id FROM foo WHERE (a = $1 AND b = $2) OR (a = $3 AND b = $4)', | ||
values: [ | ||
'a', | ||
1, | ||
'b', | ||
2 | ||
] | ||
} | ||
``` | ||
Multiple `sql.raw` fragments can be used to create a query. | ||
<a name="logs-query-parameter-values-conventions"></a> | ||
## Conventions | ||
<a name="logs-query-parameter-values-conventions-no-multiline-values"></a> | ||
### No multiline values | ||
Slonik will strip all comments and line-breaks from a query before processing it. | ||
This makes logging of the queries easier. | ||
The implication is that your query cannot contain values that include a newline character, e.g. | ||
```js | ||
// Do not do this | ||
connection.query(sql`INSERT INTO foo (bar) VALUES ('\n')`); | ||
``` | ||
If you want to communicate a value that includes a multiline character, use value placeholder interpolation, e.g. | ||
```js | ||
connection.query(sql`INSERT INTO foo (bar) VALUES (${'\n'})`); | ||
``` | ||
⊂⊂C:5⊃⊃ | ||
⊂⊂C:6⊃⊃ | ||
⊂⊂C:7⊃⊃ | ||
⊂⊂C:8⊃⊃ | ||
<a name="logs-query-parameter-values-syntax-highlighting"></a> | ||
## Syntax highlighting | ||
<a name="logs-query-parameter-values-syntax-highlighting-atom"></a> | ||
### Atom | ||
Using [Atom](https://atom.io/) IDE you can leverage the [`language-babel`](https://github.com/gandm/language-babel) package in combination with the [`language-sql`](https://github.com/atom/language-sql) to enable highlighting of the SQL strings in the codebase. | ||
![Syntax highlighting in Atom](./.README/atom-syntax-highlighting.png) | ||
To enable highlighting, you need to: | ||
1. Install `language-babel` and `language-sql` packages. | ||
1. Configure `language-babel` "JavaScript Tagged Template Literal Grammar Extensions" setting to use `language-sql` to highlight template literals with `sql` tag (configuration value: `sql:source.sql`). | ||
1. Use [`sql` helper to construct the queries](https://github.com/gajus/slonik#tagged-template-literals). | ||
For more information, refer to the [JavaScript Tagged Template Literal Grammar Extensions](https://github.com/gandm/language-babel#javascript-tagged-template-literal-grammar-extensions) documentation of `language-babel` package. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
240076
1147