import { DataSource, DataSourceOptions } from "typeorm"; /** Schemas required before TypeORM migrations and entity access. */ export const APPLICATION_SCHEMAS = [ "public", "iam", "freight", "audit", ] as const; export const APPLICATION_SEARCH_PATH = APPLICATION_SCHEMAS.join(","); /** * TypeORM creates the migrations table before any migration runs. If `public` was * dropped, current_schema() is null and CREATE TABLE migrations fails. * IAM/freight migrations assume their schemas already exist. */ export async function ensurePostgresSchemas( options: DataSourceOptions, ): Promise { const bootstrap = new DataSource({ ...options, entities: [], migrations: [], migrationsRun: false, synchronize: false, }); await bootstrap.initialize(); for (const schema of APPLICATION_SCHEMAS) { if (schema === "public") { await bootstrap.query(`CREATE SCHEMA IF NOT EXISTS public`); await bootstrap.query(`GRANT ALL ON SCHEMA public TO public`); await bootstrap.query(`GRANT CREATE ON SCHEMA public TO public`); } else { await bootstrap.query(`CREATE SCHEMA IF NOT EXISTS "${schema}"`); await bootstrap.query(`GRANT USAGE ON SCHEMA "${schema}" TO public`); await bootstrap.query( `GRANT CREATE ON SCHEMA "${schema}" TO public`, ); } } await bootstrap.query( `SET search_path TO ${APPLICATION_SEARCH_PATH}`, ); await bootstrap.destroy(); }