GithubHelp home page GithubHelp logo

sequelize / sequelize-typescript Goto Github PK

View Code? Open in Web Editor NEW
2.7K 31.0 282.0 7.04 MB

Decorators and some other features for sequelize

License: MIT License

TypeScript 99.76% JavaScript 0.20% Shell 0.03%
sequelize annotations typescript orm decorators

sequelize-typescript's Introduction

sequelize-typescript

Build Status codecov NPM

Decorators and some other features for sequelize (v6).

Installation

npm install --save-dev @types/node @types/validator
npm install sequelize reflect-metadata sequelize-typescript

Your tsconfig.json needs the following flags:

"target": "es6", // or a more recent ecmascript version
"experimentalDecorators": true,
"emitDecoratorMetadata": true

Sequelize Options

  • SequelizeConfig renamed to SequelizeOptions
  • modelPaths property renamed to models

Scopes Options

The @Scopes and @DefaultScope decorators now take lambda's as options

@DefaultScope(() => ({...}))
@Scopes(() => ({...}))

instead of deprecated way:

@DefaultScope({...})
@Scopes({...}))

Model definition

import { Table, Column, Model, HasMany } from 'sequelize-typescript';

@Table
class Person extends Model {
  @Column
  name: string;

  @Column
  birthday: Date;

  @HasMany(() => Hobby)
  hobbies: Hobby[];
}

Less strict

import { Table, Model } from 'sequelize-typescript';

@Table
class Person extends Model {}

More strict

import { Optional } from 'sequelize';
import { Table, Model } from 'sequelize-typescript';

interface PersonAttributes {
  id: number;
  name: string;
}

interface PersonCreationAttributes extends Optional<PersonAttributes, 'id'> {}

@Table
class Person extends Model<PersonAttributes, PersonCreationAttributes> {}

The model needs to extend the Model class and has to be annotated with the @Table decorator. All properties that should appear as a column in the database require the @Column annotation.

See more advanced example here.

@Table

The @Table annotation can be used without passing any parameters. To specify some more define options, use an object literal (all define options from sequelize are valid):

@Table({
  timestamps: true,
  ...
})
class Person extends Model {}

Table API

Decorator Description
@Table sets options.tableName=<CLASS_NAME> and options.modelName=<CLASS_NAME> automatically
@Table(options: DefineOptions) sets define options (also sets options.tableName=<CLASS_NAME> and options.modelName=<CLASS_NAME> if not already defined by define options)

Primary key

A primary key (id) will be inherited from base class Model. This primary key is by default an INTEGER and has autoIncrement=true (This behaviour is a native sequelize thing). The id can easily be overridden by marking another attribute as primary key. So either set @Column({primaryKey: true}) or use @PrimaryKey together with @Column.

@CreatedAt, @UpdatedAt, @DeletedAt

Annotations to define custom and type safe createdAt, updatedAt and deletedAt attributes:

  @CreatedAt
  creationDate: Date;

  @UpdatedAt
  updatedOn: Date;

  @DeletedAt
  deletionDate: Date;
Decorator Description
@CreatedAt sets timestamps=true and createdAt='creationDate'
@UpdatedAt sets timestamps=true and updatedAt='updatedOn'
@DeletedAt sets timestamps=true, paranoid=true and deletedAt='deletionDate'

@Column

The @Column annotation can be used without passing any parameters. But therefore it is necessary that the js type can be inferred automatically (see Type inference for details).

  @Column
  name: string;

If the type cannot or should not be inferred, use:

import {DataType} from 'sequelize-typescript';

  @Column(DataType.TEXT)
  name: string;

Or for a more detailed column description, use an object literal (all attribute options from sequelize are valid):

  @Column({
    type: DataType.FLOAT,
    comment: 'Some value',
    ...
  })
  value: number;

Column API

Decorator Description
@Column tries to infer dataType from js type
@Column(dataType: DataType) sets dataType explicitly
@Column(options: AttributeOptions) sets attribute options

Shortcuts

If you're in love with decorators: sequelize-typescript provides some more of them. The following decorators can be used together with the @Column annotation to make some attribute options easier available:

Decorator Description Options
@AllowNull(allowNull?: boolean) sets attribute.allowNull (default is true)
@AutoIncrement sets attribute.autoIncrement=true
@Unique(options? UniqueOptions) sets attribute.unique=true UniqueOptions
@Default(value: any) sets attribute.defaultValue to specified value
@PrimaryKey sets attribute.primaryKey=true
@Comment(value: string) sets attribute.comment to specified string
Validate annotations see Model validation

Type inference

The following types can be automatically inferred from javascript type. Others have to be defined explicitly.

Design type Sequelize data type
string STRING
boolean BOOLEAN
number INTEGER
bigint BIGINT
Date DATE
Buffer BLOB

Accessors

Get/set accessors do work as well

@Table
class Person extends Model {
  @Column
  get name(): string {
    return 'My name is ' + this.getDataValue('name');
  }

  set name(value: string) {
    this.setDataValue('name', value);
  }
}

Usage

Except for minor variations sequelize-typescript will work like pure sequelize. (See sequelize docs)

Configuration

To make the defined models available, you have to configure a Sequelize instance from sequelize-typescript(!).

import { Sequelize } from 'sequelize-typescript';

const sequelize = new Sequelize({
  database: 'some_db',
  dialect: 'sqlite',
  username: 'root',
  password: '',
  storage: ':memory:',
  models: [__dirname + '/models'], // or [Player, Team],
});

Before you can use your models you have to tell sequelize where they can be found. So either set models in the sequelize config or add the required models later on by calling sequelize.addModels([Person]) or sequelize.addModels([__dirname + '/models']):

sequelize.addModels([Person]);
sequelize.addModels(['path/to/models']);

globs

import {Sequelize} from 'sequelize-typescript';

const sequelize =  new Sequelize({
        ...
        models: [__dirname + '/**/*.model.ts']
});
// or
sequelize.addModels([__dirname + '/**/*.model.ts']);

Model-path resolving

A model is matched to a file by its filename. E.g.

// File User.ts matches the following exported model.
export class User extends Model {}

This is done by comparison of the filename against all exported members. The matching can be customized by specifying the modelMatch function in the configuration object.

For example, if your models are named user.model.ts, and your class is called User, you can match these two by using the following function:

import {Sequelize} from 'sequelize-typescript';

const sequelize =  new Sequelize({
  models: [__dirname + '/models/**/*.model.ts']
  modelMatch: (filename, member) => {
    return filename.substring(0, filename.indexOf('.model')) === member.toLowerCase();
  },
});

For each file that matches the *.model.ts pattern, the modelMatch function will be called with its exported members. E.g. for the following file

//user.model.ts
import {Table, Column, Model} from 'sequelize-typescript';

export const UserN = 'Not a model';
export const NUser = 'Not a model';

@Table
export class User extends Model {

  @Column
  nickname: string;
}

The modelMatch function will be called three times with the following arguments.

user.model UserN -> false
user.model NUser -> false
user.model User  -> true (User will be added as model)

