@rxstack/sequelize-service v0.7.0
The RxStack Sequelize Service
Sequelize service that implements @rxstack/platform adapter API and querying syntax.
Table of content
Installation
npm install @rxstack/sequelize-service --save
// peer depencencies
npm install --no-save @rxstack/core@^0.7 @rxstack/platform@^0.7 @rxstack/exceptions@^0.6 @rxstack/query-filter@^0.6 @rxstack/security@^0.7 @rxstack/async-event-dispatcher@^0.6 @rxstack/service-registry@^0.6 winston@^3.3.3and add one of the following:
npm install --save pg pg-hstore
npm install --save mysql2 // For both mysql and mariadb dialects
npm install --save sqlite3
npm install --save tedious // MSSQLSetup
SequelizeServiceModule needs to be registered in the application. Let's create the application:
In the example we are using
mysql.
import {Application, ApplicationOptions} from '@rxstack/core';
import {SequelizeServiceModule} from '@rxstack/sequilize-service';
export const APP_OPTIONS: ApplicationOptions = {
imports: [
SequelizeServiceModule.configure({
connection: {
host: process.env.MYSQL_HOST,
database: process.env.MYSQL_DATABASE,
username: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
dialect: 'mysql',
define: {
timestamps: false
}
},
logger: {
enabled: true
}
})
],
providers: [
// ...
]
};
new Application(APP_OPTIONS).start();Module Options
connection: sequelize optionslogger.enabled: enable query logging (defaults to false)logger.level: logging level
Service Options
In addition to service base options we need to set the following options:
model: sequelize model
Usage
Create interfaces
First we need to create model interface and InjectionToken:
import {InjectionToken} from 'injection-js';
import {SequelizeService} from '@rxstack/sequelize-service';
export interface Product {
id: string;
name: string;
}
export const PRODUCT_SERVICE = new InjectionToken<SequelizeService<Product>>('PRODUCT_SERVICE');Create sequelize models
import {DataTypes, Sequelize} from 'sequelize';
import {ModelStatic} from '@rxstack/sequelize-service';
export const defineProduct = (connection: Sequelize): ModelStatic => {
return <ModelStatic>connection.define('product', {
_id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING, allowNull: false, unique: true,
validate: {
notEmpty: true
}
}
});
};define all models in a singe function (useful to set associations) :
import {DataTypes, Sequelize} from 'sequelize';
import {ModelStatic} from '@rxstack/sequelize-service';
import {defineProduct} from './product.schema';
export const defineModels = (connection: Sequelize): {[key: string]: ModelStatic} => {
const product = defineProduct(connection);
// define other models here
// ...
// define associations here
return {
product
// ...
};
};then register the service and models in the application provides:
import {InjectionToken} from 'injection-js';
import {ApplicationOptions} from '@rxstack/core';
import {SequelizeService} from '@rxstack/sequelize-service';
import {SEQUELIZE_CONNECTION_TOKEN} from '@rxstack/sequelize-service'
import {ModelStatic} from '@rxstack/sequelize-service';
import {Sequelize} from 'sequelize';
export const SEQUELIZE_MODELS = new InjectionToken<{[key: string]: ModelStatic}>('SEQUELIZE_MODELS');
export const APP_OPTIONS: ApplicationOptions = {
// ...
providers: [
{
provide: SEQUELIZE_MODELS,
useFactory: (conn: Sequelize) => defineModels(conn),
deps: [SEQUELIZE_CONNECTION_TOKEN],
},
{
provide: PRODUCT_SERVICE,
useFactory: (conn: Sequelize, models: {[key: string]: ModelStatic}) => {
return new SequelizeService<Product>({
idField: '_id', defaultLimit: 25, model: models['product']
});
},
deps: [SEQUELIZE_CONNECTION_TOKEN, SEQUELIZE_MODELS],
},
]
};How to use in controller
import {Injectable} from 'injection-js';
import {Http, Request, Response, WebSocket, InjectorAwareInterface} from '@rxstack/core';
@Injectable()
export class ProductController implements InjectorAwareInterface {
@Http('POST', '/product', 'app_product_create')
@WebSocket('app_product_create')
async createAction(request: Request): Promise<Response> {
// getting connection
const conn = this.injector.get(SEQUELIZE_CONNECTION_TOKEN);
const service = this.injector.get(PRODUCT_SERVICE);
// standard use
await service.insertOne(request.body);
// with transaction and sequelize model options
await conn.transaction(async (t: any) => {
await service.insertOne(request.body, {transaction: t});
await anotherService.insertOne(request.body, {transaction: t});
});
}
}How to build queries with query-filter
If you use @rxstack/query-filter to build db queries then you need to replace default operators with sequelize specific ones:
import {QueryFilterSchema} from '@rxstack/query-filter';
import {Op} from 'sequelize';
export const myQueryFilterSchema: QueryFilterSchema = {
'properties': {
'product_name': {
'property_path': 'name',
'operators': ['$ne', '$eq'],
'replace_operators': [['$eq', Op.eq], ['$ne', Op.ne]],
'sort': true
}
},
'allowOrOperator': true,
'replaceOrOperatorWith': Op.or,
'defaultLimit': 10
};Commands
Helpful commands managing your sequelize database
Sync
Sync all defined models to the DB. More info
npm run cli sequelize:syncwith "force" option, defaults to false
npm run cli sequelize:sync -- -fDrop
Drop all tables. More info
npm run cli sequelize:dropValidation Observer
ValidationObserver converts sequelize errors to BadRequestException.
In order to return proper validation errors and status code 400 we catch the exception and throw BadRequestException.
The error messages can be accessed exception.data['errors'] and implement ValidationError[].
License
Licensed under the MIT license.