UNPKG

jsonschema2ddl

Version:
243 lines 8.83 kB
import * as crypto from "crypto"; import { COLUMNS_TYPES, COLUMNS_TYPES_PREFERENCE, FK_TYPES } from "./types"; import { db_column_name, get_one_schema } from "./utils"; /** * Object to encapsulate a Column. * * Attributes: * name(str): name of the Column. * database_flavor(str): postgres or redshift.Defaults to postgres. * comment(str): comment of the Column.Defaults to None. * constraints(Dict): other columns constraints (not implemented). * jsonschema_fields(Dict): Original fields in the jsonschema. */ export class Column { constructor({ name, database_flavor, comment, constraints, jsonschema_type, jsonschema_fields }) { this.constraints = {}; this.name = name; this.database_flavor = database_flavor || "postgres"; this.comment = comment || ''; this.constraints = constraints || {}; this.jsonschema_type = jsonschema_type || ''; this.jsonschema_fields = jsonschema_fields || {}; } get max_length() { return this.jsonschema_fields["maxLength"] || 256; } /** * Data type of the columns. * * It accounts of the mapping of the original type to the db types. * * Returns: * str: data type of the column. */ get data_type() { if ("format" in this.jsonschema_fields && this.jsonschema_fields["format"] in COLUMNS_TYPES_PREFERENCE) { this.jsonschema_type = this.jsonschema_fields["format"]; } return COLUMNS_TYPES[this.database_flavor][this.jsonschema_type] .replace('{}', String(this.max_length)); } get is_pk() { return !!this.jsonschema_fields["pk"]; } /** * Returns true if the column is a index. * * Returns: * bool: True if it is index. */ get is_index() { return !!this.jsonschema_fields["index"]; } /** * Returns true if the column is a unique. * * Returns: * bool: True if it is unique. */ get is_unique() { return !!this.jsonschema_fields["unique"]; } /** * Returns true if the column is a foreign key. * * Returns: * bool: True if it is foreign key */ get is_fk() { return false; } hash() { return crypto.createHash('sha256').update(this.name).digest('hex'); } toString() { return `Column(name=${this.name} data_type=${this.data_type})`; } } /** * Object to encapsulate a Table. * * Attributes: * ref(str): id or reference to the table in the jsonschema. * name(str): name of the table. * database_flavor(str): postgres or redshift.Defaults to postgres. * columns(List[Column]): columns of the table. * primary_key(Column): Primary key column of the table. * comment(str): comment of the table.Defaults to None. * indexes(List[str]): Table indexeses(not implemented). * unique_columns(List[str]): Table unique constraints(not implemented). * jsonschema_fields(Dict): Original fields in the jsonschema. */ export class Table { constructor({ ref, name, database_flavor, columns, primary_key, comment, indexes, unique_columns, jsonschema_fields }) { this._expanded = false; this.ref = ref; this.name = name; this.database_flavor = database_flavor || "postgres"; this.columns = columns || []; this.primary_key = primary_key; this.comment = comment; this.indexes = indexes || []; this.unique_columns = unique_columns || []; this.jsonschema_fields = jsonschema_fields || {}; } /** * Expand the columns definitions of the * * Args: * table_definitions(Dict, optional): Dictionary with the rest of the * tables definitions.It is used for recursive calls to get the * foreign keys.Defaults to dict(). * columns_definitions(Dict, optional): Dictionary with the definition * of columns outside the main properties field.Defaults to dict(). * referenced(bool, optional): Whether or not the table is referenced * by others.Used to make sure there is a Primary Key defined. * Defaults to False. * * @param table_definitions * @param columns_definitions * @param referenced * @returns */ expand_columns({ table_definitions = {}, columns_definitions = {}, referenced }) { if (this._expanded) { console.log("Already expanded table. Skipping..."); return this; } const props = this.jsonschema_fields["properties"]; for (let [col_name, col_object] of Object.entries(props)) { console.log(`Creating column ${col_name}`); col_name = db_column_name(col_name); console.log(`Renamed column to ${col_name}`); let col; if ("$ref" in col_object) { console.log(`Expanding ${col_name} reference ${col_object["$ref"]}`); console.log(JSON.stringify(table_definitions, null, 2)); if (col_object["$ref"] in table_definitions) { const myref = col_object["$ref"]; console.log(`Column is a FK! Expanding ${myref} before continue...`); table_definitions[myref] = table_definitions[myref].expand_columns({ table_definitions, referenced: true, }); col = new FKColumn({ table_ref: table_definitions[myref], name: col_name, database_flavor: this.database_flavor, }); } else if (col_object["$ref"] in columns_definitions) { console.log("Column ref a type that is not a object. Copy Column from columns definitions"); const myref = col_object["$ref"]; const ref_col = columns_definitions[myref]; const col_as_dict = Object.assign(Object.assign({}, ref_col), { "name": col_name }); col = new Column(col_as_dict); } else { console.log("Skipping ref as it is not in table definitions neither in columns definitions"); continue; } } else { if (!("type" in col_object)) { col_object = get_one_schema(col_object); } col = new Column({ name: col_name, database_flavor: this.database_flavor, jsonschema_type: col_object["type"], jsonschema_fields: col_object, }); } this.columns.push(col); if (col.is_pk) { this.primary_key = col; } console.log(`New created column ${col}`); } if (referenced && !this.primary_key) { console.log("Creating id column for the table in order to reference it as PK"); let idcol = new Column({ name: "id", database_flavor: this.database_flavor, jsonschema_type: "id", }); this.columns.push(idcol); this.primary_key = idcol; } this.columns = this._deduplicate_columns(this.columns); return this; } _deduplicate_columns(columns) { return columns.reduce((a, c) => { if (!a.find(x => x.name === c.name)) { a.push(c); } return a; }, []); } } /** * Special type of Column object to represent a foreign key * * Attributes: * table_ref(Table): Pointer to the foreign table object */ export class FKColumn extends Column { constructor(params) { super(params); this.table_ref = params.table_ref; } /** * Data type of the foreign key. * * Accounts of the data type of the primary key of the foreing table. * * Returns: * str: the column data type. */ get data_type() { var _a; const data_type_ref = ((_a = this.table_ref.primary_key) === null || _a === void 0 ? void 0 : _a.data_type) || ''; if ("varchar" === data_type_ref) { return data_type_ref; } return FK_TYPES[data_type_ref] || "bigint"; } /** * Returns true if the column is a foreign key. * * Returns: * bool: True if it is foreign key. */ get is_fk() { return true; } toString() { return `FKColumn(name=${this.name} data_type=${this.data_type} table_ref.name=${this.table_ref.name})`; } } //# sourceMappingURL=models.js.map