Sequelize typescript

Sequelize typescript DEFAULT

TypeScript

Since v5, Sequelize provides its own TypeScript definitions. Please note that only TS >= 3.1 is supported.

As Sequelize heavily relies on runtime property assignments, TypeScript won't be very useful out of the box. A decent amount of manual type declarations are needed to make models workable.

Installation

In order to avoid installation bloat for non TS users, you must install the following typing packages manually:

  • (this is universally required in node projects)

Usage

Example of a minimal TypeScript project with strict type-checking for attributes.

NOTE: Keep the following code in sync with to ensure it typechecks correctly.

Usage without strict types for attributes

The typings for Sequelize v5 allowed you to define models without specifying types for the attributes. This is still possible for backwards compatibility and for cases where you feel strict typing for attributes isn't worth it.

NOTE: Keep the following code in sync with to ensure it typechecks correctly.

Usage of

In Sequelize versions before v5, the default way of defining a model involved using . It's still possible to define models with that, and you can also add typings to these models using interfaces.

NOTE: Keep the following code in sync with to ensure it typechecks correctly.

If you're comfortable with somewhat less strict typing for the attributes on a model, you can save some code by defining the Instance to just extend without any attributes in the generic types.

NOTE: Keep the following code in sync with to ensure it typechecks correctly.

Sours: https://sequelize.org/master/manual/typescript.html

How to use sequelize-typescript

Best JavaScript code snippets using sequelize-typescript(Showing top 15 results out of 315)

@BeforeValidatepublicstatic bfValidate(user: User, options: any) { }
BelongsToMany(() => Player, { as: 'participants', through: () => Participation })
Column({ type: DataType.CHAR(30), allowNull: false, validate: { isEmail: true, isUnique: async (val: string, next: any): Promise<any> => { const isExist = UserEntity.findOne({ where: { author: val } }); if (isExist) { next('author is exist'); } next(); }, }, })
publicstatic forRoot(config: SequelizeConfig): ModuleWithServices { return { module: SequelizeModule, services: [ { provide: SEQUELIZE, lazy: true, useFactory: async () => { const sequelize = new Sequelize(config); sequelize.addModels(config.models ? config.models : []); await sequelize.sync(config); return sequelize; }, }, ], }; }
HasMany(() => Achievement, 'playerId')
@BeforeValidatepublicstatic validate(user: User, option: any){ if(!option.transaction) thrownew Error('missing transaction.'); }
BelongsToMany(() => Group, { as: 'members', through: () => Membership })
BelongsToMany(() => Competition, { as: 'participants', through: () => Participation })
HasMany(() => NameChange, 'playerId')
HasMany(() => Snapshot, 'playerId')
Sours: https://www.tabnine.com/code/javascript/modules/sequelize-typescript
  1. Mushroom kingdom moons
  2. Mushroom mythology
  3. Alternative start mod skyrim
  4. Chicago public teacher salaries

Wondering what is better for your application – TypeScript or JavaScript? This post is not about that. It is worth noticing that every valid JavaScript code is also a valid TypeScript code, so it does not take you anything. If you want to, you can stop using types and write play js code.

Nearly a month ago, the new version of TypeScript (2.5.2) was released.  It introduced some new features, which reminded me of how beautiful Typescript is. That’s why I decided to describe how simple it is to write a web app with Express.js and TypeScript and why do I prefer to use them.

Why do I prefer TypeScript and is ordinary JavaScript not enough?

You can find many arguments on why TypeScript is better than JavaScript or vice versa. However, this post is not about them. It is worth noticing that types in TypeScript are optional. Every valid JavaScript code is also a valid TypeScript code, so it does not take you anything. If you want to, you can stop using types and write play js code.

Why do I use Express.js, when there are other newer frameworks?

Express.js has some really powerful features which other frameworks do not have.
Definitely, it is the most mature Node framework that includes:

  • more contributors
  • more updates
  • fewer issues
  • more problems solved

Express.js is really lightweight. I used many popular web frameworks like spring or spring bot in java, asp .NET in c# or laravel in PHP. They are great but too fat. They ship with too many dependencies.

Before we start

