From 6788a8d5490a8ade62b9469bc2d54d38c3e049c4 Mon Sep 17 00:00:00 2001 From: Israel dela Cruz Date: Fri, 6 Aug 2021 14:49:41 -0500 Subject: [PATCH 1/9] fixed class and creation fields optionality --- src/auto-generator.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/auto-generator.ts b/src/auto-generator.ts index 8c766e37..d8cf2d10 100644 --- a/src/auto-generator.ts +++ b/src/auto-generator.ts @@ -111,7 +111,13 @@ export class AutoGenerator { if (primaryKeys.length) { str += `export type #TABLE#Pk = ${primaryKeys.map((k) => `"${recase(this.options.caseProp, k)}"`).join(' | ')};\n`; str += `export type #TABLE#Id = #TABLE#[#TABLE#Pk];\n`; - str += "export type #TABLE#CreationAttributes = Optional<#TABLE#Attributes, #TABLE#Pk>;\n\n"; + } + + const creationOptionalFields = this.getTypeScriptCreationOptionalFields(table); + + if (creationOptionalFields.length) { + str += `export type #TABLE#OptionalAttributes = ${creationOptionalFields.map((k) => `"${recase(this.options.caseProp, k)}"`).join(' | ')};\n`; + str += "export type #TABLE#CreationAttributes = Optional<#TABLE#Attributes, #TABLE#OptionalAttributes>;\n\n"; } else { str += "export type #TABLE#CreationAttributes = #TABLE#Attributes;\n\n"; } @@ -528,6 +534,14 @@ export class AutoGenerator { }); } + private getTypeScriptCreationOptionalFields(table: string): Array { + const fields = _.keys(this.tables[table]); + return fields.filter((field): boolean => { + const fieldObj = this.tables[table][field]; + return fieldObj.allowNull || (!!fieldObj.defaultValue || fieldObj.defaultValue === "") || fieldObj.primaryKey; + }); + } + /** Add schema to table so it will match the relation data. Fixes mysql problem. */ private addSchemaForRelations(table: string) { if (!table.includes('.') && !this.relations.some(rel => rel.childTable === table)) { @@ -647,7 +661,7 @@ export class AutoGenerator { private getTypeScriptFieldOptional(table: string, field: string) { const fieldObj = this.tables[table][field]; - return fieldObj.allowNull || (fieldObj.defaultValue || fieldObj.defaultValue === ""); + return fieldObj.allowNull; } private getTypeScriptType(table: string, field: string) { From 11d1235510fbd4e932d1d1987725c533c5499437 Mon Sep 17 00:00:00 2001 From: Israel dela Cruz Date: Fri, 6 Aug 2021 20:34:31 -0500 Subject: [PATCH 2/9] typeOverrides option --- src/auto-generator.ts | 76 ++++++++++++++++++++++++++++++++++++++++--- src/types.ts | 12 +++++++ 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/auto-generator.ts b/src/auto-generator.ts index d8cf2d10..df163225 100644 --- a/src/auto-generator.ts +++ b/src/auto-generator.ts @@ -1,7 +1,7 @@ import _ from "lodash"; import { ColumnDescription } from "sequelize/types"; import { DialectOptions, FKSpec } from "./dialects/dialect-options"; -import { AutoOptions, CaseOption, Field, IndexSpec, LangOption, qNameJoin, qNameSplit, recase, Relation, TableData, TSField, singularize, pluralize } from "./types"; +import { AutoOptions, CaseOption, Field, IndexSpec, LangOption, qNameJoin, qNameSplit, recase, Relation, TableData, TSField, singularize, pluralize, TypeOverrides, ColumnTypeOverride, TableTypeOverride } from "./types"; /** Generates text from each table in TableData */ export class AutoGenerator { @@ -22,6 +22,7 @@ export class AutoGenerator { additional?: any; schema?: string; singularize: boolean; + typeOverrides?: TypeOverrides; }; constructor(tableData: TableData, dialect: DialectOptions, options: AutoOptions) { @@ -103,8 +104,69 @@ export class AutoGenerator { str += ` } from './${filename}';\n`; }); + const typeOverrides = this.options.typeOverrides; + let tableTypeOverride: TableTypeOverride | undefined; + if (typeOverrides) { + if (typeOverrides.tables) { + tableTypeOverride = typeOverrides.tables[tableNameOrig!]; + const columnTypeOverridesByType: { [type: string]: ColumnTypeOverride } = {} + // type should only be imported once for each file + _.keys(tableTypeOverride).forEach((columnName) => { + const columnTypeOverride = tableTypeOverride![columnName]!; + columnTypeOverridesByType[columnTypeOverride.type] = columnTypeOverride; + }); + + // import per source + const imports: { [source: string]: { default?: string, types: string[] } } = {}; + _.keys(columnTypeOverridesByType).forEach((type) => { + const columnTypeOverride = columnTypeOverridesByType[type]; + const importData = imports[columnTypeOverride.source]; + if (importData) { + if (columnTypeOverride.isDefault) { + importData.default = columnTypeOverride.type; + } else { + importData.types.push(columnTypeOverride.type); + } + } else { + let newImportData: { default?: string, types: string[] }; + if (columnTypeOverride.isDefault) { + newImportData = { + default: columnTypeOverride.type, + types: [], + } + } else { + newImportData = { + types: [columnTypeOverride.type], + } + } + imports[columnTypeOverride.source] = newImportData; + } + }); + + const importStrArr: string[] = []; + _.keys(imports).forEach((source) => { + const importData = imports[source]; + let importStr = "import"; + if (importData.default) { + importStr += ` ${importData.default}`; + } + + if (importData.types.length !== 0) { + importStr += (importData.default ? ", " : " ") + `{ ${importData.types.join(", ")} }`; + } + + importStr += ` from '${source}';`; + importStrArr.push(importStr); + }); + + if (importStrArr.length !== 0) { + str += importStrArr.join("\n") + "\n"; + } + } + } + str += "\nexport interface #TABLE#Attributes {\n"; - str += this.addTypeScriptFields(table, true) + "}\n\n"; + str += this.addTypeScriptFields(table, true, tableTypeOverride) + "}\n\n"; const primaryKeys = this.getTypeScriptPrimaryKeys(table); @@ -123,7 +185,7 @@ export class AutoGenerator { } str += "export class #TABLE# extends Model<#TABLE#Attributes, #TABLE#CreationAttributes> implements #TABLE#Attributes {\n"; - str += this.addTypeScriptFields(table, false); + str += this.addTypeScriptFields(table, false, tableTypeOverride); str += "\n" + associations.str; str += "\n" + this.space[1] + "static initModel(sequelize: Sequelize.Sequelize): typeof " + tableName + " {\n"; str += this.space[2] + tableName + ".init({\n"; @@ -646,7 +708,7 @@ export class AutoGenerator { return { needed, str }; } - private addTypeScriptFields(table: string, isInterface: boolean) { + private addTypeScriptFields(table: string, isInterface: boolean, tableTypeOverride: TableTypeOverride | undefined) { const sp = this.space[1]; const fields = _.keys(this.tables[table]); const notNull = isInterface ? '' : '!'; @@ -654,7 +716,11 @@ export class AutoGenerator { fields.forEach(field => { const name = this.quoteName(recase(this.options.caseProp, field)); const isOptional = this.getTypeScriptFieldOptional(table, field); - str += `${sp}${name}${isOptional ? '?' : notNull}: ${this.getTypeScriptType(table, field)};\n`; + let columnTypeOverride: ColumnTypeOverride | undefined; + if (tableTypeOverride) { + columnTypeOverride = tableTypeOverride[field]; + } + str += `${sp}${name}${isOptional ? '?' : notNull}: ${columnTypeOverride ? columnTypeOverride.type : this.getTypeScriptType(table, field)};\n`; }); return str; } diff --git a/src/types.ts b/src/types.ts index 4c56f91e..059f0530 100644 --- a/src/types.ts +++ b/src/types.ts @@ -166,6 +166,8 @@ export interface AutoOptions { username?: string; /** Whether to export views (default false) */ views?: boolean; + /** Override the types of generated typescript file */ + typeOverrides?: TypeOverrides; } export type TSField = { special: string[]; elementType: string; } & ColumnDescription; @@ -208,3 +210,13 @@ export function recase(opt: CaseOption | undefined, val: string | null, singular return val; } +export interface ColumnTypeOverride { + type: string; + source: string; + isDefault: boolean; +} +export type TableTypeOverride = { [columnName: string]: ColumnTypeOverride | undefined }; +export type TableTypeOverrides = { [tableName: string]: TableTypeOverride | undefined } +export interface TypeOverrides { + tables?: TableTypeOverrides; +} From c04611a5e40cca9dc105a55dac595f3c2e1d75c0 Mon Sep 17 00:00:00 2001 From: Israel dela Cruz Date: Sat, 7 Aug 2021 01:02:38 -0500 Subject: [PATCH 3/9] added isOptional --- src/auto-generator.ts | 124 +++++++++++++++++++++++------------------- src/types.ts | 26 +++++++-- 2 files changed, 89 insertions(+), 61 deletions(-) diff --git a/src/auto-generator.ts b/src/auto-generator.ts index df163225..398857e3 100644 --- a/src/auto-generator.ts +++ b/src/auto-generator.ts @@ -1,7 +1,7 @@ import _ from "lodash"; import { ColumnDescription } from "sequelize/types"; import { DialectOptions, FKSpec } from "./dialects/dialect-options"; -import { AutoOptions, CaseOption, Field, IndexSpec, LangOption, qNameJoin, qNameSplit, recase, Relation, TableData, TSField, singularize, pluralize, TypeOverrides, ColumnTypeOverride, TableTypeOverride } from "./types"; +import { AutoOptions, CaseOption, Field, IndexSpec, LangOption, qNameJoin, qNameSplit, recase, Relation, TableData, TSField, singularize, pluralize, TypeOverrides, ColumnTypeOverride, TableTypeOverride, TableTypeOverrides } from "./types"; /** Generates text from each table in TableData */ export class AutoGenerator { @@ -107,60 +107,10 @@ export class AutoGenerator { const typeOverrides = this.options.typeOverrides; let tableTypeOverride: TableTypeOverride | undefined; if (typeOverrides) { - if (typeOverrides.tables) { - tableTypeOverride = typeOverrides.tables[tableNameOrig!]; - const columnTypeOverridesByType: { [type: string]: ColumnTypeOverride } = {} - // type should only be imported once for each file - _.keys(tableTypeOverride).forEach((columnName) => { - const columnTypeOverride = tableTypeOverride![columnName]!; - columnTypeOverridesByType[columnTypeOverride.type] = columnTypeOverride; - }); - - // import per source - const imports: { [source: string]: { default?: string, types: string[] } } = {}; - _.keys(columnTypeOverridesByType).forEach((type) => { - const columnTypeOverride = columnTypeOverridesByType[type]; - const importData = imports[columnTypeOverride.source]; - if (importData) { - if (columnTypeOverride.isDefault) { - importData.default = columnTypeOverride.type; - } else { - importData.types.push(columnTypeOverride.type); - } - } else { - let newImportData: { default?: string, types: string[] }; - if (columnTypeOverride.isDefault) { - newImportData = { - default: columnTypeOverride.type, - types: [], - } - } else { - newImportData = { - types: [columnTypeOverride.type], - } - } - imports[columnTypeOverride.source] = newImportData; - } - }); - - const importStrArr: string[] = []; - _.keys(imports).forEach((source) => { - const importData = imports[source]; - let importStr = "import"; - if (importData.default) { - importStr += ` ${importData.default}`; - } - - if (importData.types.length !== 0) { - importStr += (importData.default ? ", " : " ") + `{ ${importData.types.join(", ")} }`; - } - - importStr += ` from '${source}';`; - importStrArr.push(importStr); - }); - - if (importStrArr.length !== 0) { - str += importStrArr.join("\n") + "\n"; + if (typeOverrides.tables && tableNameOrig) { + tableTypeOverride = typeOverrides.tables[tableNameOrig]; + if (tableTypeOverride) { + str += this.getTypeScriptTableOverrideImports(tableTypeOverride); } } } @@ -708,18 +658,78 @@ export class AutoGenerator { return { needed, str }; } + private getTypeScriptTableOverrideImports(tableTypeOverride: TableTypeOverride) { + const columnTypeOverridesByType: { [type: string]: ColumnTypeOverride } = {} + // type should only be imported once for each file + _.keys(tableTypeOverride).forEach((columnName) => { + const columnTypeOverride = tableTypeOverride![columnName]!; + columnTypeOverridesByType[columnTypeOverride.type] = columnTypeOverride; + }); + + // import per source + const imports: { [source: string]: { default?: string, types: string[] } } = {}; + _.keys(columnTypeOverridesByType).forEach((type) => { + const columnTypeOverride = columnTypeOverridesByType[type]; + if (columnTypeOverride.source) { + const importData = imports[columnTypeOverride.source]; + if (importData) { + if (columnTypeOverride.isDefault) { + importData.default = columnTypeOverride.type; + } else { + importData.types.push(columnTypeOverride.type); + } + } else { + let newImportData: { default?: string, types: string[] }; + if (columnTypeOverride.isDefault) { + newImportData = { + default: columnTypeOverride.type, + types: [], + } + } else { + newImportData = { + types: [columnTypeOverride.type], + } + } + imports[columnTypeOverride.source] = newImportData; + } + } + }); + + const importStrArr: string[] = []; + _.keys(imports).forEach((source) => { + const importData = imports[source]; + let importStr = "import"; + if (importData.default) { + importStr += ` ${importData.default}`; + } + + if (importData.types.length !== 0) { + importStr += (importData.default ? ", " : " ") + `{ ${importData.types.join(", ")} }`; + } + + importStr += ` from '${source}';`; + importStrArr.push(importStr); + }); + + if (importStrArr.length !== 0) { + return importStrArr.join("\n") + "\n"; + } + + return ""; + } + private addTypeScriptFields(table: string, isInterface: boolean, tableTypeOverride: TableTypeOverride | undefined) { const sp = this.space[1]; const fields = _.keys(this.tables[table]); const notNull = isInterface ? '' : '!'; let str = ''; fields.forEach(field => { - const name = this.quoteName(recase(this.options.caseProp, field)); - const isOptional = this.getTypeScriptFieldOptional(table, field); let columnTypeOverride: ColumnTypeOverride | undefined; if (tableTypeOverride) { columnTypeOverride = tableTypeOverride[field]; } + const name = this.quoteName(recase(this.options.caseProp, field)); + const isOptional = columnTypeOverride?.isOptional || this.getTypeScriptFieldOptional(table, field); str += `${sp}${name}${isOptional ? '?' : notNull}: ${columnTypeOverride ? columnTypeOverride.type : this.getTypeScriptType(table, field)};\n`; }); return str; diff --git a/src/types.ts b/src/types.ts index 059f0530..4098fb3c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -162,12 +162,12 @@ export interface AutoOptions { storage?: string; /** Tables to export (default all) */ tables?: string[]; + /** Override the types of generated typescript file */ + typeOverrides?: TypeOverrides; /** Database username */ username?: string; /** Whether to export views (default false) */ views?: boolean; - /** Override the types of generated typescript file */ - typeOverrides?: TypeOverrides; } export type TSField = { special: string[]; elementType: string; } & ColumnDescription; @@ -210,13 +210,31 @@ export function recase(opt: CaseOption | undefined, val: string | null, singular return val; } +/** + * @type Required. Name of the type + * @source Optional. File path of the type relative to file in the directory. + * Leave undefined if overriding with primitive types + * @isDefault Optional. Whether the type is an export default + * @isOptional Optional. Whether to add ? + */ export interface ColumnTypeOverride { type: string; - source: string; - isDefault: boolean; + source?: string; + isDefault?: boolean; + isOptional?: boolean; } export type TableTypeOverride = { [columnName: string]: ColumnTypeOverride | undefined }; export type TableTypeOverrides = { [tableName: string]: TableTypeOverride | undefined } +/** + * @tables { + * roles: { + * name: { + * type: "RoleTypes", + * source: "../RoleTypes" + * } + * } + * } + */ export interface TypeOverrides { tables?: TableTypeOverrides; } From af876fef243118e3b5fffbd3d2c6f230b6624584 Mon Sep 17 00:00:00 2001 From: Israel dela Cruz Date: Mon, 9 Aug 2021 21:43:21 -0500 Subject: [PATCH 4/9] typescript. fix update attributes not accepting null --- src/auto-generator.ts | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/auto-generator.ts b/src/auto-generator.ts index d8cf2d10..3e02b0cc 100644 --- a/src/auto-generator.ts +++ b/src/auto-generator.ts @@ -649,21 +649,15 @@ export class AutoGenerator { private addTypeScriptFields(table: string, isInterface: boolean) { const sp = this.space[1]; const fields = _.keys(this.tables[table]); - const notNull = isInterface ? '' : '!'; let str = ''; fields.forEach(field => { const name = this.quoteName(recase(this.options.caseProp, field)); - const isOptional = this.getTypeScriptFieldOptional(table, field); - str += `${sp}${name}${isOptional ? '?' : notNull}: ${this.getTypeScriptType(table, field)};\n`; + const fieldObj = this.tables[table][field]; + str += `${sp}${name}${isInterface ? '' : '!'}: ${this.getTypeScriptType(table, field) + (fieldObj.allowNull ? " | null" : "")};\n`; }); return str; } - private getTypeScriptFieldOptional(table: string, field: string) { - const fieldObj = this.tables[table][field]; - return fieldObj.allowNull; - } - private getTypeScriptType(table: string, field: string) { const fieldObj = this.tables[table][field] as TSField; return this.getTypeScriptFieldType(fieldObj, "type"); From 1d3b665c42acd81f14b9196765b6dea2633155f7 Mon Sep 17 00:00:00 2001 From: Israel dela Cruz Date: Mon, 23 Aug 2021 15:56:44 -0500 Subject: [PATCH 5/9] remove pk from creation optional fields --- src/auto-generator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auto-generator.ts b/src/auto-generator.ts index 3e02b0cc..2de519f9 100644 --- a/src/auto-generator.ts +++ b/src/auto-generator.ts @@ -538,7 +538,7 @@ export class AutoGenerator { const fields = _.keys(this.tables[table]); return fields.filter((field): boolean => { const fieldObj = this.tables[table][field]; - return fieldObj.allowNull || (!!fieldObj.defaultValue || fieldObj.defaultValue === "") || fieldObj.primaryKey; + return fieldObj.allowNull || (!!fieldObj.defaultValue || fieldObj.defaultValue === ""); }); } From 621dc7f71f431f935cac5de2bd1990599f0a81cd Mon Sep 17 00:00:00 2001 From: Israel dela Cruz Date: Mon, 23 Aug 2021 21:29:46 -0500 Subject: [PATCH 6/9] useOptionalForNullColumns --- src/auto-generator.ts | 28 +++++++++++++++++++--------- src/types.ts | 10 ++++++---- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/auto-generator.ts b/src/auto-generator.ts index adc01171..10449ba7 100644 --- a/src/auto-generator.ts +++ b/src/auto-generator.ts @@ -116,7 +116,7 @@ export class AutoGenerator { } str += "\nexport interface #TABLE#Attributes {\n"; - str += this.addTypeScriptFields(table, true, tableTypeOverride) + "}\n\n"; + str += this.addTypeScriptFields(table, true, tableTypeOverride, typeOverrides?.useOptionalForNullColumns) + "}\n\n"; const primaryKeys = this.getTypeScriptPrimaryKeys(table); @@ -135,7 +135,7 @@ export class AutoGenerator { } str += "export class #TABLE# extends Model<#TABLE#Attributes, #TABLE#CreationAttributes> implements #TABLE#Attributes {\n"; - str += this.addTypeScriptFields(table, false, tableTypeOverride); + str += this.addTypeScriptFields(table, false, tableTypeOverride, typeOverrides?.useOptionalForNullColumns); str += "\n" + associations.str; str += "\n" + this.space[1] + "static initModel(sequelize: Sequelize.Sequelize): typeof " + tableName + " {\n"; str += this.space[2] + tableName + ".init({\n"; @@ -663,7 +663,9 @@ export class AutoGenerator { // type should only be imported once for each file _.keys(tableTypeOverride).forEach((columnName) => { const columnTypeOverride = tableTypeOverride![columnName]!; - columnTypeOverridesByType[columnTypeOverride.type] = columnTypeOverride; + if (columnTypeOverride.type) { + columnTypeOverridesByType[columnTypeOverride.type] = columnTypeOverride; + } }); // import per source @@ -674,20 +676,20 @@ export class AutoGenerator { const importData = imports[columnTypeOverride.source]; if (importData) { if (columnTypeOverride.isDefault) { - importData.default = columnTypeOverride.type; + importData.default = type; } else { - importData.types.push(columnTypeOverride.type); + importData.types.push(type); } } else { let newImportData: { default?: string, types: string[] }; if (columnTypeOverride.isDefault) { newImportData = { - default: columnTypeOverride.type, + default: type, types: [], } } else { newImportData = { - types: [columnTypeOverride.type], + types: [type], } } imports[columnTypeOverride.source] = newImportData; @@ -718,7 +720,7 @@ export class AutoGenerator { return ""; } - private addTypeScriptFields(table: string, isInterface: boolean, tableTypeOverride: TableTypeOverride | undefined) { + private addTypeScriptFields(table: string, isInterface: boolean, tableTypeOverride: TableTypeOverride | undefined, useOptionalForNullColumns: boolean | undefined) { const sp = this.space[1]; const fields = _.keys(this.tables[table]); let str = ''; @@ -730,7 +732,15 @@ export class AutoGenerator { } const name = this.quoteName(recase(this.options.caseProp, field)); const fieldObj = this.tables[table][field]; - str += `${sp}${name}${columnTypeOverride?.isOptional ? '?' : notOptional}: ${columnTypeOverride ? columnTypeOverride.type : (this.getTypeScriptType(table, field) + (fieldObj.allowNull ? " | null" : ""))};\n`; + let isOptional: boolean; + if (columnTypeOverride && columnTypeOverride.isOptional !== undefined) { + // override + isOptional = columnTypeOverride.isOptional; + } else { + isOptional = fieldObj.allowNull && !!useOptionalForNullColumns; + } + str += `${sp}${name}${isOptional ? '?' : notOptional}: ` + + `${columnTypeOverride && columnTypeOverride.type !== undefined ? columnTypeOverride.type : (this.getTypeScriptType(table, field) + (fieldObj.allowNull && !useOptionalForNullColumns ? " | null" : ""))};\n`; }); return str; } diff --git a/src/types.ts b/src/types.ts index 4098fb3c..999233ac 100644 --- a/src/types.ts +++ b/src/types.ts @@ -211,14 +211,14 @@ export function recase(opt: CaseOption | undefined, val: string | null, singular } /** - * @type Required. Name of the type + * @type Optional. Name of the type * @source Optional. File path of the type relative to file in the directory. * Leave undefined if overriding with primitive types - * @isDefault Optional. Whether the type is an export default - * @isOptional Optional. Whether to add ? + * @isDefault Optional. Whether the type is an export default. Default false + * @isOptional Optional. Override optionality */ export interface ColumnTypeOverride { - type: string; + type?: string; source?: string; isDefault?: boolean; isOptional?: boolean; @@ -234,7 +234,9 @@ export type TableTypeOverrides = { [tableName: string]: TableTypeOverride | unde * } * } * } + * @useOptionalForNullColumns use optional(?) otherwise use null, for nullable columns. Default false */ export interface TypeOverrides { tables?: TableTypeOverrides; + useOptionalForNullColumns?: boolean; } From fefe2620d125a273810490598ba6e45d230167e8 Mon Sep 17 00:00:00 2001 From: Israel dela Cruz Date: Tue, 24 Aug 2021 02:48:43 -0500 Subject: [PATCH 7/9] fix autoincrement optional field --- src/auto-generator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auto-generator.ts b/src/auto-generator.ts index 2de519f9..10d222d9 100644 --- a/src/auto-generator.ts +++ b/src/auto-generator.ts @@ -538,7 +538,7 @@ export class AutoGenerator { const fields = _.keys(this.tables[table]); return fields.filter((field): boolean => { const fieldObj = this.tables[table][field]; - return fieldObj.allowNull || (!!fieldObj.defaultValue || fieldObj.defaultValue === ""); + return fieldObj.allowNull || (!!fieldObj.defaultValue || fieldObj.defaultValue === "") || fieldObj.autoIncrement; }); } From 19fe53ee34c8b706009dc2550b88fd493a26f03d Mon Sep 17 00:00:00 2001 From: Israel dela Cruz Date: Sat, 4 Sep 2021 21:50:05 -0500 Subject: [PATCH 8/9] nullableFieldType option for typeOverrides option --- src/auto-generator.ts | 12 ++++++------ src/types.ts | 11 +++++++++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/auto-generator.ts b/src/auto-generator.ts index 40cf3f56..bcb3e258 100644 --- a/src/auto-generator.ts +++ b/src/auto-generator.ts @@ -1,7 +1,7 @@ import _ from "lodash"; import { ColumnDescription } from "sequelize/types"; import { DialectOptions, FKSpec } from "./dialects/dialect-options"; -import { AutoOptions, CaseFileOption, CaseOption, Field, IndexSpec, LangOption, qNameJoin, qNameSplit, recase, Relation, TableData, TSField, singularize, pluralize, TypeOverrides, TableTypeOverride, ColumnTypeOverride } from "./types"; +import { AutoOptions, CaseFileOption, CaseOption, Field, IndexSpec, LangOption, qNameJoin, qNameSplit, recase, Relation, TableData, TSField, singularize, pluralize, TypeOverrides, TableTypeOverride, ColumnTypeOverride, NullableFieldTypes } from "./types"; /** Generates text from each table in TableData */ export class AutoGenerator { @@ -116,7 +116,7 @@ export class AutoGenerator { } str += "\nexport interface #TABLE#Attributes {\n"; - str += this.addTypeScriptFields(table, true, tableTypeOverride, typeOverrides?.useOptionalForNullColumns) + "}\n\n"; + str += this.addTypeScriptFields(table, true, tableTypeOverride, typeOverrides?.nullableFieldType) + "}\n\n"; const primaryKeys = this.getTypeScriptPrimaryKeys(table); @@ -135,7 +135,7 @@ export class AutoGenerator { } str += "export class #TABLE# extends Model<#TABLE#Attributes, #TABLE#CreationAttributes> implements #TABLE#Attributes {\n"; - str += this.addTypeScriptFields(table, false, tableTypeOverride, typeOverrides?.useOptionalForNullColumns); + str += this.addTypeScriptFields(table, false, tableTypeOverride, typeOverrides?.nullableFieldType); str += "\n" + associations.str; str += "\n" + this.space[1] + "static initModel(sequelize: Sequelize.Sequelize): typeof " + tableName + " {\n"; str += this.space[2] + tableName + ".init({\n"; @@ -728,7 +728,7 @@ export class AutoGenerator { return ""; } - private addTypeScriptFields(table: string, isInterface: boolean, tableTypeOverride: TableTypeOverride | undefined, useOptionalForNullColumns: boolean | undefined) { + private addTypeScriptFields(table: string, isInterface: boolean, tableTypeOverride: TableTypeOverride | undefined, nullableFieldType: NullableFieldTypes | undefined) { const sp = this.space[1]; const fields = _.keys(this.tables[table]); let str = ''; @@ -745,10 +745,10 @@ export class AutoGenerator { // override isOptional = columnTypeOverride.isOptional; } else { - isOptional = fieldObj.allowNull && !!useOptionalForNullColumns; + isOptional = fieldObj.allowNull && nullableFieldType !== NullableFieldTypes.Null; } str += `${sp}${name}${isOptional ? '?' : notOptional}: ` + - `${columnTypeOverride && columnTypeOverride.type !== undefined ? columnTypeOverride.type : (this.getTypeScriptType(table, field) + (fieldObj.allowNull && !useOptionalForNullColumns ? " | null" : ""))};\n`; + `${columnTypeOverride && columnTypeOverride.type !== undefined ? columnTypeOverride.type : (this.getTypeScriptType(table, field) + (fieldObj.allowNull && nullableFieldType !== NullableFieldTypes.Optional ? " | null" : ""))};\n`; }); return str; } diff --git a/src/types.ts b/src/types.ts index 6bd1f81a..766d259c 100644 --- a/src/types.ts +++ b/src/types.ts @@ -238,6 +238,13 @@ export interface ColumnTypeOverride { } export type TableTypeOverride = { [columnName: string]: ColumnTypeOverride | undefined }; export type TableTypeOverrides = { [tableName: string]: TableTypeOverride | undefined } + +export enum NullableFieldTypes { + Null = "NULL", + Optional = "OPTIONAL", + NullAndOptional = "NULL_AND_OPTIONAL" +} + /** * @tables { * roles: { @@ -247,9 +254,9 @@ export type TableTypeOverrides = { [tableName: string]: TableTypeOverride | unde * } * } * } - * @useOptionalForNullColumns use optional(?) otherwise use null, for nullable columns. Default false + * @nullableFieldType use "NULL", "OPTIONAL", OR "NULL_AND_OPTIONAL" for nullable table columns. Default "NULL_AND_OPTIONAL" */ export interface TypeOverrides { tables?: TableTypeOverrides; - useOptionalForNullColumns?: boolean; + nullableFieldType?: NullableFieldTypes; } From 9c39683842d264ce70ef370b7ad4e23b04bb2d04 Mon Sep 17 00:00:00 2001 From: Steve Schmitt Date: Mon, 6 Dec 2021 16:43:18 -0800 Subject: [PATCH 9/9] TypeScript: fix syntax for HasOneCreateAssociationMixin --- src/auto-generator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/auto-generator.ts b/src/auto-generator.ts index bcb3e258..84b427fc 100644 --- a/src/auto-generator.ts +++ b/src/auto-generator.ts @@ -606,7 +606,7 @@ export class AutoGenerator { str += `${sp}${rel.childProp}!: ${rel.childModel};\n`; str += `${sp}get${pchild}!: Sequelize.HasOneGetAssociationMixin<${rel.childModel}>;\n`; str += `${sp}set${pchild}!: Sequelize.HasOneSetAssociationMixin<${rel.childModel}, ${rel.childModel}Id>;\n`; - str += `${sp}create${pchild}!: Sequelize.HasOneCreateAssociationMixin<${rel.childModel}CreationAttributes>;\n`; + str += `${sp}create${pchild}!: Sequelize.HasOneCreateAssociationMixin<${rel.childModel}>;\n`; needed[rel.childTable].add(rel.childModel); needed[rel.childTable].add(`${rel.childModel}Id`); needed[rel.childTable].add(`${rel.childModel}CreationAttributes`);