@accounter/server
Version:
Accounter GraphQL server
75 lines (67 loc) • 2.16 kB
text/typescript
import { type Client, Pool, type PoolClient } from 'pg';
import { LATEST_MIGRATION_NAME } from '../../../../migrations/src/run-pg-migrations.js';
export { LATEST_MIGRATION_NAME };
interface MigrationCheckResult {
isLatest: boolean;
latestMigrationName: string | undefined;
errorMessage?: string;
}
/**
* Check if the latest migration has been applied to the database.
* Returns result object with status - does not throw.
*/
export async function checkLatestMigration(
clientOrPool: Pool | PoolClient | Client,
schema = 'accounter_schema',
): Promise<MigrationCheckResult> {
let client: PoolClient | Client;
let shouldRelease = false;
if (clientOrPool instanceof Pool) {
const poolClient = await clientOrPool.connect();
client = poolClient;
shouldRelease = true;
} else {
// It's already a Client or PoolClient
client = clientOrPool;
}
try {
const result = await client.query(
`SELECT 1 FROM ${schema}.migration WHERE name = $1 LIMIT 1`,
[LATEST_MIGRATION_NAME],
);
const isLatest = result.rowCount === 1;
return {
isLatest,
latestMigrationName: LATEST_MIGRATION_NAME,
errorMessage: isLatest
? undefined
: `Latest migration "${LATEST_MIGRATION_NAME}" not found in database`,
};
} catch (error) {
return {
isLatest: false,
latestMigrationName: LATEST_MIGRATION_NAME,
errorMessage: `Failed to check migrations: ${error instanceof Error ? error.message : String(error)}`,
};
} finally {
if (shouldRelease && 'release' in client) {
await client.release();
}
}
}
/**
* Assert that the latest migration has been applied.
* Throws an error with helpful message if not.
*/
export async function assertLatestMigrationApplied(
clientOrPool: Pool | PoolClient | Client,
schema = 'accounter_schema',
): Promise<void> {
const result = await checkLatestMigration(clientOrPool, schema);
if (!result.isLatest) {
throw new Error(
result.errorMessage ||
`Migration check failed for ${result.latestMigrationName}. Run: yarn workspace @accounter/migrations migration:run`,
);
}
}