diff --git a/src/drivers/PostgresDriver.ts b/src/drivers/PostgresDriver.ts index a06ebdd..b117522 100644 --- a/src/drivers/PostgresDriver.ts +++ b/src/drivers/PostgresDriver.ts @@ -63,208 +63,24 @@ export class PostgresDriver extends AbstractDriver { colInfo.default = colInfo.is_generated ? null : resp.column_default; - colInfo.sql_type = resp.data_type; - switch (resp.data_type) { - case "int2": - colInfo.ts_type = "number"; - break; - case "int4": - colInfo.ts_type = "number"; - break; - case "int8": - colInfo.ts_type = "string"; - break; - case "smallint": - colInfo.ts_type = "number"; - break; - case "integer": - colInfo.ts_type = "number"; - break; - case "bigint": - colInfo.ts_type = "string"; - break; - case "decimal": - colInfo.ts_type = "string"; - break; - case "numeric": - colInfo.ts_type = "string"; - break; - case "real": - colInfo.ts_type = "number"; - break; - case "float": - colInfo.ts_type = "number"; - break; - case "float4": - colInfo.ts_type = "number"; - break; - case "float8": - colInfo.ts_type = "number"; - break; - case "double precision": - colInfo.ts_type = "number"; - break; - case "money": - colInfo.ts_type = "string"; - break; - case "character varying": - colInfo.ts_type = "string"; - break; - case "varchar": - colInfo.ts_type = "string"; - break; - case "character": - colInfo.ts_type = "string"; - break; - case "char": - colInfo.ts_type = "string"; - break; - case "text": - colInfo.ts_type = "string"; - break; - case "citext": - colInfo.ts_type = "string"; - break; - case "hstore": - colInfo.ts_type = "string"; - break; - case "bytea": - colInfo.ts_type = "Buffer"; - break; - case "bit": - colInfo.ts_type = "string"; - break; - case "varbit": - colInfo.ts_type = "string"; - break; - case "bit varying": - colInfo.ts_type = "string"; - break; - case "timetz": - colInfo.ts_type = "string"; - break; - case "timestamptz": - colInfo.ts_type = "Date"; - break; - case "timestamp": - colInfo.ts_type = "string"; - break; - case "timestamp without time zone": - colInfo.ts_type = "Date"; - break; - case "timestamp with time zone": - colInfo.ts_type = "Date"; - break; - case "date": - colInfo.ts_type = "string"; - break; - case "time": - colInfo.ts_type = "string"; - break; - case "time without time zone": - colInfo.ts_type = "string"; - break; - case "time with time zone": - colInfo.ts_type = "string"; - break; - case "interval": - colInfo.ts_type = "any"; - break; - case "bool": - colInfo.ts_type = "boolean"; - break; - case "boolean": - colInfo.ts_type = "boolean"; - break; - case "enum": - colInfo.ts_type = "string"; - break; - case "point": - colInfo.ts_type = "string | Object"; - break; - case "line": - colInfo.ts_type = "string"; - break; - case "lseg": - colInfo.ts_type = "string | string[]"; - break; - case "box": - colInfo.ts_type = "string | Object"; - break; - case "path": - colInfo.ts_type = "string"; - break; - case "polygon": - colInfo.ts_type = "string"; - break; - case "circle": - colInfo.ts_type = "string | Object"; - break; - case "cidr": - colInfo.ts_type = "string"; - break; - case "inet": - colInfo.ts_type = "string"; - break; - case "macaddr": - colInfo.ts_type = "string"; - break; - case "tsvector": - colInfo.ts_type = "string"; - break; - case "tsquery": - colInfo.ts_type = "string"; - break; - case "uuid": - colInfo.ts_type = "string"; - break; - case "xml": - colInfo.ts_type = "string"; - break; - case "json": - colInfo.ts_type = "Object"; - break; - case "jsonb": - colInfo.ts_type = "Object"; - break; - case "int4range": - colInfo.ts_type = "string"; - break; - case "int8range": - colInfo.ts_type = "string"; - break; - case "numrange": - colInfo.ts_type = "string"; - break; - case "tsrange": - colInfo.ts_type = "string"; - break; - case "tstzrange": - colInfo.ts_type = "string"; - break; - case "daterange": - colInfo.ts_type = "string"; - break; - case "USER-DEFINED": - colInfo.sql_type = resp.udt_name; - colInfo.ts_type = "string"; - switch (resp.udt_name) { - case "citext": - case "hstore": - case "geometry": - break; - default: - TomgUtils.LogError( - `Unknown USER-DEFINED column type: ${ - resp.udt_name - } table name: ${ - resp.table_name - } column name: ${resp.column_name}` - ); - break; - } - break; - default: + + var columnTypes = this.MatchColumnTypes( + resp.data_type, + resp.udt_name + ); + if (!columnTypes.sql_type || !columnTypes.ts_type) { + if ( + resp.data_type == "USER-DEFINED" || + 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}` + ); + } else { TomgUtils.LogError( `Unknown column type: ${ resp.data_type @@ -272,8 +88,19 @@ export class PostgresDriver extends AbstractDriver { resp.table_name } column name: ${resp.column_name}` ); - break; + } + return; } + colInfo.sql_type = columnTypes.sql_type; + colInfo.ts_type = columnTypes.ts_type; + colInfo.is_array = columnTypes.is_array; + if (colInfo.is_array) { + colInfo.ts_type = colInfo.ts_type + .split("|") + .map(x => x.replace("|", "").trim() + "[]") + .join(" | "); + } + if ( this.ColumnTypesWithPrecision.some( v => v == colInfo.sql_type @@ -302,11 +129,243 @@ export class PostgresDriver extends AbstractDriver { ? resp.character_maximum_length : null; } - if (colInfo.sql_type) ent.Columns.push(colInfo); + if (colInfo.sql_type && colInfo.ts_type) { + ent.Columns.push(colInfo); + } }); }); return entities; } + + MatchColumnTypes(data_type: string, udt_name: string) { + let ret: { + ts_type: + | "number" + | "string" + | "boolean" + | "Date" + | "Buffer" + | "Object" + | "string | Object" + | "string | string[]" + | "any" + | null; + sql_type: string | null; + is_array: boolean; + } = { ts_type: null, sql_type: null, is_array: false }; + ret.sql_type = data_type; + switch (data_type) { + case "int2": + ret.ts_type = "number"; + break; + case "int4": + ret.ts_type = "number"; + break; + case "int8": + ret.ts_type = "string"; + break; + case "smallint": + ret.ts_type = "number"; + break; + case "integer": + ret.ts_type = "number"; + break; + case "bigint": + ret.ts_type = "string"; + break; + case "decimal": + ret.ts_type = "string"; + break; + case "numeric": + ret.ts_type = "string"; + break; + case "real": + ret.ts_type = "number"; + break; + case "float": + ret.ts_type = "number"; + break; + case "float4": + ret.ts_type = "number"; + break; + case "float8": + ret.ts_type = "number"; + break; + case "double precision": + ret.ts_type = "number"; + break; + case "money": + ret.ts_type = "string"; + break; + case "character varying": + ret.ts_type = "string"; + break; + case "varchar": + ret.ts_type = "string"; + break; + case "character": + ret.ts_type = "string"; + break; + case "char": + ret.ts_type = "string"; + break; + case "bpchar": + ret.sql_type = "char"; + ret.ts_type = "string"; + break; + case "text": + ret.ts_type = "string"; + break; + case "citext": + ret.ts_type = "string"; + break; + case "hstore": + ret.ts_type = "string"; + break; + case "bytea": + ret.ts_type = "Buffer"; + break; + case "bit": + ret.ts_type = "string"; + break; + case "varbit": + ret.ts_type = "string"; + break; + case "bit varying": + ret.ts_type = "string"; + break; + case "timetz": + ret.ts_type = "string"; + break; + case "timestamptz": + ret.ts_type = "Date"; + break; + case "timestamp": + ret.ts_type = "string"; + break; + case "timestamp without time zone": + ret.ts_type = "Date"; + break; + case "timestamp with time zone": + ret.ts_type = "Date"; + break; + case "date": + ret.ts_type = "string"; + break; + case "time": + ret.ts_type = "string"; + break; + case "time without time zone": + ret.ts_type = "string"; + break; + case "time with time zone": + ret.ts_type = "string"; + break; + case "interval": + ret.ts_type = "any"; + break; + case "bool": + ret.ts_type = "boolean"; + break; + case "boolean": + ret.ts_type = "boolean"; + break; + case "enum": + ret.ts_type = "string"; + break; + case "point": + ret.ts_type = "string | Object"; + break; + case "line": + ret.ts_type = "string"; + break; + case "lseg": + ret.ts_type = "string | string[]"; + break; + case "box": + ret.ts_type = "string | Object"; + break; + case "path": + ret.ts_type = "string"; + break; + case "polygon": + ret.ts_type = "string"; + break; + case "circle": + ret.ts_type = "string | Object"; + break; + case "cidr": + ret.ts_type = "string"; + break; + case "inet": + ret.ts_type = "string"; + break; + case "macaddr": + ret.ts_type = "string"; + break; + case "tsvector": + ret.ts_type = "string"; + break; + case "tsquery": + ret.ts_type = "string"; + break; + case "uuid": + ret.ts_type = "string"; + break; + case "xml": + ret.ts_type = "string"; + break; + case "json": + ret.ts_type = "Object"; + break; + case "jsonb": + ret.ts_type = "Object"; + break; + case "int4range": + ret.ts_type = "string"; + break; + case "int8range": + ret.ts_type = "string"; + break; + case "numrange": + ret.ts_type = "string"; + break; + case "tsrange": + ret.ts_type = "string"; + break; + case "tstzrange": + ret.ts_type = "string"; + break; + case "daterange": + ret.ts_type = "string"; + break; + case "ARRAY": + let z = this.MatchColumnTypes(udt_name.substring(1), udt_name); + ret.ts_type = z.ts_type; + ret.sql_type = z.sql_type; + ret.is_array = true; + break; + case "USER-DEFINED": + ret.sql_type = udt_name; + ret.ts_type = "string"; + switch (udt_name) { + case "citext": + case "hstore": + case "geometry": + break; + default: + ret.ts_type = null; + ret.sql_type = null; + break; + } + break; + default: + ret.ts_type = null; + ret.sql_type = null; + break; + } + return ret; + } async GetIndexesFromEntity( entities: EntityInfo[], schema: string diff --git a/src/entity.mst b/src/entity.mst index 35ccf37..8fa72a8 100644 --- a/src/entity.mst +++ b/src/entity.mst @@ -19,7 +19,8 @@ import {Index,Entity, PrimaryColumn, Column, OneToOne, OneToMany, ManyToOne, Man precision:{{.}},{{/numericPrecision}}{{#numericScale}} scale:{{.}},{{/numericScale}}{{#isPrimary}} primary:{{isPrimary}},{{/isPrimary}}{{#enumOptions}} - enum:[{{.}}],{{/enumOptions}} + enum:[{{.}}],{{/enumOptions}}{{#is_array}} + array:{{is_array}},{{/is_array}} name:"{{sqlName}}" }) {{toPropertyName tsName}}:{{ts_type}}{{#is_nullable}} | null{{/is_nullable}}; diff --git a/src/models/ColumnInfo.ts b/src/models/ColumnInfo.ts index 455c4d4..056c2f7 100644 --- a/src/models/ColumnInfo.ts +++ b/src/models/ColumnInfo.ts @@ -21,6 +21,7 @@ export class ColumnInfo { width: number | null = null; isPrimary: boolean = false; is_generated: boolean = false; + is_array: boolean = false; numericPrecision: number | null = null; numericScale: number | null = null; enumOptions: string | null = null; diff --git a/test/drivers/MssqlDriver.test.ts b/test/drivers/MssqlDriver.test.ts index 0e28241..5cf0fa3 100644 --- a/test/drivers/MssqlDriver.test.ts +++ b/test/drivers/MssqlDriver.test.ts @@ -95,6 +95,7 @@ describe('MssqlDriver', function () { ts_type: 'number', enumOptions: null, is_unique:false, + is_array:false, relations: [], }) let result = await driver.GetCoulmnsFromEntity(entities, 'schema'); diff --git a/test/integration/entityTypes/postgres/entity/PostArrays.ts b/test/integration/entityTypes/postgres/entity/PostArrays.ts new file mode 100644 index 0000000..d880503 --- /dev/null +++ b/test/integration/entityTypes/postgres/entity/PostArrays.ts @@ -0,0 +1,191 @@ +import { Entity, PrimaryColumn, Column } from "typeorm"; + +@Entity("PostArrays") +export class PostArrays { + + @PrimaryColumn() + id: number; + + @Column() + name: string; + + @Column("int2", { array: true }) + int2: number[]; + + @Column("int4", { array: true }) + int4: number[]; + + @Column("int8", { array: true }) + int8: string[]; + + @Column("smallint", { array: true }) + smallint: number[]; + + @Column("integer", { array: true }) + integer: number[]; + + @Column("bigint", { array: true }) + bigint: string[]; + + @Column("decimal", { array: true }) + decimal: string[]; + + @Column("numeric", { array: true }) + numeric: string[]; + + @Column("real", { array: true }) + real: number[]; + + @Column("float", { array: true }) + float: number[]; + + @Column("float4", { array: true }) + float4: number[]; + + @Column("float8", { array: true }) + float8: number[]; + + @Column("double precision", { array: true }) + doublePrecision: number[]; + + @Column("money", { array: true }) + money: string[]; + + @Column("character varying", { array: true }) + characterVarying: string[]; + + @Column("varchar", { array: true }) + varchar: string[]; + + @Column("character", { array: true }) + character: string[]; + + @Column("char", { array: true }) + char: string[]; + + @Column("text", { array: true }) + text: string[]; + + @Column("citext", { array: true }) + citext: string[]; + + @Column("hstore", { array: true }) + hstore: string[]; + + @Column("bytea", { array: true }) + bytea: Buffer[]; + + @Column("bit", { array: true }) + bit: string[]; + + @Column("varbit", { array: true }) + varbit: string[]; + + @Column("bit varying", { array: true }) + bit_varying: string[]; + + @Column("timetz", { array: true }) + timetz: string[]; + + @Column("timestamptz", { array: true }) + timestamptz: Date[]; + + // @Column("timestamp", { array: true }) + // timestamp: Date[]; + + // @Column("timestamp without time zone", { array: true }) + // timestamp_without_time_zone: Date[]; + + @Column("timestamp with time zone", { array: true }) + timestamp_with_time_zone: Date[]; + + @Column("date", { array: true }) + date: string[]; + + @Column("time", { array: true }) + time: string[]; + @Column("time without time zone", { array: true }) + time_without_time_zone: string[]; + + @Column("time with time zone", { array: true }) + time_with_time_zone: string[]; + + @Column("interval", { array: true }) + interval: any[]; + + @Column("bool", { array: true }) + bool: boolean[]; + + @Column("boolean", { array: true }) + boolean: boolean[]; + + // @Column("enum", { array: true }) + // enum: string[]; + + @Column("point", { array: true }) + point: string[] | Object[]; + + @Column("line", { array: true }) + line: string[]; + + @Column("lseg", { array: true }) + lseg: string[] | string[][]; + + @Column("box", { array: true }) + box: string[] | Object[]; + + @Column("path", { array: true }) + path: string[]; + + @Column("polygon", { array: true }) + polygon: string[]; + + @Column("circle", { array: true }) + circle: string[] | Object[]; + + @Column("cidr", { array: true }) + cidr: string[]; + + @Column("inet", { array: true }) + inet: string[]; + + @Column("macaddr", { array: true }) + macaddr: string[]; + + @Column("tsvector", { array: true }) + tsvector: string[]; + + @Column("tsquery", { array: true }) + tsquery: string[]; + + @Column("uuid", { array: true }) + uuid: string[]; + + @Column("xml", { array: true }) + xml: string[]; + + @Column("json", { array: true }) + json: Object[]; + + @Column("jsonb", { array: true }) + jsonb: Object[]; + + @Column("int4range", { array: true }) + int4range: string[]; + + @Column("int8range", { array: true }) + int8range: string[]; + + @Column("numrange", { array: true }) + numrange: string[]; + + @Column("tsrange", { array: true }) + tsrange: string[]; + + @Column("tstzrange", { array: true }) + tstzrange: string[]; + + @Column("daterange", { array: true }) + daterange: string[]; + +}