Another way to match model to file is to make your model the default export.

export default class User extends Model {}

⚠️ When using paths to add models, keep in mind that they will be loaded during runtime. This means that the path may differ from development time to execution time. For instance, using .ts extension within paths will only work together with ts-node.

Build and create

Instantiation and inserts can be achieved in the good old sequelize way

const person = Person.build({ name: 'bob', age: 99 });
person.save();

Person.create({ name: 'bob', age: 99 });

but sequelize-typescript also makes it possible to create instances with new:

const person = new Person({ name: 'bob', age: 99 });
person.save();

Find and update

Finding and updating entries does also work like using native sequelize. So see sequelize docs for more details.

Person.findOne().then((person) => {
  person.age = 100;
  return person.save();
});

Person.update(
  {
    name: 'bobby',
  },
  { where: { id: 1 } }
).then(() => {});

Model association

Relations can be described directly in the model by the @HasMany, @HasOne, @BelongsTo, @BelongsToMany and @ForeignKey annotations.

One-to-many

@Table
class Player extends Model {
  @Column
  name: string;

  @Column
  num: number;

  @ForeignKey(() => Team)
  @Column
  teamId: number;

  @BelongsTo(() => Team)
  team: Team;
}

@Table
class Team extends Model {
  @Column
  name: string;

  @HasMany(() => Player)
  players: Player[];
}

That's all, sequelize-typescript does everything else for you. So when retrieving a team by find

Team.findOne({ include: [Player] }).then((team) => {
  team.players.forEach((player) => console.log(`Player ${player.name}`));
});

the players will also be resolved (when passing include: Player to the find options)

Many-to-many

@Table
class Book extends Model {
  @BelongsToMany(() => Author, () => BookAuthor)
  authors: Author[];
}

@Table
class Author extends Model {
  @BelongsToMany(() => Book, () => BookAuthor)
  books: Book[];
}

@Table
class BookAuthor extends Model {
  @ForeignKey(() => Book)
  @Column
  bookId: number;

  @ForeignKey(() => Author)
  @Column
  authorId: number;
}

Type safe through-table instance access

To access the through-table instance (instanceOf BookAuthor in the upper example) type safely, the type need to be set up manually. For Author model it can be achieved like so:

  @BelongsToMany(() => Book, () => BookAuthor)
  books: Array<Book & {BookAuthor: BookAuthor}>;

One-to-one

For one-to-one use @HasOne(...)(foreign key for the relation exists on the other model) and @BelongsTo(...) (foreign key for the relation exists on this model)

@ForeignKey, @BelongsTo, @HasMany, @HasOne, @BelongsToMany API

Decorator Description
@ForeignKey(relatedModelGetter: () => typeof Model) marks property as foreignKey for related class
@BelongsTo(relatedModelGetter: () => typeof Model) sets SourceModel.belongsTo(RelatedModel, ...) while as is key of annotated property and foreignKey is resolved from source class
@BelongsTo(relatedModelGetter: () => typeof Model, foreignKey: string) sets SourceModel.belongsTo(RelatedModel, ...) while as is key of annotated property and foreignKey is explicitly specified value
@BelongsTo(relatedModelGetter: () => typeof Model, options: AssociationOptionsBelongsTo) sets SourceModel.belongsTo(RelatedModel, ...) while as is key of annotated property and options are additional association options
@HasMany(relatedModelGetter: () => typeof Model) sets SourceModel.hasMany(RelatedModel, ...) while as is key of annotated property and foreignKey is resolved from target related class
@HasMany(relatedModelGetter: () => typeof Model, foreignKey: string) sets SourceModel.hasMany(RelatedModel, ...) while as is key of annotated property and foreignKey is explicitly specified value
@HasMany(relatedModelGetter: () => typeof Model, options: AssociationOptionsHasMany) sets SourceModel.hasMany(RelatedModel, ...) while as is key of annotated property and options are additional association options
@HasOne(relatedModelGetter: () => typeof Model) sets SourceModel.hasOne(RelatedModel, ...) while as is key of annotated property and foreignKey is resolved from target related class
@HasOne(relatedModelGetter: () => typeof Model, foreignKey: string) sets SourceModel.hasOne(RelatedModel, ...) while as is key of annotated property and foreignKey is explicitly specified value
@HasOne(relatedModelGetter: () => typeof Model, options: AssociationOptionsHasOne) sets SourceModel.hasOne(RelatedModel, ...) while as is key of annotated property and options are additional association options
@BelongsToMany(relatedModelGetter: () => typeof Model, through: (() => typeof Model)) sets SourceModel.belongsToMany(RelatedModel, {through: ThroughModel, ...}) while as is key of annotated property and foreignKey/otherKey is resolved from through class
@BelongsToMany(relatedModelGetter: () => typeof Model, through: (() => typeof Model), foreignKey: string) sets SourceModel.belongsToMany(RelatedModel, {through: ThroughModel, ...}) while as is key of annotated property, foreignKey is explicitly specified value and otherKey is resolved from through class
@BelongsToMany(relatedModelGetter: () => typeof Model, through: (() => typeof Model), foreignKey: string, otherKey: string) sets SourceModel.belongsToMany(RelatedModel, {through: ThroughModel, ...}) while as is key of annotated property and foreignKey/otherKey are explicitly specified values
@BelongsToMany(relatedModelGetter: () => typeof Model, through: string, foreignKey: string, otherKey: string) sets SourceModel.belongsToMany(RelatedModel, {through: throughString, ...}) while as is key of annotated property and foreignKey/otherKey are explicitly specified values
@BelongsToMany(relatedModelGetter: () => typeof Model, options: AssociationOptionsBelongsToMany) sets SourceModel.belongsToMany(RelatedModel, {through: throughString, ...}) while as is key of annotated property and options are additional association values, including foreignKey and otherKey.

Note that when using AssociationOptions, certain properties will be overwritten when the association is built, based on reflection metadata or explicit attribute parameters. For example, as will always be the annotated property's name, and through will be the explicitly stated value.

Multiple relations of same models

sequelize-typescript resolves the foreign keys by identifying the corresponding class references. So if you define a model with multiple relations like

@Table
class Book extends Model {
  @ForeignKey(() => Person)
  @Column
  authorId: number;

  @BelongsTo(() => Person)
  author: Person;

  @ForeignKey(() => Person)
  @Column
  proofreaderId: number;

  @BelongsTo(() => Person)
  proofreader: Person;
}

@Table
class Person extends Model {
  @HasMany(() => Book)
  writtenBooks: Book[];

  @HasMany(() => Book)
  proofedBooks: Book[];
}

sequelize-typescript cannot know which foreign key to use for which relation. So you have to add the foreign keys explicitly:

  // in class "Books":
  @BelongsTo(() => Person, 'authorId')
  author: Person;

  @BelongsTo(() => Person, 'proofreaderId')
  proofreader: Person;

  // in class "Person":
  @HasMany(() => Book, 'authorId')
  writtenBooks: Book[];

  @HasMany(() => Book, 'proofreaderId')
  proofedBooks: Book[];

