I am building application architecture and design. When we are talking about creating common methods or services, it would completely depend on the use case or types of operation we are performing.
Sequelize has already basic methods which perform common operations. Following is my idea which might put more light on your way. Please refer to below pseudo-code.
Answer 1.
Following is the method that might help you, that how do you organize your functions. It is my basic thought, so there might room for an error.
BaseModel.helper.js
class BaseModelHelper{
static async find(params){
const {model, where, attributes, include=[] offset:0, limit: 10} = params;
objFind = {};
if(Object.keys(where).length > 0){
objFind = {...objFind, where}
}
if(attributes.length > 0){
objFind = {...objFind, attributes}
}
if(include.length > 0){
objFind = {...objFind, include}
}
model.find({
where: where,
attributes: attributes,
include,
offset,
limit
}).then((data)=>{
return data;
}).catch((err)=>{
throw new Error(err);
});
}
static async create(params){
const {model, properties} = params;
model.create(properties)
.then((data)=>{
return data;
}).catch((err)=>{
throw new Error(err);
});
}
static async update(params){
const {model, newData, where} = params;
model.update(newData, {
where
})
.then((data)=>{
return data;
}).catch((err)=>{
throw new Error(err);
});
}
static async delete(params){
const {model, where} = params;
model.destroy(where)
.then((data)=>{
return data > 0 ? true : false;
}).catch((err)=>{
throw new Error(err);
});
}
}
module.exports = BaseModelHelper;
Data.services.js
const BaseModelHelper = require("BaseModel.helper.js);
class DataServices{
static async add(){
// Owner table entry
const {id} = await BaseModelHelper.create({
model: "Owner'
properties:{
name: 'Loren',
role: 'admin',
},
});
// Cat table entry
const {id: petId} = await BaseModelHelper.create({
model: "Pet'
properties:{
owner_id: 'c0eebc45-9c0b',
type: 'cat',
}
});
}
static async findWithRelations(){
const arrData = await BaseModelHelper.find({
model: 'User',
where: {
role: 'admin'
},
attributes: ['id', 'username', 'age'],
include: [{
model: pet,
through: {
attributes: ['createdAt', 'startedAt', 'finishedAt'],
where: {completed: true}
}
}]
});
}
static async findBelongs(){
const arrData = await BaseModelHelper.find({
model: 'User',
where: {
role: 'admin'
},
attributes: ['id', 'username', 'age']
});
}
static async update(){
const arrData = await BaseModelHelper.update({
Model: 'Pet',
newData:{
name: 'lina',
}
where: {
name: 'suzi',
}
});
}
static async delete(){
const arrData = await BaseModelHelper.delete({
Model: 'Pet',
where: {
name: 'lina',
}
});
}
}
module.exports = DataServices;
The above way I have described has one benefit is to you don't go to do error handling every place, if you have to manage to centralize error handler. An when an error occurred it throws an error and catches by centralizing the error handler of Express.
The above class of common db operation is build based on my experience and the frequency of the operations we have performed. I know that there is room for more possibilities than we expect, but with the method, I have suggested you might not face many obstacles.
Answer 2. You should create a whole qualified query object at your service level. Once its build at the service level, then only you will pass it to our BaseModelHelper.
Answer 3. Same thing you should create your data object at the service level. If the data object builds from multiple tables, then you first encapsulate at the service level, then you should pass to the BaseModelHelper method.
Answer 4. Yes, I also favor the same. But one thing you should keep in mind that there is always room for improvement. If you wish to create a method for each module then you should copy this BaseModelHelper to everywhere else I suggest inheriting the file at the service level.
All the database operation objects build at the service level, not the controller level. Your database service and object preparation services might be different so it will give a more clear picture. The object preparation service might scope to include more different services.
Again above approach is my thought process and I suggested you based on my experience. Again there is more room for improvement, that you might take to create.