Skip to content

Commit

Permalink
fix: Unnecessary migrations for unsigned numeric types
Browse files Browse the repository at this point in the history
In MariaDB, unsigned numeric types (``<tiny,small,medium>int`) without an explicit `width` property set would generate migrations on every run. This is due to an error in setting the default width for unsigned types.

Fixes typeorm#2943
  • Loading branch information
michaelbromley committed Aug 28, 2020
1 parent d1ed572 commit 499ebaf
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/driver/mysql/MysqlQueryRunner.ts
Expand Up @@ -1296,6 +1296,7 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner {
tableColumn.name = dbColumn["COLUMN_NAME"];
tableColumn.type = dbColumn["DATA_TYPE"].toLowerCase();

tableColumn.unsigned = tableColumn.zerofill ? true : dbColumn["COLUMN_TYPE"].indexOf("unsigned") !== -1;
if (this.driver.withWidthColumnTypes.indexOf(tableColumn.type as ColumnType) !== -1) {
const width = dbColumn["COLUMN_TYPE"].substring(dbColumn["COLUMN_TYPE"].indexOf("(") + 1, dbColumn["COLUMN_TYPE"].indexOf(")"));
tableColumn.width = width && !this.isDefaultColumnWidth(table, tableColumn, parseInt(width)) ? parseInt(width) : undefined;
Expand Down Expand Up @@ -1333,7 +1334,6 @@ export class MysqlQueryRunner extends BaseQueryRunner implements QueryRunner {
return this.driver.buildTableName(dbPrimaryKey["TABLE_NAME"], undefined, dbPrimaryKey["TABLE_SCHEMA"]) === tableFullName && dbPrimaryKey["COLUMN_NAME"] === tableColumn.name;
});
tableColumn.zerofill = dbColumn["COLUMN_TYPE"].indexOf("zerofill") !== -1;
tableColumn.unsigned = tableColumn.zerofill ? true : dbColumn["COLUMN_TYPE"].indexOf("unsigned") !== -1;
tableColumn.isGenerated = dbColumn["EXTRA"].indexOf("auto_increment") !== -1;
if (tableColumn.isGenerated)
tableColumn.generationStrategy = "increment";
Expand Down
14 changes: 11 additions & 3 deletions src/query-runner/BaseQueryRunner.ts
Expand Up @@ -324,10 +324,18 @@ export abstract class BaseQueryRunner {
return false;
}

if (this.connection.driver.dataTypeDefaults
const defaultWidthForType = this.connection.driver.dataTypeDefaults
&& this.connection.driver.dataTypeDefaults[column.type]
&& this.connection.driver.dataTypeDefaults[column.type].width) {
return this.connection.driver.dataTypeDefaults[column.type].width === width;
&& this.connection.driver.dataTypeDefaults[column.type].width;

if (defaultWidthForType) {
// the default widths of these numeric types are 1 less when the column is unsigned.
const typesWithReducedUnsignedDefault = ["int", "tinyint", "smallint", "mediumint"];
if (column.unsigned && -1 < typesWithReducedUnsignedDefault.indexOf(column.type)) {
return (defaultWidthForType - 1) === width;
} else {
return defaultWidthForType === width;
}
}

return false;
Expand Down
22 changes: 22 additions & 0 deletions test/github-issues/2943/entity/Test.ts
@@ -0,0 +1,22 @@
import { Column, Entity, PrimaryColumn } from "../../../../src";

@Entity()
export class Test {
@PrimaryColumn()
id: number;

@Column({ type: 'int', unsigned: true})
uInt: number;

@Column({ type: 'tinyint', unsigned: true})
uTinyInt: number;

@Column({ type: 'smallint', unsigned: true})
uSmallInt: number;

@Column({ type: 'mediumint', unsigned: true})
uMediumInt: number;

@Column({ type: 'bigint', unsigned: true})
uBigInt: number;
}
28 changes: 28 additions & 0 deletions test/github-issues/2943/issue-2943.ts
@@ -0,0 +1,28 @@
import "reflect-metadata";
import { expect } from "chai";
import { Connection } from "../../../src";
import { closeTestingConnections, createTestingConnections, reloadTestingDatabases } from "../../utils/test-utils";
import { Test } from "./entity/Test";

describe.only("github issues > #2932 Inappropriate migration generated", () => {

let connections: Connection[];

before(async () => {
connections = await createTestingConnections({
entities: [Test],
schemaCreate: true,
dropSchema: true
});
});
beforeEach(() => reloadTestingDatabases(connections));
after(() => closeTestingConnections(connections));

it("should not create migrations for unsigned numeric types with no specified width", () =>
Promise.all(connections.map(async (connection) => {
const sqlInMemory = await connection.driver.createSchemaBuilder().log();

expect(sqlInMemory.upQueries).to.eql([]);
expect(sqlInMemory.upQueries.length).to.eq(0);
})));
});

0 comments on commit 499ebaf

Please sign in to comment.