feat(F-002): database foundation with migrations and dev compose
- node-pg-migrate + pg: baseline migration (extensions, app_meta) with working down - src/infrastructure/db fail-fast pool and typed query helper - docker-compose: postgres:16-alpine + redis:7-alpine with one-command up - table naming convention <module>_<table> documented in README - integration tests (6) against real PostgreSQL; strict identifier validation for test DDL after security-gate hardening round - deps justified in spec/tech.md; all gates approved; verify.sh green
This commit is contained in:
41
project/src/infrastructure/db/tests/pool.itest.ts
Normal file
41
project/src/infrastructure/db/tests/pool.itest.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import pg from 'pg';
|
||||
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
||||
import { createPoolFromEnv, query } from '../pool.js';
|
||||
import { getTestDbUrl, recreateDatabase, runMigrations } from './db-test-support.js';
|
||||
|
||||
const hasDb = Boolean(process.env.TEST_DATABASE_URL);
|
||||
|
||||
describe.skipIf(!hasDb)('db pool', () => {
|
||||
const url = hasDb ? getTestDbUrl() : '';
|
||||
let pool: pg.Pool;
|
||||
|
||||
beforeAll(async () => {
|
||||
await recreateDatabase(url);
|
||||
await runMigrations(url, 'up');
|
||||
pool = createPoolFromEnv({ DATABASE_URL: url } as NodeJS.ProcessEnv);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await pool.end();
|
||||
});
|
||||
|
||||
it('connects and runs a trivial query', async () => {
|
||||
const result = await query(pool, 'SELECT 1 AS ok');
|
||||
expect(result.rows[0]?.ok).toBe(1);
|
||||
});
|
||||
|
||||
it('supports a full roundtrip on app_meta via the query helper', async () => {
|
||||
await query(pool, 'INSERT INTO app_meta (key, value) VALUES ($1, $2)', ['k1', 'v1']);
|
||||
const read = await query(pool, 'SELECT value FROM app_meta WHERE key = $1', ['k1']);
|
||||
expect(read.rows[0]?.value).toBe('v1');
|
||||
await query(pool, 'DELETE FROM app_meta WHERE key = $1', ['k1']);
|
||||
const gone = await query(pool, 'SELECT value FROM app_meta WHERE key = $1', ['k1']);
|
||||
expect(gone.rowCount).toBe(0);
|
||||
});
|
||||
|
||||
it('fails fast when DATABASE_URL is missing', () => {
|
||||
expect(() => createPoolFromEnv({} as NodeJS.ProcessEnv)).toThrowError(
|
||||
/DATABASE_URL is required/,
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user