Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

@Unique and @Column decorators unique constraint name on postgresql/sqlite #1704

Open
1 of 2 tasks
ngruychev opened this issue Jan 5, 2024 · 0 comments
Open
1 of 2 tasks

Comments

@ngruychev
Copy link

Issue

Using the @Unique constraint with postgresql/sqlite doesn't set the desired constraint name.

Versions

  • sequelize: 6.35.2
  • sequelize-typescript: 2.1.6
  • typescript: 5.3.3

Issue type

  • bug report
  • feature request

Actual behavior

Indexes follow a default naming convention - e.g. TableName_fieldName_key (TableName_fieldName1_fieldName2_key in case of composite indexes) in the case of PostgreSQL

Expected behavior

Model fields annotated with @Unique("IndexName"), @Unique({ name: "IndexName", msg: "msg" }), and @Column({ type: DataType.WHATEVER, unique: "IndexName" }) should result in unique indexes with the appropriate names in PostgreSQL and sqlite.

Steps to reproduce

Run the code below with npx ts-node index.ts. PostgreSQL and sqlite (didn't test other engines) follow Actual Behavior, while MySQL follows Expected behavior for all 4 columns, confirming what the behavior should be.

Related code

Code:

import { Model, Table, Column, DataType, Unique, PrimaryKey, AutoIncrement, Sequelize, Index } from 'sequelize-typescript';

@Table({ tableName: 'Item' })
class Item extends Model {
  @PrimaryKey
  @AutoIncrement
  @Column(DataType.INTEGER)
  id: number = 0;

  @Unique("uniqueThingIndex")
  @Column(DataType.STRING)
  thing: string = '';

  @Column({ type: DataType.STRING, unique: 'uniqueThingIndexTwo' })
  thingTwo: string = '';

  @Column(DataType.STRING)
  @Index({ name: 'indexThingThree', unique: true })
  thingThree: string = '';
}

const dialects = [
  { dialect: 'sqlite', constraintsQuery: "PRAGMA index_list('Item')", options: { storage: ':memory:' } },
  {
    dialect: 'postgres',
    constraintsQuery: "SELECT indexname FROM pg_indexes WHERE tablename = 'Item'",
    options: {
      host: 'localhost',
      port: 5432,
      username: 'test',
      password: 'test',
      database: 'test',
    },
  },
  {
    dialect: 'mysql',
    constraintsQuery: "SELECT INDEX_NAME FROM information_schema.statistics WHERE table_name = 'Item'",
    options: {
      host: 'localhost',
      port: 3306,
      username: 'test',
      password: 'test',
      database: 'test',
    },
  },
] as const;


(async () => {
  for (const { dialect, constraintsQuery, options } of dialects) {
    console.log('---', dialect, '---');
    const db = new Sequelize({
      dialect,
      storage: 'database.sqlite',
      models: [Item],
      ...options,
    });
    await db.sync();

    // get constraints via sql query
    const result = await db.query(constraintsQuery);
    console.log(result[0]);
    await db.close();
  }
})();

Output:

--- sqlite ---
Executing (default): SELECT name FROM sqlite_master WHERE type='table' AND name='Item';
Executing (default): CREATE TABLE IF NOT EXISTS `Item` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `thing` VARCHAR(255), `thingTwo` VARCHAR(255), `thingThree` VARCHAR(255), `thingFour` VARCHAR(255), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, UNIQUE (`thing`), UNIQUE (`thingTwo`), UNIQUE (`thingThree`));
Executing (default): PRAGMA INDEX_LIST(`Item`)
Executing (default): PRAGMA INDEX_INFO(`sqlite_autoindex_Item_1`)
Executing (default): PRAGMA INDEX_INFO(`sqlite_autoindex_Item_2`)
Executing (default): PRAGMA INDEX_INFO(`sqlite_autoindex_Item_3`)
Executing (default): CREATE UNIQUE INDEX `indexThingFour` ON `Item` (`thingFour`)
Executing (default): PRAGMA index_list('Item')
[
  {
    seq: 0,
    name: 'indexThingFour',
    unique: 1,
    origin: 'c',
    partial: 0
  },
  {
    seq: 1,
    name: 'sqlite_autoindex_Item_3',
    unique: 1,
    origin: 'u',
    partial: 0
  },
  {
    seq: 2,
    name: 'sqlite_autoindex_Item_2',
    unique: 1,
    origin: 'u',
    partial: 0
  },
  {
    seq: 3,
    name: 'sqlite_autoindex_Item_1',
    unique: 1,
    origin: 'u',
    partial: 0
  }
]
--- postgres ---
Executing (default): SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'Item'
Executing (default): CREATE TABLE IF NOT EXISTS "Item" ("id"  SERIAL , "thing" VARCHAR(255), "thingTwo" VARCHAR(255), "thingThree" VARCHAR(255), "thingFour" VARCHAR(255), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, UNIQUE ("thing"), UNIQUE ("thingTwo"), UNIQUE ("thingThree"), PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'Item' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): CREATE UNIQUE INDEX "indexThingFour" ON "Item" ("thingFour")
Executing (default): SELECT indexname FROM pg_indexes WHERE tablename = 'Item'
[
  { indexname: 'Item_pkey' },
  { indexname: 'Item_thing_key' },
  { indexname: 'Item_thingTwo_key' },
  { indexname: 'Item_thingThree_key' },
  { indexname: 'indexThingFour' }
]
--- mysql ---
Executing (default): SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME = 'Item' AND TABLE_SCHEMA = 'test'
Executing (default): CREATE TABLE IF NOT EXISTS `Item` (`id` INTEGER auto_increment , `thing` VARCHAR(255), `thingTwo` VARCHAR(255), `thingThree` VARCHAR(255), `thingFour` VARCHAR(255), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, UNIQUE `uniqueThingIndex` (`thing`), UNIQUE `uniqueThingIndexTwo` (`thingTwo`), UNIQUE `uniqueThingIndexThree` (`thingThree`), PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `Item` FROM `test`
Executing (default): ALTER TABLE `Item` ADD UNIQUE INDEX `indexThingFour` (`thingFour`)
Executing (default): SELECT INDEX_NAME FROM information_schema.statistics WHERE table_name = 'Item'
[
  { INDEX_NAME: 'indexThingFour' },
  { INDEX_NAME: 'PRIMARY' },
  { INDEX_NAME: 'uniqueThingIndex' },
  { INDEX_NAME: 'uniqueThingIndexThree' },
  { INDEX_NAME: 'uniqueThingIndexTwo' }
]

tsconfig:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "lib": ["esnext", "dom"],
    "module": "nodenext",
    "moduleDetection": "force",
    "strict": true,
    "target": "es2019"
  },
  "ts-node": {
    "experimentalResolver": true
  },
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant