Merge pull request #3700 from borremosch/add-simple-enum-type

Added simple-enum column type
This commit is contained in:
Umed Khudoiberdiev 2019-02-25 12:41:18 +05:00 committed by GitHub
commit d9f5581b22
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 535 additions and 15 deletions

View File

@ -18,6 +18,7 @@ feel free to ask us and community.
* added browser entry point to `package.json` ([3583](https://github.com/typeorm/typeorm/issues/3583))
* replaced backend-only drivers by dummy driver in browser builds
* added `useLocalForage` option to Sql.js connection options, which enables asynchronous load and save operations of the datatbase from the indexedDB ([#3554](https://github.com/typeorm/typeorm/issues/3554))
* added simple-enum column type ([#1414](https://github.com/typeorm/typeorm/issues/1414))
## 0.2.13 (2019-02-10)

View File

@ -64,6 +64,12 @@ export function Column(type: WithPrecisionColumnType, options?: ColumnCommonOpti
*/
export function Column(type: "enum", options?: ColumnCommonOptions & ColumnEnumOptions): Function;
/**
* Column decorator is used to mark a specific class property as a table column.
* Only properties decorated with this decorator will be persisted to the database when entity be saved.
*/
export function Column(type: "simple-enum", options?: ColumnCommonOptions & ColumnEnumOptions): Function;
/**
* Column decorator is used to mark a specific class property as a table column.
* Only properties decorated with this decorator will be persisted to the database when entity be saved.

View File

@ -439,7 +439,8 @@ export class MysqlDriver implements Driver {
} else if (columnMetadata.type === "simple-json") {
return DateUtils.simpleJsonToString(value);
} else if (columnMetadata.type === "enum") {
} else if (columnMetadata.type === "enum" || columnMetadata.type === "simple-enum") {
return "" + value;
}
@ -475,7 +476,10 @@ export class MysqlDriver implements Driver {
value = DateUtils.stringToSimpleJson(value);
} else if (
columnMetadata.type === "enum"
(
columnMetadata.type === "enum"
|| columnMetadata.type === "simple-enum"
)
&& columnMetadata.enum
&& !isNaN(value)
&& columnMetadata.enum.indexOf(parseInt(value)) >= 0
@ -515,6 +519,9 @@ export class MysqlDriver implements Driver {
} else if (column.type === "simple-array" || column.type === "simple-json") {
return "text";
} else if (column.type === "simple-enum") {
return "enum";
} else if (column.type === "double precision" || column.type === "real") {
return "double";
@ -541,7 +548,13 @@ export class MysqlDriver implements Driver {
normalizeDefault(columnMetadata: ColumnMetadata): string {
const defaultValue = columnMetadata.default;
if (columnMetadata.type === "enum" && defaultValue !== undefined) {
if (
(
columnMetadata.type === "enum" ||
columnMetadata.type === "simple-enum"
) &&
defaultValue !== undefined
) {
return `'${defaultValue}'`;
}

View File

@ -1270,7 +1270,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner {
tableColumn.scale = parseInt(dbColumn["NUMERIC_SCALE"]);
}
if (tableColumn.type === "enum") {
if (tableColumn.type === "enum" || tableColumn.type === "simple-enum") {
const colType = dbColumn["COLUMN_TYPE"];
const items = colType.substring(colType.indexOf("(") + 1, colType.indexOf(")")).split(",");
tableColumn.enum = (items as string[]).map(item => {

View File

@ -412,7 +412,13 @@ export class PostgresDriver implements Driver {
} else if (columnMetadata.type === "simple-json") {
return DateUtils.simpleJsonToString(value);
} else if (columnMetadata.type === "enum" && !columnMetadata.isArray) {
} else if (
(
columnMetadata.type === "enum"
|| columnMetadata.type === "simple-enum"
)
&& !columnMetadata.isArray
) {
return "" + value;
}
@ -462,7 +468,8 @@ export class PostgresDriver implements Driver {
} else if (columnMetadata.type === "simple-json") {
value = DateUtils.stringToSimpleJson(value);
} else if (columnMetadata.type === "enum" ) {
} else if (columnMetadata.type === "enum" || columnMetadata.type === "simple-enum" ) {
if (columnMetadata.isArray) {
// manually convert enum array to array of values (pg does not support, see https://github.com/brianc/node-pg-types/issues/56)
value = value !== "{}" ? (value as string).substr(1, (value as string).length - 2).split(",") : [];
@ -565,6 +572,9 @@ export class PostgresDriver implements Driver {
} else if (column.type === "simple-json") {
return "text";
} else if (column.type === "simple-enum") {
return "enum";
} else if (column.type === "int2") {
return "smallint";
@ -598,7 +608,12 @@ export class PostgresDriver implements Driver {
const defaultValue = columnMetadata.default;
const arrayCast = columnMetadata.isArray ? `::${columnMetadata.type}[]` : "";
if (columnMetadata.type === "enum" && defaultValue !== undefined) {
if (
(
columnMetadata.type === "enum"
|| columnMetadata.type === "simple-enum"
) && defaultValue !== undefined
) {
if (columnMetadata.isArray && Array.isArray(defaultValue)) {
return `'{${defaultValue.map((val: string) => `${val}`).join(",")}}'`;
}

View File

@ -313,7 +313,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner
// if table have column with ENUM type, we must create this type in postgres.
await Promise.all(table.columns
.filter(column => column.type === "enum")
.filter(column => column.type === "enum" || column.type === "simple-enum")
.map(async column => {
const hasEnum = await this.hasEnumType(table, column);
if (!hasEnum) {
@ -449,7 +449,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner
// rename ENUM types
newTable.columns
.filter(column => column.type === "enum")
.filter(column => column.type === "enum" || column.type === "simple-enum")
.forEach(column => {
upQueries.push(`ALTER TYPE ${this.buildEnumName(oldTable, column)} RENAME TO ${this.buildEnumName(newTable, column, false)}`);
downQueries.push(`ALTER TYPE ${this.buildEnumName(newTable, column)} RENAME TO ${this.buildEnumName(oldTable, column, false)}`);
@ -467,7 +467,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner
const upQueries: string[] = [];
const downQueries: string[] = [];
if (column.type === "enum") {
if (column.type === "enum" || column.type === "simple-enum") {
const hasEnum = await this.hasEnumType(table, column);
if (!hasEnum) {
upQueries.push(this.createEnumTypeSql(table, column));
@ -577,7 +577,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner
downQueries.push(`ALTER TABLE ${this.escapeTableName(table)} RENAME COLUMN "${newColumn.name}" TO "${oldColumn.name}"`);
// rename ENUM type
if (oldColumn.type === "enum") {
if (oldColumn.type === "enum" || oldColumn.type === "simple-enum") {
upQueries.push(`ALTER TYPE ${this.buildEnumName(table, oldColumn)} RENAME TO ${this.buildEnumName(table, newColumn, false)}`);
downQueries.push(`ALTER TYPE ${this.buildEnumName(table, newColumn)} RENAME TO ${this.buildEnumName(table, oldColumn, false)}`);
}
@ -675,7 +675,11 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner
downQueries.push(`ALTER TABLE ${this.escapeTableName(table)} ALTER COLUMN "${newColumn.name}" TYPE ${this.driver.createFullType(oldColumn)}`);
}
if (newColumn.type === "enum" && oldColumn.type === "enum" && !OrmUtils.isArraysEqual(newColumn.enum!, oldColumn.enum!)) {
if (
(newColumn.type === "enum" || newColumn.type === "simple-enum")
&& (oldColumn.type === "enum" || newColumn.type === "simple-enum")
&& !OrmUtils.isArraysEqual(newColumn.enum!, oldColumn.enum!)
) {
const enumName = this.buildEnumName(table, newColumn);
const enumNameWithoutSchema = this.buildEnumName(table, newColumn, false);
const arraySuffix = newColumn.isArray ? "[]" : "";
@ -901,7 +905,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner
downQueries.push(`ALTER TABLE ${this.escapeTableName(table)} ADD ${this.buildCreateColumnSql(table, column)}`);
// drop enum type
if (column.type === "enum") {
if (column.type === "enum" || column.type === "simple-enum") {
const hasEnum = await this.hasEnumType(table, column);
if (hasEnum) {
upQueries.push(this.dropEnumTypeSql(table, column));
@ -1895,7 +1899,7 @@ export class PostgresQueryRunner extends BaseQueryRunner implements QueryRunner
if (column.type === "bigint" || column.type === "int8")
c += " BIGSERIAL";
}
if (column.type === "enum") {
if (column.type === "enum" || column.type === "simple-enum") {
c += " " + this.buildEnumName(table, column);
if (column.isArray)
c += " array";

View File

@ -246,6 +246,8 @@ export abstract class AbstractSqliteDriver implements Driver {
} else if (columnMetadata.type === "simple-json") {
return DateUtils.simpleJsonToString(value);
} else if (columnMetadata.type === "simple-enum") {
return DateUtils.simpleEnumToString(value);
}
return value;
@ -288,6 +290,10 @@ export abstract class AbstractSqliteDriver implements Driver {
} else if (columnMetadata.type === "simple-json") {
value = DateUtils.stringToSimpleJson(value);
} else if ( columnMetadata.type === "simple-enum" ) {
value = DateUtils.stringToSimpleEnum(value, columnMetadata);
}
if (columnMetadata.transformer)
@ -385,6 +391,9 @@ export abstract class AbstractSqliteDriver implements Driver {
} else if (column.type === "simple-json") {
return "text";
} else if (column.type === "simple-enum") {
return "varchar";
} else {
return column.type as string || "";
}

View File

@ -762,6 +762,16 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen
tableColumn.generationStrategy = "increment";
}
if (tableColumn.type === "varchar") {
// Check if this is an enum
const enumMatch = sql.match(new RegExp("\"(" + tableColumn.name + ")\" varchar CHECK\\s*\\(\\s*\\1\\s+IN\\s*\\(('[^']+'(?:\\s*,\\s*'[^']+')+)\\s*\\)\\s*\\)"));
if (enumMatch) {
// This is an enum
tableColumn.type = "simple-enum";
tableColumn.enum = enumMatch[2].substr(1, enumMatch[2].length - 2).split("','");
}
}
// parse datatype and attempt to retrieve length
let pos = tableColumn.type.indexOf("(");
if (pos !== -1) {
@ -972,6 +982,8 @@ export abstract class AbstractSqliteQueryRunner extends BaseQueryRunner implemen
c += " " + this.connection.driver.createFullType(column);
}
if (column.enum)
c += " CHECK( " + column.name + " IN (" + column.enum.map(val => "'" + val + "'").join(",") + ") )";
if (column.isPrimary && !skipPrimary)
c += " PRIMARY KEY";
if (column.isGenerated === true && column.generationStrategy === "increment") // don't use skipPrimary here since updates can update already exist primary without auto inc.

View File

@ -381,6 +381,10 @@ export class SqlServerDriver implements Driver {
} else if (columnMetadata.type === "simple-json") {
return DateUtils.simpleJsonToString(value);
} else if (columnMetadata.type === "simple-enum") {
return DateUtils.simpleEnumToString(value);
}
return value;
@ -414,6 +418,10 @@ export class SqlServerDriver implements Driver {
} else if (columnMetadata.type === "simple-json") {
value = DateUtils.stringToSimpleJson(value);
} else if (columnMetadata.type === "simple-enum") {
value = DateUtils.stringToSimpleEnum(value, columnMetadata);
}
if (columnMetadata.transformer)
@ -447,6 +455,9 @@ export class SqlServerDriver implements Driver {
} else if (column.type === "simple-array" || column.type === "simple-json") {
return "ntext";
} else if (column.type === "simple-enum") {
return "nvarchar";
} else if (column.type === "dec") {
return "decimal";

View File

@ -1553,6 +1553,28 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner
tableColumn.scale = dbColumn["NUMERIC_SCALE"];
}
if (tableColumn.type === "nvarchar") {
// Check if this is an enum
const columnCheckConstraints = columnConstraints.filter(constraint => constraint["CONSTRAINT_TYPE"] === "CHECK");
if (columnCheckConstraints.length) {
const isEnumRegexp = new RegExp("^\\(\\[" + tableColumn.name + "\\]='[^']+'(?: OR \\[" + tableColumn.name + "\\]='[^']+')*\\)$");
for (const checkConstraint of columnCheckConstraints) {
if (isEnumRegexp.test(checkConstraint["definition"])) {
// This is an enum constraint, make column into an enum
tableColumn.type = "simple-enum";
tableColumn.enum = [];
const enumValueRegexp = new RegExp("\\[" + tableColumn.name + "\\]='([^']+)'", "g");
let result;
while ((result = enumValueRegexp.exec(checkConstraint["definition"])) !== null) {
tableColumn.enum.unshift(result[1]);
}
// Skip other column constraints
break;
}
}
}
}
tableColumn.default = dbColumn["COLUMN_DEFAULT"] !== null && dbColumn["COLUMN_DEFAULT"] !== undefined
? this.removeParenthesisFromDefault(dbColumn["COLUMN_DEFAULT"])
: undefined;
@ -1895,6 +1917,10 @@ export class SqlServerQueryRunner extends BaseQueryRunner implements QueryRunner
*/
protected buildCreateColumnSql(table: Table, column: TableColumn, skipIdentity: boolean, createDefault: boolean) {
let c = `"${column.name}" ${this.connection.driver.createFullType(column)}`;
if (column.enum)
c += " CHECK( " + column.name + " IN (" + column.enum.map(val => "'" + val + "'").join(",") + ") )";
if (column.collation)
c += " COLLATE " + column.collation;

View File

@ -81,6 +81,8 @@ export type SimpleColumnType =
|"simple-json" // typeorm-specific, automatically mapped to string
|"simple-enum" // typeorm-specific, automatically mapped to string
// numeric types
|"bit" // mssql
|"int2" // postgres, sqlite

View File

@ -87,6 +87,9 @@ export class SubjectChangedColumnsComputer {
} else if (column.type === "simple-array") {
normalizedValue = DateUtils.simpleArrayToString(entityValue);
databaseValue = DateUtils.simpleArrayToString(databaseValue);
} else if (column.type === "simple-enum") {
normalizedValue = DateUtils.simpleEnumToString(entityValue);
databaseValue = DateUtils.simpleEnumToString(databaseValue);
}
}

View File

@ -1,3 +1,5 @@
import { ColumnMetadata } from "../metadata/ColumnMetadata";
/**
* Provides utilities to transform hydrated and persisted data.
*/
@ -171,6 +173,23 @@ export class DateUtils {
return typeof value === "string" ? JSON.parse(value) : value;
}
static simpleEnumToString(value: any) {
return "" + value;
}
static stringToSimpleEnum(value: any, columnMetadata: ColumnMetadata) {
if (
columnMetadata.enum
&& !isNaN(value)
&& columnMetadata.enum.indexOf(parseInt(value)) >= 0
) {
// convert to number if that exists in poosible enum options
value = parseInt(value);
}
return value;
}
// -------------------------------------------------------------------------
// Private Static Methods
// -------------------------------------------------------------------------

View File

@ -5,6 +5,7 @@ import {closeTestingConnections, createTestingConnections, reloadTestingDatabase
import {PostWithOptions} from "./entity/PostWithOptions";
import {PostWithoutTypes} from "./entity/PostWithoutTypes";
import {DateUtils} from "../../../../../src/util/DateUtils";
import {FruitEnum} from "./enum/FruitEnum";
describe("database schema > column types > mssql", () => { // https://github.com/tediousjs/tedious/issues/722
@ -66,6 +67,8 @@ describe("database schema > column types > mssql", () => { // https://github.com
post.geometry3 = "GEOMETRYCOLLECTION (POINT (4 0), LINESTRING (4 2, 5 3), POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0), (1 1, 1 2, 2 2, 2 1, 1 1)))";
post.simpleArray = ["A", "B", "C"];
post.simpleJson = { param: "VALUE" };
post.simpleEnum = "A";
post.simpleClassEnum1 = FruitEnum.Apple;
await postRepository.save(post);
const loadedPost = (await postRepository.findOne(1))!;
@ -112,6 +115,8 @@ describe("database schema > column types > mssql", () => { // https://github.com
loadedPost.simpleArray[1].should.be.equal(post.simpleArray[1]);
loadedPost.simpleArray[2].should.be.equal(post.simpleArray[2]);
loadedPost.simpleJson.param.should.be.equal(post.simpleJson.param);
loadedPost.simpleEnum.should.be.equal(post.simpleEnum);
loadedPost.simpleClassEnum1.should.be.equal(post.simpleClassEnum1);
table!.findColumnByName("id")!.type.should.be.equal("int");
table!.findColumnByName("name")!.type.should.be.equal("nvarchar");
@ -150,6 +155,14 @@ describe("database schema > column types > mssql", () => { // https://github.com
table!.findColumnByName("geometry1")!.type.should.be.equal("geometry");
table!.findColumnByName("simpleArray")!.type.should.be.equal("ntext");
table!.findColumnByName("simpleJson")!.type.should.be.equal("ntext");
table!.findColumnByName("simpleEnum")!.type.should.be.equal("simple-enum");
table!.findColumnByName("simpleEnum")!.enum![0].should.be.equal("A");
table!.findColumnByName("simpleEnum")!.enum![1].should.be.equal("B");
table!.findColumnByName("simpleEnum")!.enum![2].should.be.equal("C");
table!.findColumnByName("simpleClassEnum1")!.type.should.be.equal("simple-enum");
table!.findColumnByName("simpleClassEnum1")!.enum![0].should.be.equal("apple");
table!.findColumnByName("simpleClassEnum1")!.enum![1].should.be.equal("pineapple");
table!.findColumnByName("simpleClassEnum1")!.enum![2].should.be.equal("banana");
})));

View File

@ -1,6 +1,7 @@
import {Entity} from "../../../../../../src/decorator/entity/Entity";
import {PrimaryColumn} from "../../../../../../src/decorator/columns/PrimaryColumn";
import {Column} from "../../../../../../src/decorator/columns/Column";
import {FruitEnum} from "../enum/FruitEnum";
@Entity()
export class Post {
@ -138,4 +139,10 @@ export class Post {
@Column("simple-json")
simpleJson: { param: string };
@Column("simple-enum", { enum: ["A", "B", "C"] })
simpleEnum: string;
@Column("simple-enum", { enum: FruitEnum })
simpleClassEnum1: FruitEnum;
}

View File

@ -0,0 +1,5 @@
export enum FruitEnum {
Apple = "apple",
Pineapple = "pineapple",
Banana = "banana"
}

View File

@ -80,6 +80,8 @@ describe("database schema > column types > mysql", () => {
post.json = { id: 1, name: "Post" };
post.simpleArray = ["A", "B", "C"];
post.simpleJson = { param: "VALUE" };
post.simpleEnum = "A";
post.simpleClassEnum1 = FruitEnum.Apple;
await postRepository.save(post);
const loadedPost = (await postRepository.findOne(1))!;
@ -136,6 +138,8 @@ describe("database schema > column types > mysql", () => {
loadedPost.simpleArray[1].should.be.equal(post.simpleArray[1]);
loadedPost.simpleArray[2].should.be.equal(post.simpleArray[2]);
loadedPost.simpleJson.param.should.be.equal(post.simpleJson.param);
loadedPost.simpleEnum.should.be.equal(post.simpleEnum);
loadedPost.simpleClassEnum1.should.be.equal(post.simpleClassEnum1);
table!.findColumnByName("id")!.type.should.be.equal("int");
table!.findColumnByName("bit")!.type.should.be.equal("bit");
@ -195,6 +199,14 @@ describe("database schema > column types > mysql", () => {
table!.findColumnByName("json")!.type.should.be.equal("json");
table!.findColumnByName("simpleArray")!.type.should.be.equal("text");
table!.findColumnByName("simpleJson")!.type.should.be.equal("text");
table!.findColumnByName("simpleEnum")!.type.should.be.equal("enum");
table!.findColumnByName("simpleEnum")!.enum![0].should.be.equal("A");
table!.findColumnByName("simpleEnum")!.enum![1].should.be.equal("B");
table!.findColumnByName("simpleEnum")!.enum![2].should.be.equal("C");
table!.findColumnByName("simpleClassEnum1")!.type.should.be.equal("enum");
table!.findColumnByName("simpleClassEnum1")!.enum![0].should.be.equal("apple");
table!.findColumnByName("simpleClassEnum1")!.enum![1].should.be.equal("pineapple");
table!.findColumnByName("simpleClassEnum1")!.enum![2].should.be.equal("banana");
})));

View File

@ -192,4 +192,10 @@ export class Post {
@Column("simple-json")
simpleJson: { param: string };
@Column("simple-enum", { enum: ["A", "B", "C"] })
simpleEnum: string;
@Column("simple-enum", { enum: FruitEnum })
simpleClassEnum1: FruitEnum;
}

View File

@ -11,6 +11,9 @@ export class Post {
@Column("enum", { enum: ["A", "B", "C"] })
enum: string;
@Column("simple-enum", { enum: ["A", "B", "C"] })
simpleEnum: string;
@Column()
name: string;
}

View File

@ -26,13 +26,16 @@ describe("database schema > column types > postgres-enum", () => {
const post = new Post();
post.enum = "A";
post.simpleEnum = "A";
post.name = "Post #1";
await postRepository.save(post);
const loadedPost = (await postRepository.findOne(1))!;
loadedPost.enum.should.be.equal(post.enum);
loadedPost.simpleEnum.should.be.equal(post.simpleEnum);
table!.findColumnByName("enum")!.type.should.be.equal("enum");
table!.findColumnByName("simpleEnum")!.type.should.be.equal("enum");
})));
it("should create ENUM column and revert creation", () => Promise.all(connections.map(async connection => {

View File

@ -89,6 +89,7 @@ describe("database schema > column types > postgres", () => {
post.array = [1, 2, 3];
post.simpleArray = ["A", "B", "C"];
post.simpleJson = { param: "VALUE" };
post.simpleEnum = "A";
await postRepository.save(post);
const loadedPost = (await postRepository.findOne(1))!;
@ -162,6 +163,7 @@ describe("database schema > column types > postgres", () => {
loadedPost.simpleArray[1].should.be.equal(post.simpleArray[1]);
loadedPost.simpleArray[2].should.be.equal(post.simpleArray[2]);
loadedPost.simpleJson.param.should.be.equal(post.simpleJson.param);
loadedPost.simpleEnum.should.be.equal(post.simpleEnum);
table!.findColumnByName("id")!.type.should.be.equal("integer");
table!.findColumnByName("name")!.type.should.be.equal("character varying");
@ -224,6 +226,7 @@ describe("database schema > column types > postgres", () => {
table!.findColumnByName("array")!.isArray!.should.be.true;
table!.findColumnByName("simpleArray")!.type.should.be.equal("text");
table!.findColumnByName("simpleJson")!.type.should.be.equal("text");
table!.findColumnByName("simpleEnum")!.type.should.be.equal("enum");
})));

View File

@ -251,4 +251,7 @@ export class Post {
@Column("simple-json")
simpleJson: { param: string };
@Column("simple-enum", { enum: ["A", "B", "C"] })
simpleEnum: string;
}

View File

@ -3,6 +3,7 @@ import {Post} from "./entity/Post";
import {Connection} from "../../../../../src/connection/Connection";
import {closeTestingConnections, createTestingConnections, reloadTestingDatabases} from "../../../../utils/test-utils";
import {PostWithoutTypes} from "./entity/PostWithoutTypes";
import {FruitEnum} from "./enum/FruitEnum";
describe("database schema > column types > sqlite", () => {
@ -56,6 +57,8 @@ describe("database schema > column types > sqlite", () => {
post.datetime.setMilliseconds(0);
post.simpleArray = ["A", "B", "C"];
post.simpleJson = { param: "VALUE" };
post.simpleEnum = "A";
post.simpleClassEnum1 = FruitEnum.Apple;
await postRepository.save(post);
const loadedPost = (await postRepository.findOne(1))!;
@ -92,6 +95,8 @@ describe("database schema > column types > sqlite", () => {
loadedPost.simpleArray[1].should.be.equal(post.simpleArray[1]);
loadedPost.simpleArray[2].should.be.equal(post.simpleArray[2]);
loadedPost.simpleJson.param.should.be.equal(post.simpleJson.param);
loadedPost.simpleEnum.should.be.equal(post.simpleEnum);
loadedPost.simpleClassEnum1.should.be.equal(post.simpleClassEnum1);
table!.findColumnByName("id")!.type.should.be.equal("integer");
table!.findColumnByName("name")!.type.should.be.equal("varchar");
@ -123,6 +128,14 @@ describe("database schema > column types > sqlite", () => {
table!.findColumnByName("datetime")!.type.should.be.equal("datetime");
table!.findColumnByName("simpleArray")!.type.should.be.equal("text");
table!.findColumnByName("simpleJson")!.type.should.be.equal("text");
table!.findColumnByName("simpleEnum")!.type.should.be.equal("simple-enum");
table!.findColumnByName("simpleEnum")!.enum![0].should.be.equal("A");
table!.findColumnByName("simpleEnum")!.enum![1].should.be.equal("B");
table!.findColumnByName("simpleEnum")!.enum![2].should.be.equal("C");
table!.findColumnByName("simpleClassEnum1")!.type.should.be.equal("simple-enum");
table!.findColumnByName("simpleClassEnum1")!.enum![0].should.be.equal("apple");
table!.findColumnByName("simpleClassEnum1")!.enum![1].should.be.equal("pineapple");
table!.findColumnByName("simpleClassEnum1")!.enum![2].should.be.equal("banana");
})));

View File

@ -1,6 +1,7 @@
import {Entity} from "../../../../../../src/decorator/entity/Entity";
import {PrimaryColumn} from "../../../../../../src/decorator/columns/PrimaryColumn";
import {Column} from "../../../../../../src/decorator/columns/Column";
import {FruitEnum} from "../enum/FruitEnum";
@Entity()
export class Post {
@ -117,4 +118,10 @@ export class Post {
@Column("simple-json")
simpleJson: { param: string };
}
@Column("simple-enum", { enum: ["A", "B", "C"] })
simpleEnum: string;
@Column("simple-enum", { enum: FruitEnum })
simpleClassEnum1: FruitEnum;
}

View File

@ -0,0 +1,5 @@
export enum FruitEnum {
Apple = "apple",
Pineapple = "pineapple",
Banana = "banana"
}

View File

@ -0,0 +1,105 @@
import { Entity, Column, PrimaryColumn } from "../../../../../src";
export enum NumericEnum {
ADMIN,
EDITOR,
MODERATOR,
GHOST
}
export enum StringEnum {
ADMIN = "a",
EDITOR = "e",
MODERATOR = "m",
GHOST = "g"
}
export enum StringNumericEnum {
ONE = "1",
TWO = "2",
THREE = "3",
FOUR = "4"
}
export enum HeterogeneousEnum {
NO = 0,
YES = "YES",
}
export type ArrayDefinedStringEnumType = "admin" | "editor" | "ghost";
export type ArrayDefinedNumericEnumType = 11 | 12 | 13;
@Entity()
export class EnumArrayEntity {
@PrimaryColumn()
id: number;
@Column({
type: "simple-enum",
enum: NumericEnum,
array: true,
default: [NumericEnum.GHOST, NumericEnum.ADMIN]
})
numericEnums: NumericEnum[];
@Column({
type: "simple-enum",
enum: StringEnum,
array: true,
default: []
})
stringEnums: StringEnum[];
@Column({
type: "simple-enum",
enum: StringNumericEnum,
array: true,
default: [StringNumericEnum.THREE, StringNumericEnum.ONE]
})
stringNumericEnums: StringNumericEnum[];
@Column({
type: "simple-enum",
enum: HeterogeneousEnum,
array: true,
default: [HeterogeneousEnum.YES]
})
heterogeneousEnums: HeterogeneousEnum[];
@Column({
type: "simple-enum",
enum: ["admin", "editor", "ghost"],
array: true,
default: ["admin"]
})
arrayDefinedStringEnums: ArrayDefinedStringEnumType[];
@Column({
type: "simple-enum",
enum: [11, 12, 13],
array: true,
default: [11, 13]
})
arrayDefinedNumericEnums: ArrayDefinedNumericEnumType[];
@Column({
type: "simple-enum",
enum: StringEnum,
array: true,
nullable: true
})
enumWithoutDefault: StringEnum[];
@Column({
type: "simple-enum",
enum: StringEnum,
array: true,
default: "{}"
})
legacyDefaultAsString: StringEnum[];
}

View File

@ -0,0 +1,62 @@
import "reflect-metadata";
import { Connection } from "../../../../src";
import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../../utils/test-utils";
import { EnumArrayEntity, NumericEnum, StringEnum, HeterogeneousEnum, StringNumericEnum } from "./entity/EnumArrayEntity";
describe("database schema > simple enum arrays", () => {
let connections: Connection[];
before(async () => {
connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
enabledDrivers: ["postgres"]
});
});
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("should correctly create default values", () => Promise.all(connections.map(async connection => {
const enumEntityRepository = connection.getRepository(EnumArrayEntity);
const enumEntity = new EnumArrayEntity();
enumEntity.id = 1;
await enumEntityRepository.save(enumEntity);
const loadedEnumEntity = await enumEntityRepository.findOne(1);
loadedEnumEntity!.numericEnums.should.be.eql([NumericEnum.GHOST, NumericEnum.ADMIN]);
loadedEnumEntity!.stringEnums.should.be.eql([]);
loadedEnumEntity!.stringNumericEnums.should.be.eql([StringNumericEnum.THREE, StringNumericEnum.ONE]);
loadedEnumEntity!.heterogeneousEnums.should.be.eql([HeterogeneousEnum.YES]);
loadedEnumEntity!.arrayDefinedStringEnums.should.be.eql(["admin"]);
loadedEnumEntity!.arrayDefinedNumericEnums.should.be.eql([11, 13]);
})));
it("should correctly save and retrieve", () => Promise.all(connections.map(async connection => {
const enumEntityRepository = connection.getRepository(EnumArrayEntity);
const enumEntity = new EnumArrayEntity();
enumEntity.id = 1;
enumEntity.numericEnums = [NumericEnum.GHOST, NumericEnum.EDITOR];
enumEntity.stringEnums = [StringEnum.MODERATOR];
enumEntity.stringNumericEnums = [StringNumericEnum.FOUR];
enumEntity.heterogeneousEnums = [HeterogeneousEnum.NO];
enumEntity.arrayDefinedStringEnums = ["editor"];
enumEntity.arrayDefinedNumericEnums = [12, 13];
await enumEntityRepository.save(enumEntity);
const loadedEnumEntity = await enumEntityRepository.findOne(1);
loadedEnumEntity!.numericEnums.should.be.eql([NumericEnum.GHOST, NumericEnum.EDITOR]);
loadedEnumEntity!.stringEnums.should.be.eql([StringEnum.MODERATOR]);
loadedEnumEntity!.stringNumericEnums.should.be.eql([StringNumericEnum.FOUR]);
loadedEnumEntity!.heterogeneousEnums.should.be.eql([HeterogeneousEnum.NO]);
loadedEnumEntity!.arrayDefinedStringEnums.should.be.eql(["editor"]);
loadedEnumEntity!.arrayDefinedNumericEnums.should.be.eql([12, 13]);
})));
});

View File

@ -0,0 +1,89 @@
import { Entity, Column, PrimaryColumn } from "../../../../../src";
export enum NumericEnum {
ADMIN,
EDITOR,
MODERATOR,
GHOST
}
export enum StringEnum {
ADMIN = "a",
EDITOR = "e",
MODERATOR = "m",
GHOST = "g"
}
export enum StringNumericEnum {
ONE = "1",
TWO = "2",
THREE = "3",
FOUR = "4"
}
export enum HeterogeneousEnum {
NO = 0,
YES = "YES",
}
export type ArrayDefinedStringEnumType = "admin" | "editor" | "ghost";
export type ArrayDefinedNumericEnumType = 11 | 12 | 13;
@Entity()
export class SimpleEnumEntity {
@PrimaryColumn()
id: number;
@Column({
type: "simple-enum",
enum: NumericEnum,
default: NumericEnum.MODERATOR
})
numericEnum: NumericEnum;
@Column({
type: "simple-enum",
enum: StringEnum,
default: StringEnum.GHOST
})
stringEnum: StringEnum;
@Column({
type: "simple-enum",
enum: StringNumericEnum,
default: StringNumericEnum.FOUR
})
stringNumericEnum: StringNumericEnum;
@Column({
type: "simple-enum",
enum: HeterogeneousEnum,
default: HeterogeneousEnum.NO
})
heterogeneousEnum: HeterogeneousEnum;
@Column({
type: "simple-enum",
enum: ["admin", "editor", "ghost"],
default: "ghost"
})
arrayDefinedStringEnum: ArrayDefinedStringEnumType;
@Column({
type: "simple-enum",
enum: [11, 12, 13],
default: 12
})
arrayDefinedNumericEnum: ArrayDefinedNumericEnumType;
@Column({
type: "simple-enum",
enum: StringEnum,
})
enumWithoutdefault: StringEnum;
}

View File

@ -0,0 +1,63 @@
import "reflect-metadata";
import { Connection } from "../../../../src";
import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../../utils/test-utils";
import { SimpleEnumEntity, NumericEnum, StringEnum, HeterogeneousEnum, StringNumericEnum } from "./entity/SimpleEnumEntity";
describe("database schema > simple-enums", () => {
let connections: Connection[];
before(async () => {
connections = await createTestingConnections({
entities: [__dirname + "/entity/*{.js,.ts}"],
enabledDrivers: ["mysql", "mariadb", "postgres", "sqlite", "mssql"]
});
});
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));
it("should correctly use default values", () => Promise.all(connections.map(async connection => {
const enumEntityRepository = connection.getRepository(SimpleEnumEntity);
const enumEntity = new SimpleEnumEntity();
enumEntity.id = 1;
enumEntity.enumWithoutdefault = StringEnum.EDITOR;
await enumEntityRepository.save(enumEntity);
const loadedEnumEntity = await enumEntityRepository.findOne(1);
loadedEnumEntity!.numericEnum.should.be.eq(NumericEnum.MODERATOR);
loadedEnumEntity!.stringEnum.should.be.eq(StringEnum.GHOST);
loadedEnumEntity!.stringNumericEnum.should.be.eq(StringNumericEnum.FOUR);
loadedEnumEntity!.heterogeneousEnum.should.be.eq(HeterogeneousEnum.NO);
loadedEnumEntity!.arrayDefinedStringEnum.should.be.eq("ghost");
loadedEnumEntity!.arrayDefinedNumericEnum.should.be.eq(12);
})));
it("should correctly save and retrieve", () => Promise.all(connections.map(async connection => {
const enumEntityRepository = connection.getRepository(SimpleEnumEntity);
const enumEntity = new SimpleEnumEntity();
enumEntity.id = 1;
enumEntity.numericEnum = NumericEnum.EDITOR;
enumEntity.stringEnum = StringEnum.ADMIN;
enumEntity.stringNumericEnum = StringNumericEnum.TWO;
enumEntity.heterogeneousEnum = HeterogeneousEnum.YES;
enumEntity.arrayDefinedStringEnum = "editor";
enumEntity.arrayDefinedNumericEnum = 13;
enumEntity.enumWithoutdefault = StringEnum.ADMIN;
await enumEntityRepository.save(enumEntity);
const loadedEnumEntity = await enumEntityRepository.findOne(1);
loadedEnumEntity!.numericEnum.should.be.eq(NumericEnum.EDITOR);
loadedEnumEntity!.stringEnum.should.be.eq(StringEnum.ADMIN);
loadedEnumEntity!.stringNumericEnum.should.be.eq(StringNumericEnum.TWO);
loadedEnumEntity!.heterogeneousEnum.should.be.eq(HeterogeneousEnum.YES);
loadedEnumEntity!.arrayDefinedStringEnum.should.be.eq("editor");
loadedEnumEntity!.arrayDefinedNumericEnum.should.be.eq(13);
})));
});