The main question is: what kind of application will we build? We will create a simple web application using mentioned tech stack. It is worth to show, how easily with the use of Express.js we can develop properly secured app from scratch. You can do it without tons of dependencies and external libraries, where you have to trust the author’s code.
They also can be poorly written.
I assume that you have installed npm with Node, Mysql and your favourite code editor. I chose Visual Studio Code.
Let’s install the following dependencies.
At first, Express.js with Sequelize ORM and Mysql driver.

As I said before,  express.js is lightweight and plugin-oriented, which means that we need to install some plugins/middleware to handle everything beyond basic functionality.

We want to include user’s authentication into our app, so we need libraries for handling jwt tokens and password hashing.

Finally, we need TypeScript with types.

It is essential to mention npx. Notice that everything above was installed locally. For some reasons, it is better to install libraries in that way, but those installed globally are easier to run. Npx allows you to use packages installed locally as they are installed globally.

I’ve organised my folders in the following structure.
Backend with Node: Express.js, TypeScript, Sequelize
Generally, you only need tsconfig.json and index.ts files from here (for now), but it is nice to organise your folder correctly.

Our TypeScript config file specifies:

  • which files need to be compiled by ts,
  • where to put the compiled file,
  • module system,
  • Javascript ‘version’
  • source maps for easy debugging in the future

App entry point: index.ts


Fill index.ts like above, run  with and type in your browser localhost:4001 and here it is. Comment lines define middlewares which are optional for now, but we need to enable cors and parsing json from post body, so better uncomment this.
Now, we have to connect with the database using Sequentlize.

Next, we should define the database with the required tables. For our app, the only table with users is mandatory.

I will create two similar routes in this app. First one is going to be unprotected. Access to the second route will be granted based on the jwt token. We need to define a database user model.

I’ve created four different user models. The last one is the most important. It allows us to query the database using Sequelize. Others are just types and names are self-descriptive.

Prepare and secure routing

Our app will contain four routes:

  • /register
  • /login
  • /some-resource
  • /some-protected-resource

We need to create an appropriate router and service for them. We also need to define post body validator, which will be checking user credentials for example.
Here we have user service that contains methods for:

  • signing in,
  • signing up
  • verifying jwt token

I do not want to expose the entire user model in the response body. In the code below you can see only id and email.


Our token guard middleware will check the existence of token in protected requests. If the token is not provided, it will return 403.

In the next step, we define rules of post body data validator for the appropriate route. Notice that you can specify them in your way. I prefer to expose as a plain js object.

Let’s define route logic and apply validator to the corresponding route.

Notice that the order of registering middleware is essential. Firstly, we define the unprotected route, then we register token guard middleware. It will be applied to any routes defined below.

Summing up

It wasn’t so hard or time-consuming to write own authentication/authorisation middleware. It is an independent, easily extensible, and we developed it, so we know how it works. We don’t need to worry about magic code or unexpected behaviour while the app grows.
Thank you for your attention. If you have any questions, please leave a comment.

_

Sours: https://gorrion.io/blog/node-express-js-typescript-sequelize/

How to use TypeScript with Sequelize

Using Decorators is something you should avoid as much as possible, they are not ECMAScript standard. They are even consider legacy. It is why I'm going to show you how to use sequelize with typescript.

we just need to follow the docs: https://sequelize.org/v5/manual/typescript.html but as it is not very clear, or at least to me. It took me a while understand it.

There it says that you need to install this tree things

then let's assume your project looks like so:

Let's create the user model first

Now just to play arrow let's create another-model.ts

Our Entities are done. now the db connection.

open there is where we gonna place the seqelize instance

on our index.ts add, if you just want to open connection

or if you want to create them tables

some like this

Once again the sky is the limit. If you do this you'll have all the power of the autocomplete. here an example: https://github.com/EnetoJara/resume-app

Sours: https://stackoverflow.com/questions/60014874/how-to-use-typescript-with-sequelize

Typescript sequelize

sequelize-typescript

Build StatuscodecovNPMDependency Status

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 needs the following flags:

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

Sequelize Options

  • renamed to
  • property renamed to

Scopes Options

The and 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' @TableclassPersonextendsModel{ @Columnname: string @Columnbirthday: Date @HasMany(()=>Hobby)hobbies: Hobby[]}

Less strict

import{Table,Model}from'sequelize-typescript' @TableclassPersonextendsModel{}

More strict

