From 3bbabd127bb1a02a558a2e60470e3d8712cef3b5 Mon Sep 17 00:00:00 2001 From: Vasil Rangelov Date: Thu, 14 Nov 2019 11:46:18 +0200 Subject: [PATCH 1/2] Nullable columns now also add "| null" to the type declaration. Unknown DB types now generate properties with type "NonNullable" that also adds "| null" if the column is nullable. --- src/drivers/AbstractDriver.ts | 12 ++++++++++-- src/drivers/MssqlDriver.ts | 2 +- src/drivers/MysqlDriver.ts | 2 +- src/drivers/OracleDriver.ts | 2 +- src/drivers/PostgresDriver.ts | 37 +++++++++++++---------------------- src/drivers/SqliteDriver.ts | 2 +- src/templates/entity.mst | 2 +- 7 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 2b0072a..3002fae 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -376,11 +376,19 @@ export default abstract class AbstractDriver { ownerColumns[0].tscName, ownerEntity ); + let relationIdType = ownerColumns[0].tscType; + if (ownerColumns[0].options.nullable) { + relationIdType += " | null"; + } ownerEntity.relationIds.push({ fieldName: relationIdFieldName, fieldType: isOneToMany - ? `${ownerColumns[0].tscType}[]` - : ownerColumns[0].tscType, + ? `${ + relationIdType.includes(" ") + ? `(${relationIdType})` + : relationIdType + }[]` + : relationIdType, relationField: ownerRelation.fieldName }); // TODO: RelationId on ManyToMany diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 92efbc3..94a84a0 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -90,7 +90,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG resp.COLUMN_DEFAULT ); const columnType = resp.DATA_TYPE; - let tscType = ""; + let tscType = "NonNullable"; switch (resp.DATA_TYPE) { case "bigint": tscType = "string"; diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 75aab4a..7964dc3 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -69,7 +69,7 @@ export default class MysqlDriver extends AbstractDriver { .filter(filterVal => filterVal.TABLE_NAME === ent.tscName) .forEach(resp => { const tscName = resp.COLUMN_NAME; - let tscType = ""; + let tscType = "NonNullable"; const options: Column["options"] = { name: resp.COLUMN_NAME }; diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 38cf79b..9215935 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -87,7 +87,7 @@ export default class OracleDriver extends AbstractDriver { ); const DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, ""); const columnType = DATA_TYPE.toLowerCase(); - let tscType = ""; + let tscType = "NonNullable"; switch (DATA_TYPE.toLowerCase()) { case "char": tscType = "string"; diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index c34402f..ce91556 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -99,7 +99,7 @@ export default class PostgresDriver extends AbstractDriver { resp.udt_name, resp.enumvalues ); - if (!columnTypes.sqlType || !columnTypes.tsType) { + if (columnTypes.tsType === "NonNullable") { if ( resp.data_type === "USER-DEFINED" || resp.data_type === "ARRAY" @@ -152,16 +152,15 @@ export default class PostgresDriver extends AbstractDriver { ? resp.character_maximum_length : undefined; } - if (columnType && tscType) { - ent.columns.push({ - generated, - type: columnType, - default: defaultValue, - options, - tscName, - tscType - }); - } + + ent.columns.push({ + generated, + type: columnType, + default: defaultValue, + options, + tscName, + tscType + }); }); }); return entities; @@ -173,17 +172,16 @@ export default class PostgresDriver extends AbstractDriver { enumValues: string | null ) { let ret: { - tsType?: Column["tscType"]; - sqlType: string | null; + tsType: Column["tscType"]; + sqlType: string; isArray: boolean; enumValues: string[]; } = { - tsType: undefined, - sqlType: null, + tsType: "NonNullable", + sqlType: dataType, isArray: false, enumValues: [] }; - ret.sqlType = dataType; switch (dataType) { case "int2": ret.tsType = "number"; @@ -389,17 +387,10 @@ export default class PostgresDriver extends AbstractDriver { .join('" | "')}"` as never) as string; ret.sqlType = "enum"; ret.enumValues = enumValues.split(","); - } else { - ret.tsType = undefined; - ret.sqlType = null; } break; } break; - default: - ret.tsType = undefined; - ret.sqlType = null; - break; } return ret; } diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 64ce684..7f8e993 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -65,7 +65,7 @@ export default class SqliteDriver extends AbstractDriver { }>(`PRAGMA table_info('${ent.tscName}');`); response.forEach(resp => { const tscName = resp.name; - let tscType = ""; + let tscType = "NonNullable"; const options: Column["options"] = { name: resp.name }; if (resp.notnull === 0) options.nullable = true; const isPrimary = resp.pk > 0 ? true : undefined; diff --git a/src/templates/entity.mst b/src/templates/entity.mst index 6e16182..8667a11 100644 --- a/src/templates/entity.mst +++ b/src/templates/entity.mst @@ -6,7 +6,7 @@ import { {{toEntityName .}} } from './{{toFileName .}}' {{/inline}} {{#*inline "Column"}} {{#generated}}@PrimaryGeneratedColumn({ type:"{{type}}", {{/generated}}{{^generated}}@Column("{{type}}",{ {{#primary}}primary:{{primary}},{{/primary}}{{/generated}}{{json options}}{{#default}},default: {{.}},{{/default}} }) -{{printPropertyVisibility}}{{toPropertyName tscName}}{{strictMode}}:{{tscType}}; +{{printPropertyVisibility}}{{toPropertyName tscName}}{{strictMode}}:{{tscType}}{{#if options.nullable}} | null{{/if}}; {{/inline}} {{#*inline "JoinColumnOptions"}} From f0a6f67429aab4cd1e8bd17946725d05f9765d6f Mon Sep 17 00:00:00 2001 From: Kononnable Date: Sun, 29 Dec 2019 22:54:30 +0100 Subject: [PATCH 2/2] code changes, test for nullable columns --- src/drivers/AbstractDriver.ts | 21 +++++++++-------- src/drivers/MssqlDriver.ts | 22 ++++++++---------- src/drivers/MysqlDriver.ts | 21 ++++++++--------- src/drivers/OracleDriver.ts | 21 ++++++++--------- src/drivers/PostgresDriver.ts | 10 +++++--- src/drivers/SqliteDriver.ts | 23 +++++++++---------- test/drivers/MssqlDriver.test.ts | 3 +-- .../github-issues/227/entity/Post.ts | 15 ++++++++++++ 8 files changed, 75 insertions(+), 61 deletions(-) create mode 100644 test/integration/github-issues/227/entity/Post.ts diff --git a/src/drivers/AbstractDriver.ts b/src/drivers/AbstractDriver.ts index 3002fae..24d6c84 100644 --- a/src/drivers/AbstractDriver.ts +++ b/src/drivers/AbstractDriver.ts @@ -376,19 +376,20 @@ export default abstract class AbstractDriver { ownerColumns[0].tscName, ownerEntity ); - let relationIdType = ownerColumns[0].tscType; - if (ownerColumns[0].options.nullable) { - relationIdType += " | null"; + + let fieldType = ""; + if (isOneToMany) { + fieldType = `${ownerColumns[0].tscType}[]`; + } else { + fieldType = ownerColumns[0].tscType; + if (ownerColumns[0].options.nullable) { + fieldType += " | null"; + } } + ownerEntity.relationIds.push({ fieldName: relationIdFieldName, - fieldType: isOneToMany - ? `${ - relationIdType.includes(" ") - ? `(${relationIdType})` - : relationIdType - }[]` - : relationIdType, + fieldType, relationField: ownerRelation.fieldName }); // TODO: RelationId on ManyToMany diff --git a/src/drivers/MssqlDriver.ts b/src/drivers/MssqlDriver.ts index 94a84a0..706042b 100644 --- a/src/drivers/MssqlDriver.ts +++ b/src/drivers/MssqlDriver.ts @@ -90,7 +90,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG resp.COLUMN_DEFAULT ); const columnType = resp.DATA_TYPE; - let tscType = "NonNullable"; + let tscType = ""; switch (resp.DATA_TYPE) { case "bigint": tscType = "string"; @@ -192,6 +192,7 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG tscType = "string"; break; default: + tscType = "NonNullable"; TomgUtils.LogError( `Unknown column type: ${resp.DATA_TYPE} table name: ${resp.TABLE_NAME} column name: ${resp.COLUMN_NAME}` ); @@ -218,17 +219,14 @@ WHERE TABLE_TYPE='BASE TABLE' and TABLE_SCHEMA in (${schema}) AND TABLE_CATALOG ? resp.CHARACTER_MAXIMUM_LENGTH : undefined; } - - if (columnType) { - ent.columns.push({ - generated, - type: columnType, - default: defaultValue, - options, - tscName, - tscType - }); - } + ent.columns.push({ + generated, + type: columnType, + default: defaultValue, + options, + tscName, + tscType + }); }); }); return entities; diff --git a/src/drivers/MysqlDriver.ts b/src/drivers/MysqlDriver.ts index 7964dc3..88d5786 100644 --- a/src/drivers/MysqlDriver.ts +++ b/src/drivers/MysqlDriver.ts @@ -69,7 +69,7 @@ export default class MysqlDriver extends AbstractDriver { .filter(filterVal => filterVal.TABLE_NAME === ent.tscName) .forEach(resp => { const tscName = resp.COLUMN_NAME; - let tscType = "NonNullable"; + let tscType = ""; const options: Column["options"] = { name: resp.COLUMN_NAME }; @@ -214,6 +214,7 @@ export default class MysqlDriver extends AbstractDriver { tscType = "string"; break; default: + tscType = "NonNullable"; TomgUtils.LogError( `Unknown column type: ${resp.DATA_TYPE} table name: ${resp.TABLE_NAME} column name: ${resp.COLUMN_NAME}` ); @@ -250,16 +251,14 @@ export default class MysqlDriver extends AbstractDriver { : undefined; } - if (columnType) { - ent.columns.push({ - generated, - type: columnType, - default: defaultValue, - options, - tscName, - tscType - }); - } + ent.columns.push({ + generated, + type: columnType, + default: defaultValue, + options, + tscName, + tscType + }); }); }); return entities; diff --git a/src/drivers/OracleDriver.ts b/src/drivers/OracleDriver.ts index 9215935..08ea44e 100644 --- a/src/drivers/OracleDriver.ts +++ b/src/drivers/OracleDriver.ts @@ -87,7 +87,7 @@ export default class OracleDriver extends AbstractDriver { ); const DATA_TYPE = resp.DATA_TYPE.replace(/\([0-9]+\)/g, ""); const columnType = DATA_TYPE.toLowerCase(); - let tscType = "NonNullable"; + let tscType = ""; switch (DATA_TYPE.toLowerCase()) { case "char": tscType = "string"; @@ -177,6 +177,7 @@ export default class OracleDriver extends AbstractDriver { tscType = "number"; break; default: + tscType = "NonNullable"; TomgUtils.LogError( `Unknown column type:${DATA_TYPE}` ); @@ -201,16 +202,14 @@ export default class OracleDriver extends AbstractDriver { resp.DATA_LENGTH > 0 ? resp.DATA_LENGTH : undefined; } - if (columnType) { - ent.columns.push({ - generated, - type: columnType, - default: defaultValue, - options, - tscName, - tscType - }); - } + ent.columns.push({ + generated, + type: columnType, + default: defaultValue, + options, + tscName, + tscType + }); }); }); return entities; diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index ce91556..d5169ad 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -105,15 +105,16 @@ export default class PostgresDriver extends AbstractDriver { resp.data_type === "ARRAY" ) { TomgUtils.LogError( - `Unknown ${resp.data_type} column type: ${resp.udt_name} table name: ${resp.table_name} column name: ${resp.column_name}` + `Unknown ${resp.data_type} column type: ${resp.udt_name} table name: ${resp.table_name} column name: ${resp.column_name}` ); } else { TomgUtils.LogError( - `Unknown column type: ${resp.data_type} table name: ${resp.table_name} column name: ${resp.column_name}` + `Unknown column type: ${resp.data_type} table name: ${resp.table_name} column name: ${resp.column_name}` ); } return; } + const columnType = columnTypes.sqlType; let tscType = columnTypes.tsType; if (columnTypes.isArray) options.array = true; @@ -177,7 +178,7 @@ export default class PostgresDriver extends AbstractDriver { isArray: boolean; enumValues: string[]; } = { - tsType: "NonNullable", + tsType: "", sqlType: dataType, isArray: false, enumValues: [] @@ -391,6 +392,9 @@ export default class PostgresDriver extends AbstractDriver { break; } break; + default: + ret.tsType = "NonNullable"; + break; } return ret; } diff --git a/src/drivers/SqliteDriver.ts b/src/drivers/SqliteDriver.ts index 7f8e993..87392dc 100644 --- a/src/drivers/SqliteDriver.ts +++ b/src/drivers/SqliteDriver.ts @@ -65,7 +65,7 @@ export default class SqliteDriver extends AbstractDriver { }>(`PRAGMA table_info('${ent.tscName}');`); response.forEach(resp => { const tscName = resp.name; - let tscType = "NonNullable"; + let tscType = ""; const options: Column["options"] = { name: resp.name }; if (resp.notnull === 0) options.nullable = true; const isPrimary = resp.pk > 0 ? true : undefined; @@ -164,6 +164,7 @@ export default class SqliteDriver extends AbstractDriver { tscType = "Date"; break; default: + tscType = "NonNullable"; TomgUtils.LogError( `Unknown column type: ${columnType} table name: ${ent.tscName} column name: ${resp.name}` ); @@ -218,17 +219,15 @@ export default class SqliteDriver extends AbstractDriver { ); } - if (columnType) { - ent.columns.push({ - generated, - primary: isPrimary, - type: columnType, - default: defaultValue, - options, - tscName, - tscType - }); - } + ent.columns.push({ + generated, + primary: isPrimary, + type: columnType, + default: defaultValue, + options, + tscName, + tscType + }); }); }) ); diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index bfa577f..cf132be 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -74,7 +74,7 @@ describe("MssqlDriver", () => { COLUMN_DEFAULT: "'a'", COLUMN_NAME: "name", DATA_TYPE: "int", - IS_NULLABLE: "YES", + IS_NULLABLE: "NO", NUMERIC_PRECISION: 0, NUMERIC_SCALE: 0, IsIdentity: 1 @@ -99,7 +99,6 @@ describe("MssqlDriver", () => { const expected: Entity[] = JSON.parse(JSON.stringify(entities)); expected[0].columns.push({ options: { - nullable: true, name: "name" }, type: "int", diff --git a/test/integration/github-issues/227/entity/Post.ts b/test/integration/github-issues/227/entity/Post.ts new file mode 100644 index 0000000..20ce4c5 --- /dev/null +++ b/test/integration/github-issues/227/entity/Post.ts @@ -0,0 +1,15 @@ +import { PrimaryGeneratedColumn, Column, Entity, OneToOne, JoinColumn, Index } from "typeorm"; + +@Entity("Post") +export class Post { + + @PrimaryGeneratedColumn() + id: number; + + @Column("varchar", { nullable: true }) + title: string | null; + + @Column() + text: string; + +}