pgsql-test 2.6.2 → 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 +1 -2
- package/esm/connect.js +1 -2
- package/esm/manager.js +25 -3
- package/esm/test-client.js +17 -4
- package/manager.d.ts +6 -1
- package/manager.js +25 -3
- package/package.json +2 -2
- package/test-client.d.ts +9 -2
- package/test-client.js +17 -4
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
|
-
|
|
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
|
}
|
package/esm/test-client.js
CHANGED
|
@@ -4,7 +4,8 @@ export class PgTestClient {
|
|
|
4
4
|
client;
|
|
5
5
|
ctxStmts = '';
|
|
6
6
|
_ended = false;
|
|
7
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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",
|
|
@@ -69,5 +69,5 @@
|
|
|
69
69
|
"pg-copy-streams": "^6.0.6",
|
|
70
70
|
"pg-env": "^1.1.0"
|
|
71
71
|
},
|
|
72
|
-
"gitHead": "
|
|
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
|
-
|
|
9
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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);
|