Type safe usage of auto generated functions

With the creation of a relation, sequelize generates some method on the corresponding models. So when you create a 1:n relation between ModelA and ModelB, an instance of ModelA will have the functions getModelBs, setModelBs, addModelB, removeModelB, hasModelB. These functions still exist with sequelize-typescript. But TypeScript wont recognize them and will complain if you try to access getModelB, setModelB or addModelB. To make TypeScript happy, the Model.prototype of sequelize-typescript has $set, $get, $add functions.

@Table
class ModelA extends Model {
  @HasMany(() => ModelB)
  bs: ModelB[];
}

@Table
class ModelB extends Model {
  @BelongsTo(() => ModelA)
  a: ModelA;
}

To use them, pass the property key of the respective relation as the first parameter:

const modelA = new ModelA();

modelA
  .$set('bs', [
    /* instance */
  ])
  .then(/* ... */);
modelA.$add('b' /* instance */).then(/* ... */);
modelA.$get('bs').then(/* ... */);
modelA.$count('bs').then(/* ... */);
modelA.$has('bs').then(/* ... */);
modelA.$remove('bs' /* instance */).then(/* ... */);
modelA.$create('bs' /* value */).then(/* ... */);

Indexes

@Index

The @Index annotation can be used without passing any parameters.

@Table
class Person extends Model {
  @Index // Define an index with default name
  @Column
  name: string;

  @Index // Define another index
  @Column
  birthday: Date;
}

To specify index and index field options, use an object literal (see indexes define option):

@Table
class Person extends Model {
  @Index('my-index') // Define a multi-field index on name and birthday
  @Column
  name: string;

  @Index('my-index') // Add birthday as the second field to my-index
  @Column
  birthday: Date;

  @Index({
    // index options
    name: 'job-index',
    parser: 'my-parser',
    type: 'UNIQUE',
    unique: true,
    where: { isEmployee: true },
    concurrently: true,
    using: 'BTREE',
    operator: 'text_pattern_ops',
    prefix: 'test-',
    // index field options
    length: 10,
    order: 'ASC',
    collate: 'NOCASE',
  })
  @Column
  jobTitle: string;

  @Column
  isEmployee: boolean;
}

Index API

Decorator Description
@Index adds new index on decorated field to options.indexes
@Index(name: string) adds new index or adds the field to an existing index with specified name
@Table(options: IndexDecoratorOptions) sets both index and index field options

createIndexDecorator()

The createIndexDecorator() function can be used to create a decorator for an index with options specified with an object literal supplied as the argument. Fields are added to the index by decorating properties.

const SomeIndex = createIndexDecorator();
const JobIndex = createIndexDecorator({
  // index options
  name: 'job-index',
  parser: 'my-parser',
  type: 'UNIQUE',
  unique: true,
  where: { isEmployee: true },
  concurrently: true,
  using: 'BTREE',
  operator: 'text_pattern_ops',
  prefix: 'test-',
});

@Table
class Person extends Model {
  @SomeIndex // Add name to SomeIndex
  @Column
  name: string;

  @SomeIndex // Add birthday to SomeIndex
  @Column
  birthday: Date;

  @JobIndex({
    // index field options
    length: 10,
    order: 'ASC',
    collate: 'NOCASE',
  })
  @Column
  jobTitle: string;

  @Column
  isEmployee: boolean;
}

Repository mode

With sequelize-typescript@1 comes a repository mode. See docs for details.

The repository mode makes it possible to separate static operations like find, create, ... from model definitions. It also empowers models so that they can be used with multiple sequelize instances.

How to enable repository mode?

Enable repository mode by setting repositoryMode flag:

const sequelize = new Sequelize({
  repositoryMode: true,
  ...,
});

How to use repository mode?

Retrieve repository to create instances or perform search operations:

const userRepository = sequelize.getRepository(User);

const luke = await userRepository.create({ name: 'Luke Skywalker' });
const luke = await userRepository.findOne({ where: { name: 'luke' } });

How to use associations with repository mode?

For now one need to use the repositories within the include options in order to retrieve or create related data:

const userRepository = sequelize.getRepository(User);
const addressRepository = sequelize.getRepository(Address);

userRepository.find({ include: [addressRepository] });
userRepository.create({ name: 'Bear' }, { include: [addressRepository] });

⚠️ This will change in the future: One will be able to refer the model classes instead of the repositories.

Limitations of repository mode

Nested scopes and includes in general won't work when using @Scope annotation together with repository mode like:

@Scopes(() => ({
  // includes
  withAddress: {
    include: [() => Address],
  },
  // nested scopes
  withAddressIncludingLatLng: {
    include: [() => Address.scope('withLatLng')],
  },
}))
@Table
class User extends Model {}

⚠️ This will change in the future: Simple includes will be implemented.

Model validation

Validation options can be set through the @Column annotation, but if you prefer to use separate decorators for validation instead, you can do so by simply adding the validate options as decorators: So that validate.isEmail=true becomes @IsEmail, validate.equals='value' becomes @Equals('value') and so on. Please notice that a validator that expects a boolean is translated to an annotation without a parameter.

See sequelize docs for all validators.

Exceptions

The following validators cannot simply be translated from sequelize validator to an annotation:

Validator Annotation
validate.len=[number, number] @Length({max?: number, min?: number})
validate[customName: string] For custom validators also use the @Is(...) annotation: Either @Is('custom', (value) => { /* ... */}) or with named function @Is(function custom(value) { /* ... */})

Example

const HEX_REGEX = /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/;

@Table
export class Shoe extends Model {
  @IsUUID(4)
  @PrimaryKey
  @Column
  id: string;

  @Equals('lala')
  @Column
  readonly key: string;

  @Contains('Special')
  @Column
  special: string;

  @Length({ min: 3, max: 15 })
  @Column
  brand: string;

  @IsUrl
  @Column
  brandUrl: string;

  @Is('HexColor', (value) => {
    if (!HEX_REGEX.test(value)) {
      throw new Error(`"${value}" is not a hex color value.`);
    }
  })
  @Column
  primaryColor: string;

  @Is(function hexColor(value: string): void {
    if (!HEX_REGEX.test(value)) {
      throw new Error(`"${value}" is not a hex color value.`);
    }
  })
  @Column
  secondaryColor: string;

  @Is(HEX_REGEX)
  @Column
  tertiaryColor: string;

  @IsDate
  @IsBefore('2017-02-27')
  @Column
  producedAt: Date;
}

Scopes

Scopes can be defined with annotations as well. The scope options are identical to native sequelize (See sequelize docs for more details)

@DefaultScope and @Scopes

@DefaultScope(() => ({
  attributes: ['id', 'primaryColor', 'secondaryColor', 'producedAt'],
}))
@Scopes(() => ({
  full: {
    include: [Manufacturer],
  },
  yellow: {
    where: { primaryColor: 'yellow' },
  },
}))
@Table
export class ShoeWithScopes extends Model {
  @Column
  readonly secretKey: string;

  @Column
  primaryColor: string;

