@adrdp/pg-rest 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +184 -2
- package/dist/adapter-SqPs6SuJ.d.ts +27 -0
- package/dist/adapters/bun.d.ts +22 -0
- package/dist/adapters/bun.js +22 -0
- package/dist/adapters/node-postgres.d.ts +27 -0
- package/dist/adapters/node-postgres.js +34 -0
- package/dist/adapters/pglite.d.ts +24 -0
- package/dist/adapters/pglite.js +20 -0
- package/dist/adapters/postgres-js.d.ts +24 -0
- package/dist/adapters/postgres-js.js +21 -0
- package/dist/index.d.ts +259 -0
- package/dist/index.js +3549 -0
- package/package.json +87 -4
package/README.md
CHANGED
|
@@ -1,3 +1,185 @@
|
|
|
1
|
-
#
|
|
1
|
+
# pg-rest
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A [PostgREST](https://postgrest.org) (v16 behaviour) reimplementation as a **library**: a web-standard
|
|
4
|
+
`handle(Request) => Promise<Response>` on top of a tiny database-adapter interface.
|
|
5
|
+
|
|
6
|
+
- **Runtime-agnostic.** The core uses only web standards (`Request`/`Response`/`Headers`) and has no driver and no runtime API
|
|
7
|
+
of its own. It is tested on Bun and Node.js 22 and should run anywhere your Postgres driver does.
|
|
8
|
+
- **Bring your own driver.** You create the driver and pass it in through a small adapter. Adapters for
|
|
9
|
+
Bun.sql, node-postgres, postgres.js and PGlite ship as separate entry points (`pg-rest/adapters/*`); the drivers are
|
|
10
|
+
*optional peer dependencies*, so you only install the one you use.
|
|
11
|
+
- **No JWT and no server.** You decide who the caller is (cookie, API key, session, mTLS…) and hand pg-rest a role, claims and
|
|
12
|
+
settings; they are applied per request with `set_config`, so Postgres Row Level Security sees them exactly as it would behind PostgREST.
|
|
13
|
+
|
|
14
|
+
## Quick start
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm i pg-rest pg # or: bun add pg-rest (Bun.sql is built in), postgres, @electric-sql/pglite
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import pg from "pg";
|
|
22
|
+
import { createPgRest } from "pg-rest";
|
|
23
|
+
import { nodePostgresAdapter } from "pg-rest/adapters/node-postgres";
|
|
24
|
+
|
|
25
|
+
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
|
|
26
|
+
|
|
27
|
+
const pgRest = await createPgRest({
|
|
28
|
+
db: nodePostgresAdapter(pool), // you create and close the driver
|
|
29
|
+
schemas: ["api"], // first one is the default schema
|
|
30
|
+
anonymousRole: "anon",
|
|
31
|
+
resolveContext: async (req) => {
|
|
32
|
+
const user = await mySessionLookup(req);
|
|
33
|
+
return user ? { role: "authenticated", claims: { sub: user.id, email: user.email } } : undefined;
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// any host that speaks Request/Response:
|
|
38
|
+
// Bun: Bun.serve({ fetch: (req) => pgRest.handle(req) })
|
|
39
|
+
// Node: serve({ fetch: (req) => pgRest.handle(req) }) // @hono/node-server (or srvx, ...)
|
|
40
|
+
// Hono: app.all("/api/*", (c) => pgRest.handle(c.req.raw))
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Examples
|
|
44
|
+
|
|
45
|
+
Self-contained projects in [`examples/`](examples) (a todo API with Row Level Security; each has its own README, schema and `server.ts`):
|
|
46
|
+
|
|
47
|
+
| example | runtime | driver | needs a database server |
|
|
48
|
+
| --- | --- | --- | --- |
|
|
49
|
+
| [`with-bun`](examples/with-bun) | Bun | `Bun.sql` (built in) | yes (docker-compose included) |
|
|
50
|
+
| [`with-node-postgres`](examples/with-node-postgres) | Node.js ≥ 22.18 | `pg` | yes (docker-compose included) |
|
|
51
|
+
| [`with-postgres-js`](examples/with-postgres-js) | Node.js ≥ 22.18 | `postgres` | yes (docker-compose included) |
|
|
52
|
+
| [`with-pglite`](examples/with-pglite) | Node.js ≥ 22.18 | `@electric-sql/pglite` | no (Postgres in WebAssembly) |
|
|
53
|
+
| [`with-better-auth`](examples/with-better-auth) | Node.js ≥ 22.18 | `pg` + [Better Auth](https://better-auth.com) sessions | yes (docker-compose included) |
|
|
54
|
+
|
|
55
|
+
## Database adapters
|
|
56
|
+
|
|
57
|
+
`db` is a `DbAdapter` — the only thing pg-rest needs from a driver:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
interface DbAdapter {
|
|
61
|
+
query(text: string, params?: (string | null)[]): Promise<Record<string, unknown>[]>;
|
|
62
|
+
transaction<A>(fn: (session: { query: DbAdapter["query"] }) => Promise<A>): Promise<A>; // one connection, BEGIN/COMMIT/ROLLBACK
|
|
63
|
+
close?(): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
| import | wraps | peer dependency |
|
|
68
|
+
| --- | --- | --- |
|
|
69
|
+
| `pg-rest/adapters/bun` → `bunSqlAdapter(sql)` | `new SQL(url)` from `"bun"` | none (built into Bun) |
|
|
70
|
+
| `pg-rest/adapters/node-postgres` → `nodePostgresAdapter(pool)` | `new pg.Pool(...)` | `pg` ≥ 8 |
|
|
71
|
+
| `pg-rest/adapters/postgres-js` → `postgresJsAdapter(sql)` | `postgres(url)` | `postgres` ≥ 3 |
|
|
72
|
+
| `pg-rest/adapters/pglite` → `pgliteAdapter(db)` | `new PGlite()` | `@electric-sql/pglite` |
|
|
73
|
+
|
|
74
|
+
The adapters are structural (they never import the driver; you pass the client in), so a project only loads the code it imports.
|
|
75
|
+
To support another driver, implement the interface above (about 20 lines) — the adapter sources in `src/adapters` are good templates.
|
|
76
|
+
|
|
77
|
+
Parameters are always text with an explicit `$n::text` cast in the SQL, so no type inference is needed. Database errors are recognised
|
|
78
|
+
by SQLSTATE (`code`, `errno` or `sqlState` on the thrown error), so adapters don't have to translate them. pg-rest never closes your
|
|
79
|
+
driver; `pgRest.close()` only stops the handler.
|
|
80
|
+
|
|
81
|
+
In SQL, policies read the same GUCs as with PostgREST:
|
|
82
|
+
|
|
83
|
+
```sql
|
|
84
|
+
CREATE POLICY own ON api.notes USING (owner = (current_setting('request.jwt.claims', true)::json ->> 'sub'));
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Performance
|
|
88
|
+
|
|
89
|
+
[`bench/`](bench) load-tests pg-rest against the real PostgREST 16 on the same database, data and pool size, after checking that both return identical
|
|
90
|
+
results. In a small 2-vCPU sandbox pg-rest on Bun was on par with or faster than PostgREST in every scenario, and slower on a few of the cheapest ones
|
|
91
|
+
when run on Node (it also uses more memory); the benchmark includes `bun build --compile`, `--bytecode` and `bun compile` variants; see [`bench/README.md`](bench/README.md) for the numbers, the caveats and how to run it on your own hardware.
|
|
92
|
+
|
|
93
|
+
### Which runtime?
|
|
94
|
+
|
|
95
|
+
Numbers from one run on a small 2-vCPU sandbox (indicative only; see the benchmark README). Throughput is relative to PostgREST 16.
|
|
96
|
+
|
|
97
|
+
| | Bun (`bun run`) | Bun, compiled (`bun compile`, experimental) | Node + `pg` |
|
|
98
|
+
| --- | --- | --- | --- |
|
|
99
|
+
| Throughput | 1.2–1.5× on most reads, ~2× on writes | same as plain Bun (within noise) | 0.7–0.9× on the cheapest queries, ahead on heavier ones |
|
|
100
|
+
| Peak memory | ~80 MB | ~50 MB | ~125 MB |
|
|
101
|
+
| Setup | nothing extra | single executable; needs a recent (canary) Bun | Node (tested on 22) |
|
|
102
|
+
| Pick it when | you can run Bun (default choice) | memory or deployment size matters and you accept an experimental feature | Bun is not an option |
|
|
103
|
+
|
|
104
|
+
`bun build --compile` and `--bytecode` performed like plain Bun, so they are only worth it if you want a single binary. PostgREST itself uses the least memory (about 40–47 MB).
|
|
105
|
+
|
|
106
|
+
## Options
|
|
107
|
+
|
|
108
|
+
| option | meaning |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| `db` | a `DbAdapter` built from your driver (see [Database adapters](#database-adapters)) |
|
|
111
|
+
| `schemas` | exposed schemas; selected with `Accept-Profile` / `Content-Profile` |
|
|
112
|
+
| `anonymousRole` | role when no context is resolved (`PGRST302` if unset and none given); `false` refuses anonymous requests |
|
|
113
|
+
| `planEnabled` | allow `Accept: application/vnd.pgrst.plan` (EXPLAIN output); off by default, like `db-plan-enabled` |
|
|
114
|
+
| `resolveContext(req)` | return `{ role, claims, settings }`; throw `PgRestError` to reject (e.g. 401) |
|
|
115
|
+
| `handle(req, ctx?)` | an explicit context overrides `resolveContext` |
|
|
116
|
+
| `maxRows` | cap on rows returned |
|
|
117
|
+
| `basePath` | URL prefix to strip |
|
|
118
|
+
| `extraSearchPath` | extra schemas appended to `search_path` |
|
|
119
|
+
| `requestSettings` | set `request.method/path/headers/cookies` GUCs (default on) |
|
|
120
|
+
| `preRequest` | SQL function name or `(session, info) => void`, run inside the request transaction |
|
|
121
|
+
| `allowTxOverride` | honour `Prefer: tx=rollback` |
|
|
122
|
+
| `openApi` | serve the Swagger 2.0 document at `/` |
|
|
123
|
+
|
|
124
|
+
Also returned: `reloadSchema()` (call after migrations), `schemaCache()`, `close()`.
|
|
125
|
+
|
|
126
|
+
## Supported
|
|
127
|
+
|
|
128
|
+
Reads with embedding (m2o, o2m, o2o, m2m, aliases, hints, `!inner`, spread of to-one, nested, filters/order/limit on embeds),
|
|
129
|
+
all filter operators and `and/or/not`, JSON paths, casts, aggregates, ordering, `Range`/`limit`/`offset`,
|
|
130
|
+
spread of to-many, order by related column, embedding through views and computed relationships, aggregates in embeds,
|
|
131
|
+
`Prefer: count=exact|planned|estimated`, inserts (bulk, `columns`, `missing=default`), upsert, PATCH, PUT, DELETE,
|
|
132
|
+
`return=` / `handling=` / `max-affected` / `timezone` / `tx`, RPC (GET/POST, overloads, `VARIADIC`, bulk calls, set/scalar/void, unnamed json arg,
|
|
133
|
+
response GUC headers/status), CSV / singular / `nulls=stripped` / plan representations, custom media type handlers (domains and aggregates named after a media type), `application/geo+json` (with PostGIS), `WWW-Authenticate` on 401, OpenAPI, PostgREST error codes
|
|
134
|
+
and `PTxyz` / `RAISE ... SQLSTATE 'PGRST'` conventions.
|
|
135
|
+
|
|
136
|
+
## Not supported
|
|
137
|
+
|
|
138
|
+
Two different things are listed here. Don't confuse them.
|
|
139
|
+
|
|
140
|
+
### By design: will not be implemented
|
|
141
|
+
|
|
142
|
+
pg-rest is a library, not a server. Anything whose job is to run the process, authenticate the caller, or configure PostgREST from outside the
|
|
143
|
+
code is handled by *your* application instead. These are not gaps: adding them would work against the goals of the project.
|
|
144
|
+
|
|
145
|
+
| PostgREST feature | Why pg-rest doesn't do it | What to do instead |
|
|
146
|
+
| --- | --- | --- |
|
|
147
|
+
| JWT validation, JWKS, `jwt-secret`, audience, role claim path | The point of the project is that **you** decide who the caller is, by any means: a session cookie, an API key, Better Auth, mTLS. Baking JWT in would force one scheme and add crypto and key-rotation code (and dependencies) to the library. | `resolveContext(req)` or `handle(req, ctx)` returns `{ role, claims, settings }`. pg-rest applies it with `set_config`, so RLS and `current_setting('request.jwt.claims')` work as usual. See `examples/with-better-auth`. |
|
|
148
|
+
| Standalone server, CLI, host/port, unix sockets, TLS, `log-level`, `server-timing` | `handle(Request) => Response` is web-standard and runs under `Bun.serve`, Hono (`@hono/node-server`), or any framework that gives you a `Request`... Owning the server would tie the library to one runtime and duplicate what your framework already does. | Mount `handle` in your own server. |
|
|
149
|
+
| Admin server (`/live`, `/ready`, `/metrics`) | Health checks and metrics belong to the host process. | Expose them in your app. |
|
|
150
|
+
| CORS headers | Policy depends on your deployment. | Set them in your server or middleware. |
|
|
151
|
+
| Config file, environment variables, `PGRST_*` settings | Configuration is the `createPgRest(options)` call, which is typed and lives with the code. | Pass options; read env vars yourself. |
|
|
152
|
+
| Connection pool and `db-uri` | The pool belongs to your driver, and the driver is your choice (`DbAdapter`). pg-rest never opens connections. | Create the pool, wrap it in an adapter. |
|
|
153
|
+
| In-database configuration (`db-pre-config`, per-role `ALTER ROLE ... SET pgrst.*`) | Settings are options in code, not rows in the database, so they are versioned and visible with the application. | Use the options; `preRequest` can still call a SQL function if you want database-side logic. |
|
|
154
|
+
| Schema cache refresh over SQL: `NOTIFY pgrst, 'reload schema'` / `db-channel`, `SIGUSR1`/`SIGUSR2`, DDL event triggers | They require a dedicated `LISTEN` connection and signal handling, which a library must not hold open or assume (serverless, PGlite and pooled connections can't `LISTEN`). The introspection itself (`pg_catalog`) is implemented. | Call `reloadSchema()` after migrations, or wire it to your own `LISTEN`. A failed reload keeps the old cache. |
|
|
155
|
+
|
|
156
|
+
## Security notes
|
|
157
|
+
|
|
158
|
+
Request values are never concatenated raw: values become escaped literals or `$n::text` parameters, identifiers are quoted,
|
|
159
|
+
cast targets must match a strict type allowlist, GUC names must be dotted. See `tests/security.test.ts`.
|
|
160
|
+
|
|
161
|
+
## Development
|
|
162
|
+
|
|
163
|
+
`mise.toml` pins the PostgREST binary the differential test needs and runs a throwaway Postgres 16 **with PostGIS**
|
|
164
|
+
(required: the `application/geo+json` cases fail without it). Nothing is installed system-wide.
|
|
165
|
+
|
|
166
|
+
```sh
|
|
167
|
+
bun install
|
|
168
|
+
mise install # PostgREST 16.5, the official static release
|
|
169
|
+
mise run db:start # Postgres 16 + PostGIS under .cache/ (also db:stop, db:reset)
|
|
170
|
+
mise run test # the whole suite, differential and GeoJSON cases included
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Or bring your own Postgres 16 and PostgREST:
|
|
174
|
+
|
|
175
|
+
```sh
|
|
176
|
+
TEST_DATABASE_URL=postgres://user@host:5432/postgres bun test # a server you can create databases on
|
|
177
|
+
POSTGREST_BIN=/path/to/postgrest TEST_DATABASE_URL=... bun run test:compare # see PARITY.md
|
|
178
|
+
bun run typecheck && bun run build
|
|
179
|
+
|
|
180
|
+
# run an example end to end; the second argument is a database URL with the schema loaded
|
|
181
|
+
scripts/check-example.sh with-node-postgres postgres://user@host:5432/mydb
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
The examples depend on `pg-rest` by version, so use `bun run link:examples [name]` to point them at the local
|
|
185
|
+
build; `bun run check:examples` asserts they match the root `package.json`.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/adapter.d.ts
|
|
2
|
+
/** A row returned by the database. */
|
|
3
|
+
type Row = Record<string, unknown>;
|
|
4
|
+
/** Something that can run a single SQL statement. */
|
|
5
|
+
interface DbSession {
|
|
6
|
+
/**
|
|
7
|
+
* Run one statement. Only plain `text` parameters are ever passed, and each
|
|
8
|
+
* one is explicitly cast in SQL (`$1::text`), so adapters need no type
|
|
9
|
+
* inference. Throw a {@link DbQueryError} on database errors.
|
|
10
|
+
*/
|
|
11
|
+
query(text: string, params?: ReadonlyArray<string | null>): Promise<Row[]>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The only thing pg-rest needs from a Postgres driver. Implement it to plug in
|
|
15
|
+
* any driver (Bun.sql, postgres.js, node-postgres, PGlite...).
|
|
16
|
+
*/
|
|
17
|
+
interface DbAdapter extends DbSession {
|
|
18
|
+
/**
|
|
19
|
+
* Run `fn` in a single transaction on one connection. Commit when it
|
|
20
|
+
* resolves, roll back when it throws (and rethrow).
|
|
21
|
+
*/
|
|
22
|
+
transaction<A>(fn: (session: DbSession) => Promise<A>): Promise<A>;
|
|
23
|
+
/** Release resources. Optional. */
|
|
24
|
+
close?(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { DbSession as n, Row as r, DbAdapter as t };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { t as DbAdapter } from "../adapter-SqPs6SuJ.js";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/bun.d.ts
|
|
4
|
+
/** The subset of `Bun.SQL` that is used (structural: no import from "bun" needed). */
|
|
5
|
+
interface BunSqlLike {
|
|
6
|
+
unsafe(query: string, values?: any[]): PromiseLike<any>;
|
|
7
|
+
begin<T>(fn: (tx: BunSqlLike) => Promise<T>): Promise<T>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* pg-rest adapter for Bun's built-in Postgres client.
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { SQL } from "bun";
|
|
14
|
+
* const sql = new SQL(process.env.DATABASE_URL!);
|
|
15
|
+
* const api = await createPgRest({ db: bunSqlAdapter(sql), schemas: ["api"] });
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
declare const bunSqlAdapter: (sql: BunSqlLike & {
|
|
19
|
+
close?(): Promise<void>;
|
|
20
|
+
}) => DbAdapter;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { bunSqlAdapter };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/adapters/bun.ts
|
|
2
|
+
const session = (sql) => ({ async query(text, params) {
|
|
3
|
+
const res = await sql.unsafe(text, params ? [...params] : void 0);
|
|
4
|
+
return Array.from(res);
|
|
5
|
+
} });
|
|
6
|
+
/**
|
|
7
|
+
* pg-rest adapter for Bun's built-in Postgres client.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { SQL } from "bun";
|
|
11
|
+
* const sql = new SQL(process.env.DATABASE_URL!);
|
|
12
|
+
* const api = await createPgRest({ db: bunSqlAdapter(sql), schemas: ["api"] });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
const bunSqlAdapter = (sql) => ({
|
|
16
|
+
query: session(sql).query,
|
|
17
|
+
transaction: (fn) => sql.begin((tx) => fn(session(tx))),
|
|
18
|
+
...sql.close ? { close: () => sql.close() } : {}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { bunSqlAdapter };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { r as Row, t as DbAdapter } from "../adapter-SqPs6SuJ.js";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/node-postgres.d.ts
|
|
4
|
+
/** The subset of node-postgres (`pg`) that is used. */
|
|
5
|
+
interface PgClientLike {
|
|
6
|
+
query(text: string, values?: unknown[]): Promise<{
|
|
7
|
+
rows: Row[];
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
interface PgPoolLike extends PgClientLike {
|
|
11
|
+
connect(): Promise<PgClientLike & {
|
|
12
|
+
release(): void;
|
|
13
|
+
}>;
|
|
14
|
+
end(): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* pg-rest adapter for node-postgres. Works on Node.js, Deno, Bun...
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* import pg from "pg";
|
|
21
|
+
* const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
|
|
22
|
+
* const api = await createPgRest({ db: nodePostgresAdapter(pool), schemas: ["api"] });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare const nodePostgresAdapter: (pool: PgPoolLike) => DbAdapter;
|
|
26
|
+
//#endregion
|
|
27
|
+
export { nodePostgresAdapter };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//#region src/adapters/node-postgres.ts
|
|
2
|
+
const session = (c) => ({ async query(text, params) {
|
|
3
|
+
return (await c.query(text, params ? [...params] : [])).rows;
|
|
4
|
+
} });
|
|
5
|
+
/**
|
|
6
|
+
* pg-rest adapter for node-postgres. Works on Node.js, Deno, Bun...
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import pg from "pg";
|
|
10
|
+
* const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
|
|
11
|
+
* const api = await createPgRest({ db: nodePostgresAdapter(pool), schemas: ["api"] });
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
const nodePostgresAdapter = (pool) => ({
|
|
15
|
+
query: session(pool).query,
|
|
16
|
+
async transaction(fn) {
|
|
17
|
+
const client = await pool.connect();
|
|
18
|
+
try {
|
|
19
|
+
await client.query("BEGIN");
|
|
20
|
+
const out = await fn(session(client));
|
|
21
|
+
await client.query("COMMIT");
|
|
22
|
+
return out;
|
|
23
|
+
} catch (e) {
|
|
24
|
+
await client.query("ROLLBACK").catch(() => {});
|
|
25
|
+
throw e;
|
|
26
|
+
} finally {
|
|
27
|
+
client.release();
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
close: () => pool.end()
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { nodePostgresAdapter };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { r as Row, t as DbAdapter } from "../adapter-SqPs6SuJ.js";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/pglite.d.ts
|
|
4
|
+
/** The subset of PGlite (`@electric-sql/pglite`) that is used. */
|
|
5
|
+
interface PGliteQueryable {
|
|
6
|
+
query(text: string, params?: unknown[]): Promise<{
|
|
7
|
+
rows: Row[];
|
|
8
|
+
}>;
|
|
9
|
+
}
|
|
10
|
+
interface PGliteLike extends PGliteQueryable {
|
|
11
|
+
transaction<T>(fn: (tx: PGliteQueryable) => Promise<T>): Promise<T>;
|
|
12
|
+
close?(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* pg-rest adapter for PGlite (Postgres in WebAssembly): no server, ideal for tests, demos and local-first apps.
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { PGlite } from "@electric-sql/pglite";
|
|
19
|
+
* const api = await createPgRest({ db: pgliteAdapter(new PGlite()), schemas: ["api"] });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
declare const pgliteAdapter: (db: PGliteLike) => DbAdapter;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { pgliteAdapter };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
//#region src/adapters/pglite.ts
|
|
2
|
+
const session = (db) => ({ async query(text, params) {
|
|
3
|
+
return (await db.query(text, params ? [...params] : [])).rows;
|
|
4
|
+
} });
|
|
5
|
+
/**
|
|
6
|
+
* pg-rest adapter for PGlite (Postgres in WebAssembly): no server, ideal for tests, demos and local-first apps.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { PGlite } from "@electric-sql/pglite";
|
|
10
|
+
* const api = await createPgRest({ db: pgliteAdapter(new PGlite()), schemas: ["api"] });
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
const pgliteAdapter = (db) => ({
|
|
14
|
+
query: session(db).query,
|
|
15
|
+
transaction: (fn) => db.transaction((tx) => fn(session(tx))),
|
|
16
|
+
...db.close ? { close: () => db.close() } : {}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
export { pgliteAdapter };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { t as DbAdapter } from "../adapter-SqPs6SuJ.js";
|
|
2
|
+
|
|
3
|
+
//#region src/adapters/postgres-js.d.ts
|
|
4
|
+
/** All that is needed to run a query, inside a transaction or outside one. */
|
|
5
|
+
interface PostgresJsQueryable {
|
|
6
|
+
unsafe(query: string, params?: any[]): PromiseLike<any>;
|
|
7
|
+
}
|
|
8
|
+
/** The subset of postgres.js (`postgres`) that is used. */
|
|
9
|
+
interface PostgresJsLike extends PostgresJsQueryable {
|
|
10
|
+
begin<T>(fn: (tx: PostgresJsQueryable) => Promise<T>): Promise<T>;
|
|
11
|
+
end(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* pg-rest adapter for postgres.js.
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* import postgres from "postgres";
|
|
18
|
+
* const sql = postgres(process.env.DATABASE_URL!);
|
|
19
|
+
* const api = await createPgRest({ db: postgresJsAdapter(sql), schemas: ["api"] });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
declare const postgresJsAdapter: (sql: PostgresJsLike) => DbAdapter;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { postgresJsAdapter };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/adapters/postgres-js.ts
|
|
2
|
+
const session = (sql) => ({ async query(text, params) {
|
|
3
|
+
return Array.from(await sql.unsafe(text, params ? [...params] : []));
|
|
4
|
+
} });
|
|
5
|
+
/**
|
|
6
|
+
* pg-rest adapter for postgres.js.
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* import postgres from "postgres";
|
|
10
|
+
* const sql = postgres(process.env.DATABASE_URL!);
|
|
11
|
+
* const api = await createPgRest({ db: postgresJsAdapter(sql), schemas: ["api"] });
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
const postgresJsAdapter = (sql) => ({
|
|
15
|
+
query: session(sql).query,
|
|
16
|
+
transaction: (fn) => sql.begin((tx) => fn(session(tx))),
|
|
17
|
+
close: () => sql.end()
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
//#endregion
|
|
21
|
+
export { postgresJsAdapter };
|