Modli is an NPM module designed to help create unified data modelling, validation
and CRUD operations across numerous data sources. It accomplishes this by exposing
a model object and an adapter object which are extended upon eachother with
the desired adapter for a data source to create a more standard, extensible
object.
npm install modli --save
Below is an example of a basic setup where a model and an adapter
are added. Once added they are available to be use'd to create an
instance of the object with the methods from the adapter, validation, etc.
In this example, the modli-nedb is
utilized (npm install modli-nedb --save).
// Import all the Modli methods
import { model, adapter, use } from 'modli';
// Import the adapter to use
import nedb from 'modli-nedb';
// Create adapter object
adapter.add({
name: 'testNEDB',
// Uses the built-in NeDB adapter
source: nedb,
// Initiates adapter with following config
config: {
inMemoryOnly: true
}
});
// Add a Model
model.add({
// Set a name
name: 'testUser',
// Set the version
version: 1,
// Define the schema
schema: {
id: { type: 'number', required: true },
fname: { type: 'string' },
lname: { type: 'string' },
email: { type: 'email', required: true }
}
});
// Create user object by using the model and adapter
const user = use('testUser', 'testNEDB');The above example will return the model object with a number of methods for performing data operations. This will always include core CRUD methods:
// Create
user.create({ /*...data...*/ }).then(/*...*/).catch(/*...*/);
// Read
user.read({ /*...query...*/ }).then(/*...*/).catch(/*...*/);
// Update
user.update({ /*...query, data...*/ }).then(/*...*/).catch(/*...*/);
// Delete
user.delete({ /*...query...*/ }).then(/*...*/).catch(/*...*/);Yes, it's all based on Promises. You're welcome.
Modli supports easy addition of custom functionality through plugins. Using the above example, a plugin can be added to extend the Modli instance:
// Create a plugin function
const getSchemas = function () {
return this.schemas;
}
// Use the `plugin` method to add the plugin
user.plugin(getSchemas);
// Call the plugin
const schemas = user.getSchemas(); // <- would return all schemas in userWhile the team behind Modli provides a number of adapters, Modli core is also designed to accept a path to a custom adapter:
adapter.use({
name: 'myCustomAdapter',
source: 'path/to/myCustomAdapter'
config: {
/*...custom config properties...*/
}
});To see a functional example of a custom adapter see /examples/custom-adapter
Adapters can be esily extended upon. For example, a custom method could be added to the NeDB adapter used in the Getting Started section:
import nedb from 'modli-nedb';
nedb.extend('myCustomMethod', (someVal) => {
// Just return the value passed
return someVal;
});All adapters contain the extend method which becomes part of the created object
when a model and adapter are use'd, so the adapter can be extended before
initialization with a model, or inline:
// Initial setup
adapter.add({ name: 'myAdapter', /*...*/ });
model.add({ name: 'myModel', /*...*/ });
// Usable object
const myTest = use('myModel', 'myAdapter');
// Extend...
myTest.extend('myCustomMethod', (someVal) => {
// Just return the value passed
return someVal;
});The above would allow you to then call myTest.myCustomMethod('foo') and expect
the response to be foo.
Validation of model data is done by the adapter when data is being insertered,
i.e. create and update procedures. The adapter inherits the model's validate
method which utilizes the Obey library to ensure
properties are correct.
By default, the validation method's fail response will return the Obey error
object. This can be overridden using the following:
model.customValidationError = (err) => {
// ... custom formatting here ...
};For example, if you wanted to just show the "human" error response text:
model.customValidationError = (err) => {
return err[0].message;
}The above would return "id" must be a number if the above model was tested
with an invalid string id when the expected input was an integer.
When the adapter is extended upon the model to which it is applied it exposes
the model's validate method. Adapters can utilize this via the following:
const validationErrors = this.validate(body, version);The validate method in the above returns errors to the validationErrors
constant. If no validation errors are present it simply returns null.
The version paramater is optional and will default to the latest (last added)
model if not specificed.
The sanitize method is available for creating a cross-adapter compatible method
for parsing data after read. The default action of this method is a simple
return of the data, this can be easily overwritten on a model:
modelName.sanitize = data => {
// Perform actions on data...
}A Makefile is included for managing build and install tasks. The commands are
then referenced in the package.json scripts if that is the preferred
task method:
all(default) will run all build tasksstartwill run the main scriptcleanwill remove the/node_modulesdirectoriesbuildwill transpile ES2015 code in/srcto/buildtestwill run all spec files in/test/srctest-coverwill run code coverage on all testslintwill lint all files in/src
Running make test will run the full test suite.
Test Inidividual File
An individual spec can be run by specifying the FILE. This is convenient when
working on an individual adapter.
make test FILE=/some.spec.js
The FILE is relative to the /test directory.
Deploys
For deploying releases, the deploy TAG={VERSION} can be used where VERSION can be:
<newversion> | major | minor | patch | premajor
Both make {COMMAND} and npm run {COMMAND} work for any of the above commands.
Modli is licensed under the MIT license. Please see LICENSE.txt for full details.
Modli was designed and created at TechnologyAdvice.