  @Column
  secondaryColor: string;

  @Column
  producedAt: Date;

  @ForeignKey(() => Manufacturer)
  @Column
  manufacturerId: number;

  @BelongsTo(() => Manufacturer)
  manufacturer: Manufacturer;
}

Hooks

Hooks can be attached to your models. All Model-level hooks are supported. See the related unit tests for a summary.

Each hook must be a static method. Multiple hooks can be attached to a single method, and you can define multiple methods for a given hook.

The name of the method cannot be the same as the name of the hook (for example, a @BeforeCreate hook method cannot be named beforeCreate). That’s because Sequelize has pre-defined methods with those names.

@Table
export class Person extends Model {
  @Column
  name: string;

  @BeforeUpdate
  @BeforeCreate
  static makeUpperCase(instance: Person) {
    // this will be called when an instance is created or updated
    instance.name = instance.name.toLocaleUpperCase();
  }

  @BeforeCreate
  static addUnicorn(instance: Person) {
    // this will also be called when an instance is created
    instance.name += ' 🦄';
  }
}

Why () => Model?

@ForeignKey(Model) is much easier to read, so why is @ForeignKey(() => Model) so important? When it comes to circular-dependencies (which are in general solved by node for you) Model can be undefined when it gets passed to @ForeignKey. With the usage of a function, which returns the actual model, we prevent this issue.

Recommendations and limitations

One Sequelize instance per model (without repository mode)

Unless you are using the repository mode, you won't be able to add one and the same model to multiple Sequelize instances with differently configured connections. So that one model will only work for one connection.

One model class per file

This is not only good practice regarding design, but also matters for the order of execution. Since Typescript creates a __metadata("design:type", SomeModel) call due to emitDecoratorMetadata compile option, in some cases SomeModel is probably not defined(not undefined!) and would throw a ReferenceError. When putting SomeModel in a separate file, it would look like __metadata("design:type", SomeModel_1.SomeModel), which does not throw an error.

Minification

If you need to minify your code, you need to set tableName and modelName in the DefineOptions for @Table annotation. sequelize-typescript uses the class name as default name for tableName and modelName. When the code is minified the class name will no longer be the originally defined one (So that class User will become class b for example).

Contributing

To contribute you can:

  • Open issues and participate in discussion of other issues.
  • Fork the project to open up PR's.
  • Update the types of Sequelize.
  • Anything else constructively helpful.

In order to open a pull request please:

  • Create a new branch.
  • Run tests locally (npm install && npm run build && npm run cover) and ensure your commits don't break the tests.
  • Document your work well with commit messages, a good PR description, comments in code when necessary, etc.

In order to update the types for sequelize please go to the Definitely Typed repo, it would also be a good idea to open a PR into sequelize so that Sequelize can maintain its own types, but that might be harder than getting updated types into microsoft's repo. The Typescript team is slowly trying to encourage npm package maintainers to maintain their own typings, but Microsoft still has dedicated and good people maintaining the DT repo, accepting PR's and keeping quality high.

Keep in mind sequelize-typescript does not provide typings for sequelize - these are seperate things. A lot of the types in sequelize-typescript augment, refer to, or extend what sequelize already has.

sequelize-typescript's People

Contributors

ahmedshaaban avatar bilby91 avatar blankstar85 avatar dependabot[bot] avatar devoto13 avatar diluka avatar dolsem avatar donaldpipowitch avatar elisabaum avatar fschuetz04 avatar gloorx avatar hiradimir avatar iam-dev0 avatar igorszymanski avatar intellix avatar iziklisbon avatar jack-philippi avatar jackphilippi avatar johannes-scharlach avatar kapitanoczywisty avatar lukashroch avatar matthiaskunnen avatar moribvndvs avatar natesilva avatar papb avatar robinbuschmann avatar theoludwig avatar vasanth3008 avatar victorivens05 avatar wikirik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sequelize-typescript's Issues

How to enable logging?

In sequelize we use
logging: false
when create new sequelize like this

new _sequelize(connectionUri, {//options
  logging: false
});

to enable logging SQL queries.

Now when use sequelize-typescript,How to?

Add excludes / includes option

Based on the discussion within #23 we can add a feature in the ISequelizeOptions for support of includes/excludes options. To fully support this, we should add support for globs.

Still a bit of discussion as to whether or not modelPaths should only be paths - since it would be easier to implement if we could just concatenate both the includes array and modelPaths array together and have logic in the reduce loop to discriminate between directories, files, or a glob pattern. Or possibly use the reduce loop to pass through the array once to expand all glob patterns/directories, building an array of only files, then after the reduce loop map over them with require - although this would require first pulling out all passed in Models from the array so we just get an array of models and an array of strings. Meh, maybe not worth the effort.

The excludes option seems far easier to grapple with. We already have a filter in models.ts -> getModels function so we just add that in.

when unique=true is violated it doesnt returns in Model.validate errors

thew model:

export class User extends Model<User> {
    @Column({ primaryKey: true, autoIncrement: true, type: DataType.INTEGER, allowNull: false })
    user_id: number;

    @ForeignKey(() => Role)
    @Column({ type: DataType.INTEGER, allowNull: false })
    role_id: number;

    @BelongsTo(() => Role)
    role: Role;

    @Length({ min: 2, msg: 'user name must be at least 2 characters' })
    @Column({ unique: true, type: DataType.STRING, allowNull: false })
    username: string;

    @Default('PENDING')
    @Column({ allowNull: false, type: DataType.ENUM('ACTIVE', 'DELETED', 'PENDING') })
    user_status: UserStatus;

    @Default('Network User')
    @Column({ allowNull: false, type: DataType.ENUM('Network User', 'Local User', 'Network  Group') })
    user_type: UserType

    @Unique
    @IsEmail
    @Column({ type: DataType.STRING })
    email: string;

    @Column(DataType.STRING)
    firstname: string;

    @Column(DataType.STRING)
    lastname: string;

    @CreatedAt
    @Column({ type: DataType.DATE })
    created_at: Date;

    @UpdatedAt
    @Column({ type: DataType.DATE })
    updated_at: Date;

    @Length({min: 1})
    @Column({ type: DataType.STRING, allowNull: false })
    hashed_password: string;

    @Length({min: 6, msg: 'password must be at least 6 characters'})
    @Column({ type: DataType.VIRTUAL, allowNull: false })
    password: string;

    @Column({ type: DataType.DATE })
    last_login_at: Date;

    @Column({ type: DataType.STRING })
    session_token: string;

    static generateHash = (data: string) : string  =>
        bcrypt.hashSync(data, bcrypt.genSaltSync(10));

