sequelize-modeler
sequelize-modeler is powerful set of tools built in around Sequelize and Express focused in REST API functionalities such as aliased fields, dynamic database connections, powerful query filtering and formatting
Install
$ npm install --save sequelize-modeler
Usage
Defining a Model:
// SomeModel.jsconst Model = Model moduleexports = static { let config = options: tableName: 'MyTable' primaryKey: 'myPrimaryKey' dateFormat: 'YYYY-DD-MM HH:mm:ss' // (optional) any moment format connectionId sequelize fields: // field, alias, label and other properties are all optional, you can define your model normaly and they will be auto generated MyColumn: field: 'MyColumn' as: 'MyColumnCustomName' label: 'Name The Column Should be Showed With' type: DataTypesSTRING defaultValue: 'Some Value' allowNull: false ... }
Initializing a Model:
Quick start:
const Catalog = Catalog// initialize your sequelize instanceconst sequelize = ...options // register your connection to the catalog// connectionId will be a generated unique idconst connectionId = Catalog // initialize your models// all models are returned mapped with their classnames and ready to useconst MyModel MyOtherModel ...etc = Catalog MyModel
Defining your own connection ids:
CatalogCatalog
using a model:
Getting a custom formatted instance:
For the following Model Fields:
... fields: NumberColumn: field: 'NumberColumn' as: 'number' type: DataTypesINTEGER DateColumn: field: 'DateColumn' as: 'date' type: DataTypesDATE format: 'dddd, MMMM Do YYYY, h:mm:ss a' ...
You have to call the format()
method of an instance
let instance = await theModelconsole
Output would be
Getting your model meta-data:
theModel
Output would look like this
Generate an api endpoint:
const router = router
The .generateApi()
method returns an express router with:
[GET] '/theModel'
responds with a paginated list of all rows[GET] '/theModel/:id'
responds with a single row with the matching id (primaryKey)[GET] '/theModel/meta'
responds with some meta-data of the model like th field list, number of rows, visible and filterable fields also according to the request query (more on that here)[POST] '/theModel'
creates an instance, saves it and returns it (response is false if creation fails)[PUT] '/theModel/:id'
edits the instance and returns the new value[DELETE] '/theModel/:id'
deletes the instance and responds with true or false accordingly
All enpoints responses and expected data is aliased with the corresponding configuration.
Supported query parameters for [GET]
:
- Fields :
?fields=field1,field2,field3
specifies wich fields the instances are be sent with - Order :
?order_by=field1(asc),field2(desc),field3
specifies how data should be ordered before pagination, with priority given by the order sent (field1 > field2 > field3
). direction defaults toasc
- Pagination :
?limit=30&offset=2
where limit defines page size, and offset defines number of page, the given example would return rows 31 to 60.limit
defaults to25
andoffset
defaults to1
- Filtering :
- simple filter :
?foo=bar&exclusive=true
will return all rows wherefoo
column conainsbar
. Useful for filtering data tables or autocomplete inputsit also applies to numeric fields?number=12
- exclusive filter :
?foo=bar
will return all rows wherefoo
column equals tobar
, all values are converted to their respective type with their respective formatting declared in the model configuration - power filtering : Allows for complex querying
?field1(and,contains)=value1,field2(and,>)=value2,field3(or,<>)=value3
where the expected format isfieldName(condition,operator)=value
, if the power format is matched at least once the api will expect it on each of the fields. numeric fields are supported by all operators.- conditions :
and
or
- operators :
eq
: equal to<
: lower than>
: greater than<eq
: lower than or equal to>eq
: greater than or equal to<>
: not equal tocontains
: contains!contains
: not containsstartsWith
: starts with!startsWith
: not starts withendWith
: ends with!endWith
: not ends with
- conditions :
- simple filter :
Adding extra middlewares :
Middlewares can be added to all different generated endpoints either before or after them, if the response should be sent, just add next:true
to the options and the reponse will be carried to the next middleware as req.body._carried_
this can be either an instance, a list of instances, an error, or undefined
depending on the endpoint and if was successful or failed.
const router = // we will add this middleware before the generated get endpointlet { reqquerycolor = 'red' reqqueryexclusive = false // do whatever you want here } router
Example using carried data:
const router = const afterMiddleware = { let createdInstanceOrError = reqbody_carried_ // handle you output here} router
Other options :
config.model
- Model to be used (Model | Function | string
)
config.connection
- Connection to be used when model is string (Connection | string
)
Examples of dynamic model:
const Model Catalog = const modelList = // list of not initialized models const connection = Catalog // active connection forlet model of modelList // models will be initialized in their respective generated routers router// an api fo every model 🚀
Using the model name:
const Model Catalog = let model = 'SomeModelName'let connection = Catalog // active connection router
Using a Function to infer the model :
const Model Catalog = const model = { // req, res, next passed from express let model // do stuff... // populate model with some initialized model return model} // note that connection is no longer required, since you return an initialized model router
config.failed
- callback to be excecuted when creation fails
const router = const failed = { // instance can be undefined // this will be excecuted when something expected fails, like an insert, or edition} router
config.failed
- callbback to be excecuted in case of an internal error, by deafult res.status(500).send('Internal Server Error')
const router = const error = { // this will be excecuted when something unexpected like sequelize throwing an error} router
config.empty
- Map of values to assign to null fields of each different dataType, or for every dataType
// empty map integer: number decimal: number bigint: number float: number real: number double: number string: string text: string citext: string date: Moment dateonly: Moment boolean: boolean enum: any array: any json: Object jsonb: Object blob: BlobPart uuid: string cidr: any inet: any macaddr: any range: any geometry: any all: any
config.apiname
- Name used to build href of models, all instances have a href: http://example.com/apiname/:id
, you get to change the apiname
part of it
config.next
- Toggles the excecution of next()
, defaults to false
config.middlewares
- Extra optional middlwares to be added {[{place:'before'|'after', handler:Middleware}]}
place indicates if middlware must be excecuted before or after the generated one, see example above
config.get
- Toggles the [GET]
method, defaults to true
config.getOne
- Toggles the [GET] /:id
endpoint, defaults to true
config.post
- Toggles the [POST]
method, defaults to true
config.put
- Toggles the [PUT]
method, defaults to true
config.delet
- Toggles the [DELETE]
method, defaults to true
config.meta
- Toggles the /meta
endpoint, defaults to true
config.fields
- List of fields to be used by the model, all instances and meta-data will be mapped to the given field list
const router = // you don't need to put every atribute of each field, just what you wantlet fields = "key": "Column1" "as": "one" "dataType": "decimal" "key": "Column2" "as": "two" "dataType": "date" "format": "dddd, MMMM Do YYYY, h:mm:ss a" "key": "Column56" "as": "thisCoulmnDoesNotExist" "dataType": "string" router
Output instances would be like this:
one: 15 two: "Sunday, February 14th 2010, 3:25:50 pm" thisCoulmnDoesNotExist: null href: "http://example.com/theModel/15"