import{Optional}from'sequelize'import{Table,Model}from'sequelize-typescript'interfacePersonAttributes{id: numbername: string}interfacePersonCreationAttributesextendsOptional<PersonAttributes,'id'>{} @TableclassPersonextendsModel<PersonAttributes,PersonCreationAttributes>{}

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

See more advanced example here.

The 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, ... })classPersonextendsModel{}

Table API

DecoratorDescription
sets and automatically
sets define options (also sets and if not already defined by define options)

Primary key

A primary key () will be inherited from base class . This primary key is by default an and has (This behaviour is a native sequelize thing). The id can easily be overridden by marking another attribute as primary key. So either set or use together with .

, ,

Annotations to define custom and type safe , and attributes:

@CreatedAt creationDate: Date; @UpdatedAt updatedOn: Date; @DeletedAt deletionDate: Date;
DecoratorDescription
sets and
sets and
sets , and

The 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).

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

DecoratorDescription
tries to infer dataType from js type
sets dataType explicitly
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:

DecoratorDescriptionOptions
sets (default is )
sets
sets UniqueOptions
sets to specified value
sets
sets to specified string
Validate annotationssee Model validation

Type inference

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

Design typeSequelize data type

Accessors

Get/set accessors do work as well

@TableclassPersonextendsModel{ @Columngetname(): string{return'My name is '+this.getDataValue('name')}setname(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 instance from (!).

import{Sequelize}from'sequelize-typescript'constsequelize=newSequelize({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 in the sequelize config or add the required models later on by calling or :

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

Sours: https://github.com/RobinBuschmann/sequelize-typescript
SQL no Node.js com Sequelize - Masterclass #01

Sequelize + TypeScript - What you need to know

Hi Dev community 👋🏾!

I just decided that I want to write a post so here I AM. I didn't know what to write about and I landed on the idea of Sequelize + TypeScript my experience working with Sequelize and adding TypeScript to it.

Table of Content

A Little bit of Background

So the idea came from a project that I was managing and the client decided that they wanted the project handed in yesterday (as usual), so the company put together a small group of Jr. Engineers plus me as the Senior/Lead Engineer so I would be in charge of choosing the stack so I took the decision of using:

  • Express/NodeJS (Backend)
  • PostgreSQL (Database)
  • Plain React (Frontend)
  • Sequelize (ORM)

Since any of the Jr. Engineers had any experience developing on TypeScript nor working on a microservices-based architecture I decided that it would be good for us to use plained JS and monolithic architecture since that what they knew at the moment and I didn't want to slow down the project.

Now I hear you asking what does this have to do with Sequelize + TypeScript? Well, everything. The company decided to use the project as a base ground for another project and it's here when we noticed all the limitations and problems that we have with the current setup. Just to name a few:

  1. A lot of duplicated code both in the Backend and the Frontend
  2. Slow dev environment
  3. Weird bugs that cause the project to crash
  4. It was hard to understand what is doing what
  5. Database Models were messy
  6. And more...

So here I'm refactoring the project using TypeScript and setting up a Microservice-based architecture with Event-Based Communication (as it should) while my team is working on bug fixes and waiting for me to be done with the refactoring.

Well enough talking let's dive in and set up Sequelize to use TypeScript.

Setup Sequelize

I'll be using the sequelize-cli tool which generates the Sequelize folder structure and configuration based on the file which should look like this

You can now run and you will have the following project structure

Your file will look like this

Yeah, a bunch of code, but this essentially eases the use of models and reduces the amount of that you'd do in your models in the future.

Pretty cool stuff, but I want to use TypeScript I hear you say. Ok so let's change our first file to TypeScript. Rename the file to and let's change some things in it

Yup, that's it!

Ok, let me explain why we removed a bunch of code from the file, and the reason is due to TypeScript being TypeScript. I just didn't want to type the Object that is being generated based on the files inside the directory. So we removed all of that and just exported (Class) and (instance). The instance has a reference to the database connection so when we create our models we use this instance so we can communicate with the database through the models.

The first file is done and a bunch more to go.

Setup Sequelize Models

If we were to use JS a Sequelize model would look like this.

NOTE: I'll be declaring two example models: Author, and Book.

Let's first see how to add a Sequelize Model using JS. The Author Model would look like the following

So let's give the TypeScript treat to the Author model as well. Change the name to and let's define some interfaces

We need these interfaces to tell TypeScript which properties an author instance has.

Now let's define the Author Model in the TS way

Now you should be wondering, why do I have to go through all of that if I'll end up doing the same? Well, if you made a typo on any property of the model define object, TypeScript will yell at you and tell you that the property is missing, same if you try to add a property that is not defined on the interface TypeScript will tell you that property is not defined on type

Now that we know how to declare a Sequelize model using TypeScript let's define the model.

That's it! That's how you define a Sequelize Model using TypeScript.

Adding Model Association

If you want to add associations to the model let's say then in JS you'd do something like this

So do you remember when I said that the code generated when we ran will help us when trying to do ? That time has come!

Sequelize will try to run the associate function if defined and will add the defined associations to the Models.

But we are here for TypeScript not for JS, so how do we do this in our defined models in TypeScript? Let's see how.

I hear you say. Well, if things were that simple in this world I wouldn't be writing this post 😅.

So why wouldn't this work? Sequelize has a weird way to work and if we try to define this association in their respective files (as we do in JS) Sequelize will throw this error:

At first, I thought I was missing something or that I didn't type the Author Model as a Sequelize Model but after double-checking everything was good, TypeScript was not complaining that I was trying to call the method with something else that's not a Sequelize Model. So I was wondering why is this happening? 🤔

I was reading the Sequelize documentation and posts from around the web and didn't find anything that would work, except someone (sorry didn't find the link to the StackOverflow thread) that suggested that one should put their association in one Model file. I was skeptical about it since I said to myself: how would this work since I'm exporting the same model that is in my file. However, I gave it a try. I moved the call to the file:

And Lord and behold my project was running:

It is weird but it seems that you have to define the association in the same file that you set the or the association.

Conclusion

In the end, setting up Sequelize with TypeScript wasn't hard at all, and now we know which properties belong to which model.

For me, it was a valuable experience since I thought that translating my JS files to TS would just be done by renaming the file and that would be it since I believed that Sequelize would handle the typing work in the background.

Note: I know that there is a package out there called sequelize-typescript but I didn't feel like adding another dependency to my project, plus this package is not maintained by the Sequelize team. However, I just tried it and it's pretty cool, so give it a try if you don't want a setup like mine.

By the end of the day, I don't feel like having another dependency in my project, and I was able to accomplish the goal of adding TypeScript to Sequlize without a third-party library just with pure TS.

Sorry for the long post, but I hope you find it useful if you are trying to use Sequelize and TypeScript together.👋🏾

Sours: https://dev.to/jctaveras/sequelize-typescript-what-you-need-to-know-41mj

You will also be interested:

npm

Build StatuscodecovNPMDependency Status

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 needs the following flags:

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

Sequelize Options

  • renamed to
  • property renamed to

Scopes Options

The and 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' @TableclassPersonextendsModel{ @Columnname: string @Columnbirthday: Date @HasMany(()=>Hobby)hobbies: Hobby[]}

Less strict

import{Table,Model}from'sequelize-typescript' @TableclassPersonextendsModel{}

More strict

import{Optional}from'sequelize'import{Table,Model}from'sequelize-typescript'interfacePersonAttributes{id: numbername: string}interfacePersonCreationAttributesextendsOptional<PersonAttributes,'id'>{} @TableclassPersonextendsModel<PersonAttributes,PersonCreationAttributes>{}

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

See more advanced example here.

The 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, ... })classPersonextendsModel{}

Table API

DecoratorDescription
sets and automatically
sets define options (also sets and if not already defined by define options)

Primary key

A primary key () will be inherited from base class . This primary key is by default an and has (This behaviour is a native sequelize thing). The id can easily be overridden by marking another attribute as primary key. So either set or use together with .

, ,

Annotations to define custom and type safe , and attributes:

@CreatedAt creationDate: Date; @UpdatedAt updatedOn: Date; @DeletedAt deletionDate: Date;
DecoratorDescription
sets and
sets and
sets , and

The 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).

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