    static validatePassword = (userPassword: string, realPassword: string) =>
        bcrypt.compareSync(userPassword, realPassword);
}
addUser = (req: RgRequest<User>, res: Response, next: NextFunction) => {
        const user = new User({
            role_id: req.body.role_id,
            username: req.body.username,
            hashed_password: User.generateHash(req.body.password),
            password: req.body.password,
            email: req.body.email,
            firstname: req.body.firstname,
            lastname: req.body.lastname
        });

        return user.validate().then(ValidationErr => {
            if (ValidationErr) {
                res.status(400).send(ValidationErr);
            }
            return user.save().then(dbUser => {
                dbUser.hashed_password = null;
                res.status(201).send(dbUser);
            }).catch(saveErr => {
                const errList = saveErr.errors.map(err => { return { message: err.message, path: err.path } });
                res.status(400).send(errList)
            })
        });
    };

When I pass violated username, password and email the following happends
password and username appears in ValidationErr.
when I fix them and submit again email appears in saveErr.

disregard definition files

I am using using node v 7.10 with typescript 2.3.3 and sequelize-typescript 0.3.3.
.d.ts files in the model directory should be disregarded. instead I am getting:
Cannot find module '../some-model.d'
(which is not even a thing because it's a d.ts and not d.js). Either consider only .js files or disregard .d.ts files.

include when adding model.

I have a user:

@Table
export class User extends Model<User> {
    @Column({ primaryKey: true, autoIncrement: true, type: DataType.INTEGER, allowNull: false })
    user_id: number;

    @ForeignKey(() => Role)
    @Column({ type: DataType.INTEGER, allowNull: false })
    role_id: number;

    @BelongsTo(() => Role)
    role: Role;

    @Length({ min: 2, msg: 'user name must be at least 2 characters' })
    @Column({ unique: true, type: DataType.STRING, allowNull: false })
    username: string;

    @Column(DataType.STRING)
    firstname: string;

    @Column(DataType.STRING)
    lastname: string;

    @CreatedAt
    @Column({ type: DataType.DATE })
    created_at: Date;

    @UpdatedAt
    @Column({ type: DataType.DATE })
    updated_at: Date;
 }

how do I include the role model to the user when adding new user? ( the role is already in the DB.)

Make a relation: add a foreign key

Hi
I made two Model and I search to add a relation between them, simply a foreign key.

Password.ts

@Table
export default class Password extends Model<Password> {

    @PrimaryKey
    @AutoIncrement
    @Column(DataType.BIGINT)
    readonly id_password: number;

    @AllowNull(false)
    @Column
    value: string;

    @AllowNull(false)
    @Column(DataType.ARRAY(DataType.INTEGER))
    salt: Array<number>;

}

User.ts

@Table
export default class User extends Model<User> {

    @PrimaryKey
    @AutoIncrement
    @Column(DataType.BIGINT)
    readonly id_user: number;

    @Length({min: 3, max: 16})
    @AllowNull(false)
    @Column
    readonly username: string;

    @BelongsTo(() => Password, 'id_password')
    password: Password;

    @IsEmail
    @AllowNull(false)
    @Column
    email: string;

    @CreatedAt
    @AllowNull(false)
    @Column
    readonly date_register: Date;

    @UpdatedAt
    @AllowNull(false)
    @Column
    date_last_activity: Date;

}

And I test that :

this.sequelize.sync({force: true}).then(err => {

            const password = new Password({
                id_password: 2,
                value: 'test_pwd',
                salt: [21, 34, 56]
            });

            const user = new User({
                username: "Chnapy",
                password: password,
                email: "[email protected]",
                date_register: new Date(),
                date_last_activity: new Date()
            });

            password.save();
            user.save();

        });

The database result is :

  • For Password table:
    image
  • For User table:
    image
    You can see that id_password is empty, and there is no constraint on this field. 😕

I tried to use @ForeignKey or @HasOne in User.ts instead of @BelongsTo without success.

Thank you for your help, i'm still new to this framework :simple_smile:

Is it possible to implement class-table inheritance?

Hello!

Thank you for your hard work, this module looks very promising.

However, do you mind if I ask? Maybe you are familiar with this problem. Is it possible to implement class-table inheritance with Sequelize and this module?

Thank you.

enum column

@RobinBuschmann

How do I write an enum column?

enum RoleStatus { ACTIVE, DELETED, PENDING}

I want the default value to be pending

Cannot define a varbinary column type.

Sequelize does not natively support the binary column types, but their recommendation is to use the string 'binary(100)' or 'varbinary(max)' etc... when specifying the column type.

I've tried many variations of this, and don't seem to be able to specify the column correctly for my password field. I've tried this:

@Column({type: "VARBINARY(MAX)")
Password: any;

and

@Column({type: "VARBINARY(MAX)")
Password: string;

and

@Column(DataType.STRING)
Password: string;

(which I don't expect to work, of course)
and

@Column("VARBINARY(MAX)")
Password: string;

and probably a couple others.

Every single time, I get an error:

SequelizeDatabaseError: Implicit conversion from data type nvarchar to varbinary is not allowed. Use the CONVERT function to run this query.

when it tries to run a query like this:

UPDATE [User] SET [Password]=N'$2a$11$ynNqEXn1xf7y.0/cXVN.CugvvBQ2uaARqbXV8Ck59EYAigB027D6G' OUTPUT INSERTED.* WHERE [UserId] = 1000

classMethods / instanceMethods

Hi, thank you for writing this promising module! Right now, we are migrating from our existing sequelize model definitions to sequelize-typescript, but we are struggling with existing instance- and class-Methods. Is there a way to migrate them? If so, could you please provide an example? Thank you!

Greetings, Tim

Polymorphic Relationships

First off, thank you for this package, it's made my transition to Sequelize insanely easy!

I'm running into an issue w/ polymorphic relationships. On the sequelize docs, it mentions that I need to set a scope and a constraints on the HasMany side of the relationship and a constraints and as on the BelongsTo side). There's also unique, scope, and constraints options on the BelongsToMany relationships.

Would something like a function overload be possible here to allow us to pass in the additional options w/ an object?

// 1:m
class Post extends Model<Post> {
  // ...
  @HasMany({ 
    model: () => Comment,
    constraints: false, 
    scope: { commentable: "post" }
  }, 'foreign_key')
  comments: Comment[];
}

class Comment extends Model<Comment> {
  // ...
  @BelongsTo({ 
    model: () => Post,
    constraints: false, 
    as: "post" }, 
    'foreign_key'
  )
  post: Post;
}
// n:m
class Post extends Model<Post> {
  // ...
  @BelongsToMany(
    () => Tag,
    { 
      through: () => ItemTag,
      unique: false, 
      constraints: false,
      scope: { taggable: "post" }
    }, 
    'foreign_key'
  )
  tags: Tag[];
}

class Tag extends Model<Tag> {
  // ...
  @BelongsToMany(
    model: () => Post,
    { 
      through: () => ItemTag
      unique: false, 
    },
    {
      foreignKey: 'foreign_key',
      constraints: false
    }
  )
  post: Post;
}

class ItemTag extends Model<ItemTag> {
  // ...
}

How to enabe CLS?

In this link show how to enable cls for sequelize.

What are we can do it in sequelize-typescript?

Provide association options

I'm trying to set some association options. For example, I have a HasMany where I want to disallow null in the FK and cascade on delete.

In Sequelize, I'd do something like:

childModel.belongsTo(parentModel, {
   foreignKey: {
      allowNull: false
   },
  onDelete: 'CASCADE'
});

I don't see any place in the association attributes or ForeignKey to pass in those options. See foreign keys (Their documentation on this subject is a bit messy).

I'd like to be able to do the following, using BelongsTo as an example:

export class Child extends Model<Child> {
   @BelongsTo(() => Parent, { foreignKey: { allowNull: false }, onDelete: 'CASCADE'})
    public parent: Parent;
}

I'm using Sequelize 4, but I think the issue is the same for 3.

Order by joined table

Hi, I have something like that

Restaurant.findOne({
where: { domain: domain },
include: [
{ model: Promotion, where: { code: null } }
]
});

and it generates:

SELECT "Restaurant".*, "promotions"."id" AS "promotions.id", "promotions"."type" AS "promotions.type", "promotions"."title" AS "promotions.title", "promotions"."description" AS "promotions.description", "promotions"."value" AS "promotions.value"
, "promotions"."value2" AS "promotions.value2", "promotions"."code" AS "promotions.code", "promotions"."isCompatible" AS "promotions.isCompatible", "promotions"."isActive" AS "promotions.isActive", "promotions"."maxDate" AS "promotions.maxDate", "promotions"."numberAllowedU
ses" AS "promotions.numberAllowedUses", "promotions"."currentUses" AS "promotions.currentUses", "promotions"."categoryIds" AS "promotions.categoryIds", "promotions"."itemIds" AS "promotions.itemIds", "promotions"."restaurantId" AS "promotions.restaurantId" FROM (SELECT "Res
taurant"."id", "Restaurant"."name", "Restaurant"."domain", "Restaurant"."address", "Restaurant"."shippingCosts", "Restaurant"."secondId", "Restaurant"."createdAt", "Restaurant"."updatedAt" FROM "Restaurant" AS "Restaurant" WHERE "Restaurant"."domain" = 'localhost' AND ( SEL
ECT "restaurantId" FROM "Promotion" AS "Promotion" WHERE ("Promotion"."restaurantId" = "Restaurant"."id" AND "Promotion"."code" IS NULL) LIMIT 1 ) IS NOT NULL LIMIT 1) AS "Restaurant" INNER JOIN "Promotion" AS "promotions" ON "Restaurant"."id" = "promotions"."restaurantId"
AND "promotions"."code" IS NULL;

My question is how can I order by for example promotion.currentUsers. I have tried several options like

Restaurant.findOne({
where: { domain: domain },
include: [
{ model: Promotion, where: { code: null } }
],
order:["Promotion.currentUses"]
});
and it says me "TypeError: Cannot read property 'type' of undefined"
or
order:["promotions.currentUses"] :the same
or
order:["promotion.currentUses"] :the same
etc
if I do
order:[{model:Promotion}] :Unable to find a valid association for model, 'Promotion'
or
order:[{model:Promotion, as:"promotions"}]: Unknown structure passed to order / group: promotions

so...how can I achieve this behavior please?

Roadmap & Contributing

hey, nice work! Do you have any roadmap that you can share ? I would like to contribute to make it more stable. I've also seen that you are working on refactoring branch.

Specifying another model's scope

I have two models in n:m association, A and B, and third one in association with A in 1:n association. Default scope of B has include: [() => C] but I want to specify in default scope of A not to include C when loading B, so I created a new scope on B which doesn't include C.

Sequelize docs says that you can say B.scope('scopeName') (the last example in this section). When I try to do that like include: [() => B.scope('scopeName')], I get next error on app start:

Invalid scope scopeName called.
     at /node_modules/sequelize/lib/model.js:1224:13
     at Array.forEach (native)....

I've noticed that it can be due to the fact that A comes before B, so when the lib tries to load model A it hasn't loaded model B yet so it's logical why is this scope invalid.

But when I change the order of model loading (A becomes B and B becomes A), I get another error:

TypeError: self.$expandAttributes is not a function
     at conformOptions (/node_modules/sequelize/lib/model.js:250:10)
     at conformInclude (/node_modules/sequelize/lib/model.js:307:5)

So my question is if this scoped include is supported in sequelize-typescript or not? And if it is, what's the syntax?

EDIT: I forgot to mention I'm using v3 of Sequelize.

create/ update with model relation

I have your example:

@Table
class Book extends Model<Book> { 

  @BelongsToMany(() => Author, () => BookAuthor)
  authors: Author[];
}
 
@Table
class Author extends Model<Author> {
 
  @BelongsToMany(() => Book, () => BookAuthor)
  books: Book[];
}
 
@Table
class BookAuthor extends Model<BookAuthor> {
 
  @ForeignKey(() => Book)
  @Column
  bookId: number;
 
  @ForeignKey(() => Author)
  @Column
  authorId: number;
}

I want to create/ update a book. How do I do that that the map table will also be updated?

Model loading, ignore declaration files

When passing a directory to the modelPaths option in the constructor, it would be nice if sequelize-typescript only looked for .js files.

I see two instances where people could run into this:

  1. mocha-typescript requires my main application to be compiled with the "declarations": true option so that it can consume the application's types to (if the test suite and app are two different typescript apps). Unfortunately, this means in my output directory not only will typescript emit js files but also .d.ts. Anyone else using declarations will run into this.

  2. Any source maps map file alongside the models will also junk up the output directory.

This can be easily worked around with a little but of code with fs and some filtering, but maybe this extra nicety could be baked into sequelize-typescript? I'm going to be writing up a PR, since I'll be using the same logic in my own code if this doesn't make it into the repo. Feel free to either close this issue if you don't want it baked in, or assign it to me if you do.

Thanks for reading! <3<3

hasTrigger option in @Table

I'm trying to set this option, but it seems typescript doesn't think it exists. It is definitely in the d.ts file under DefineOptions. Do you have any insights (or workarounds?)

Specifying string length does not appear to generate proper schema (sqlite3)

If using the "@column" attribute with DataType.String(someLength) the model does not appear to generate the correct schema and instead generates a column in the sqlite database with an incorrect "[object Object]" column type, very bizarre. I've tried using @column({type: DataType.String(someLength)}) and have used the raw Sequelize.STRING type as well. With no arguments the column generates properly with a VARCHAR(255) data type but when length is specified it does not appear to work. Thoughts?

Belongs to issue

Say we have the following models :

Users:

  @HasOne(() => Detail, 'userId')
  public detail: Detail;

Details:

  @BelongsTo(() => User, 'userId')
  public user: User;

The constrain in the database is:

CONSTRAINT "Detail_pkey" PRIMARY KEY (id),
  CONSTRAINT "Detail_userId_fkey" FOREIGN KEY ("userId")
      REFERENCES public."User" (id) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE SET NULL

That means that the same user can have multiple 'Details'

Easiest way to fix, is to support the constrain 'Unique' (maybe as an annotation) or have belongsToOne type of relation ?

@RobinBuschmann If i missed something, can you point me in the right direction on how to force the relation of HasOne and BelongsTo to only accept a one-to-one ?

Model.scope().findAll({...}) cannot infer `as` in `include` option

Assuming the following defined models:

class User extends Model<User> {
  companies: Company[];
}

class CompanyUser extends Model<CompanyUser> {
 @ForeignKey(() => Company) 
 @Column
 companyId: number;

 @ForeignKey(() => User) 
 @Column
 userId: number;
}

@Scopes({bla: {...}})
class Company extends Model<Company> {
  users: User[];
}

When selecting entities of a scoped model, the as value of the include options, that are NOT defined within the scope, is not inferred by sequelize-typescript:

Company
   .scope('bla')
   .findAll({include: [User]})
  .catch(...) // throws "User is not associated to Company!"
;

Current workaround:

Company
   .scope('bla')
   .findAll({include: [{
     model: User,
     as: 'users' // <-- this need to be set explicitly
   }]})
  .catch(...)
;

usage with async, await

error appeared code.

  const foundUser: Model<User> = await User.findOne(
        {
          where: { email },
          include: [
            { model: UserAvatarImage, as: 'avatarImage' }
          ]
        }
      );
  if (!foundUser) {
    const err = new Room36Error('cannot find user.');
    err.status = 404;
    return next(err);
  }
  foundUser.comparePassword(password);

Problem scenario is.

when i use promise, i use like

User.fineOne({}).then((foundUser: User) => {})

like this. This way is not occured error.
However, when i use like this

const foundUser: User = await User.fineOne({})

It error occured,

Type 'Model<{}>' is not assignable to type 'User'.
Property 'id' is optional in type 'Model<{}>' but required in type 'User'.

So I did is

const foundUser: Model<User> = await User.fineOne({})

and error is disappeared.
However, now i must use instance method (comparePassword in this scenario), so I did

foundUser.comparePassword(password);

then, boom! error appeared.

[ts] Property 'comparePassword' does not exist on type 'Model'.

How can i fix this?
I'm stucked.

p.s sorry for bad english, I hope you can understand.

Using @CreatedAt causes Sequelize to also create updatedAt column

Model:

@Table({tableName: 'user'})
class User extends Model<User> {
  ...
    @CreatedAt
    @Column({ field: 'created_at' })
    createdAt: Date;
  ...
}

Expected Sequelize output:

Executing (default): CREATE TABLE IF NOT EXISTS user (... created_at DATETIME ...) ...

Actual Sequelize output:

Executing (default): CREATE TABLE IF NOT EXISTS user ( ... created_at DATETIME, updatedAt DATETIME NOT NULL ...) ...

This also makes methods like findAll unusable if my tables were created manually and do not contain updatedAt field.

Class constructor Model cannot be invoked without 'new'

Hi,
I'm trying to load the models and getting the error Class constructor Model cannot be invoked without 'new'

Here's the ./models/index.ts:

import {Sequelize} from 'sequelize-typescript';
import * as configEnv   from './../config/config.json';
import {User} from './user;

const env = process.env.NODE_ENV || 'development';
const sequelize_main =  new Sequelize(configEnv[env]);

sequelize_main.addModels([
      User
])

export const db = sequelize_main;

In controller ./routes/registration:


import {db} from './models';
import {User} from './models/user';
const models = db.models;
const router = express.Router();

router.get('/', (req, res, next)=>{
    
    let user = new User({
        email:'[email protected]'
    });
});

This way i'm getting the error Class constructor Model cannot be invoked without 'new'

Also I've tried another way and got the same error:

router.get('/', (req, res, next)=>{
    
    let user = models.User.build({
        email:'[email protected]'
    });
});

Is it a correct way to load and enable the sequelize models? So, the problem might be related with the environment

Thank you!

How to make self relation

Hi
I want to make an association between 2 same objects, like this:

User.ts

@Table
export default class User extends Model<User> {

    @PrimaryKey
    @AutoIncrement
    @Column(DataType.BIGINT)
    readonly id_user: number;

    //...

    @BelongsTo(() => User, 'id_top')
    top: User;
 
}

app.ts

            const top = new User({
                username: "C2aaaa",
                email: "[email protected]",
                //...
            });

            const user = new User({
                username: "Chnapy",
                email: "[email protected]",
                //...
                top: top
            }, {include: [{model: Password}]});

            user.save()

I haven't any error, but the DB column id_top is set at null and the first user is not insert to the DB.
I tried to add {model: User} to the includes without success.
I switched to the 0.4.0-beta and tried to use the association options for the BelongsTo with setting as and use it in app.ts with {model: User, as: 'top'} but again without success.

Thanks for any help.

(Semi)automatic includes

Whats the problem that should been solved?

It should be possible to define includes dynamically when retrieving or writing data.

Current situation

Selecting data including related data:

// Find all projects with a least one task where task.state === project.state
Project.findAll({
    include: [{
        model: Task,
        where: { state: Sequelize.col('project.state') }
    }]
})

from sequelize docs

Specifying attributes work like this:

Model.findAll({
  attributes: ['foo', 'bar']
});

from sequelize docs

Writing entities including related models:

return Product.create({
  title: 'Chair',
  user: {
    first_name: 'Mick',
    last_name: 'Broadstone',
    addresses: [{
      type: 'home',
      line_1: '100 Main St.',
      city: 'Austin',
      state: 'TX',
      zip: '78704'
    }]
  }
}, {
  include: [{
    association: Product.User,
    include: [ User.Addresses ]
  }]
});

from sequelize docs

Idea

In sequelize-typescript related data is described through a normal property of a class with a HasMany/HasOne/BelongsTo/BelongsToMany decorator:

class User extends Model<User> {
  /* … */

  @BelongsToMany(User, UserFollower)
  followers: User[];
}

How to find data and get included entities (semi)automatically:

So instead of setting an include option for related data, the attribute key, which describes the related data, could be defined in the attribute options like so

User.findAll({
  attributes: ['followers']
})

Additionally the attributes of the related Model can be defined like:

User.findAll({
  attributes: ['followers.name']
})

(Probably a flag should be set somewhere)

How to write data and set includes automatically:

So instead of explicitly specifying includes when writing, the related data can be detected by its attribute key.

Question.create({
  text: "Which one is the better star wars movie?",
  answers: [
    {text: "Rogue One: A Star Wars Story"},
    {text: "Star Wars: The Force Awakens"}
  ]
}, {inferIncludes: true})

To prevent unexpected behavior a flag like inferIncludes should be set to true.

Downsides

  • sequelize-typescript changes behavior of sequelize (one can argue, that we already doing this on the one or other feature)

Reminder

When implementing think of

  • attributes: {exclude: ["foo"]}
  • scopes

Sequelize Officially released 4.1.0

$ npm ls sequelize version

  + [email protected]                         
  added 19 packages in 7.347s               
  [email protected] C:\dorianRepos\newhotness
  `-- [email protected]                       

Looks like sequelize has officially been updated in the npm registry. We should target the latest stable versions for testing. Here are all the versions of sequelize above 3.30.0:

$ npm view sequelize@'>3.30.0' version 
[email protected] '3.30.1'              
[email protected] '3.30.2'              
[email protected] '3.30.3'              
[email protected] '3.30.4'              
[email protected] '4.0.0'                
[email protected] '4.1.0'                

I propose package.json be changed to target 3.30.4 and 4.1.0 in the prepare scripts. I'll make a PR and link it. I'm mostly interested in getting rid of npm install [email protected] now that most people installing sequelize from now on will get 4.1.0.

My initial attempts yielded one failed test in the v4 tests. Line 995 of model.spec.ts - the test where it throws an error if no where clause is given. Maybe something changed? I'll look into it. v3 tests ran fine.

npm dependencies

Hi, I've noticed that dependencies in package.json are a bit mixed up: @types are in dependencies and regular libraries that are used are in dev-dependencies.

The thing is that npm won't install dev-dependencies when you install the package, but only dependencies. So if you say that someone needs to install reflect-metadata when they install this package, that's an obvious "smell" you need it in your dependencies.

I'll make a PR soon with a fix 🙂

Scopes and FK

Hello, I am trying to create Models with FK. I am having trouble understanding the scope model, when to
set as model: () => Customer, or just () =>. How I have my scope set up now, I get undefined errors for the fields I am trying to reference. Thanks for the help in advance.

Usage with ts-node

The getModels function assumes the models are located in .js files. When using ts-node, nothing is compiled so it doesn't find anything. Would it work if that function looked for .ts files too?

Running tests on windows

This relates to a previous discussion about the node environment variable.

I've made some headway on this branch so that windows users can run npm run exec-tests and get all the mocha goodies (moved the environment variable into travis - local environments need to specify the variable themselves).

However, nyc still isn't returning successfully. Running npm run cover on a windows machine still generates errors. I'm investigating further... being able to run all the npm scripts without errors will help other people contribute.

I suspect it's the file glob pattern of the --exclude option for nyc. The nyc README says it uses micromatch for file globbing, but perhaps specifying the excludes in the npm script like that is passing it to the shell to parse the file glob, which may or may not work on windows depending on the shell... I'll have to investigate this later (maybe tomorrow). As I thought the single quotes would pass the path string into nyc (so that it can use micromatch)... I'm not really sure, just guessing.

The error I'm currently running into is this:

$ npm run build
  ... output is good ...
$ npm run cover
  ... scripts, tests, etc ...
npm ERR! [email protected] cover-v4:
  `npm run prepare-test-v4 && nyc --exclude 'lib/models/v3/**/*.js' --all
    --require source-map-support/register mocha test/specs/`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] cover-v4 script.

Installing nyc globally and running the nyc part of the command by itself worked fine. Frustrating!

Next thing I might try is messing with quotes/no quotes/other ways of passing options to nyc.

Using types in front

Hi:

I have defined my types in server side using annotations
@Table export default class Car extends Model<Car> { @Column name: string; }

I am creating a API with node to consume it from front (Angular 2). my question is, are there any way to use Car class in front? of course I dont want to use save method etc etc but I would like to use Car attributtes ('name' in this case) directly in my front without to have to create a dto or something like that.

Thanks.

Is there any hook example?

I searched, but i can't see.

here is my sample table

@Table({
  indexes: [],
  instanceMethods: {},
  classMethods: {},
  timestamps: true
})
export class Role extends Model<Role> {
  @PrimaryKey
  @Column(DataType.UUID)
  id: string;

  @BelongsToMany(() => Group, () => RoleGroup)
  groups: Group[];

  @CreatedAt
  createAt: Date;

  @UpdatedAt
  updateAt: Date;
}

Role.beforeCreate(function(model, options): Promise<any> {
  return new Promise((resolve, reject) => {
      model.myInstanceMethodsSample(model.myFieldSample);
      resolve();
  });
});

My question is... I don't know, model equals above Role class. because as you can see,
I need to use instance method in this beforeCreate hook.

It will be great that i can see any example in hook.

p.s.
In decorator Table, there is classmethods and instancemethods. but it is useless because I just write function in class. am I right?

populating the connecting object in many-to-many relationship

Hi!

I am not sure whether this is just missing feature, or I just don't understand enough of the library/sequelize, but i'll put this here anyway..

I have implemented a many-to-many relationship as described with ForeignKey's. However I am not sure how to control the query output of the connecting object. This is the object connecting Team and User, and having number as additional info:


@DefaultScope({
  include: [() => Team, () => User],
  attributes: ['number']
})
@Table
export default class TeamPlayer extends Model<TeamPlayer> {

  @ForeignKey(() => User)
  @Column
  userId: number;

  @ForeignKey(() => Team)
  @Column
  teamId: number;

  @Unique
  @Column
  number: number;
}

When I query for eg. teams, I do get the following object out:

{
  "id": 1,
  "name": "Doe's Team",
  "players": [
    {
      "id": 1,
      "firstName": "John",
      "lastName": "Doe",
      "TeamPlayer": {
        "userId": 1,
        "teamId": 1,
        "number": 32
    }
 }]
}

Things I want to improve here:

  1. I want to rename the TeamPlayer to something like "membership"; but not by changing the name of the class
  2. the content of TeamPlayer should not have the id`s, but I want it to contain the data of the team, for example:
{
  "firstName": "John",
  "lastName": "Doe"
  "membership": {
     "number": 32,
   }
 }

Any ideas whether this is possible?

(edit: I've also posted a question about this in stackoverlow: https://stackoverflow.com/questions/45130037/sequelize-typescript-many-to-many-relationship-model-data-with)

Defining timestamps: true in the new Sequelize() class doesn't work.

private setupDatabase(): void {
    this.db = this.app.context.db = new Sequelize({
      ...this.config.db,
      modelPaths: [ this.config.app.modelsDir ],
      define: {
        timestamps: true,
        underscored: true,
        freezeTableName: true,
        charset: 'utf8',
        collate: 'utf8_general_ci',
        createdAt: 'created_date',
        updatedAt: 'updated_date',
        deletedAt: 'deleted_date'
      },
      logging: this.config.db.sync.logging,
      sync: this.config.db.sync,
      validateOnly: false
    });
  }

When i call sync() it doesn't create with created_date, updated_date....

Configuration for Connecting to Microsoft SQL Server

(note: I am just creating this issue so it is documented in case anyone else has the same problem in the future)

The default configuration for sequelize uses a property called database to specify the name of the database to connect to, like so:

  "production": {
    "username": "root",
    "password": null,
    "database": "database_production",
    "host": "127.0.0.1",
    "dialect": "mssql"
  }

However, this does not work with sequelize-typescript. Instead, it expects a property called name in order to specify which database to use, like this:

  "production": {
    "username": "root",
    "password": null,
    "name": "database_production",
    "host": "127.0.0.1",
    "dialect": "mssql"
  }

Add @IsNot

I use below validation in sequelize
validate: { len: [1, 128], notEmpty: true, not: ["^ *$",'i'] }
But in sequelize-typescript not support not in validation
Please add @IsNot for this purpose

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.