Mantra how-to guide
Doing DAL in the right way
In each project, how components access its data it's extremely important and following the right principles is a must
DAL (or data access layer) is an important concept in most of software applications. Despite DAL is just a concept, represents somehow that thin layer of software that should expose methods to access the data persistance of the application.
In Mantra, each component is responsible to access its own data according to its data model, and this is one of the main features of Mantra development culture because of its benefits.
However, more important than that, is how clients consume the data persisted by a component. Let's see how to do it in the right way.
These principles and recommendations follow one goal: reduce technical debt and increase the maintenability of the project.
Define a DAL module in your component
Mantra allows you (and encourages you) to define a DAL module in your component that will be the only entry point to access the data persisted of the component data model.
To do that, you only have to create such a module inside /model folder, where the data model of the component resides.
That module implements the methods needed by its component to access its data. Like in this real example:
"use strict";
module.exports = {
Add: async (Mantra, userId, title, subtitle, type, format, content, tags, isPublished ) => {
return Mantra.model.articles.articles.I()
.V( {
userid: userId,
title: title,
subtitle: subtitle,
type: type,
format: format,
content: content,
tags: tags,
published: isPublished
}).R();
},
Update: async (Mantra, articleId, title, subtitle, type, format, content, tags, isPublished ) => {
return Mantra.model.articles.articles.U().W("ID=?", articleId)
.V(["title", "subtitle", "type", "format", "content", "tags", "published"],
[title, subtitle, type, format, content, tags, isPublished]).R();
},
Exists: async (Mantra, articleId) => {
return Mantra.model.articles.articles.S()
.W("ID=?",articleId).Exists();
},
GetById: async (Mantra, articleId) => {
return Mantra.model.articles.articles.S().W("ID=?",articleId).Single();
},
GetUserIdByArticleId: async (Mantra, articleId) => {
let entity = await Mantra.model.articles.articles.S("userid").W("ID=?",articleId).Single();
return entity.userid;
},
GetCount: async (Mantra, type) => {
return Mantra.model.articles.articles.S().W("type=? and published=?",[type,true]).Count();
}
//...
}
Note how easy and fast is to write typical CRUD operations with Mantra (using RedEntities object mapper).
This is a real example of component "articles" used by Mantra site.
Remember that DAL module file name should be in: "dal.[component name].js". Read more about DAL in official documentation.
During Mantra bootstrap process when starting the application, Mantra looksup all "dal" modules that exist inside /model folders in the component. By doing so, any component within the project can access their methods directly with "dal" property of Mantra API object, like this:
const articlesCount = Mantra.dal.articles.GetCount( Mantra, "howto" );
Fine, but necesary but not enough.
Expose component data to other components using APIs
The principle to follow is that, as mentioned above, the only client to call DAL methods of a component is just that component.
Then, how to expose the functionality that other components need to know about "articles"?
Articles component should implement and expose an API to expose exactly the functionality or articles data that other components need. Read about components API in official documentation.
By doing so, there's only one entry point in the whole project that access the data persisted in a database (in this example, dal.articles.js), and this gives us de ability of having a having degree of decoupling in our project.