@remix-run/data-table-postgres 0.4.0 → 0.5.1

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 CHANGED
@@ -1,13 +1,12 @@
1
1
  # data-table-postgres
2
2
 
3
- PostgreSQL adapter for [`remix/data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table).
4
- Use this package when you want `data-table` APIs backed by `pg`.
3
+ PostgreSQL database driver for [`remix/data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table), backed by `pg`.
5
4
 
6
5
  ## Features
7
6
 
8
- - **Native `pg` Integration**: Works with `pg` `Pool` and `PoolClient` instances
7
+ - **Native `pg` Integration**: Creates a pool from `pg` configuration or uses an existing pool or client
9
8
  - **Full `data-table` API Support**: Queries, relations, writes, and transactions
10
- - **Adapter-Owned Compiler**: SQL compilation lives in this adapter, with optional shared pure helpers from `data-table`
9
+ - **PostgreSQL Compiler**: SQL compilation is handled automatically for PostgreSQL
11
10
  - **Multi-Statement Migrations**: `executeScript()` runs `up.sql` / `down.sql` files natively via `pg`
12
11
  - **Postgres Capabilities Enabled By Default**:
13
12
  - `returning: true`
@@ -25,21 +24,20 @@ npm i remix pg
25
24
  ## Usage
26
25
 
27
26
  ```ts
28
- import { Pool } from 'pg'
29
- import { createDatabase } from 'remix/data-table'
30
- import { createPostgresDatabaseAdapter } from 'remix/data-table/postgres'
27
+ import { createPostgresDatabase } from 'remix/data-table/postgres'
31
28
 
32
- let pool = new Pool({
29
+ let db = createPostgresDatabase({
33
30
  connectionString: process.env.DATABASE_URL,
34
31
  })
35
-
36
- let db = createDatabase(createPostgresDatabaseAdapter(pool))
37
32
  ```
38
33
 
39
- Use `db.query(...)`, relation loading, and transactions from `remix/data-table`.
40
- Import any driver-specific types you need directly from `pg`.
34
+ Use `db.query(...)`, relation loading, and transactions from `remix/data-table`. Import any driver-specific types you need directly from `pg`.
35
+
36
+ Config-backed databases support `db.wipe()` and `db.reset()`. Call `await db.close()` during application shutdown to close the internally created pool. You may pass an existing `pg` pool or client when your application owns the driver lifecycle; `db.close()` leaves supplied clients alone, and destructive lifecycle methods are unavailable in that mode. `db.wipe()` requires a database name resolvable from the connection config (`database`, the path of `connectionString`, or the `PGDATABASE` environment variable) and throws when none is present.
41
37
 
42
- ## Adapter Capabilities
38
+ Migration runs reserve one connection for the PostgreSQL advisory lock, migration SQL, and journal updates. Lock acquisition waits up to 60 seconds (via `lock_timeout`) and fails with an error instead of blocking forever. After a successful run the connection is unlocked and returned to the pool; if the migration or unlock fails, the reserved connection is destroyed instead of being reused, so a dirty session can never leak back into the pool. Nested migration lock acquisition throws instead of deadlocking.
39
+
40
+ ## Database Capabilities
43
41
 
44
42
  `data-table-postgres` reports this capability set by default:
45
43
 
@@ -53,7 +51,7 @@ Import any driver-specific types you need directly from `pg`.
53
51
 
54
52
  ### Transaction Options
55
53
 
56
- Transaction options are passed through to the adapter as hints.
54
+ Transaction options are passed through to PostgreSQL as hints.
57
55
 
58
56
  ```ts
59
57
  await db.transaction(async (txDb) => txDb.exec('select 1'), {
@@ -62,12 +60,38 @@ await db.transaction(async (txDb) => txDb.exec('select 1'), {
62
60
  })
63
61
  ```
64
62
 
63
+ ## Running integration tests locally
64
+
65
+ To start a local Postgres container matching CI:
66
+
67
+ ```sh
68
+ podman run --name postgres \
69
+ -e POSTGRES_USER=postgres \
70
+ -e POSTGRES_PASSWORD=postgres \
71
+ -e POSTGRES_DB=remix \
72
+ -p 5432:5432 \
73
+ -d postgres:16
74
+ ```
75
+
76
+ Then run:
77
+
78
+ ```sh
79
+ REMIX_DATA_TABLE_POSTGRES_TEST_URL=postgres://postgres:postgres@127.0.0.1:5432/remix \
80
+ pnpm test src/lib/driver.integration.test.ts
81
+ ```
82
+
83
+ Remove the container when you are done:
84
+
85
+ ```sh
86
+ podman rm -f postgres
87
+ ```
88
+
65
89
  ## Related Packages
66
90
 
67
91
  - [`data-table`](https://github.com/remix-run/remix/tree/main/packages/data-table) - Core query/relations API
68
92
  - [`data-schema`](https://github.com/remix-run/remix/tree/main/packages/data-schema) - Schema parsing and validation
69
- - [`data-table-mysql`](https://github.com/remix-run/remix/tree/main/packages/data-table-mysql) - MySQL adapter
70
- - [`data-table-sqlite`](https://github.com/remix-run/remix/tree/main/packages/data-table-sqlite) - SQLite adapter
93
+ - [`data-table-mysql`](https://github.com/remix-run/remix/tree/main/packages/data-table-mysql) - MySQL database driver
94
+ - [`data-table-sqlite`](https://github.com/remix-run/remix/tree/main/packages/data-table-sqlite) - SQLite database driver
71
95
 
72
96
  ## License
73
97
 
package/dist/index.d.ts CHANGED
@@ -1,2 +1,4 @@
1
- export { createPostgresDatabaseAdapter, PostgresDatabaseAdapter } from './lib/adapter.ts';
1
+ export { createPostgresDatabase, PostgresDatabase } from './lib/database.ts';
2
+ export type { PostgresDatabaseOptions } from './lib/database.ts';
3
+ export type { PostgresDatabaseInput } from './lib/driver.ts';
2
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,6BAA6B,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAC5E,YAAY,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAChE,YAAY,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA"}
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export { createPostgresDatabaseAdapter, PostgresDatabaseAdapter } from "./lib/adapter.js";
1
+ export { createPostgresDatabase, PostgresDatabase } from './lib/database.js';
@@ -0,0 +1,35 @@
1
+ import { Database, type DatabaseOptions } from '@remix-run/data-table';
2
+ import { type PostgresDatabaseInput } from './driver.ts';
3
+ /** Options for creating a PostgreSQL database. */
4
+ export interface PostgresDatabaseOptions extends DatabaseOptions {
5
+ /** Database used while dropping and recreating the configured database (`postgres` by default). */
6
+ maintenanceDatabase?: string;
7
+ /** Template used to recreate the configured database (`template0` by default). */
8
+ template?: string;
9
+ }
10
+ /** A {@link Database} backed by PostgreSQL. */
11
+ export declare class PostgresDatabase extends Database<'postgres'> {
12
+ /**
13
+ * Creates a PostgreSQL-backed database.
14
+ * @param input PostgreSQL pool configuration, pool, or client.
15
+ * @param options Database runtime and recreation options.
16
+ */
17
+ constructor(input: PostgresDatabaseInput, options?: PostgresDatabaseOptions);
18
+ }
19
+ /**
20
+ * Creates a PostgreSQL-backed database.
21
+ *
22
+ * @param input PostgreSQL pool configuration, pool, or client.
23
+ * @param options Database runtime and recreation options.
24
+ * @returns A PostgreSQL database.
25
+ * @example
26
+ * ```ts
27
+ * import { createPostgresDatabase } from 'remix/data-table/postgres'
28
+ *
29
+ * let db = createPostgresDatabase({
30
+ * connectionString: process.env.DATABASE_URL,
31
+ * })
32
+ * ```
33
+ */
34
+ export declare function createPostgresDatabase(input: PostgresDatabaseInput, options?: PostgresDatabaseOptions): PostgresDatabase;
35
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAEtE,OAAO,EAA0B,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAEhF,kDAAkD;AAClD,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC9D,mGAAmG;IACnG,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,+CAA+C;AAC/C,qBAAa,gBAAiB,SAAQ,QAAQ,CAAC,UAAU,CAAC;IACxD;;;;OAIG;IACH,YAAY,KAAK,EAAE,qBAAqB,EAAE,OAAO,GAAE,uBAA4B,EAE9E;CACF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,qBAAqB,EAC5B,OAAO,GAAE,uBAA4B,GACpC,gBAAgB,CAElB"}
@@ -0,0 +1,31 @@
1
+ import { Database } from '@remix-run/data-table';
2
+ import { PostgresDatabaseDriver } from './driver.js';
3
+ /** A {@link Database} backed by PostgreSQL. */
4
+ export class PostgresDatabase extends Database {
5
+ /**
6
+ * Creates a PostgreSQL-backed database.
7
+ * @param input PostgreSQL pool configuration, pool, or client.
8
+ * @param options Database runtime and recreation options.
9
+ */
10
+ constructor(input, options = {}) {
11
+ super(new PostgresDatabaseDriver(input, options), options);
12
+ }
13
+ }
14
+ /**
15
+ * Creates a PostgreSQL-backed database.
16
+ *
17
+ * @param input PostgreSQL pool configuration, pool, or client.
18
+ * @param options Database runtime and recreation options.
19
+ * @returns A PostgreSQL database.
20
+ * @example
21
+ * ```ts
22
+ * import { createPostgresDatabase } from 'remix/data-table/postgres'
23
+ *
24
+ * let db = createPostgresDatabase({
25
+ * connectionString: process.env.DATABASE_URL,
26
+ * })
27
+ * ```
28
+ */
29
+ export function createPostgresDatabase(input, options = {}) {
30
+ return new PostgresDatabase(input, options);
31
+ }
@@ -1,26 +1,36 @@
1
- import type { DataManipulationRequest, DataManipulationResult, DataManipulationOperation, DatabaseAdapter, SqlStatement, TableRef, TransactionOptions, TransactionToken } from '@remix-run/data-table';
1
+ import type { DataManipulationOperation, DataManipulationRequest, DataManipulationResult, DatabaseDriver, SqlStatement, TableRef, TransactionOptions, TransactionToken } from '@remix-run/data-table';
2
+ import pg from 'pg';
2
3
  import type { Client as PostgresClient, Pool as PostgresPool, PoolClient as PostgresPoolClient } from 'pg';
4
+ type PostgresPoolConfig = ConstructorParameters<typeof pg.Pool>[0];
5
+ /** Database recreation options for a config-backed PostgreSQL driver. */
6
+ export interface PostgresDatabaseDriverOptions {
7
+ /** Database used while dropping and recreating the configured database (`postgres` by default). */
8
+ maintenanceDatabase?: string;
9
+ /** Template used to recreate the configured database (`template0` by default). */
10
+ template?: string;
11
+ }
3
12
  type PostgresQueryable = PostgresClient | PostgresPool | PostgresPoolClient;
13
+ export type PostgresDatabaseInput = PostgresPoolConfig | PostgresQueryable;
4
14
  /**
5
- * `DatabaseAdapter` implementation for postgres-compatible clients.
15
+ * PostgreSQL database driver backed by a postgres-compatible client.
6
16
  */
7
- export declare class PostgresDatabaseAdapter implements DatabaseAdapter {
17
+ export declare class PostgresDatabaseDriver implements DatabaseDriver<'postgres'> {
8
18
  #private;
9
19
  /**
10
- * The SQL dialect identifier reported by this adapter.
20
+ * The SQL dialect identifier reported by this database.
11
21
  */
12
- dialect: string;
22
+ get dialect(): 'postgres';
13
23
  /**
14
- * Feature flags describing the postgres behaviors supported by this adapter.
24
+ * Feature flags describing the PostgreSQL behaviors supported by this database.
15
25
  */
16
- capabilities: {
17
- returning: boolean;
18
- savepoints: boolean;
19
- upsert: boolean;
20
- transactionalDdl: boolean;
21
- migrationLock: boolean;
22
- };
23
- constructor(client: PostgresQueryable);
26
+ get capabilities(): Readonly<{
27
+ returning: true;
28
+ savepoints: true;
29
+ upsert: true;
30
+ transactionalDdl: true;
31
+ migrationLock: true;
32
+ }>;
33
+ constructor(config: PostgresDatabaseInput, options?: PostgresDatabaseDriverOptions);
24
34
  /**
25
35
  * Compiles a data-manipulation operation to postgres SQL statements.
26
36
  * @param operation Operation to compile.
@@ -98,32 +108,24 @@ export declare class PostgresDatabaseAdapter implements DatabaseAdapter {
98
108
  */
99
109
  releaseSavepoint(token: TransactionToken, name: string): Promise<void>;
100
110
  /**
101
- * Acquires the postgres migration lock.
102
- * @returns A promise that resolves when the lock is acquired.
111
+ * Destructively recreates the configured PostgreSQL database.
112
+ * @returns A promise that resolves when the database is ready for use.
103
113
  */
104
- acquireMigrationLock(): Promise<void>;
114
+ wipe(): Promise<void>;
115
+ /** Closes a pool created from configuration. Supplied clients and pools remain caller-owned. */
116
+ close(): Promise<void>;
105
117
  /**
106
- * Releases the postgres migration lock.
107
- * @returns A promise that resolves when the lock is released.
118
+ * Runs migration work on the postgres connection that owns the advisory lock.
119
+ *
120
+ * Lock acquisition waits up to 60 seconds and throws when the lock cannot
121
+ * be acquired. Re-entering this method from inside `run` throws instead of
122
+ * deadlocking, and a failed run destroys the reserved connection instead of
123
+ * returning it to the pool.
124
+ * @param name Logical migration lock name.
125
+ * @param run Migration work to run with a connection-bound driver.
126
+ * @returns The callback result.
108
127
  */
109
- releaseMigrationLock(): Promise<void>;
128
+ withMigrationLock<result>(name: string, run: (driver: DatabaseDriver<'postgres'>) => Promise<result>): Promise<result>;
110
129
  }
111
- /**
112
- * Creates a postgres `DatabaseAdapter`.
113
- * @param client `pg` pool or pool client.
114
- * @param options Optional adapter capability overrides.
115
- * @returns A configured postgres adapter.
116
- * @example
117
- * ```ts
118
- * import { Pool } from 'pg'
119
- * import { createDatabase } from 'remix/data-table'
120
- * import { createPostgresDatabaseAdapter } from 'remix/data-table/postgres'
121
- *
122
- * let pool = new Pool({ connectionString: process.env.DATABASE_URL })
123
- * let adapter = createPostgresDatabaseAdapter(pool)
124
- * let db = createDatabase(adapter)
125
- * ```
126
- */
127
- export declare function createPostgresDatabaseAdapter(client: PostgresQueryable): PostgresDatabaseAdapter;
128
130
  export {};
129
- //# sourceMappingURL=adapter.d.ts.map
131
+ //# sourceMappingURL=driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/lib/driver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,uBAAuB,EACvB,sBAAsB,EACtB,cAAc,EACd,YAAY,EACZ,QAAQ,EACR,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,uBAAuB,CAAA;AAI9B,OAAO,EAAE,MAAM,IAAI,CAAA;AACnB,OAAO,KAAK,EACV,MAAM,IAAI,cAAc,EACxB,IAAI,IAAI,YAAY,EACpB,UAAU,IAAI,kBAAkB,EACjC,MAAM,IAAI,CAAA;AASX,KAAK,kBAAkB,GAAG,qBAAqB,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;AAGlE,yEAAyE;AACzE,MAAM,WAAW,6BAA6B;IAC5C,mGAAmG;IACnG,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,KAAK,iBAAiB,GAAG,cAAc,GAAG,YAAY,GAAG,kBAAkB,CAAA;AAU3E,MAAM,MAAM,qBAAqB,GAAG,kBAAkB,GAAG,iBAAiB,CAAA;AAE1E;;GAEG;AACH,qBAAa,sBAAuB,YAAW,cAAc,CAAC,UAAU,CAAC;;IACvE;;OAEG;IACH,IAAI,OAAO,IAAI,UAAU,CAExB;IAED;;OAEG;IACH,IAAI,YAAY;;;;;;OAEf;IAYD,YAAY,MAAM,EAAE,qBAAqB,EAAE,OAAO,GAAE,6BAAkC,EAUrF;IAED;;;;OAIG;IACH,UAAU,CAAC,SAAS,EAAE,yBAAyB,GAAG,YAAY,EAAE,CAG/D;IAED;;;;OAIG;IACG,OAAO,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAuB/E;IAED;;;;;;;;OAQG;IACG,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAG9E;IAED;;;;;OAKG;IACG,QAAQ,CAAC,KAAK,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAMhF;IAED;;;;;;OAMG;IACG,SAAS,CACb,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,MAAM,EACd,WAAW,CAAC,EAAE,gBAAgB,GAC7B,OAAO,CAAC,OAAO,CAAC,CASlB;IAED;;;;OAIG;IACG,gBAAgB,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAiC9E;IAED;;;;OAIG;IACG,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwB9D;IAED;;;;OAIG;IACG,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBhE;IAED;;;;;OAKG;IACG,eAAe,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1E;IAED;;;;;OAKG;IACG,mBAAmB,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG9E;IAED;;;;;OAKG;IACG,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG3E;IAED;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CA+B1B;IAED,gGAAgG;IAC1F,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAK3B;IAED;;;;;;;;;;OAUG;IACG,iBAAiB,CAAC,MAAM,EAC5B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,GAC3D,OAAO,CAAC,MAAM,CAAC,CAiDjB;CAmEF"}