pgsql-test 2.6.1 → 2.6.3

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/connect.js CHANGED
@@ -46,7 +46,6 @@ const getConnections = async (cn = {}, seedAdapters = [seed_1.seed.launchql()])
46
46
  admin.installExtensions(connOpts.extensions);
47
47
  }
48
48
  await admin.grantConnect(connOpts.connection.user, config.database);
49
- // Main admin client (optional unless needed elsewhere)
50
49
  manager = manager_1.PgTestConnector.getInstance();
51
50
  const pg = manager.getClient(config);
52
51
  if (seedAdapters.length) {
@@ -57,7 +56,6 @@ const getConnections = async (cn = {}, seedAdapters = [seed_1.seed.launchql()])
57
56
  pg: manager.getClient(config)
58
57
  });
59
58
  }
60
- // App user connection
61
59
  const db = manager.getClient({
62
60
  ...config,
63
61
  user: connOpts.connection.user,
@@ -65,6 +63,7 @@ const getConnections = async (cn = {}, seedAdapters = [seed_1.seed.launchql()])
65
63
  });
66
64
  db.setContext({ role: 'anonymous' });
67
65
  const teardown = async () => {
66
+ manager.beginTeardown();
68
67
  await (0, pg_cache_1.teardownPgPools)();
69
68
  await manager.closeAll();
70
69
  };
package/esm/connect.js CHANGED
@@ -42,7 +42,6 @@ export const getConnections = async (cn = {}, seedAdapters = [seed.launchql()])
42
42
  admin.installExtensions(connOpts.extensions);
43
43
  }
44
44
  await admin.grantConnect(connOpts.connection.user, config.database);
45
- // Main admin client (optional unless needed elsewhere)
46
45
  manager = PgTestConnector.getInstance();
47
46
  const pg = manager.getClient(config);
48
47
  if (seedAdapters.length) {
@@ -53,7 +52,6 @@ export const getConnections = async (cn = {}, seedAdapters = [seed.launchql()])
53
52
  pg: manager.getClient(config)
54
53
  });
55
54
  }
56
- // App user connection
57
55
  const db = manager.getClient({
58
56
  ...config,
59
57
  user: connOpts.connection.user,
@@ -61,6 +59,7 @@ export const getConnections = async (cn = {}, seedAdapters = [seed.launchql()])
61
59
  });
62
60
  db.setContext({ role: 'anonymous' });
63
61
  const teardown = async () => {
62
+ manager.beginTeardown();
64
63
  await teardownPgPools();
65
64
  await manager.closeAll();
66
65
  };
