createIndexDecorator has problems with "underscored" or "field" params
Versions
- sequelize: 5.21.3
- sequelize-typescript: 1.1.0
- typescript 3.7.4
I'm submitting a ... [x] bug report [ ] feature request
Actual behavior:
I've tried using new feature - createIndexDecorator, but it doesn't take into account the underscored table param (field param on the column doesn't work either) - therefor it errors out on database level, because there are no such fields existing.
Expected behavior: Successful creation of index.
Steps to reproduce: Code is below.
Related code:
const OwnedItemUniqueIndex = createIndexDecorator({type: "UNIQUE"});
@Table({
tableName: "game_owned_items",
underscored: true
})
export default class OwnedItem extends Model<OwnedItem> {
@PrimaryKey
@AutoIncrement
@Column
public id: number;
@OwnedItemUniqueIndex
@Column
public ownerId: number;
@OwnedItemUniqueIndex
@Column
public itemId: number;
}
"Temporary fix"
const OwnedItemUniqueIndex = createIndexDecorator({ type: "UNIQUE" });
@Table({
tableName: "game_owned_items",
underscored: true
})
export default class OwnedItem extends Model<OwnedItem> {
@PrimaryKey
@AutoIncrement
@Column
public id: number;
// @ts-ignore
@OwnedItemUniqueIndex({ name: "owner_id"})
@ForeignKey(() => Soldier)
@Column
public ownerId: number;
// @ts-ignore
@OwnedItemUniqueIndex({ name: "item_id" })
@ForeignKey(() => Item)
@Column
public itemId: number;
}
Works with PostgreSQL.
Hey @piotrmoszkowicz, thanks for reporting.
I have a similar problem where:
@Table({
underscored: true,
})
class Foo extends Model<Foo> {
@Index
@CreatedAt
createdAt: Date;
}
raises:
SequelizeDatabaseError: column "createdAt" does not exist
My workaround is:
@Table({
underscored: true,
})
class Foo extends Model<Foo> {
@Index
@CreatedAt
createdAt: Date;
@Index
// eslint-disable-next-line @typescript-eslint/camelcase
get created_at(): Date {
return this.createdAt;
}
}
I would love not to have to do this...
EDIT: Don't use this over-complicated solution. Just use jessemyers solution here instead if you want a decorator that works. Or use my other solution if you don't like decorators for some reason.
~~I also have this issue, and as jessemyers have pointed out, the problem is directly related to the @Index decorator, not just the createIndexDecorator function.~~
~~My solution was to use two fields, one with the correct name for the database (database field) and one virtual field for the code (application field) with magic get/set functions.~~
my_field = database field
myField = application field
@Table({
tableName: 'my_table',
underscored: true,
})
export class MyModel extends Model<MyModel> {
@PrimaryKey
@Column
id: string;
@Index
@Column
my_field: string;
@Column({
type: DataType.VIRTUAL,
set(myField: string) {
this.setDataValue('my_field', myField);
},
get(): string {
return this.getDataValue('my_field');
},
})
myField: string;
}
~~This solution requires some extra code, but the application field will be fully working, just like a normal field. And the database field is persisted and named correctly in the database so when this bug is fixed you just need to remove this workaround code.~~
~~Just remember that, with this solution, when creating a new instance of this model, both the database and application fields will be available. Like myInstance.my_field and myInstance.myField.~~
Same here. It's about @Index itself, not just others.
I think it is quite critical issue for who has already existing schemas.
It seems to me considering to change sequelize-typescript to TypeORM..
Same here when i'm set underscored property is true (Cuz they missing underscore when create indexing) It is critical issues on me .. ;
I've found another potential fix for this, by not using the @Index decorator at all but instead just specifying the indices in the @Table decorator instead, and manually specifying the field(s). Like this:
@Table({
tableName: 'user',
underscored: true,
indexes: [
{
// Column name with underscores here
fields: ['first_name'],
},
],
})
export class User extends Model<User> {
@PrimaryKey
@Column
id: string;
@Column
firstName: string;
});
I've also been experimenting with a decorator wrapper:
import { snakeCase } from 'lodash';
import { annotateModelWithIndex } from 'sequelize-typescript';
function UnderscoredIndex<T>(target: T, key: string): void {
annotateModelWithIndex(target, snakeCase(key));
}
Then replace @Index with @UnderscoredIndex.
Still not optimal.
If anyone is interested, extended @jessemyers 's solution to a generic decorator, so we could use it with parameters:
declare type IndexDecoratorOptions = IndexOptions & Pick<IndexFieldOptions, Exclude<keyof IndexFieldOptions, 'name'>>;
type AnnotationFunction = <T>(
target: T,
propertyName: string,
) => void;
/**
* Support @UnderscoredIndex('index_name')
*/
export function UnderscoredIndex(name: string): AnnotationFunction;
/**
* Support @UnderscoredIndex({ name: 'index_name', unique: true })
*/
export function UnderscoredIndex(indexOptions: IndexOptions): AnnotationFunction;
/**
* Support @UnderscoredIndex
*/
export function UnderscoredIndex<T>(
target: T,
propertyName: string,
indexDecoratorOptions?: IndexDecoratorOptions,
): void;
/**
* Overloaded decorator to support all variants of @UnderscoredIndex
*/
export function UnderscoredIndex<T>(...args: unknown[]): AnnotationFunction | void {
if (arguments.length >= 2) {
const type: T = <T>args[0];
const key: string = <string>args[1];
const indexDecoratorOptions: IndexDecoratorOptions = <IndexDecoratorOptions> args[2];
annotateModelWithIndex(type, snakeCase(key), indexDecoratorOptions);
} else {
return <Type>(target: Type, propertyName: string) => {
const indexDecoratorOptions: IndexDecoratorOptions = <IndexDecoratorOptions> args[0];
annotateModelWithIndex(target, snakeCase(propertyName), indexDecoratorOptions);
};
}
}
Bump
Same issue duplicated at #1424
Fixed as part of the merge of sequelize-typescript in sequelize https://github.com/sequelize/sequelize/pull/15482
I'm still having this problem with sequalize-typescript - 2.1.5
For those of us using @ranhalprin 's solution and using a subset of IndexFieldOptions in the decorator...
~~export function UnderscoredIndex(indexOptions: IndexOptions): AnnotationFunction;~~ export function UnderscoredIndex(indexOptions: IndexDecoratorOptions): AnnotationFunction;
still having problem with this on 2.1.6
This issue will not be fixed in sequelize-typescript, but it is fixed in @sequelize/core v7 which has TypeScript as a first class citizen and removes the need for sequelize-typescript. @sequelize/core v7 is still in alpha, but quite stable. Once the first full version is out we will start to deprecate sequelize-typescript
very nice. looking forward to it. Any ETA?