Files
edr-platform/apps/edr-freight-api/src/config/database.config.ts

220 lines
6.6 KiB
TypeScript

import { registerAs } from "@nestjs/config";
import { TypeOrmModuleOptions } from "@nestjs/typeorm";
import { DataSourceOptions } from "typeorm";
import { join, dirname } from "path";
import {
DefaultPosition,
DefaultUnit,
EmployeePosition,
Employee,
OrganizationConfiguration,
GlobalOrganizationConfiguration,
OrganizationType,
Organization,
PositionConfiguration,
PositionPermission,
PositionTypeConfiguration,
PositionTypePermission,
PositionType,
Position,
Project,
GlobalUnitConfiguration,
Unit,
EmployeeSignature,
EmployeeStamp,
RecordFooter,
RecordHeader,
Seal,
AccountConfiguration,
Application,
DocumentaryRequirement,
Permission,
RolePermission,
Role,
Session,
UserCredential,
UserDocument,
UserRole,
UserVerification,
User,
Notification,
NotificationEvent,
NotificationPlaceholder,
NotificationReceiverField,
NotificationReceiver,
NotificationTemplate,
} from "@tria-plc/iamapi-common";
import { OrganizationSetting } from "@tria-plc/iamapi-common/entities/iam/organization-structure/organization-setting.entity";
import { UnitSetting } from "@tria-plc/iamapi-common/entities/iam/organization-structure/unit-setting.entity";
import { UnitDetail } from "@tria-plc/iamapi-common/entities/iam/organization-structure/unit-detail.entity";
import { OrganizationDetail } from "@tria-plc/iamapi-common/entities/iam/organization-structure/organization-detail.entity";
import { UnitCluster } from "@tria-plc/iamapi-common/entities/iam/organization-structure/unit-cluster.entity";
import { Location } from "@tria-plc/iamapi-common/entities/iam/organization-structure/location.entity";
import { LocationType } from "@tria-plc/iamapi-common/entities/iam/organization-structure/location-type.entity";
import { DelegationTerminationReason } from "@tria-plc/iamapi-common/entities/iam/organization-structure/delegation-termination-reason.entity";
import { EmployeePositionActivePeriod } from "@tria-plc/iamapi-common/entities/iam/organization-structure/employee-position-active-period.entity";
import { UnitConfiguration } from "@tria-plc/iamapi-common/entities/iam/organization-structure/unit-configuration.entity";
import { Site } from "@tria-plc/iamapi-common/entities/iam/site/site.entity";
import { SiteSetting } from "@tria-plc/iamapi-common/entities/iam/site/site-setting.entity";
const iamEntities = [
UnitSetting,
UnitDetail,
OrganizationDetail,
UnitCluster,
Location,
LocationType,
DelegationTerminationReason,
EmployeePositionActivePeriod,
UnitConfiguration,
Site,
SiteSetting,
DefaultPosition,
DefaultUnit,
EmployeePosition,
Employee,
OrganizationConfiguration,
GlobalOrganizationConfiguration,
OrganizationSetting,
OrganizationType,
Organization,
PositionConfiguration,
PositionPermission,
PositionTypeConfiguration,
PositionTypePermission,
PositionType,
Position,
Project,
GlobalUnitConfiguration,
Unit,
EmployeeSignature,
EmployeeStamp,
RecordFooter,
RecordHeader,
Seal,
AccountConfiguration,
Application,
DocumentaryRequirement,
Permission,
RolePermission,
Role,
Session,
UserCredential,
UserDocument,
UserRole,
UserVerification,
User,
Notification,
NotificationEvent,
NotificationPlaceholder,
NotificationReceiverField,
NotificationReceiver,
NotificationTemplate,
];
const iamMigrationsGlob = join(
dirname(require.resolve("@tria-plc/iamapi-common/package.json")),
"dist/db/migrations/*.js",
);
const freightMigrationsGlob = join(__dirname, "../migrations/*.js");
/**
* Migration history is split per owner instead of sharing one `public.migrations`
* table:
*
* - IAM migrations ship with `@tria-plc/iamapi-common`, target the `iam` schema
* and are recorded in `iam.typeorm_migrations` — the same table the package's
* own CLI (`pnpm iam:migration:run|show|revert`) uses, so both paths agree on
* what has been applied.
* - Freight migrations are recorded in `freight.migrations`.
*
* `public.migrations` is the pre-split table; `src/scripts/migrate.ts` adopts its
* rows into the two tables above on first run and then leaves it untouched.
*/
export const IAM_MIGRATIONS = {
schema: "iam",
table: "typeorm_migrations",
} as const;
export const FREIGHT_MIGRATIONS = {
schema: "freight",
table: "migrations",
} as const;
export const LEGACY_MIGRATIONS = {
schema: "public",
table: "migrations",
} as const;
function buildConnectionOptions() {
return {
type: "postgres" as const,
host: process.env.DB_HOST ?? "localhost",
port: parseInt(process.env.DB_PORT ?? "5433", 10),
username: process.env.DB_USER ?? "postgres",
password: process.env.DB_PASSWORD ?? "",
database: process.env.DB_NAME ?? "edr_freight",
// NOTE: do NOT pass `extra.options: '-c search_path=...'`. That sends the
// Postgres startup `options` parameter, which connection poolers (PgBouncer /
// proxies fronting the remote edr_dev DB) reject with
// `08P01 unsupported startup parameter in options: search_path`.
// The search_path is instead applied per-connection via a pool `connect`
// handler (app.module.ts `setPoolSearchPath`, migrate.ts `applySearchPath`).
synchronize: false,
logging:
process.env.TYPEORM_LOGGING === "true"
? true
: (["error", "warn"] as DataSourceOptions["logging"]),
};
}
/**
* Runtime options for the API (and the seed scripts using `AppDataSource`).
* Carries no migrations: migrations run only through `src/scripts/migrate.ts`,
* which uses the two dedicated DataSources below.
*/
export function buildDataSourceOptions(): DataSourceOptions {
return {
...buildConnectionOptions(),
schema: "public",
entities: [
__dirname + "/../**/*.entity.{ts,js}",
...iamEntities,
],
migrations: [],
};
}
/** IAM migrations only, recorded in `iam.typeorm_migrations`. */
export function buildIamMigrationDataSourceOptions(): DataSourceOptions {
return {
...buildConnectionOptions(),
schema: IAM_MIGRATIONS.schema,
entities: [],
migrations: [iamMigrationsGlob],
migrationsTableName: IAM_MIGRATIONS.table,
migrationsTransactionMode: "each",
};
}
/** Freight migrations only, recorded in `freight.migrations`. */
export function buildFreightMigrationDataSourceOptions(): DataSourceOptions {
return {
...buildConnectionOptions(),
schema: FREIGHT_MIGRATIONS.schema,
entities: [],
migrations: [freightMigrationsGlob],
migrationsTableName: FREIGHT_MIGRATIONS.table,
migrationsTransactionMode: "each",
};
}
export default registerAs(
"database",
(): TypeOrmModuleOptions => ({
...buildDataSourceOptions(),
autoLoadEntities: true,
migrationsRun: false,
}),
);