package/esm/manager.js CHANGED
@@ -22,7 +22,9 @@ export class PgTestConnector {
22
22
  clients = new Set();
23
23
  pgPools = new Map();
24
24
  seenDbConfigs = new Map();
25
+ pendingConnects = new Set();
25
26
  verbose = false;
27
+ shuttingDown = false;
26
28
  constructor(verbose = false) {
27
29
  this.verbose = verbose;
28
30
  SYS_EVENTS.forEach((event) => {
@@ -44,6 +46,19 @@ export class PgTestConnector {
44
46
  dbKey(config) {
45
47
  return `${config.host}:${config.port}/${config.database}`;
46
48
  }
49
+ beginTeardown() {
50
+ this.shuttingDown = true;
51
+ }
52
+ registerConnect(p) {
53
+ this.pendingConnects.add(p);
54
+ p.finally(() => this.pendingConnects.delete(p));
55
+ }
56
+ async awaitPendingConnects() {
57
+ const arr = Array.from(this.pendingConnects);
58
+ if (arr.length) {
59
+ await Promise.allSettled(arr);
60
+ }
61
+ }
47
62
  getPool(config) {
48
63
  const key = this.poolKey(config);
49
64
  if (!this.pgPools.has(key)) {
@@ -54,7 +69,10 @@ export class PgTestConnector {
54
69
  return this.pgPools.get(key);
55
70
  }
56
71
  getClient(config) {
57
- const client = new PgTestClient(config);
72
+ if (this.shuttingDown) {
73
+ throw new Error('PgTestConnector is shutting down; no new clients allowed');
74
+ }
75
+ const client = new PgTestClient(config, { trackConnect: (p) => this.registerConnect(p) });
58
76
  this.clients.add(client);
59
77
  const key = this.dbKey(config);
60
78
  this.seenDbConfigs.set(key, config);
@@ -62,6 +80,8 @@ export class PgTestConnector {
62
80
  return client;
63
81
  }
64
82
  async closeAll() {
83
+ this.beginTeardown();
84
+ await this.awaitPendingConnects();
65
85
  log.info('🧹 Closing all PgTestClients...');
66
86
  await Promise.all(Array.from(this.clients).map(async (client) => {
67
87
  try {
@@ -93,6 +113,8 @@ export class PgTestConnector {
93
113
  }));
94
114
  this.seenDbConfigs.clear();
95
115
  log.success('✅ All PgTestClients closed, pools disposed, databases dropped.');
116
+ this.pendingConnects.clear();
117
+ this.shuttingDown = false;
96
118
  }
97
119
  close() {
98
120
  this.closeAll();
@@ -104,8 +126,8 @@ export class PgTestConnector {
104
126
  log.warn(`🧨 Dropped database: ${config.database}`);
105
127
  this.seenDbConfigs.delete(key);
106
128
  }
107
- kill(client) {
108
- client.close();
129
+ async kill(client) {
130
+ await client.close();
109
131
  this.drop(client.config);
110
132
  }
111
133
  }
@@ -4,7 +4,8 @@ export class PgTestClient {
4
4
  client;
5
5
  ctxStmts = '';
6
6
  _ended = false;
7
- constructor(config) {
7
+ connectPromise = null;
8
+ constructor(config, opts = {}) {
8
9
  this.config = config;
9
10
  this.client = new Client({
10
11
  host: this.config.host,
@@ -13,11 +14,24 @@ export class PgTestClient {
13
14
  user: this.config.user,
14
15
  password: this.config.password
15
16
  });
16
- this.client.connect();
17
+ if (!opts.deferConnect) {
18
+ this.connectPromise = this.client.connect();
19
+ if (opts.trackConnect)
20
+ opts.trackConnect(this.connectPromise);
21
+ }
22
+ }
23
+ async ensureConnected() {
24
+ if (this.connectPromise) {
25
+ try {
26
+ await this.connectPromise;
27
+ }
28
+ catch { }
29
+ }
17
30
  }
18
- close() {
31
+ async close() {
19
32
  if (!this._ended) {
20
33
  this._ended = true;
34
+ await this.ensureConnected();
21
35
  this.client.end();
22
36
  }
23
37
  }
@@ -83,7 +97,6 @@ export class PgTestClient {
83
97
  const result = await this.client.query(query, values);
84
98
  return result;
85
99
  }
86
- // exposing so we can use for graphile-test
87
100
  async ctxQuery() {
88
101
  if (this.ctxStmts) {
89
102
  await this.client.query(this.ctxStmts);
package/manager.d.ts CHANGED
@@ -6,15 +6,20 @@ export declare class PgTestConnector {
6
6
  private readonly clients;
7
7
  private readonly pgPools;
8
8
  private readonly seenDbConfigs;
9
+ private readonly pendingConnects;
9
10
  private verbose;
11
+ private shuttingDown;
10
12
  private constructor();
11
13
  static getInstance(verbose?: boolean): PgTestConnector;
12
14
  private poolKey;
13
15
  private dbKey;
16
+ beginTeardown(): void;
17
+ private registerConnect;
18
+ private awaitPendingConnects;
14
19
  getPool(config: PgConfig): Pool;
15
20
  getClient(config: PgConfig): PgTestClient;
16
21
  closeAll(): Promise<void>;
17
22
  close(): void;
18
23
  drop(config: PgConfig): void;
19
- kill(client: PgTestClient): void;
24
+ kill(client: PgTestClient): Promise<void>;
20
25
  }
package/manager.js CHANGED
@@ -25,7 +25,9 @@ class PgTestConnector {
25
25
  clients = new Set();
26
26
  pgPools = new Map();
27
27
  seenDbConfigs = new Map();
28
+ pendingConnects = new Set();
28
29
  verbose = false;
30
+ shuttingDown = false;
29
31
  constructor(verbose = false) {
30
32
  this.verbose = verbose;
31
33
  SYS_EVENTS.forEach((event) => {
@@ -47,6 +49,19 @@ class PgTestConnector {
47
49
  dbKey(config) {
48
50
  return `${config.host}:${config.port}/${config.database}`;
49
51
  }
52
+ beginTeardown() {
53
+ this.shuttingDown = true;
54
+ }
55
+ registerConnect(p) {
56
+ this.pendingConnects.add(p);
57
+ p.finally(() => this.pendingConnects.delete(p));
58
+ }
59
+ async awaitPendingConnects() {
60
+ const arr = Array.from(this.pendingConnects);
61
+ if (arr.length) {
62
+ await Promise.allSettled(arr);
63
+ }
64
+ }
50
65
  getPool(config) {
51
66
  const key = this.poolKey(config);
52
67
  if (!this.pgPools.has(key)) {
@@ -57,7 +72,10 @@ class PgTestConnector {
57
72
  return this.pgPools.get(key);
58
73
  }
59
74
  getClient(config) {
60
- const client = new test_client_1.PgTestClient(config);
75
+ if (this.shuttingDown) {
76
+ throw new Error('PgTestConnector is shutting down; no new clients allowed');
77
+ }
78
+ const client = new test_client_1.PgTestClient(config, { trackConnect: (p) => this.registerConnect(p) });
61
79
  this.clients.add(client);
62
80
  const key = this.dbKey(config);
63
81
  this.seenDbConfigs.set(key, config);
@@ -65,6 +83,8 @@ class PgTestConnector {
65
83
  return client;
66
84
  }
67
85
  async closeAll() {
86
+ this.beginTeardown();
87
+ await this.awaitPendingConnects();
68
88
  log.info('🧹 Closing all PgTestClients...');
69
89
  await Promise.all(Array.from(this.clients).map(async (client) => {
70
90
  try {
@@ -96,6 +116,8 @@ class PgTestConnector {
96
116
  }));
97
117
  this.seenDbConfigs.clear();
98
118
  log.success('✅ All PgTestClients closed, pools disposed, databases dropped.');
119
+ this.pendingConnects.clear();
120
+ this.shuttingDown = false;
99
121
  }
100
122
  close() {
101
123
  this.closeAll();
@@ -107,8 +129,8 @@ class PgTestConnector {
107
129
  log.warn(`🧨 Dropped database: ${config.database}`);
108
130
  this.seenDbConfigs.delete(key);
109
131
  }
110
- kill(client) {
111
- client.close();
132
+ async kill(client) {
133
+ await client.close();
112
134
  this.drop(client.config);
113
135
  }
114
136
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pgsql-test",
3
- "version": "2.6.1",
3
+ "version": "2.6.3",
4
4
  "author": "Dan Lynch <pyramation@gmail.com>",
5
5
  "description": "pgsql-test offers isolated, role-aware, and rollback-friendly PostgreSQL environments for integration tests — giving developers realistic test coverage without external state pollution",
6
6
  "main": "index.js",
@@ -60,7 +60,7 @@
60
60
  "@types/pg-copy-streams": "^1.2.5"
61
61
  },
62
62
  "dependencies": {
63
- "@launchql/core": "^2.7.0",
63
+ "@launchql/core": "^2.7.1",
64
64
  "@launchql/env": "^2.2.1",
65
65
  "@launchql/server-utils": "^2.2.1",
66
66
  "@launchql/types": "^2.3.0",
@@ -69,5 +69,5 @@
69
69
  "pg-copy-streams": "^6.0.6",
70
70
  "pg-env": "^1.1.0"
71
71
  },
72
- "gitHead": "245029576886f5ac650aa5e8fa8cd8d5f47c258f"
72
+ "gitHead": "db2ca1845fa1a62604f0f85367120ba10e4915a6"
73
73
  }
package/test-client.d.ts CHANGED
@@ -1,12 +1,18 @@
1
1
  import { Client, QueryResult } from 'pg';
2
2
  import { PgConfig } from 'pg-env';
3
+ type PgTestClientOpts = {
4
+ deferConnect?: boolean;
5
+ trackConnect?: (p: Promise<any>) => void;
6
+ };
3
7
  export declare class PgTestClient {
4
8
  config: PgConfig;
5
9
  client: Client;
6
10
  private ctxStmts;
7
11
  private _ended;
8
- constructor(config: PgConfig);
9
- close(): void;
12
+ private connectPromise;
13
+ constructor(config: PgConfig, opts?: PgTestClientOpts);
14
+ private ensureConnected;
15
+ close(): Promise<void>;
10
16
  begin(): Promise<void>;
11
17
  savepoint(name?: string): Promise<void>;
12
18
  rollback(name?: string): Promise<void>;
@@ -24,3 +30,4 @@ export declare class PgTestClient {
24
30
  query<T = any>(query: string, values?: any[]): Promise<QueryResult<T>>;
25
31
  ctxQuery(): Promise<void>;
26
32
  }
33
+ export {};
package/test-client.js CHANGED
@@ -7,7 +7,8 @@ class PgTestClient {
7
7
  client;
8
8
  ctxStmts = '';
9
9
  _ended = false;
10
- constructor(config) {
10
+ connectPromise = null;
11
+ constructor(config, opts = {}) {
11
12
  this.config = config;
12
13
  this.client = new pg_1.Client({
13
14
  host: this.config.host,
@@ -16,11 +17,24 @@ class PgTestClient {
16
17
  user: this.config.user,
17
18
  password: this.config.password
18
19
  });
19
- this.client.connect();
20
+ if (!opts.deferConnect) {
21
+ this.connectPromise = this.client.connect();
22
+ if (opts.trackConnect)
23
+ opts.trackConnect(this.connectPromise);
24
+ }
25
+ }
26
+ async ensureConnected() {
27
+ if (this.connectPromise) {
28
+ try {
29
+ await this.connectPromise;
30
+ }
31
+ catch { }
32
+ }
20
33
  }
21
- close() {
34
+ async close() {
22
35
  if (!this._ended) {
23
36
  this._ended = true;
37
+ await this.ensureConnected();
24
38
  this.client.end();
25
39
  }
26
40
  }
@@ -86,7 +100,6 @@ class PgTestClient {
86
100
  const result = await this.client.query(query, values);
87
101
  return result;
88
102
  }
89
- // exposing so we can use for graphile-test
90
103
  async ctxQuery() {
91
104
  if (this.ctxStmts) {
92
105
  await this.client.query(this.ctxStmts);