diff --git a/README.md b/README.md index 20e3127..4fd9609 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ npm install pgstrap --save-dev - `npm run db:migrate` - Run pending migrations - `npm run db:reset` - Drop and recreate the database, then run all migrations -- `npm run db:generate` - Generate types and structure dumps. Use `pgstrap generate --pglite` to run migrations against an in-memory PGlite instance. +- `npm run db:generate` - Generate types and structure dumps from migrations using an in-memory PGlite instance, without a running PostgreSQL server. Use `pgstrap generate --no-pglite` to generate from your configured PostgreSQL database instead. - `npm run db:create-migration` - Create a new migration file ### Configuration diff --git a/src/cli.ts b/src/cli.ts index 9a9bdec..68f5baf 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -35,7 +35,7 @@ import { getProjectContext } from "./get-project-context" "generate", "generate types and sql documentation from database", (yargs) => { - yargs.option("pglite", { type: "boolean", default: false }) + yargs.option("pglite", { type: "boolean", default: true }) }, async (argv) => { generate({ ...(await getProjectContext()), pglite: !!argv.pglite }) diff --git a/src/generate.ts b/src/generate.ts index f337094..3ab932d 100644 --- a/src/generate.ts +++ b/src/generate.ts @@ -60,7 +60,7 @@ export const generate = async ({ }) }) - await new Promise((resolve) => server.listen(0, resolve)) + await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)) const port = (server.address() as any).port const connectionString = `postgres://postgres:postgres@127.0.0.1:${port}/postgres` diff --git a/src/get-project-context.ts b/src/get-project-context.ts index 8d01d80..35680a8 100644 --- a/src/get-project-context.ts +++ b/src/get-project-context.ts @@ -1,5 +1,6 @@ import fs from "fs" import path from "path" +import { pathToFileURL } from "url" import { PgstrapConfig } from "./define-config" export interface Context extends PgstrapConfig { @@ -13,7 +14,9 @@ export const getProjectContext = async (): Promise => { ) } - const config = await import(path.join(process.cwd(), "pgstrap.config.js")) + const config = await import( + pathToFileURL(path.join(process.cwd(), "pgstrap.config.js")).href + ) return { cwd: process.cwd(), diff --git a/tests/generate.cli.test.ts b/tests/generate.cli.test.ts new file mode 100644 index 0000000..f08de1f --- /dev/null +++ b/tests/generate.cli.test.ts @@ -0,0 +1,87 @@ +import { test, expect } from "bun:test" +import fs from "fs" +import os from "os" +import path from "path" + +test("generate defaults to PGlite without a running PostgreSQL server", async () => { + const tmp = fs.mkdtempSync(path.join(os.tmpdir(), "pgstrap-cli-")) + const dbDir = path.join(tmp, "db") + const migrationsDir = path.join(dbDir, "migrations") + fs.mkdirSync(migrationsDir, { recursive: true }) + fs.writeFileSync( + path.join(tmp, "pgstrap.config.js"), + `module.exports = ${JSON.stringify({ schemas: ["public"], defaultDatabase: "postgres", dbDir })}`, + ) + fs.writeFileSync( + path.join(migrationsDir, "001_create_table.js"), + `exports.up = (pgm) => pgm.createTable("cli_items", { id: "id" })\nexports.down = (pgm) => pgm.dropTable("cli_items")`, + ) + + const child = Bun.spawn( + [ + process.execPath, + "run", + path.join(import.meta.dir, "../src/cli.ts"), + "generate", + ], + { + cwd: tmp, + env: { + ...process.env, + DATABASE_URL: "postgres://postgres:postgres@127.0.0.1:1/postgres", + }, + stdout: "pipe", + stderr: "pipe", + }, + ) + + const timeout = setTimeout(() => child.kill(), 45_000) + try { + const [exitCode, stdout, stderr] = await Promise.all([ + child.exited, + new Response(child.stdout).text(), + new Response(child.stderr).text(), + ]) + expect({ exitCode, stdout, stderr }).toMatchObject({ exitCode: 0 }) + expect(fs.existsSync(path.join(dbDir, "zapatos", "schema.d.ts"))).toBe(true) + expect( + fs.readFileSync(path.join(dbDir, "zapatos", "schema.d.ts"), "utf8"), + ).toContain("cli_items") + expect( + fs.existsSync( + path.join( + dbDir, + "structure", + "public", + "tables", + "cli_items", + "table.sql", + ), + ), + ).toBe(true) + expect( + fs.readFileSync( + path.join( + dbDir, + "structure", + "public", + "tables", + "cli_items", + "table.sql", + ), + "utf8", + ), + ).toContain("cli_items") + } finally { + clearTimeout(timeout) + child.kill() + const resolved = path.resolve(tmp) + if ( + !resolved.startsWith(path.resolve(os.tmpdir()) + path.sep) || + !path.basename(resolved).startsWith("pgstrap-cli-") + ) { + throw new Error("Unexpected temporary directory") + } + fs.rmSync(resolved, { recursive: true, force: true }) + } +}, 60_000)