Skip to content

Commit

Permalink
fix: resolve issue when enum that has functions is used in entity (#7653
Browse files Browse the repository at this point in the history
)

Closes: #7651
  • Loading branch information
dariosn85 committed May 15, 2021
1 parent e326fa2 commit dba327d
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 1 deletion.
9 changes: 8 additions & 1 deletion src/metadata/ColumnMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,14 @@ export class ColumnMetadata {
if (options.args.options.enum) {
if (options.args.options.enum instanceof Object && !Array.isArray(options.args.options.enum)) {
this.enum = Object.keys(options.args.options.enum)
.filter(key => isNaN(+key)) // remove numeric keys - typescript numeric enum types generate them
// remove numeric keys - typescript numeric enum types generate them
// From the documentation: “declaration merging” means that the compiler merges two separate declarations
// declared with the same name into a single definition. This concept is often used to merge enum with namespace
// where in namespace we define e.g. utility methods for creating enum. This is well known in other languages
// like Java (enum methods). Here in case if enum have function, we need to remove it from metadata, otherwise
// generated SQL statements contains string representation of that function which leads into syntax error
// at database side.
.filter(key => isNaN(+key) && typeof (options.args.options.enum as ObjectLiteral)[key] !== "function")
.map(key => (options.args.options.enum as ObjectLiteral)[key]);

} else {
Expand Down
16 changes: 16 additions & 0 deletions test/github-issues/7651/entity/order-test.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Column, Entity, PrimaryColumn } from "../../../../src";
import { Order } from "./order";

@Entity({ name: "order_test" })
export class OrderTestEntity {

@PrimaryColumn()
id: number;

@Column({ type: "enum", enum: Order, default: Order.FIRST })
order: Order;

@Column({ type: "enum", enum: Order, default: [Order.FIRST], array: true })
orders: Order[];

}
20 changes: 20 additions & 0 deletions test/github-issues/7651/entity/order.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export enum Order {
FIRST = "first",
SECOND = "second",
THIRD = "third"
}

export namespace Order {
export function from(value: string): Order {
switch (value) {
case "_1":
return Order.FIRST;
case "_2":
return Order.SECOND;
case "_3":
return Order.THIRD;
default:
return Order.FIRST;
}
}
}
75 changes: 75 additions & 0 deletions test/github-issues/7651/issue-7651.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import "reflect-metadata";
import { Connection } from "../../../src";
import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../utils/test-utils";
import { Order } from "./entity/order";
import { OrderTestEntity } from "./entity/order-test.entity";

describe("github issues > #7651 Enum that contains functions is not accordingly translated to SQL", () => {

describe("entity", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
schemaCreate: true,
dropSchema: true,
enabledDrivers: ["postgres"]
}));
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));

it("should correctly save and retrieve enum fields when declaration merging technique is used and enum contains functions", () => Promise.all(connections.map(async connection => {
// GIVEN
const orderEntity = new OrderTestEntity();
orderEntity.id = 1;
orderEntity.order = Order.from("_2"); // example of function call on enum to retrieve enum from string

const orderEntityRepository = connection.getRepository(OrderTestEntity);
await orderEntityRepository.save(orderEntity);

// WHEN
const loadedOrderEntity = await orderEntityRepository.findOne(1);

// THEN
loadedOrderEntity!.order.should.be.eq(Order.SECOND);
})));

it("should correctly save and retrieve enum array", () => Promise.all(connections.map(async connection => {
// GIVEN
const orderEntity = new OrderTestEntity();
orderEntity.id = 1;
orderEntity.orders = [Order.from("_2"), Order.THIRD];

const orderEntityRepository = connection.getRepository(OrderTestEntity);
await orderEntityRepository.save(orderEntity);

// WHEN
const loadedOrderEntity = await orderEntityRepository.findOne(1);

// THEN
loadedOrderEntity!.orders.should.be.eql([Order.SECOND, Order.THIRD]);
})));
});

describe("schema", () => {
let connections: Connection[];
before(async () => connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
schemaCreate: false,
dropSchema: true,
enabledDrivers: ["postgres"],
migrations: []
}));
after(() => closeTestingConnections(connections));

it("should contain SQL for enum type without function", () => Promise.all(connections.map(async connection => {
const sqlInMemory = await connection.driver.createSchemaBuilder().log();

sqlInMemory!.upQueries.length.should.be.greaterThan(0);
sqlInMemory.upQueries.forEach(query => {
// there should be no function string in query when our ENUM TYPE is provided
query.query.should.not.contain("function");
});
})));
});

});

0 comments on commit dba327d

Please sign in to comment.