312 lines
13 KiB
Markdown
312 lines
13 KiB
Markdown
# Options and configuration
|
|
|
|
## `neon(...)` function
|
|
|
|
The `neon(...)` function returns a query function that can be used both as a tagged-template function and as an ordinary function:
|
|
|
|
```typescript
|
|
import { neon } from '@neondatabase/serverless';
|
|
const sql = neon(process.env.DATABASE_URL);
|
|
|
|
// as a tagged-template function
|
|
const rowsA = await sql`SELECT * FROM posts WHERE id = ${postId}`;
|
|
|
|
// as an ordinary function (exactly equivalent)
|
|
const rowsB = await sql('SELECT * FROM posts WHERE id = $1', [postId]);
|
|
```
|
|
|
|
By default, the query function returned by `neon(...)` returns only the rows resulting from the provided SQL query, and it returns them as an array of objects where the keys are column names. For example:
|
|
|
|
```typescript
|
|
import { neon } from '@neondatabase/serverless';
|
|
const sql = neon(process.env.DATABASE_URL);
|
|
const rows = await sql`SELECT * FROM posts WHERE id = ${postId}`;
|
|
// -> [{ id: 12, title: "My post", ... }]
|
|
```
|
|
|
|
However, you can customise the return format of the query function using the configuration options `fullResults` and `arrayMode`. These options are available both on the `neon(...)` function and on the query function it returns (but only when the query function is called as an ordinary function, not as a tagged-template function).
|
|
|
|
### `arrayMode: boolean`
|
|
|
|
When `arrayMode` is true, rows are returned as an array of arrays instead of an array of objects:
|
|
|
|
```typescript
|
|
import { neon } from '@neondatabase/serverless';
|
|
const sql = neon(process.env.DATABASE_URL, { arrayMode: true });
|
|
const rows = await sql`SELECT * FROM posts WHERE id = ${postId}`;
|
|
// -> [[12, "My post", ...]]
|
|
```
|
|
|
|
Or, with the same effect:
|
|
|
|
```typescript
|
|
import { neon } from '@neondatabase/serverless';
|
|
const sql = neon(process.env.DATABASE_URL);
|
|
const rows = await sql('SELECT * FROM posts WHERE id = $1', [postId], {
|
|
arrayMode: true,
|
|
});
|
|
// -> [[12, "My post", ...]]
|
|
```
|
|
|
|
### `fullResults: boolean`
|
|
|
|
When `fullResults` is true, additional metadata is returned alongside the result rows, which are then found in the `rows` property of the return value. The metadata matches what would be returned by node-postgres:
|
|
|
|
```typescript
|
|
import { neon } from '@neondatabase/serverless';
|
|
const sql = neon(process.env.DATABASE_URL, { fullResults: true });
|
|
const results = await sql`SELECT * FROM posts WHERE id = ${postId}`;
|
|
/* -> {
|
|
rows: [{ id: 12, title: "My post", ... }],
|
|
fields: [
|
|
{ name: "id", dataTypeID: 23, ... },
|
|
{ name: "title", dataTypeID: 25, ... },
|
|
...
|
|
],
|
|
rowCount: 1,
|
|
rowAsArray: false,
|
|
command: "SELECT"
|
|
}
|
|
*/
|
|
```
|
|
|
|
Or, with the same effect:
|
|
|
|
```typescript
|
|
import { neon } from '@neondatabase/serverless';
|
|
const sql = neon(process.env.DATABASE_URL);
|
|
const results = await sql('SELECT * FROM posts WHERE id = $1', [postId], {
|
|
fullResults: true,
|
|
});
|
|
// -> { ... same as above ... }
|
|
```
|
|
|
|
### `fetchOptions: Record<string, any>`
|
|
|
|
The `fetchOptions` option can be passed to `neon(...)`, the `transaction` function, or the query function (if not within a `transaction` function). This option takes an object that is merged with the options to the `fetch` call.
|
|
|
|
For example, to increase the priority of every database `fetch` request:
|
|
|
|
```typescript
|
|
import { neon } from '@neondatabase/serverless';
|
|
const sql = neon(process.env.DATABASE_URL, {
|
|
fetchOptions: { priority: 'high' },
|
|
});
|
|
const rows = await sql`SELECT * FROM posts WHERE id = ${postId}`;
|
|
```
|
|
|
|
Or to implement a `fetch` timeout:
|
|
|
|
```typescript
|
|
import { neon } from '@neondatabase/serverless';
|
|
const sql = neon(process.env.DATABASE_URL);
|
|
const abortController = new AbortController();
|
|
const timeout = setTimeout(() => abortController.abort('timed out'), 10000);
|
|
const rows = await sql('SELECT * FROM posts WHERE id = $1', [postId], {
|
|
fetchOptions: { signal: abortController.signal },
|
|
}); // throws an error if no result received within 10s
|
|
clearTimeout(timeout);
|
|
```
|
|
|
|
### `authToken: string | (() => Promise<string> | string)`
|
|
|
|
The `authToken` option can be passed to `neon(...)` to set the `Authorization` header for the `fetch` request. This allows you to authenticate database requests against third-party authentication providers. So, this mechanism can be used to ensure that access control and authorization are managed effectively across different systems.
|
|
|
|
Example of usage:
|
|
|
|
```typescript
|
|
import { neon } from '@neondatabase/serverless';
|
|
// Retrieve the JWT token (implementation depends on your auth system)
|
|
const authToken = getAuthToken();
|
|
// Initialize the Neon client with a connection string and auth token
|
|
const sql = neon(process.env.DATABASE_URL, { authToken });
|
|
// Run a query
|
|
const posts = await sql('SELECT * FROM posts');
|
|
```
|
|
|
|
## `transaction(...)` function
|
|
|
|
The `transaction(queriesOrFn, options)` function is exposed as a property on the query function. It allows multiple queries to be executed within a single, non-interactive transaction.
|
|
|
|
The first argument to `transaction()`, `queriesOrFn`, is either (1) an array of queries or (2) a non-`async` function that receives a query function as its argument and returns an array of queries.
|
|
|
|
The array-of-queries case looks like this:
|
|
|
|
```javascript
|
|
import { neon } from '@neondatabase/serverless';
|
|
const sql = neon(process.env.DATABASE_URL);
|
|
const showLatestN = 10;
|
|
|
|
const [posts, tags] = await sql.transaction(
|
|
[
|
|
sql`SELECT * FROM posts ORDER BY posted_at DESC LIMIT ${showLatestN}`,
|
|
sql`SELECT * FROM tags`,
|
|
],
|
|
{
|
|
isolationLevel: 'RepeatableRead',
|
|
readOnly: true,
|
|
},
|
|
);
|
|
```
|
|
|
|
Or as an example of the function case:
|
|
|
|
```javascript
|
|
const [authors, tags] = await neon(process.env.DATABASE_URL).transaction(
|
|
(txn) => [txn`SELECT * FROM authors`, txn`SELECT * FROM tags`],
|
|
);
|
|
```
|
|
|
|
The optional second argument to `transaction()`, `options`, has the same keys as the options to the ordinary query function -- `arrayMode`, `fullResults` and `fetchOptions` -- plus three additional keys that concern the transaction configuration. These transaction-related keys are: `isolationMode`, `readOnly` and `deferrable`. They are described below. Defaults for the transaction-related keys can also be set as options to the `neon` function.
|
|
|
|
The `fetchOptions` option cannot be supplied for individual queries inside `transaction()`, since only a single `fetch` is performed for the transaction as a whole. The TypeScript types also currently do not allow `arrayMode` or `fullResults` options to be supplied for individual queries within `transaction()` (although this does have the expected effect if the type errors are ignored).
|
|
|
|
### `isolationMode`
|
|
|
|
This option selects a Postgres [transaction isolation mode](https://www.postgresql.org/docs/current/transaction-iso.html). If present, it must be one of: `'ReadUncommitted'`, `'ReadCommitted'`, `'RepeatableRead'` or `'Serializable'`.
|
|
|
|
### `readOnly`
|
|
|
|
If `true`, this option ensures that a `READ ONLY` transaction is used to execute the queries passed.
|
|
|
|
### `deferrable`
|
|
|
|
If `true` (and if `readOnly` is also `true`, and `isolationMode` is `'Serializable'`), this option ensures that a `DEFERRABLE` transaction is used to execute the queries passed.
|
|
|
|
## `neonConfig` configuration
|
|
|
|
In most cases, there are two ways to set configuration options:
|
|
|
|
1. Import `neonConfig` from the package and set global default options on that.
|
|
2. Set options on individual `Client` instances using their `neonConfig` property.
|
|
|
|
For example:
|
|
|
|
```javascript
|
|
import { Client, neonConfig } from '@neondatabase/serverless';
|
|
import ws from 'ws';
|
|
|
|
// set default option for all clients
|
|
neonConfig.webSocketConstructor = ws;
|
|
|
|
// override the default option on an individual client
|
|
const client = new Client(process.env.DATABASE_URL);
|
|
client.neonConfig.webSocketConstructor = ws;
|
|
```
|
|
|
|
A few configuration options can only be set globally, and these are noted as such below.
|
|
|
|
#### `webSocketConstructor: typeof WebSocket | undefined`
|
|
|
|
Set this parameter if you're using the driver in an environment where the `WebSocket` global is not defined, such as Node.js, and you need transaction or session support.
|
|
|
|
For example:
|
|
|
|
```javascript
|
|
import { neonConfig } from '@neondatabase/serverless';
|
|
import ws from 'ws';
|
|
neonConfig.webSocketConstructor = ws;
|
|
```
|
|
|
|
### Advanced configuration
|
|
|
|
If you're using `@neondatabase/serverless` to connect to a Neon database, you usually **won't** need to touch the following configuration options. These options are intended for testing, troubleshooting, and supporting access to non-Neon Postgres instances via self-hosted WebSocket proxies.
|
|
|
|
#### `poolQueryViaFetch: boolean`
|
|
|
|
**Experimentally**, when `poolQueryViaFetch` is `true` and no listeners for the `"connect"`, `"acquire"`, `"release"` or `"remove"` events are set on the `Pool`, queries via `Pool.query()` will be sent by low-latency HTTP `fetch` request.
|
|
|
|
Default: currently `false` (but may be `true` in future).
|
|
|
|
Note: this option can only be set globally, **not** on an individual `Client` instance.
|
|
|
|
#### `fetchEndpoint: string | ((host: string, port: number | string) => string)`
|
|
|
|
Set `fetchEndpoint` to set the server endpoint to be sent queries via http fetch.
|
|
|
|
This may be useful for local development (e.g. to set a port that's not the default 443).
|
|
|
|
Provide either the full endpoint URL, or a function that takes the database host address and port and returns the full endpoint URL (including protocol).
|
|
|
|
Default: `host => 'https://' + host + '/sql'`
|
|
|
|
Note: this option can only be set globally, **not** on an individual `Client` instance.
|
|
|
|
#### `fetchFunction: any`
|
|
|
|
The `fetchFunction` option allows you to supply an alternative function for making http requests. The function must accept the same arguments as native `fetch`.
|
|
|
|
Default: `undefined`.
|
|
|
|
Note: this option can only be set globally, **not** on an individual `Client` instance.
|
|
|
|
#### `wsProxy: string | (host: string, port: number | string) => string`
|
|
|
|
If connecting to a non-Neon database, the `wsProxy` option should point to [your WebSocket proxy](DEPLOY.md). It can either be a string, which will have `?address=host:port` appended to it, or a function with the signature `(host: string, port: number | string) => string`. Either way, the protocol must _not_ be included, because this depends on other options. For example, when using the `wsproxy` proxy, the `wsProxy` option should look something like this:
|
|
|
|
```javascript
|
|
// either:
|
|
neonConfig.wsProxy = (host, port) =>
|
|
`my-wsproxy.example.com/v1?address=${host}:${port}`;
|
|
// or (with identical effect):
|
|
neonConfig.wsProxy = 'my-wsproxy.example.com/v1';
|
|
```
|
|
|
|
Default: `host => host + '/v2'`.
|
|
|
|
#### `pipelineConnect: "password" | false`
|
|
|
|
To speed up connection times, the driver will pipeline the first three messages to the database (startup, authentication and first query) if `pipelineConnect` is set to `"password"`. Note that this will only work if you've configured cleartext password authentication for the relevant user and database.
|
|
|
|
If your connection doesn't support password authentication, set `pipelineConnect` to `false` instead.
|
|
|
|
Default: `"password"`.
|
|
|
|
#### `coalesceWrites: boolean`
|
|
|
|
When this option is `true`, multiple network writes generated in a single iteration of the JavaScript run-loop are coalesced into a single WebSocket message. Since node-postgres sends a lot of very short messages, this may reduce TCP/IP overhead.
|
|
|
|
Default: `true`.
|
|
|
|
#### `forceDisablePgSSL: boolean`
|
|
|
|
This option disables TLS encryption in the Postgres protocol (as set via e.g. `?sslmode=require` in the connection string). Security is not compromised if used in conjunction with `useSecureWebSocket = true`.
|
|
|
|
Default: `true`.
|
|
|
|
#### `useSecureWebSocket: boolean`
|
|
|
|
This option switches between secure (the default) and insecure WebSockets.
|
|
|
|
To use experimental pure-JS encryption, set `useSecureWebSocket = false` and `forceDisablePgSSL = false`, and append `?sslmode=verify-full` to your database connection string.
|
|
|
|
**Remember that pure-JS encryption is currently experimental and not suitable for use in production.**
|
|
|
|
Default: `true`.
|
|
|
|
#### `subtls: any`
|
|
|
|
**Only when using experimental pure-JS TLS encryption**, you must supply the [subtls](https://github.com/jawj/subtls) TLS library to the `subtls` option like so:
|
|
|
|
```typescript
|
|
import { neonConfig } from '@neondatabase/serverless';
|
|
import * as subtls from 'subtls';
|
|
neonConfig.subtls = subtls;
|
|
```
|
|
|
|
Default: `undefined`.
|
|
|
|
#### `rootCerts: string /* PEM format */`
|
|
|
|
**Only when using experimental pure-JS TLS encryption**, the `rootCerts` option determines what root (certificate authority) certificates are trusted.
|
|
|
|
Its value is a string containing zero or more certificates in PEM format.
|
|
|
|
Default: `""` (the empty string).
|
|
|
|
#### `pipelineTLS: boolean`
|
|
|
|
**Only when using experimental pure-JS encryption**, the driver will pipeline the SSL request message and TLS Client Hello if `pipelineTLS` is set to `true`. Currently, this is only supported by Neon database hosts, and will fail when communicating with an ordinary Postgres or pgbouncer back-end.
|
|
|
|
Default: `false`.
|