import { JSONSchema4 } from 'json-schema'; import { PgColumn, PgFkColumn, PgTable, TableSmartTags, } from '../../abstractions'; import { PublishSchemaToDbOptions } from '../../publish-schema-to-db-options'; import { FkColumn, PkColumn, PrimitiveColumn } from '../columns'; import { isPrimitiveProperty, mapToPgType } from '../json-schema-parse-utils'; import { buildAdditionalTableStatements, buildCreateTable, buildDropTableIfExists, buildFullTableName, buildInsertUpdateGrants, buildName, buildSelectDeleteGrants, } from '../pg-sql-gen-utils'; import { buildAttributeSmartTags, buildFkConstraintSmartTags, snakeCaseToCamelCase, } from '../pgl-utils'; /** * Table model for storing complex/object properties (licensing, video streams etc.) of a root entity. * It will have a FK relation to the root entity in the database. */ export class ObjectPropertyTable 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 ObjectPropertyTable. * @param propertyName - Name of the property. * @param schema - DB schema where this table will be created. * @param jsonSchema - JSON schema describing this object property. * @param contentEntityPk - PK of the content entity this object property belongs to. */ constructor( options: PublishSchemaToDbOptions, propertyName: string, jsonSchema: JSONSchema4, contentEntityPk: PgColumn, ) { const isArray = jsonSchema.type === 'array'; jsonSchema = isArray ? (jsonSchema?.items as JSONSchema4) : jsonSchema; this.options = options; this.name = buildName(contentEntityPk.table.name, propertyName); this.displayName = snakeCaseToCamelCase(propertyName); this.description = jsonSchema.description; // 1. Create a synthetic PK for this table. this.pk = new PkColumn(this, 'INTEGER'); // 2. Iterate over object properties, convert them to column definitions. for (const key in jsonSchema.properties) { if (options.ignoredProperties.includes(key)) { continue; } const propSchema = jsonSchema.properties[key] as JSONSchema4; if (!isPrimitiveProperty(propSchema)) { throw new TypeError( `Unsupported property in object schema: ${propSchema}`, ); } this.columns.push( new PrimitiveColumn(key, mapToPgType(propSchema), this, { description: propSchema.description, }), ); } // 3. Add FK(s). this.fks.push(new FkColumn(contentEntityPk, this)); } buildFullName(): string { return buildFullTableName(this.name, this.options.dbSchema); } buildSmartTags(): TableSmartTags { return { description: this.description, attribute: buildAttributeSmartTags(this.columns), tags: { omitFromQueryRoot: true, omit: 'create,update,delete', }, constraint: buildFkConstraintSmartTags(this.fks), }; } buildStatements(): string[] { return [ buildDropTableIfExists(this), buildCreateTable(this), ...buildAdditionalTableStatements(this), buildSelectDeleteGrants(this), buildInsertUpdateGrants(this), ]; } }