Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,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)

Expand Down
6 changes: 6 additions & 0 deletions src/decorator/columns/Column.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
19 changes: 16 additions & 3 deletions src/driver/mysql/MysqlDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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";

Expand All @@ -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}'`;
}

Expand Down
2 changes: 1 addition & 1 deletion src/driver/mysql/MysqlQueryRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {
Expand Down
21 changes: 18 additions & 3 deletions src/driver/postgres/PostgresDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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(",") : [];
Expand Down Expand Up @@ -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";

Expand Down Expand Up @@ -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(",")}}'`;
}
Expand Down
18 changes: 11 additions & 7 deletions src/driver/postgres/PostgresQueryRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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)}`);
Expand All @@ -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));
Expand Down Expand Up @@ -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)}`);
}
Expand Down Expand Up @@ -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 ? "[]" : "";
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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";
Expand Down
9 changes: 9 additions & 0 deletions src/driver/sqlite-abstract/AbstractSqliteDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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" ) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since sqlite supports enum now, it should have enum type as well

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, don't forget to list new types in the docs (website)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or using CHECK constraint in sqlite can't be called enum ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot find native enum support on the SQLite website: https://www.sqlite.org/datatype3.html.

I would say it makes sense to have enum for native enum types, and simple-enum for the emulated enum type. That way it will be more clear when you are using a derived/emulated type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is currently no section on either enums or simple- types on the website. Do you want me to create one in a pull request?

Also, are you aware that the website certificate is invalid when accessing it from https://typeorm.io/?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, are you aware that the website certificate is invalid when accessing it from https://typeorm.io/?

yes =(

There is currently no section on either enums or simple- types on the website. Do you want me to create one in a pull request?

yes feel free please

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value = DateUtils.stringToSimpleEnum(value, columnMetadata);

}

if (columnMetadata.transformer)
Expand Down Expand Up @@ -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 || "";
}
Expand Down
12 changes: 12 additions & 0 deletions src/driver/sqlite-abstract/AbstractSqliteQueryRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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.
Expand Down
11 changes: 11 additions & 0 deletions src/driver/sqlserver/SqlServerDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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";

Expand Down
26 changes: 26 additions & 0 deletions src/driver/sqlserver/SqlServerQueryRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down
2 changes: 2 additions & 0 deletions src/driver/types/ColumnTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions src/persistence/SubjectChangedColumnsComputer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
19 changes: 19 additions & 0 deletions src/util/DateUtils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ColumnMetadata } from "../metadata/ColumnMetadata";

/**
* Provides utilities to transform hydrated and persisted data.
*/
Expand Down Expand Up @@ -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
// -------------------------------------------------------------------------
Expand Down
Loading