DecoratorDescription
tries to infer dataType from js type
sets dataType explicitly
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:

DecoratorDescriptionOptions
sets (default is )
sets
sets UniqueOptions
sets to specified value
sets
sets to specified string
Validate annotationssee Model validation

Type inference

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

Design typeSequelize data type

Accessors

Get/set accessors do work as well

@TableclassPersonextendsModel{ @Columngetname(): string{return'My name is '+this.getDataValue('name')}setname(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 instance from (!).

import{Sequelize}from'sequelize-typescript'constsequelize=newSequelize({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 in the sequelize config or add the required models later on by calling or :

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

globs

import{Sequelize}from'sequelize-typescript';constsequelize=newSequelize({ ... models: [__dirname+'/**/*.model.ts']});// orsequelize.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.exportclassUserextendsModel{}

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

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

import{Sequelize}from'sequelize-typescript';constsequelize=newSequelize({models: [__dirname+'/models/**/*.model.ts']modelMatch: (filename,member)=>{returnfilename.substring(0, filename.indexOf('.model'))===member.toLowerCase();},});

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

//user.model.tsimport{Table,Column,Model}from'sequelize-typescript';exportconstUserN='Not a model';exportconstNUser='Not a model'; @TableexportclassUserextendsModel{ @Columnnickname: string;}

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

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

exportdefaultclassUserextendsModel{}

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 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

constperson=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 :

constperson=newPerson({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=100returnperson.save()})Person.update({name: 'bobby'},{where: {id: 1}}).then(()=>{})

Model association

Relations can be described directly in the model by the , , , and annotations.

One-to-many

@TableclassPlayerextendsModel{ @Columnname: string @Columnnum: number @ForeignKey(()=>Team) @ColumnteamId: number @BelongsTo(()=>Team)team: Team} @TableclassTeamextendsModel{ @Columnname: string @HasMany(()=>Player)players: Player[]}

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

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

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

Many-to-many

@TableclassBookextendsModel{ @BelongsToMany(()=>Author,()=>BookAuthor)authors: Author[]} @TableclassAuthorextendsModel{ @BelongsToMany(()=>Book,()=>BookAuthor)books: Book[]} @TableclassBookAuthorextendsModel{ @ForeignKey(()=>Book) @ColumnbookId: number @ForeignKey(()=>Author) @ColumnauthorId: number}

Type safe through-table instance access

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

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

One-to-one

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

, , , , API

DecoratorDescription
marks property as for related class
sets while is key of annotated property and is resolved from source class
sets while is key of annotated property and is explicitly specified value
sets while is key of annotated property and are additional association options
sets while is key of annotated property and is resolved from target related class
sets while is key of annotated property and is explicitly specified value
sets while is key of annotated property and are additional association options
sets while is key of annotated property and is resolved from target related class
sets while is key of annotated property and is explicitly specified value
sets while is key of annotated property and are additional association options
sets while is key of annotated property and / is resolved from through class
sets while is key of annotated property, is explicitly specified value and is resolved from through class
sets while is key of annotated property and / are explicitly specified values
sets while is key of annotated property and / are explicitly specified values
sets while is key of annotated property and are additional association values, including and .

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, will always be the annotated property's name, and 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

@TableclassBookextendsModel{ @ForeignKey(()=>Person) @ColumnauthorId: number @BelongsTo(()=>Person)author: Person @ForeignKey(()=>Person) @ColumnproofreaderId: number @BelongsTo(()=>Person)proofreader: Person} @TableclassPersonextendsModel{ @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 and , an instance of will have the functions , , , , . These functions still exist with sequelize-typescript. But TypeScript wont recognize them and will complain if you try to access , or . To make TypeScript happy, the of sequelize-typescript has , , functions.

@TableclassModelAextendsModel{ @HasMany(()=>ModelB)bs: ModelB[]} @TableclassModelBextendsModel{ @BelongsTo(()=>ModelA)a: ModelA}

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

constmodelA=newModelA()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

The annotation can be used without passing any parameters.

@TableclassPersonextendsModel{ @Index// Define an index with default name @Columnname: string @Index// Define another index @Columnbirthday: Date}

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

@TableclassPersonextendsModel{ @Index('my-index')// Define a multi-field index on name and birthday @Columnname: string @Index('my-index')// Add birthday as the second field to my-index @Columnbirthday: Date @Index({// index optionsname: 'job-index',parser: 'my-parser',type: 'UNIQUE',unique: true,where: {isEmployee: true},concurrently: true,using: 'BTREE',operator: 'text_pattern_ops',prefix: 'test-',// index field optionslength: 10,order: 'ASC',collate: 'NOCASE'}) @ColumnjobTitle: string @ColumnisEmployee: boolean}

Index API

DecoratorDescription
adds new index on decorated field to
adds new index or adds the field to an existing index with specified name
sets both index and index field options

The 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.

constSomeIndex=createIndexDecorator()constJobIndex=createIndexDecorator({// index optionsname: 'job-index',parser: 'my-parser',type: 'UNIQUE',unique: true,where: {isEmployee: true},concurrently: true,using: 'BTREE',operator: 'text_pattern_ops',prefix: 'test-'}) @TableclassPersonextendsModel{ @SomeIndex// Add name to SomeIndex @Columnname: string @SomeIndex// Add birthday to SomeIndex @Columnbirthday: Date @JobIndex({// index field optionslength: 10,order: 'ASC',collate: 'NOCASE'}) @ColumnjobTitle: string @ColumnisEmployee: boolean}

Repository mode

With comes a repository mode. See docs for details.

The repository mode makes it possible to separate static operations like , , ... 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 flag:

constsequelize=newSequelize({repositoryMode: true, ...,});

How to use repository mode?

Retrieve repository to create instances or perform search operations:

constuserRepository=sequelize.getRepository(User)constluke=awaituserRepository.create({name: 'Luke Skywalker'})constluke=awaituserRepository.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:

constuserRepository=sequelize.getRepository(User)constaddressRepository=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 annotation together with repository mode like:

@Scopes(()=>({// includeswithAddress: {include: [()=>Address]},// nested scopeswithAddressIncludingLatLng: {include: [()=>Address.scope('withLatLng')]}})) @TableclassUserextendsModel{}

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

Model validation

Validation options can be set through the 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 becomes , becomes 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:

ValidatorAnnotation
For custom validators also use the annotation: Either or with named function

Example

constHEX_REGEX=/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/ @TableexportclassShoeextendsModel{ @IsUUID(4) @PrimaryKey @Columnid: string @Equals('lala') @Columnreadonlykey: string @Contains('Special') @Columnspecial: string @Length({min: 3,max: 15}) @Columnbrand: string @IsUrl @ColumnbrandUrl: string @Is('HexColor',(value)=>{if(!HEX_REGEX.test(value)){thrownewError(`"${value}" is not a hex color value.`)}}) @ColumnprimaryColor: string @Is(functionhexColor(value: string): void{if(!HEX_REGEX.test(value)){thrownewError(`"${value}" is not a hex color value.`)}}) @ColumnsecondaryColor: string @Is(HEX_REGEX) @ColumntertiaryColor: string @IsDate @IsBefore('2017-02-27') @ColumnproducedAt: Date}

Scopes

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

and

@DefaultScope(()=>({attributes: ['id','primaryColor','secondaryColor','producedAt']})) @Scopes(()=>({full: {include: [Manufacturer]},yellow: {where: {primaryColor: 'yellow'}}})) @TableexportclassShoeWithScopesextendsModel{ @ColumnreadonlysecretKey: string @ColumnprimaryColor: string @ColumnsecondaryColor: string @ColumnproducedAt: Date @ForeignKey(()=>Manufacturer) @ColumnmanufacturerId: 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 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 hook method cannot be named ). That’s because Sequelize has pre-defined methods with those names.

@TableexportclassPersonextendsModel{ @Columnname: string @BeforeUpdate @BeforeCreatestaticmakeUpperCase(instance: Person){// this will be called when an instance is created or updatedinstance.name=instance.name.toLocaleUpperCase()} @BeforeCreatestaticaddUnicorn(instance: Person){// this will also be called when an instance is createdinstance.name+=' 🦄'}}

Why ?

is much easier to read, so why is so important? When it comes to circular-dependencies (which are in general solved by node for you) can be 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 call due to compile option, in some cases is probably not defined(not undefined!) and would throw a . When putting in a separate file, it would look like , which does not throw an error.

Minification

If you need to minify your code, you need to set and in the for annotation. sequelize-typescript uses the class name as default name for and . When the code is minified the class name will no longer be the originally defined one (So that will become 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 () 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 does not provide typings for - these are seperate things. A lot of the types in augment, refer to, or extend what sequelize already has.

Sours: https://www.npmjs.com/package/sequelize-typescript


308 309 310 311 312