Skip to content

Commit

Permalink
feat: add option to Column to specify the complete enumName (#4824)
Browse files Browse the repository at this point in the history
  • Loading branch information
ejose19 authored and pleerock committed Oct 18, 2019
1 parent ea17094 commit d967180
Show file tree
Hide file tree
Showing 11 changed files with 182 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/decorator/options/ColumnEnumOptions.ts
Expand Up @@ -7,5 +7,9 @@ export interface ColumnEnumOptions {
* Array of possible enumerated values.
*/
enum?: any[]|Object;
/**
* Exact name of enum
*/
enumName?: string;

}
4 changes: 4 additions & 0 deletions src/decorator/options/ColumnOptions.ts
Expand Up @@ -128,6 +128,10 @@ export interface ColumnOptions extends ColumnCommonOptions {
* Array of possible enumerated values.
*/
enum?: (string|number)[]|Object;
/**
* Exact name of enum
*/
enumName?: string;

/**
* Generated column expression. Supports only in MySQL.
Expand Down
9 changes: 9 additions & 0 deletions src/driver/postgres/PostgresQueryRunner.ts
Expand Up @@ -1989,6 +1989,15 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner
* Builds ENUM type name from given table and column.
*/
protected buildEnumName(table: Table, columnOrName: TableColumn|string, withSchema: boolean = true, disableEscape?: boolean, toOld?: boolean): string {
/**
* If enumName is specified in column options then use it instead
*/
if (columnOrName instanceof TableColumn && columnOrName.enumName) {
let enumName = columnOrName.enumName;
if (toOld)
enumName = enumName + "_old";
return disableEscape ? enumName : `"${enumName}"`;
}
const columnName = columnOrName instanceof TableColumn ? columnOrName.name : columnOrName;
const schema = table.name.indexOf(".") === -1 ? this.driver.options.schema : table.name.split(".")[0];
const tableName = table.name.indexOf(".") === -1 ? table.name : table.name.split(".")[1];
Expand Down
8 changes: 8 additions & 0 deletions src/metadata/ColumnMetadata.ts
Expand Up @@ -158,6 +158,11 @@ export class ColumnMetadata {
*/
enum?: (string|number)[];

/**
* Exact name of enum
*/
enumName?: string;

/**
* Generated column expression. Supports only in MySQL.
*/
Expand Down Expand Up @@ -371,6 +376,9 @@ export class ColumnMetadata {
this.enum = options.args.options.enum;
}
}
if (options.args.options.enumName) {
this.enumName = options.args.options.enumName;
}
if (options.args.options.asExpression) {
this.asExpression = options.args.options.asExpression;
this.generatedType = options.args.options.generatedType ? options.args.options.generatedType : "VIRTUAL";
Expand Down
5 changes: 5 additions & 0 deletions src/schema-builder/options/TableColumnOptions.ts
Expand Up @@ -113,6 +113,11 @@ export interface TableColumnOptions {
*/
enum?: string[];

/**
* Exact name of enum
*/
enumName?: string;

/**
* Generated column expression. Supports only in MySQL.
*/
Expand Down
7 changes: 7 additions & 0 deletions src/schema-builder/table/TableColumn.ts
Expand Up @@ -115,6 +115,11 @@ export class TableColumn {
*/
enum?: string[];

/**
* Exact name of enum
*/
enumName?: string;

/**
* Generated column expression. Supports only in MySQL.
*/
Expand Down Expand Up @@ -161,6 +166,7 @@ export class TableColumn {
this.isArray = options.isArray || false;
this.comment = options.comment;
this.enum = options.enum;
this.enumName = options.enumName;
this.asExpression = options.asExpression;
this.generatedType = options.generatedType;
this.spatialFeatureType = options.spatialFeatureType;
Expand Down Expand Up @@ -188,6 +194,7 @@ export class TableColumn {
zerofill: this.zerofill,
unsigned: this.unsigned,
enum: this.enum,
enumName: this.enumName,
asExpression: this.asExpression,
generatedType: this.generatedType,
default: this.default,
Expand Down
1 change: 1 addition & 0 deletions src/schema-builder/util/TableUtils.ts
Expand Up @@ -28,6 +28,7 @@ export class TableUtils {
isUnique: driver.normalizeIsUnique(columnMetadata),
isArray: columnMetadata.isArray || false,
enum: columnMetadata.enum ? columnMetadata.enum.map(val => val + "") : columnMetadata.enum,
enumName: columnMetadata.enumName,
spatialFeatureType: columnMetadata.spatialFeatureType,
srid: columnMetadata.srid
};
Expand Down
26 changes: 26 additions & 0 deletions test/github-issues/4106/entity/Animal.ts
@@ -0,0 +1,26 @@
import { Entity } from "../../../../src/decorator/entity/Entity";
import { Column } from "../../../../src/decorator/columns/Column";
import { PrimaryColumn } from "../../../../src/decorator/columns/PrimaryColumn";

import { Gender } from "./GenderEnum";

@Entity()
export class Animal {

@PrimaryColumn()
id: number;

@Column()
name: string;

@Column({
type: "enum",
enum: Gender,
enumName: "genderEnum"
})
gender: Gender;

@Column()
specie: string;

}
4 changes: 4 additions & 0 deletions test/github-issues/4106/entity/GenderEnum.ts
@@ -0,0 +1,4 @@
export enum Gender {
male = "male",
female = "female"
}
24 changes: 24 additions & 0 deletions test/github-issues/4106/entity/Human.ts
@@ -0,0 +1,24 @@
import { Entity } from "../../../../src/decorator/entity/Entity";
import { Column } from "../../../../src/decorator/columns/Column";
import { PrimaryColumn } from "../../../../src/decorator/columns/PrimaryColumn";

import { Gender } from "./GenderEnum";

@Entity()
export class Human {

@PrimaryColumn()
id: number;

@Column()
name: string;

@Column({
type: "enum",
enum: Gender,
enumName: "genderEnum",
name: "Gender"
})
gender: Gender;

}
90 changes: 90 additions & 0 deletions test/github-issues/4106/issue-4106.ts
@@ -0,0 +1,90 @@
import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../utils/test-utils";
import { Connection } from "../../../src/connection/Connection";
import { Human } from "./entity/Human";
import { Animal } from "./entity/Animal";
import { Gender } from "./entity/GenderEnum";
import { EntityManager } from "../../../src/entity-manager/EntityManager";
import { expect } from "chai";

describe("github issues > #4106 Specify enum type name in postgres", () => {
let connections: Connection[];
before(
async () =>
(connections = await createTestingConnections({
entities: [Human, Animal],
dropSchema: true,
enabledDrivers: ["postgres"],
}))
);
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));

async function prepareData(connection: Connection) {
const human = new Human();
human.id = 1;
human.name = "Jane Doe";
human.gender = Gender.female;
await connection.manager.save(human);

const animal = new Animal();
animal.id = 1;
animal.name = "Miko";
animal.specie = "Turtle";
animal.gender = Gender.male;
await connection.manager.save(animal);
}

it("should create an enum with the name specified in column options -> enumName", () =>
Promise.all(
connections.map(async connection => {
const em = new EntityManager(connection);
const types = await em.query(`SELECT typowner, n.nspname as "schema",
pg_catalog.format_type(t.oid, NULL) AS "name",
pg_catalog.obj_description(t.oid, 'pg_type') as "description"
FROM pg_catalog.pg_type t
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
WHERE (t.typrelid = 0 OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid))
AND NOT EXISTS(SELECT 1 FROM pg_catalog.pg_type el WHERE el.oid = t.typelem AND el.typarray = t.oid)
AND pg_catalog.pg_type_is_visible(t.oid)
AND n.nspname = 'public'
ORDER BY 1, 2;`);

// Enum name must be exactly the same as stated
// Quoted here since the name contains mixed case
expect(types.some((type: any) => type.name === `"genderEnum"`)).to.be.true;
})
));

it("should insert data with the correct enum", () =>
Promise.all(
connections.map(async connection => {
await prepareData(connection);

const em = new EntityManager(connection);

const humanTable = await em.query(`SELECT column_name as "columnName", data_type as "dataType", udt_name as "udtName" FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'human'
ORDER BY ordinal_position;`);
const animalTable = await em.query(`SELECT column_name as "columnName", data_type as "dataType", udt_name as "udtName" FROM information_schema.columns
WHERE table_schema = 'public' AND table_name = 'animal'
ORDER BY ordinal_position;`);

expect(humanTable[2].dataType).to.equal("USER-DEFINED");
expect(humanTable[2].udtName).to.equal("genderEnum");

expect(animalTable[2].dataType).to.equal("USER-DEFINED");
expect(animalTable[2].udtName).to.equal("genderEnum");

const HumanRepository = connection.manager.getRepository(Human);
const AnimalRepository = connection.manager.getRepository(Animal);

const human = await HumanRepository.find();
const animal = await AnimalRepository.find();

expect(human[0].gender).to.equal("female");
expect(animal[0].gender).to.equal("male");
})
));


});

0 comments on commit d967180

Please sign in to comment.