import { JSONSchema4 } from 'json-schema'; import { PgColumn, PgFkColumn, PgTable, TableSmartTags, } from '../../abstractions'; import { PublishSchemaToDbOptions } from '../../publish-schema-to-db-options'; import { PkColumn, PrimitiveColumn } from '../columns'; import { filterProperties, isPrimitiveProperty, mapToPgType, } from '../json-schema-parse-utils'; import { buildAdditionalTableStatements, buildCreateTable, buildDropTableIfExists, buildFullTableName, buildInsertUpdateGrants, buildSelectDeleteGrants, } from '../pg-sql-gen-utils'; import { buildAttributeSmartTags } from '../pgl-utils'; /** * Table model for storing primitive properties of a root entity (movie, collection etc.). */ export class ContentEntityTable 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 creating ContentEntityTable. * @param name - Name of the table. * @param schema - Name of the database schema. * @param jsonSchemas - Schemas of primitive properties. */ constructor( options: PublishSchemaToDbOptions, name: string, jsonSchemas: { [p: string]: JSONSchema4 }, description?: string, ) { this.options = options; this.name = name; this.description = description; if (jsonSchemas[options.idKey] === undefined) { throw Error(`Could not find the expected PK property "${options.idKey}"`); } // 1. Create the PK. this.pk = new PkColumn(this, mapToPgType(jsonSchemas[options.idKey])); // 2. Iterate over (already separated) primitive properties. const excluded = [...options.ignoredProperties, options.idKey]; for (const propertyName in filterProperties(jsonSchemas, excluded)) { const schema = jsonSchemas[propertyName] as JSONSchema4; if (!isPrimitiveProperty(schema)) { throw new Error( 'Non-primitive properties are not supported in content entities', ); } // 3. Create regular 'data' columns. this.columns.push( new PrimitiveColumn(propertyName, mapToPgType(schema), this, { description: schema.description, indexable: propertyName === 'order_no', // Somewhat stinky but it could also be a part of convention. }), ); } } buildFullName(): string { return buildFullTableName(this.name, this.options.dbSchema); } buildStatements(): string[] { return [ buildDropTableIfExists(this), buildCreateTable(this), ...buildAdditionalTableStatements(this), buildSelectDeleteGrants(this), buildInsertUpdateGrants(this), ]; } buildSmartTags(): TableSmartTags { return { description: this.description, attribute: buildAttributeSmartTags(this.columns), tags: { omit: 'create,update,delete', }, }; } }