postgres-memory-server 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/LICENSE +21 -0
- package/README.md +339 -0
- package/dist/cli.js +390 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +121 -0
- package/dist/index.js +504 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import process from "process";
|
|
5
|
+
|
|
6
|
+
// src/PostgresMemoryServer.ts
|
|
7
|
+
import { promises as fs } from "fs";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import { PostgreSqlContainer } from "@testcontainers/postgresql";
|
|
10
|
+
import { Client } from "pg";
|
|
11
|
+
|
|
12
|
+
// src/errors.ts
|
|
13
|
+
var PostgresMemoryServerError = class extends Error {
|
|
14
|
+
constructor(message, options) {
|
|
15
|
+
super(message, options);
|
|
16
|
+
this.name = new.target.name;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var SnapshotUnsupportedError = class extends PostgresMemoryServerError {
|
|
20
|
+
constructor(database) {
|
|
21
|
+
super(
|
|
22
|
+
`Snapshots are not supported when the database name is "${database}". Use a non-system database name such as "testdb" before calling snapshot() or restore().`
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var ServerStoppedError = class extends PostgresMemoryServerError {
|
|
27
|
+
constructor() {
|
|
28
|
+
super("The PostgresMemoryServer has already been stopped.");
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// src/presets.ts
|
|
33
|
+
var POSTGRES_IMAGE_REPOSITORY = "postgres";
|
|
34
|
+
var PARADEDB_IMAGE_REPOSITORY = "paradedb/paradedb";
|
|
35
|
+
var DEFAULT_POSTGRES_VERSION = "17";
|
|
36
|
+
var DEFAULT_PARADEDB_VERSION = "0.22.3-pg17";
|
|
37
|
+
var DEFAULT_POSTGRES_IMAGE = getImageForVersion(
|
|
38
|
+
"postgres",
|
|
39
|
+
DEFAULT_POSTGRES_VERSION
|
|
40
|
+
);
|
|
41
|
+
var DEFAULT_PARADEDB_IMAGE = getImageForVersion(
|
|
42
|
+
"paradedb",
|
|
43
|
+
DEFAULT_PARADEDB_VERSION
|
|
44
|
+
);
|
|
45
|
+
var DEFAULT_DATABASE = "testdb";
|
|
46
|
+
var DEFAULT_USERNAME = "testuser";
|
|
47
|
+
var DEFAULT_PASSWORD = "testpassword";
|
|
48
|
+
var PARADEDB_DEFAULT_EXTENSIONS = ["pg_search", "vector"];
|
|
49
|
+
function normalizeOptions(options = {}) {
|
|
50
|
+
const preset = options.preset ?? "postgres";
|
|
51
|
+
const version = options.version;
|
|
52
|
+
const image = options.image ?? getImage(preset, version);
|
|
53
|
+
const database = options.database ?? DEFAULT_DATABASE;
|
|
54
|
+
const username = options.username ?? DEFAULT_USERNAME;
|
|
55
|
+
const password = options.password ?? DEFAULT_PASSWORD;
|
|
56
|
+
const extensions = options.extensions ?? getDefaultExtensions(preset);
|
|
57
|
+
const initSql = options.initSql ?? [];
|
|
58
|
+
return {
|
|
59
|
+
preset,
|
|
60
|
+
version,
|
|
61
|
+
image,
|
|
62
|
+
database,
|
|
63
|
+
username,
|
|
64
|
+
password,
|
|
65
|
+
extensions,
|
|
66
|
+
initSql
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function getImageForVersion(preset, version) {
|
|
70
|
+
const repository = preset === "paradedb" ? PARADEDB_IMAGE_REPOSITORY : POSTGRES_IMAGE_REPOSITORY;
|
|
71
|
+
return `${repository}:${version}`;
|
|
72
|
+
}
|
|
73
|
+
function getDefaultImage(preset) {
|
|
74
|
+
return preset === "paradedb" ? DEFAULT_PARADEDB_IMAGE : DEFAULT_POSTGRES_IMAGE;
|
|
75
|
+
}
|
|
76
|
+
function getImage(preset, version) {
|
|
77
|
+
return version ? getImageForVersion(preset, version) : getDefaultImage(preset);
|
|
78
|
+
}
|
|
79
|
+
function getDefaultExtensions(preset) {
|
|
80
|
+
return preset === "paradedb" ? [...PARADEDB_DEFAULT_EXTENSIONS] : [];
|
|
81
|
+
}
|
|
82
|
+
function buildInitStatements(options) {
|
|
83
|
+
const extensionStatements = options.extensions.map(
|
|
84
|
+
(extension) => `CREATE EXTENSION IF NOT EXISTS ${quoteIdentifier(extension)};`
|
|
85
|
+
);
|
|
86
|
+
return [...extensionStatements, ...options.initSql];
|
|
87
|
+
}
|
|
88
|
+
function quoteIdentifier(name) {
|
|
89
|
+
if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
|
|
90
|
+
return name;
|
|
91
|
+
}
|
|
92
|
+
return `"${name.replaceAll('"', '""')}"`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/PostgresMemoryServer.ts
|
|
96
|
+
var PostgresMemoryServer = class _PostgresMemoryServer {
|
|
97
|
+
constructor(container, options) {
|
|
98
|
+
this.container = container;
|
|
99
|
+
this.options = options;
|
|
100
|
+
this.snapshotSupported = options.database !== "postgres";
|
|
101
|
+
}
|
|
102
|
+
stopped = false;
|
|
103
|
+
snapshotSupported;
|
|
104
|
+
static async create(options = {}) {
|
|
105
|
+
const normalized = normalizeOptions(options);
|
|
106
|
+
const container = await new PostgreSqlContainer(normalized.image).withDatabase(normalized.database).withUsername(normalized.username).withPassword(normalized.password).start();
|
|
107
|
+
const server = new _PostgresMemoryServer(container, normalized);
|
|
108
|
+
const initStatements = buildInitStatements(normalized);
|
|
109
|
+
if (initStatements.length > 0) {
|
|
110
|
+
await server.runSql(initStatements);
|
|
111
|
+
}
|
|
112
|
+
return server;
|
|
113
|
+
}
|
|
114
|
+
static createPostgres(options = {}) {
|
|
115
|
+
return _PostgresMemoryServer.create({ ...options, preset: "postgres" });
|
|
116
|
+
}
|
|
117
|
+
static createParadeDb(options = {}) {
|
|
118
|
+
return _PostgresMemoryServer.create({ ...options, preset: "paradedb" });
|
|
119
|
+
}
|
|
120
|
+
getUri() {
|
|
121
|
+
this.ensureRunning();
|
|
122
|
+
return this.container.getConnectionUri();
|
|
123
|
+
}
|
|
124
|
+
getHost() {
|
|
125
|
+
this.ensureRunning();
|
|
126
|
+
return this.container.getHost();
|
|
127
|
+
}
|
|
128
|
+
getPort() {
|
|
129
|
+
this.ensureRunning();
|
|
130
|
+
return this.container.getPort();
|
|
131
|
+
}
|
|
132
|
+
getDatabase() {
|
|
133
|
+
return this.options.database;
|
|
134
|
+
}
|
|
135
|
+
getUsername() {
|
|
136
|
+
return this.options.username;
|
|
137
|
+
}
|
|
138
|
+
getPassword() {
|
|
139
|
+
return this.options.password;
|
|
140
|
+
}
|
|
141
|
+
getImage() {
|
|
142
|
+
return this.options.image;
|
|
143
|
+
}
|
|
144
|
+
getConnectionOptions() {
|
|
145
|
+
return {
|
|
146
|
+
host: this.getHost(),
|
|
147
|
+
port: this.getPort(),
|
|
148
|
+
database: this.getDatabase(),
|
|
149
|
+
user: this.getUsername(),
|
|
150
|
+
password: this.getPassword()
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
async query(text, params) {
|
|
154
|
+
return this.withClient((client) => {
|
|
155
|
+
if (typeof text === "string") {
|
|
156
|
+
if (params === void 0) {
|
|
157
|
+
return client.query(text);
|
|
158
|
+
}
|
|
159
|
+
return client.query(text, params);
|
|
160
|
+
}
|
|
161
|
+
return client.query(text);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
async withClient(callback) {
|
|
165
|
+
this.ensureRunning();
|
|
166
|
+
const client = new Client({
|
|
167
|
+
connectionString: this.getUri()
|
|
168
|
+
});
|
|
169
|
+
await client.connect();
|
|
170
|
+
try {
|
|
171
|
+
return await callback(client);
|
|
172
|
+
} finally {
|
|
173
|
+
await client.end();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
async runSql(sql) {
|
|
177
|
+
const statements = Array.isArray(sql) ? sql : [sql];
|
|
178
|
+
await this.withClient(async (client) => {
|
|
179
|
+
for (const statement of statements) {
|
|
180
|
+
await client.query(statement);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
async runSqlFile(filePath) {
|
|
185
|
+
const sql = await fs.readFile(filePath, "utf8");
|
|
186
|
+
await this.runSql(sql);
|
|
187
|
+
}
|
|
188
|
+
async runMigrationsDir(dirPath) {
|
|
189
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
190
|
+
const files = entries.filter(
|
|
191
|
+
(entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".sql")
|
|
192
|
+
).map((entry) => entry.name).sort((left, right) => left.localeCompare(right));
|
|
193
|
+
for (const file of files) {
|
|
194
|
+
await this.runSqlFile(path.join(dirPath, file));
|
|
195
|
+
}
|
|
196
|
+
return files;
|
|
197
|
+
}
|
|
198
|
+
async snapshot() {
|
|
199
|
+
this.ensureRunning();
|
|
200
|
+
this.ensureSnapshotSupported();
|
|
201
|
+
await this.container.snapshot();
|
|
202
|
+
}
|
|
203
|
+
async restore() {
|
|
204
|
+
this.ensureRunning();
|
|
205
|
+
this.ensureSnapshotSupported();
|
|
206
|
+
await this.container.restoreSnapshot();
|
|
207
|
+
}
|
|
208
|
+
async stop() {
|
|
209
|
+
if (this.stopped) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
this.stopped = true;
|
|
213
|
+
await this.container.stop();
|
|
214
|
+
}
|
|
215
|
+
ensureRunning() {
|
|
216
|
+
if (this.stopped) {
|
|
217
|
+
throw new ServerStoppedError();
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
ensureSnapshotSupported() {
|
|
221
|
+
if (!this.snapshotSupported) {
|
|
222
|
+
throw new SnapshotUnsupportedError(this.options.database);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// src/cli.ts
|
|
228
|
+
async function main() {
|
|
229
|
+
const { options, initFiles, json } = parseArgs(process.argv.slice(2));
|
|
230
|
+
const server = await PostgresMemoryServer.create(options);
|
|
231
|
+
try {
|
|
232
|
+
for (const file of initFiles) {
|
|
233
|
+
await server.runSqlFile(file);
|
|
234
|
+
}
|
|
235
|
+
const payload = {
|
|
236
|
+
uri: server.getUri(),
|
|
237
|
+
host: server.getHost(),
|
|
238
|
+
port: server.getPort(),
|
|
239
|
+
database: server.getDatabase(),
|
|
240
|
+
username: server.getUsername(),
|
|
241
|
+
password: server.getPassword(),
|
|
242
|
+
image: server.getImage()
|
|
243
|
+
};
|
|
244
|
+
if (json) {
|
|
245
|
+
process.stdout.write(`${JSON.stringify(payload, null, 2)}
|
|
246
|
+
`);
|
|
247
|
+
} else {
|
|
248
|
+
process.stdout.write(`POSTGRES_MEMORY_SERVER_URI=${payload.uri}
|
|
249
|
+
`);
|
|
250
|
+
process.stdout.write(`POSTGRES_MEMORY_SERVER_HOST=${payload.host}
|
|
251
|
+
`);
|
|
252
|
+
process.stdout.write(`POSTGRES_MEMORY_SERVER_PORT=${payload.port}
|
|
253
|
+
`);
|
|
254
|
+
process.stdout.write(
|
|
255
|
+
`POSTGRES_MEMORY_SERVER_DATABASE=${payload.database}
|
|
256
|
+
`
|
|
257
|
+
);
|
|
258
|
+
process.stdout.write(
|
|
259
|
+
`POSTGRES_MEMORY_SERVER_USERNAME=${payload.username}
|
|
260
|
+
`
|
|
261
|
+
);
|
|
262
|
+
process.stdout.write(
|
|
263
|
+
`POSTGRES_MEMORY_SERVER_PASSWORD=${payload.password}
|
|
264
|
+
`
|
|
265
|
+
);
|
|
266
|
+
process.stdout.write(`POSTGRES_MEMORY_SERVER_IMAGE=${payload.image}
|
|
267
|
+
`);
|
|
268
|
+
process.stdout.write("\nPress Ctrl+C to stop the container.\n");
|
|
269
|
+
}
|
|
270
|
+
const stop = async () => {
|
|
271
|
+
await server.stop();
|
|
272
|
+
process.exit(0);
|
|
273
|
+
};
|
|
274
|
+
process.on("SIGINT", () => {
|
|
275
|
+
void stop();
|
|
276
|
+
});
|
|
277
|
+
process.on("SIGTERM", () => {
|
|
278
|
+
void stop();
|
|
279
|
+
});
|
|
280
|
+
await new Promise(() => {
|
|
281
|
+
});
|
|
282
|
+
} catch (error) {
|
|
283
|
+
await server.stop();
|
|
284
|
+
throw error;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function parseArgs(argv) {
|
|
288
|
+
const options = {};
|
|
289
|
+
const initFiles = [];
|
|
290
|
+
const extensions = [];
|
|
291
|
+
let json = false;
|
|
292
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
293
|
+
const arg = argv[index];
|
|
294
|
+
switch (arg) {
|
|
295
|
+
case "--preset": {
|
|
296
|
+
const value = readValue(
|
|
297
|
+
argv,
|
|
298
|
+
++index,
|
|
299
|
+
arg
|
|
300
|
+
);
|
|
301
|
+
options.preset = value;
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
case "--image": {
|
|
305
|
+
options.image = readValue(argv, ++index, arg);
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
case "--version": {
|
|
309
|
+
options.version = readValue(argv, ++index, arg);
|
|
310
|
+
break;
|
|
311
|
+
}
|
|
312
|
+
case "--database": {
|
|
313
|
+
options.database = readValue(argv, ++index, arg);
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
case "--username": {
|
|
317
|
+
options.username = readValue(argv, ++index, arg);
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
case "--password": {
|
|
321
|
+
options.password = readValue(argv, ++index, arg);
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
case "--extension": {
|
|
325
|
+
extensions.push(readValue(argv, ++index, arg));
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
case "--init-file": {
|
|
329
|
+
initFiles.push(readValue(argv, ++index, arg));
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
case "--json": {
|
|
333
|
+
json = true;
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
case "--help": {
|
|
337
|
+
printHelp();
|
|
338
|
+
process.exit(0);
|
|
339
|
+
}
|
|
340
|
+
default: {
|
|
341
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (extensions.length > 0) {
|
|
346
|
+
options.extensions = extensions;
|
|
347
|
+
}
|
|
348
|
+
return { options, initFiles, json };
|
|
349
|
+
}
|
|
350
|
+
function readValue(argv, index, flag) {
|
|
351
|
+
const value = argv[index];
|
|
352
|
+
if (!value) {
|
|
353
|
+
throw new Error(`Missing value for ${flag}`);
|
|
354
|
+
}
|
|
355
|
+
return value;
|
|
356
|
+
}
|
|
357
|
+
function printHelp() {
|
|
358
|
+
process.stdout.write(`postgres-memory-server
|
|
359
|
+
|
|
360
|
+
`);
|
|
361
|
+
process.stdout.write(`Options:
|
|
362
|
+
`);
|
|
363
|
+
process.stdout.write(` --preset postgres|paradedb
|
|
364
|
+
`);
|
|
365
|
+
process.stdout.write(` --version <tag>
|
|
366
|
+
`);
|
|
367
|
+
process.stdout.write(` --image <image>
|
|
368
|
+
`);
|
|
369
|
+
process.stdout.write(` --database <name>
|
|
370
|
+
`);
|
|
371
|
+
process.stdout.write(` --username <name>
|
|
372
|
+
`);
|
|
373
|
+
process.stdout.write(` --password <password>
|
|
374
|
+
`);
|
|
375
|
+
process.stdout.write(` --extension <name> repeatable
|
|
376
|
+
`);
|
|
377
|
+
process.stdout.write(` --init-file <path> repeatable
|
|
378
|
+
`);
|
|
379
|
+
process.stdout.write(` --json
|
|
380
|
+
`);
|
|
381
|
+
process.stdout.write(` --help
|
|
382
|
+
`);
|
|
383
|
+
}
|
|
384
|
+
void main().catch((error) => {
|
|
385
|
+
const message = error instanceof Error ? error.stack ?? error.message : String(error);
|
|
386
|
+
process.stderr.write(`${message}
|
|
387
|
+
`);
|
|
388
|
+
process.exit(1);
|
|
389
|
+
});
|
|
390
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/PostgresMemoryServer.ts","../src/errors.ts","../src/presets.ts"],"sourcesContent":["import process from \"node:process\";\n\nimport { PostgresMemoryServer } from \"./PostgresMemoryServer.js\";\nimport type {\n PostgresMemoryServerOptions,\n PostgresMemoryServerPreset,\n} from \"./types.js\";\n\nasync function main(): Promise<void> {\n const { options, initFiles, json } = parseArgs(process.argv.slice(2));\n\n const server = await PostgresMemoryServer.create(options);\n\n try {\n for (const file of initFiles) {\n await server.runSqlFile(file);\n }\n\n const payload = {\n uri: server.getUri(),\n host: server.getHost(),\n port: server.getPort(),\n database: server.getDatabase(),\n username: server.getUsername(),\n password: server.getPassword(),\n image: server.getImage(),\n };\n\n if (json) {\n process.stdout.write(`${JSON.stringify(payload, null, 2)}\\n`);\n } else {\n process.stdout.write(`POSTGRES_MEMORY_SERVER_URI=${payload.uri}\\n`);\n process.stdout.write(`POSTGRES_MEMORY_SERVER_HOST=${payload.host}\\n`);\n process.stdout.write(`POSTGRES_MEMORY_SERVER_PORT=${payload.port}\\n`);\n process.stdout.write(\n `POSTGRES_MEMORY_SERVER_DATABASE=${payload.database}\\n`,\n );\n process.stdout.write(\n `POSTGRES_MEMORY_SERVER_USERNAME=${payload.username}\\n`,\n );\n process.stdout.write(\n `POSTGRES_MEMORY_SERVER_PASSWORD=${payload.password}\\n`,\n );\n process.stdout.write(`POSTGRES_MEMORY_SERVER_IMAGE=${payload.image}\\n`);\n process.stdout.write(\"\\nPress Ctrl+C to stop the container.\\n\");\n }\n\n const stop = async () => {\n await server.stop();\n process.exit(0);\n };\n\n process.on(\"SIGINT\", () => {\n void stop();\n });\n process.on(\"SIGTERM\", () => {\n void stop();\n });\n\n await new Promise<void>(() => {\n // Intentionally never resolve. Signals will stop the process.\n });\n } catch (error) {\n await server.stop();\n throw error;\n }\n}\n\ntype ParsedArgs = {\n options: PostgresMemoryServerOptions;\n initFiles: string[];\n json: boolean;\n};\n\nfunction parseArgs(argv: string[]): ParsedArgs {\n const options: PostgresMemoryServerOptions = {};\n const initFiles: string[] = [];\n const extensions: string[] = [];\n let json = false;\n\n for (let index = 0; index < argv.length; index += 1) {\n const arg = argv[index];\n\n switch (arg) {\n case \"--preset\": {\n const value = readValue(\n argv,\n ++index,\n arg,\n ) as PostgresMemoryServerPreset;\n options.preset = value;\n break;\n }\n case \"--image\": {\n options.image = readValue(argv, ++index, arg);\n break;\n }\n case \"--version\": {\n options.version = readValue(argv, ++index, arg);\n break;\n }\n case \"--database\": {\n options.database = readValue(argv, ++index, arg);\n break;\n }\n case \"--username\": {\n options.username = readValue(argv, ++index, arg);\n break;\n }\n case \"--password\": {\n options.password = readValue(argv, ++index, arg);\n break;\n }\n case \"--extension\": {\n extensions.push(readValue(argv, ++index, arg));\n break;\n }\n case \"--init-file\": {\n initFiles.push(readValue(argv, ++index, arg));\n break;\n }\n case \"--json\": {\n json = true;\n break;\n }\n case \"--help\": {\n printHelp();\n process.exit(0);\n }\n default: {\n throw new Error(`Unknown argument: ${arg}`);\n }\n }\n }\n\n if (extensions.length > 0) {\n options.extensions = extensions;\n }\n\n return { options, initFiles, json };\n}\n\nfunction readValue(argv: string[], index: number, flag: string): string {\n const value = argv[index];\n if (!value) {\n throw new Error(`Missing value for ${flag}`);\n }\n return value;\n}\n\nfunction printHelp(): void {\n process.stdout.write(`postgres-memory-server\\n\\n`);\n process.stdout.write(`Options:\\n`);\n process.stdout.write(` --preset postgres|paradedb\\n`);\n process.stdout.write(` --version <tag>\\n`);\n process.stdout.write(` --image <image>\\n`);\n process.stdout.write(` --database <name>\\n`);\n process.stdout.write(` --username <name>\\n`);\n process.stdout.write(` --password <password>\\n`);\n process.stdout.write(` --extension <name> repeatable\\n`);\n process.stdout.write(` --init-file <path> repeatable\\n`);\n process.stdout.write(` --json\\n`);\n process.stdout.write(` --help\\n`);\n}\n\nvoid main().catch((error: unknown) => {\n const message =\n error instanceof Error ? (error.stack ?? error.message) : String(error);\n process.stderr.write(`${message}\\n`);\n process.exit(1);\n});\n","import { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\n\nimport { PostgreSqlContainer } from \"@testcontainers/postgresql\";\nimport { Client, type QueryResultRow } from \"pg\";\n\nimport { ServerStoppedError, SnapshotUnsupportedError } from \"./errors.js\";\nimport { buildInitStatements, normalizeOptions } from \"./presets.js\";\nimport type {\n PostgresConnectionOptions,\n PostgresMemoryServerOptions,\n QueryParams,\n QueryResponse,\n QueryText,\n} from \"./types.js\";\n\nexport type StartedPostgreSqlContainer = Awaited<\n ReturnType<PostgreSqlContainer[\"start\"]>\n>;\n\nexport class PostgresMemoryServer {\n private stopped = false;\n private readonly snapshotSupported: boolean;\n\n private constructor(\n private readonly container: StartedPostgreSqlContainer,\n private readonly options: ReturnType<typeof normalizeOptions>,\n ) {\n this.snapshotSupported = options.database !== \"postgres\";\n }\n\n static async create(\n options: PostgresMemoryServerOptions = {},\n ): Promise<PostgresMemoryServer> {\n const normalized = normalizeOptions(options);\n\n const container = await new PostgreSqlContainer(normalized.image)\n .withDatabase(normalized.database)\n .withUsername(normalized.username)\n .withPassword(normalized.password)\n .start();\n\n const server = new PostgresMemoryServer(container, normalized);\n\n const initStatements = buildInitStatements(normalized);\n if (initStatements.length > 0) {\n await server.runSql(initStatements);\n }\n\n return server;\n }\n\n static createPostgres(\n options: Omit<PostgresMemoryServerOptions, \"preset\"> = {},\n ): Promise<PostgresMemoryServer> {\n return PostgresMemoryServer.create({ ...options, preset: \"postgres\" });\n }\n\n static createParadeDb(\n options: Omit<PostgresMemoryServerOptions, \"preset\"> = {},\n ): Promise<PostgresMemoryServer> {\n return PostgresMemoryServer.create({ ...options, preset: \"paradedb\" });\n }\n\n getUri(): string {\n this.ensureRunning();\n return this.container.getConnectionUri();\n }\n\n getHost(): string {\n this.ensureRunning();\n return this.container.getHost();\n }\n\n getPort(): number {\n this.ensureRunning();\n return this.container.getPort();\n }\n\n getDatabase(): string {\n return this.options.database;\n }\n\n getUsername(): string {\n return this.options.username;\n }\n\n getPassword(): string {\n return this.options.password;\n }\n\n getImage(): string {\n return this.options.image;\n }\n\n getConnectionOptions(): PostgresConnectionOptions {\n return {\n host: this.getHost(),\n port: this.getPort(),\n database: this.getDatabase(),\n user: this.getUsername(),\n password: this.getPassword(),\n };\n }\n\n async query<Row extends QueryResultRow = QueryResultRow>(\n text: QueryText<Row>,\n params?: QueryParams,\n ): Promise<QueryResponse<Row>> {\n return this.withClient((client) => {\n if (typeof text === \"string\") {\n if (params === undefined) {\n return client.query<Row>(text);\n }\n\n return client.query<Row>(text, params);\n }\n\n return client.query<Row>(text);\n });\n }\n\n async withClient<T>(callback: (client: Client) => Promise<T>): Promise<T> {\n this.ensureRunning();\n\n const client = new Client({\n connectionString: this.getUri(),\n });\n\n await client.connect();\n try {\n return await callback(client);\n } finally {\n await client.end();\n }\n }\n\n async runSql(sql: string | string[]): Promise<void> {\n const statements = Array.isArray(sql) ? sql : [sql];\n\n await this.withClient(async (client) => {\n for (const statement of statements) {\n await client.query(statement);\n }\n });\n }\n\n async runSqlFile(filePath: string): Promise<void> {\n const sql = await fs.readFile(filePath, \"utf8\");\n await this.runSql(sql);\n }\n\n async runMigrationsDir(dirPath: string): Promise<string[]> {\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n const files = entries\n .filter(\n (entry) => entry.isFile() && entry.name.toLowerCase().endsWith(\".sql\"),\n )\n .map((entry) => entry.name)\n .sort((left, right) => left.localeCompare(right));\n\n for (const file of files) {\n await this.runSqlFile(path.join(dirPath, file));\n }\n\n return files;\n }\n\n async snapshot(): Promise<void> {\n this.ensureRunning();\n this.ensureSnapshotSupported();\n await this.container.snapshot();\n }\n\n async restore(): Promise<void> {\n this.ensureRunning();\n this.ensureSnapshotSupported();\n await this.container.restoreSnapshot();\n }\n\n async stop(): Promise<void> {\n if (this.stopped) {\n return;\n }\n\n this.stopped = true;\n await this.container.stop();\n }\n\n private ensureRunning(): void {\n if (this.stopped) {\n throw new ServerStoppedError();\n }\n }\n\n private ensureSnapshotSupported(): void {\n if (!this.snapshotSupported) {\n throw new SnapshotUnsupportedError(this.options.database);\n }\n }\n}\n","export class PostgresMemoryServerError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = new.target.name;\n }\n}\n\nexport class SnapshotUnsupportedError extends PostgresMemoryServerError {\n constructor(database: string) {\n super(\n `Snapshots are not supported when the database name is \"${database}\". ` +\n `Use a non-system database name such as \"testdb\" before calling snapshot() or restore().`,\n );\n }\n}\n\nexport class ServerStoppedError extends PostgresMemoryServerError {\n constructor() {\n super(\"The PostgresMemoryServer has already been stopped.\");\n }\n}\n","import type {\n NormalizedPostgresMemoryServerOptions,\n PostgresMemoryServerOptions,\n PostgresMemoryServerPreset,\n} from \"./types.js\";\n\nexport const POSTGRES_IMAGE_REPOSITORY = \"postgres\";\nexport const PARADEDB_IMAGE_REPOSITORY = \"paradedb/paradedb\";\nexport const DEFAULT_POSTGRES_VERSION = \"17\";\nexport const DEFAULT_PARADEDB_VERSION = \"0.22.3-pg17\";\nexport const DEFAULT_POSTGRES_IMAGE = getImageForVersion(\n \"postgres\",\n DEFAULT_POSTGRES_VERSION,\n);\nexport const DEFAULT_PARADEDB_IMAGE = getImageForVersion(\n \"paradedb\",\n DEFAULT_PARADEDB_VERSION,\n);\n\nconst DEFAULT_DATABASE = \"testdb\";\nconst DEFAULT_USERNAME = \"testuser\";\nconst DEFAULT_PASSWORD = \"testpassword\";\n\nconst PARADEDB_DEFAULT_EXTENSIONS = [\"pg_search\", \"vector\"];\n\nexport function normalizeOptions(\n options: PostgresMemoryServerOptions = {},\n): NormalizedPostgresMemoryServerOptions {\n const preset = options.preset ?? \"postgres\";\n const version = options.version;\n const image = options.image ?? getImage(preset, version);\n const database = options.database ?? DEFAULT_DATABASE;\n const username = options.username ?? DEFAULT_USERNAME;\n const password = options.password ?? DEFAULT_PASSWORD;\n const extensions = options.extensions ?? getDefaultExtensions(preset);\n const initSql = options.initSql ?? [];\n\n return {\n preset,\n version,\n image,\n database,\n username,\n password,\n extensions,\n initSql,\n };\n}\n\nexport function getImageForVersion(\n preset: PostgresMemoryServerPreset,\n version: string,\n): string {\n const repository =\n preset === \"paradedb\"\n ? PARADEDB_IMAGE_REPOSITORY\n : POSTGRES_IMAGE_REPOSITORY;\n\n return `${repository}:${version}`;\n}\n\nexport function getDefaultImage(preset: PostgresMemoryServerPreset): string {\n return preset === \"paradedb\"\n ? DEFAULT_PARADEDB_IMAGE\n : DEFAULT_POSTGRES_IMAGE;\n}\n\nfunction getImage(\n preset: PostgresMemoryServerPreset,\n version?: string,\n): string {\n return version\n ? getImageForVersion(preset, version)\n : getDefaultImage(preset);\n}\n\nexport function getDefaultExtensions(\n preset: PostgresMemoryServerPreset,\n): string[] {\n return preset === \"paradedb\" ? [...PARADEDB_DEFAULT_EXTENSIONS] : [];\n}\n\nexport function buildInitStatements(\n options: NormalizedPostgresMemoryServerOptions,\n): string[] {\n const extensionStatements = options.extensions.map(\n (extension) =>\n `CREATE EXTENSION IF NOT EXISTS ${quoteIdentifier(extension)};`,\n );\n\n return [...extensionStatements, ...options.initSql];\n}\n\nfunction quoteIdentifier(name: string): string {\n if (/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n return name;\n }\n\n return `\"${name.replaceAll('\"', '\"\"')}\"`;\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { QueryResultRow, QueryConfig, QueryResult, Client } from 'pg';
|
|
2
|
+
|
|
3
|
+
type PostgresMemoryServerPreset = "postgres" | "paradedb";
|
|
4
|
+
interface PostgresMemoryServerOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Preset used to choose the default image and default extensions.
|
|
7
|
+
* Defaults to "postgres".
|
|
8
|
+
*/
|
|
9
|
+
preset?: PostgresMemoryServerPreset;
|
|
10
|
+
/**
|
|
11
|
+
* Version or tag to use for the selected preset.
|
|
12
|
+
* Examples: "16" for postgres, "0.22.3-pg17" for ParadeDB.
|
|
13
|
+
* Ignored when image is provided.
|
|
14
|
+
*/
|
|
15
|
+
version?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Container image to start.
|
|
18
|
+
* Defaults to postgres:17 for the postgres preset
|
|
19
|
+
* and paradedb/paradedb:0.22.3-pg17 for the ParadeDB preset.
|
|
20
|
+
* Takes precedence over version when both are provided.
|
|
21
|
+
*/
|
|
22
|
+
image?: string;
|
|
23
|
+
/** Database name created inside the container. Defaults to testdb. */
|
|
24
|
+
database?: string;
|
|
25
|
+
/** Username for the test database. Defaults to testuser. */
|
|
26
|
+
username?: string;
|
|
27
|
+
/** Password for the test database. Defaults to testpassword. */
|
|
28
|
+
password?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Extensions to create after the container starts.
|
|
31
|
+
* Each entry becomes CREATE EXTENSION IF NOT EXISTS <name>.
|
|
32
|
+
*/
|
|
33
|
+
extensions?: string[];
|
|
34
|
+
/** Additional SQL statements to run after the container starts. */
|
|
35
|
+
initSql?: string[];
|
|
36
|
+
}
|
|
37
|
+
interface NormalizedPostgresMemoryServerOptions {
|
|
38
|
+
preset: PostgresMemoryServerPreset;
|
|
39
|
+
version?: string;
|
|
40
|
+
image: string;
|
|
41
|
+
database: string;
|
|
42
|
+
username: string;
|
|
43
|
+
password: string;
|
|
44
|
+
extensions: string[];
|
|
45
|
+
initSql: string[];
|
|
46
|
+
}
|
|
47
|
+
interface PostgresConnectionOptions {
|
|
48
|
+
host: string;
|
|
49
|
+
port: number;
|
|
50
|
+
database: string;
|
|
51
|
+
user: string;
|
|
52
|
+
password: string;
|
|
53
|
+
}
|
|
54
|
+
type QueryParams = unknown[];
|
|
55
|
+
type QueryText<Row extends QueryResultRow = QueryResultRow> = string | QueryConfig<QueryParams>;
|
|
56
|
+
type QueryResponse<Row extends QueryResultRow = QueryResultRow> = QueryResult<Row>;
|
|
57
|
+
|
|
58
|
+
declare class PostgresMemoryServer {
|
|
59
|
+
private readonly container;
|
|
60
|
+
private readonly options;
|
|
61
|
+
private stopped;
|
|
62
|
+
private readonly snapshotSupported;
|
|
63
|
+
private constructor();
|
|
64
|
+
static create(options?: PostgresMemoryServerOptions): Promise<PostgresMemoryServer>;
|
|
65
|
+
static createPostgres(options?: Omit<PostgresMemoryServerOptions, "preset">): Promise<PostgresMemoryServer>;
|
|
66
|
+
static createParadeDb(options?: Omit<PostgresMemoryServerOptions, "preset">): Promise<PostgresMemoryServer>;
|
|
67
|
+
getUri(): string;
|
|
68
|
+
getHost(): string;
|
|
69
|
+
getPort(): number;
|
|
70
|
+
getDatabase(): string;
|
|
71
|
+
getUsername(): string;
|
|
72
|
+
getPassword(): string;
|
|
73
|
+
getImage(): string;
|
|
74
|
+
getConnectionOptions(): PostgresConnectionOptions;
|
|
75
|
+
query<Row extends QueryResultRow = QueryResultRow>(text: QueryText<Row>, params?: QueryParams): Promise<QueryResponse<Row>>;
|
|
76
|
+
withClient<T>(callback: (client: Client) => Promise<T>): Promise<T>;
|
|
77
|
+
runSql(sql: string | string[]): Promise<void>;
|
|
78
|
+
runSqlFile(filePath: string): Promise<void>;
|
|
79
|
+
runMigrationsDir(dirPath: string): Promise<string[]>;
|
|
80
|
+
snapshot(): Promise<void>;
|
|
81
|
+
restore(): Promise<void>;
|
|
82
|
+
stop(): Promise<void>;
|
|
83
|
+
private ensureRunning;
|
|
84
|
+
private ensureSnapshotSupported;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
declare const DEFAULT_JEST_ENV_VAR_NAME = "DATABASE_URL";
|
|
88
|
+
declare const DEFAULT_JEST_STATE_FILE: string;
|
|
89
|
+
interface JestGlobalSetupOptions extends PostgresMemoryServerOptions {
|
|
90
|
+
envVarName?: string;
|
|
91
|
+
stateFilePath?: string;
|
|
92
|
+
}
|
|
93
|
+
interface JestGlobalTeardownOptions {
|
|
94
|
+
stateFilePath?: string;
|
|
95
|
+
}
|
|
96
|
+
declare function createJestGlobalSetup(options?: JestGlobalSetupOptions): () => Promise<void>;
|
|
97
|
+
declare function createJestGlobalTeardown(options?: JestGlobalTeardownOptions): () => Promise<void>;
|
|
98
|
+
|
|
99
|
+
declare const POSTGRES_IMAGE_REPOSITORY = "postgres";
|
|
100
|
+
declare const PARADEDB_IMAGE_REPOSITORY = "paradedb/paradedb";
|
|
101
|
+
declare const DEFAULT_POSTGRES_VERSION = "17";
|
|
102
|
+
declare const DEFAULT_PARADEDB_VERSION = "0.22.3-pg17";
|
|
103
|
+
declare const DEFAULT_POSTGRES_IMAGE: string;
|
|
104
|
+
declare const DEFAULT_PARADEDB_IMAGE: string;
|
|
105
|
+
declare function normalizeOptions(options?: PostgresMemoryServerOptions): NormalizedPostgresMemoryServerOptions;
|
|
106
|
+
declare function getImageForVersion(preset: PostgresMemoryServerPreset, version: string): string;
|
|
107
|
+
declare function getDefaultImage(preset: PostgresMemoryServerPreset): string;
|
|
108
|
+
declare function getDefaultExtensions(preset: PostgresMemoryServerPreset): string[];
|
|
109
|
+
declare function buildInitStatements(options: NormalizedPostgresMemoryServerOptions): string[];
|
|
110
|
+
|
|
111
|
+
declare class PostgresMemoryServerError extends Error {
|
|
112
|
+
constructor(message: string, options?: ErrorOptions);
|
|
113
|
+
}
|
|
114
|
+
declare class SnapshotUnsupportedError extends PostgresMemoryServerError {
|
|
115
|
+
constructor(database: string);
|
|
116
|
+
}
|
|
117
|
+
declare class ServerStoppedError extends PostgresMemoryServerError {
|
|
118
|
+
constructor();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export { DEFAULT_JEST_ENV_VAR_NAME, DEFAULT_JEST_STATE_FILE, DEFAULT_PARADEDB_IMAGE, DEFAULT_PARADEDB_VERSION, DEFAULT_POSTGRES_IMAGE, DEFAULT_POSTGRES_VERSION, type JestGlobalSetupOptions, type JestGlobalTeardownOptions, type NormalizedPostgresMemoryServerOptions, PARADEDB_IMAGE_REPOSITORY, POSTGRES_IMAGE_REPOSITORY, type PostgresConnectionOptions, PostgresMemoryServer, PostgresMemoryServerError, type PostgresMemoryServerOptions, type PostgresMemoryServerPreset, type QueryResponse, type QueryText, ServerStoppedError, SnapshotUnsupportedError, buildInitStatements, createJestGlobalSetup, createJestGlobalTeardown, getDefaultExtensions, getDefaultImage, getImageForVersion, normalizeOptions };
|