import { Validators, ValidatorFn } from '@angular/forms'; import { FormlyFieldConfig } from '@ngx-formly/core'; import { Observable } from 'rxjs/Observable'; import { FormContract } from '../../contracts'; import { ColumnsContract } from './contracts'; export const COLUMNS_PROPERTY = { "TABLE_CATALOG": "TABLE_CATALOG", //"e.g def" "TABLE_SCHEMA": "TABLE_SCHEMA", //"e.g silo" "TABLE_NAME": "TABLE_NAME", //"e.g users" "COLUMN_NAME": "COLUMN_NAME", //"e.g id" //title, label "ORDINAL_POSITION": "ORDINAL_POSITION", //e.g 1 //field position "COLUMN_DEFAULT": "COLUMN_DEFAULT", //e.g null //placeholder, default selection "IS_NULLABLE": "IS_NULLABLE", //"e.g YES" //required "DATA_TYPE": "DATA_TYPE", //"e.g int" //field type "CHARACTER_MAXIMUM_LENGTH": "CHARACTER_MAXIMUM_LENGTH", //"e.g null | 255" //field input validation "CHARACTER_OCTET_LENGTH": "CHARACTER_OCTET_LENGTH", //"e.g null | 1020" "NUMERIC_PRECISION": "NUMERIC_PRECISION", //e.g 10 //field input validation "NUMERIC_SCALE": "NUMERIC_SCALE", //e.g 0 //field input validation "DATETIME_PRECISION": "DATETIME_PRECISION", //e.g null "CHARACTER_SET_NAME": "CHARACTER_SET_NAME", //e.g null "COLLATION_NAME": "COLLATION_NAME",//e.g null "COLUMN_TYPE": "COLUMN_TYPE", //e.g int(10) unsigned", "COLUMN_KEY": "COLUMN_KEY", //"e.g PRI", "EXTRA": "EXTRA", //"e.g auto_increment", "PRIVILEGES": "PRIVILEGES", //"e.g select,insert,update,references", "COLUMN_COMMENT": "COLUMN_COMMENT", //"e.g " //? file | editor "GENERATION_EXPRESSION": "GENERATION_EXPRESSION" //"e.g " } export class FormFactory{ private formFields: FormlyFieldConfig[] = []; constructor(private columns: ColumnsContract[], private data: Object = {}, private excludes?: string[]){} make(): Observable{ this.columns.forEach(column => { if(this.shouldExclude(column)){ this.formFields.push({ id: this.fieldTitle(column), key: this.fieldTitle(column), name: this.fieldTitle(column), className: 'col-md-12', type: this.fieldElementType(column), templateOptions: { type: this.inputFieldType(column), label: this.fieldTitle(column, true).toUpperCase() + ((this.isFieldRequired(column)) ? '*' : '' ), placeholder: this.fieldPlaceholder(column), description: this.fieldDesc(column), // disabled: false, options: this.fieldOptions(column), // hidden: false, // max: 10, // min: 10, // minLength: 10, // maxLength: 10, required: this.isFieldRequired(column), // multiple: true, // accept: ".pdf,.doc,.docx", }, optionsTypes: [''], defaultValue: '', validators: { validation: this.validationRules(column) } }); } }); return Observable.of({ title: this.formTitle(), fields: this.formFields, resource: this.data, summary: '...' }); } shouldExclude(column: ColumnsContract){ return !(['id'].concat(this.excludes).includes( column[COLUMNS_PROPERTY.COLUMN_NAME].split('_').map((column, index) => { return (index > 0) ? column.charAt(0).toUpperCase() + column.slice(1) : column; }).join('')) ); } formTitle(): string{ return this.columns[0][COLUMNS_PROPERTY.TABLE_NAME].toUpperCase() + " Form"; } fieldDesc(column: ColumnsContract){ // return column[COLUMNS_PROPERTY.COLUMN_COMMENT]; return ""; } fieldTitle(column: ColumnsContract, pretify: boolean = false): string{ return (pretify) ? column[COLUMNS_PROPERTY.COLUMN_NAME].replace('_', ' ') : column[COLUMNS_PROPERTY.COLUMN_NAME]; } fieldPosition(column: ColumnsContract): string{ return column[COLUMNS_PROPERTY.ORDINAL_POSITION]; } fieldPlaceholder(column: ColumnsContract): string{ if(this.fieldElementType(column) == "input"){ return (column[COLUMNS_PROPERTY.COLUMN_DEFAULT])? column[COLUMNS_PROPERTY.COLUMN_DEFAULT] : 'enter ' + column[COLUMNS_PROPERTY.COLUMN_NAME]; } } isFieldRequired(column: ColumnsContract): boolean{ return (column[COLUMNS_PROPERTY.IS_NULLABLE] == 'NO') ? true : false; } fieldElementType(column: ColumnsContract): string{ //first check if comment contain custom type declaration if(column[COLUMNS_PROPERTY.COLUMN_COMMENT].includes('editor')){ return "editor"; } if(column[COLUMNS_PROPERTY.COLUMN_COMMENT].includes('uploader')){ return "uploader"; } if(column[COLUMNS_PROPERTY.COLUMN_COMMENT].includes('timepicker')){ return "timepicker"; } //Numbers + Logic + Time + More Time if(["int", "tinyint", "smallint", "mediumint", "integer", "bigint", "decimal", "dec", "float", "double", "date", "datetime", "time", "timestamp", "year", "char", "binary", "varbinary", "tinyblob","mediumblob", "longblob", "blob" ].includes(column[COLUMNS_PROPERTY.DATA_TYPE])){ return "input"; } //Logic else if(["boolean", "bool", "enum", "set"].includes(column[COLUMNS_PROPERTY.DATA_TYPE])){ return "select"; } //Long Strings else if(["varchar", "tinytext", "mediumtext", "longtext", "text", "json"].includes(column[COLUMNS_PROPERTY.DATA_TYPE])){ return (column[COLUMNS_PROPERTY.CHARACTER_MAXIMUM_LENGTH] > 255) ? "textarea" : "input"; } //Default else{ return "input"; } } inputFieldType(column: ColumnsContract): string{ //first check if comment contain 'file' if(column[COLUMNS_PROPERTY.COLUMN_COMMENT].includes('uploader')){ return "file"; } //first check if comment contain 'password' if(column[COLUMNS_PROPERTY.COLUMN_COMMENT].includes('password')){ return "password"; } //Numbers if(["int", "tinyint", "smallint", "mediumint", "integer", "bigint", "decimal", "dec", "float", "double"].includes(column[COLUMNS_PROPERTY.DATA_TYPE])){ return "number"; } //Logic else if(["boolean", "bool"].includes(column[COLUMNS_PROPERTY.DATA_TYPE])){ return "radio"; } //Time else if(["date", "datetime", "time"].includes(column[COLUMNS_PROPERTY.DATA_TYPE])){ return column[COLUMNS_PROPERTY.DATA_TYPE]; } //More Time else if(["timestamp", "year"].includes(column[COLUMNS_PROPERTY.DATA_TYPE])){ return "datetime"; } //Strings else if(["char", "varchar", "binary", "varbinary", "tinytext", "mediumtext", "longtext", "text", "enum", "set", "tinyblob","mediumblob", "longblob", "blob", "json"].includes(column[COLUMNS_PROPERTY.DATA_TYPE])){ return "text"; } } validationRules(column: ColumnsContract): ValidatorFn{ return Validators.compose([ (this.isFieldRequired(column)) ? Validators.required : null, Validators.minLength(4), Validators.maxLength(24) ]); } fieldOptions(column): Object[]{ //if column type is enum //retrieve enum values and turn to array //"enum('event','activity','report')" if(column[COLUMNS_PROPERTY.COLUMN_TYPE] && column[COLUMNS_PROPERTY.COLUMN_TYPE].includes('enum')){ return column[COLUMNS_PROPERTY.COLUMN_TYPE] .replace("enum('", "") .replace("')", "") .split("','") .map((value)=>{ return { label: value, value: value }; }); } } }