In version 8 we introduced the application-wide scopes and dynamic smart action form along with hooks on bulk and global smart actions.
Since version 7, we introduced a new structure of our generated projects to ease the support of multiple databases.
This new structure is the major change we need to consider to correctly perform the migration of your files. The idea of this document is to guide you through the project architecture and make as few changes as possible to benefit from TypeScript.
The key concepts to handle multi databases are the following:
A configuration file to export your connection options to your databases.
A dynamic loading mechanism to dynamically load your models depending on their database connections.
The files related to these key concepts are the files under the /models and the /config directories. Let's handles these files first.
Define your models
Goals:
Create models class and interfaces to code using TypeScript
Synchronize models with the database
To migrate our JavaScript models to TypeScript, we will take the following model generated by lumber as an example:
To declare our models using TypeScript we need to follow the documentation from Sequelize. Two interfaces need to be created describing the attributes for the creation and existing records, and a model class should use these interfaces to benefit from TypeScript:
Note the static associate function. This function is mandatory to perform dynamic loading and associate models with each other, we will dive into that later on.
Now our TypeScript definitions are done, we still need to initialize our interfaces and class with the articles table in the database using Sequelize:
models/articles.ts
import { Model, Sequelize, DataTypes, ModelCtor } from'sequelize';...//previous class and interfaces are hidden to ease readingexportdefaultfunction(sequelize:Sequelize, dataTypes:typeof DataTypes):typeof Model {Article.init({ id: { type:dataTypes.INTEGER, autoIncrement:true, primaryKey:true, }, title: { type:newdataTypes.STRING(128), allowNull:true, }, body: { type:newdataTypes.STRING(128), allowNull:true, }, },{ tableName:'articles', underscored:true, modelName:'articles', sequelize, });return Article;}
Note that the function to initialize the model is the default export from the model file. This is mandatory and will be explained in the next section.
And that's it! Your model definition is finished and you will be able to use it in your code soon, just go ahead to the next section to see how to instantiate your models.
Connect to your databases
Goals:
Connect to each of your databases
Import models definition in those connections
The database connections are configured in config/databases.js. Here is an example of a fresh new generated project with one connection:
This file is responsible for providing the database connections with the corresponding options. In the end, this file should export an array of connections. If we translate this file into TypeScript, we have to export the same database structure, here is an example:
Now your connections are configured, let's load the models for every connection.
A generated project uses a dynamic model instantiation approach. To do so, the models/index.js file under the models folder is responsible for browsing your connections' configuration and models to load them. Here is an example of this generated file:
Note that line 20 is the place where we should use the default export from our model files. At this line, this default export should be called and Sequelize will automatically detect that it is an initialization function, and will instantiate our Article class for example.
Also, note that the association between models is done from line 28 to line 32. We should call the associate function we kept on our models at this same place. Otherwise, our models will not be linked to each other.
Finally, we still need to export at least Sequelize as objectMapping and the connections, the same way it is done in JavaScript.
Here is an implementation of all those requirements in TypeScript:
Please read line 16 carefully and observe that we also filter*.js.map files. If you do use mapping files you need to skip them as in this example, to not consider them as model files to import.
Nothing special needs to be done in your routes. Change the files extension to .ts , change the way dependencies are imported, and let yourself be guided by the Types we provide. Here is an example for the route to get an Article:
Note the request: ForestRequest to have access to user and query
Customize your collections
As for the previous sections, nothing special needs to be changed to your collection configuration. Change the files extension to .ts , change the way dependencies are imported, and let yourself be guided by the Types we provide. Here is an example for the Article collection: