import { PgColumn, PgFkColumn, PgTable, PgType, TableSmartTags, } from '../../abstractions'; import { PublishSchemaToDbOptions } from '../../publish-schema-to-db-options'; import { FkColumn, PkColumn, PrimitiveColumn, PrimitiveColumnOptions, VirtualFkColumn, } from '../columns'; import { buildAdditionalTableStatements, buildCreateTable, buildDropTableIfExists, buildFullTableName, buildInsertUpdateGrants, buildName, buildSelectDeleteGrants, } from '../pg-sql-gen-utils'; import { buildFkConstraintSmartTags, buildVirtualFkSmartTags, } from '../pgl-utils'; /** * Configuration interface for creating additional columns in the relations table. */ export interface AdditionalColumnOptions { /** Name of the column. */ name: string; /** Type of the column. */ type: PgType; /** Additional options. */ options?: PrimitiveColumnOptions; } /** * Table model for maintaining arbitrary (soft/virtual) on-to-many relationships. */ export class RelationsTable implements PgTable { name: string; displayName?: string; readonly description?: string; readonly pk: PgColumn; readonly fks: PgFkColumn[] = []; readonly virtualFks: PgFkColumn[] = []; readonly columns: PgColumn[] = []; private options: PublishSchemaToDbOptions; /** * Constructor for RelationsTable. * @param contentEntity - Content entity these relations are attached to. * @param relatedEntities - Array of other content entities to create relations to. * @param schema - DB schema where this table will be created. * @param displayName - Display name of this table, used in the generated GQL API. * @param additionalColumnOptions - Array of configuration objects for constructing additional PrimitiveColumn instances. */ constructor( config: PublishSchemaToDbOptions, contentEntity: PgTable, relatedEntities: PgTable[], displayName: string, additionalColumnOptions?: AdditionalColumnOptions[], description?: string, ) { this.options = config; this.displayName = displayName; this.name = buildName(contentEntity.pk.table.name, displayName, 'relation'); this.description = description; this.pk = new PkColumn(this, 'INTEGER'); this.fks.push(new FkColumn(contentEntity.pk, this)); if (additionalColumnOptions) { this.columns.push( ...additionalColumnOptions.map( (o) => new PrimitiveColumn(o.name, o.type, this, o.options), ), ); } for (const relatedEntity of relatedEntities) { this.virtualFks.push(new VirtualFkColumn(relatedEntity.pk, this)); } } buildFullName(): string { return buildFullTableName(this.name, this.options.dbSchema); } buildSmartTags(): TableSmartTags { return { description: this.description, tags: { omitFromQueryRoot: true, omit: 'create,update,delete', foreignKey: buildVirtualFkSmartTags(this.virtualFks), }, constraint: buildFkConstraintSmartTags(this.fks), }; } buildStatements(): string[] { return [ buildDropTableIfExists(this), buildCreateTable(this), ...buildAdditionalTableStatements(this), buildSelectDeleteGrants(this), buildInsertUpdateGrants(this), ]; } }