Data-modela is a promise-based Javascript ORM that enable you easily switch between using an actual database and in-memory dummy data when building your APIs. At this time, it works primarily with PostgreSQL database and exposes the following methods create
, bulkCreate
, find
, findById
, findAll
, update
, and destroy
, clear
. You can also use the rawQuery
method if other methods does not met your requirement.
The module also expose the connect
function which would be used for making the make the database connection and can be used to bind models with the connection.
$ npm install data-modela
install the package
import the module into your project
$ import DummyData from data-modela
$ import { connect } from data-modela
if you are using es5
$ const Modela = require('data-modele').default;
The default behavior for the module is to store your model data in-memory. To switch to using a database, you need to provide the database connection string as with key DATABASE_URL
and USE_DB=1
in environment variables. What actually control whether you are using database or not is the USE_DB
variable which you can switch between 0 and 1, 1 indicating you want to use DB. Database connection string need to be present in your environment to enable successful connection to the database. Once the database connection exist, all the method described below will operating on the database instead of being stored in-memory.
To complete the process of enabling use of database, use the connect
function to bind the database connection to models. The function will accept the database connectionString, and an array of models to bind to. If the connection is successful, the models will have the dbConnection
property which is used internally for connecting to the DB. As demonstrated in the example below, if USE_DB
is set in environment, database will be used. Otherwise data is stored in-memory, thus making it an easy toggle.
The model initialization let you define the schema for your model. The schema controls how the is stored and retrieved. Also, if you are using DB, the schema definition will be used to generation table queryString. The queryString will be used to create the relation when you want to create your first record.
const users = new DataModela('users', schema = {});
const connection = connect(connectionString, [ list of models... ]);
Example
const users = new DataModela('users', {
id: {},
name: {},
email: {},
username: {},
createdAt: {},
updatedAt: {},
});
if (parseInt(process.env.USE_DB)) {
const { DATABASE_URL } = process.env;
const connection = connect(DATABASE_URL, [ users ]);
}
You can specify properties in your model fields object, to control the how the behavior of the model. The following properties can be configured.
-
dataType:
'string' || 'char' || 'varchar' || 'boolean' || 'time' || 'timestamp', ||'timestampz' || 'array' || date
// default to string for all fields exceptid
,createdAt
andupdatedAt
. -
required: true || false // default to false if not provided.
-
unique: true || false // boolean, default to false if not provided
-
defaultValue: specify the default value for the field.
-
arrayOfType:
'char' || 'varchar' || 'number' || 'boolean' use if you provide **dataType** as
array` -
charLength:
IntegerValue
e.g 40. Use if you specify dataType asarray
and arrayOfType aschar
.
Example
const users = new DataModela('users', {
id: {},
name: {
dataType: 'string',
},
email: {
dataType: 'string',
unique: true,
required: true,
},
username: {
unique: true,
required: true,
dataType: 'char',
charLength: '30',
},
createdAt: {},
updatedAt: {},
});
To create models you can user create
method or the bulkCreate
method and pass in the values for the fields specified in the schema. Optionally, you can provided array of fields to return after the model is created. If id
, createdAt
, updatedAt
are specified in the schema but are not provided in the create
method, the values will be automatically added. The default behavior of the id
field is to auto increment the value. So you generally won't worry about providing it in the create
method.
If the model creation is successful, it will return an object representing the model created or an object with the fields specified as return fields.
model.create({
// object to create
}, [ fields to return ]);
Example
!(function() {
return users
.create({
name: 'John doe',
email: '[email protected]',
username: 'johndoe',
})
.then(res => {
console.log('Creating a new record for a model')
console.log(res);
})
.catch(err => console.log(err));
}());
// return
Creating a new record for a model
{ name: 'John doe',
email: '[email protected]',
username: 'johndoe',
createdAt: '2021-01-17T18:19:52.452Z',
updatedAt: '2021-01-17T18:19:52.452Z',
id: 1 }
Specifying return fields
!(function() {
return users
.create({
name: 'John doe',
email: '[email protected]',
username: 'johndoe',
}, ['name', 'email', 'createdAt'])
.then(res => {
console.log('Creating a new record for a model')
console.log(res);
})
.catch(err => console.log(err));
}());
// return
Creating a new record for a model
{ id: 1,
name: 'John doe',
email: '[email protected]',
createdAt: '2021-01-17T18:37:14.698Z' }
To create multiple models at once, you can use the bulkCreate
methods. This similar to the create method expect that the individaul model to be created are provided as in array to the bulkCreate
method. You can
!(function() {
return users
.bulkCreate([{
name: 'John doe',
email: '[email protected]',
username: 'johndoe',
}])
.then(res => {
console.log('Creating models using bulkCreate')
console.log(res);
})
.catch(err => console.log(err));
}());
// return
Creating models using bulkCreate
[ { name: 'John doe',
email: '[email protected]',
username: 'johndoe',
id: 1 } ]
Specifying return fields
!(function() {
return users
.bulkCreate([{
name: 'John doe',
email: '[email protected]',
username: 'johndoe',
}], ['id', 'name', 'email', 'createdAt'])
.then(res => {
console.log('Creating a new record for a model')
console.log(res);
})
.catch(err => console.log(err));
}());
// return
[ { id: 1, name: 'John doe', email: '[email protected]' } ]
To update model properties, you use the update
method. This method accepts the properties to update, an object with conditions on how to update the model, and optionally an array of fields to return.
If the model is successfully updated, the object representing the updated model is returned.
!(function() {
return users
.update(
{
name: 'Jane doe',
email: '[email protected]',
},
{
where: {
id: 1,
},
})
.then(res => {
console.log('Updating a model')
console.log(res)
process.stdout.write('\n')
})
.catch(err => console.log(err));
}());
// return
Updating a model
{ name: 'Janet doe',
email: '[email protected]',
username: 'johndoe',
createdAt: '2021-01-17T19:09:03.245Z',
updatedAt: 2021-01-17T19:09:03.353Z,
id: 1 }
Specifying return fields
!(function() {
return users
.update(
{
name: 'Jane doe',
email: '[email protected]',
},
{
where: {
id: 1,
},
}, ['id', 'name', 'username', 'createdAt'])
.then(res => {
console.log('Updating a model')
console.log(res)
process.stdout.write('\n')
})
.catch(err => console.log(err));
}());
// return
{ id: 1,
name: 'Jane doe',
username: 'johndoe',
createdAt: '2021-01-17T19:11:55.939Z' }
One way to retrieve models is the findAll
method. By default this method will return all models in the collection. But specify conditions to search for matching models by passing an object with conditions to the method. You are also able to specify the fields to return.
The method will return an array containing the matching models. If no model exist in the collection or no matching model is found an empty array []
is returned.
model.findAll(condition = 'all' || {}, returnFields=[]);
Example
!(function() {
return users
.findAll()
.then(res => {
console.log('Find all model');
console.log(res);
process.stdout.write('\n');
})
}());
// return
Find all model
[ { name: 'John doe',
email: '[email protected]',
username: 'johndoe',
createdAt: '2021-01-17T19:32:13.406Z',
updatedAt: '2021-01-17T19:32:13.406Z',
id: 1 } ]
Specifying Return fields
!(function() {
return users
.findAll('all', ['id', 'name', 'email'])
.then(res => {
console.log('Find all model with return fields'');
console.log(res);
process.stdout.write('\n');
})
}());
// return
Find all model with return fields'
[ { name: 'John doe',
email: '[email protected]',
username: 'johndoe',
createdAt: '2021-01-17T19:36:21.340Z',
updatedAt: '2021-01-17T19:36:21.340Z',
id: 1 } ]
Specifying conditions
!(function() {
return users
.findAll({ where: { name: 'John doe'} }, ['id', 'name', 'email'])
.then(res => {
console.log('Find all model with return fields');
console.log(res);
process.stdout.write('\n');
})
.catch(err => console.log(err));
}());
// returns
Find all model with return fields
[ { id: 1, name: 'John doe', email: '[email protected]' } ]
// Without matching condition
!(function() {
return users
.findAll({ where: { name: 'Jane doe'} }, ['id', 'name', 'email'])
.then(res => {
console.log('Find all model with return fields');
console.log(res);
process.stdout.write('\n');
})
.catch(err => console.log(err));
}());
// returns
Find all model with return fields
[]
A convenient to get a specify model if the id of the model is known is the findById
method. You simple provide the id of the model of interest.
This method will either return the model if it is found or return a not found error message.
model.findById(id);
Example
!(function() {
return users
.findById(1)
.then(res => {
console.log('Find a model by Id');
console.log(res);
})
.catch(err => console.log(err));
}());
// return
Find a model by Id
{ name: 'John doe',
email: '[email protected]',
username: 'johndoe',
createdAt: '2021-01-17T20:04:10.966Z',
updatedAt: '2021-01-17T20:04:10.966Z',
id: 1 }
!(function() {
return users
.findById(100)
.then(res => {
console.log('Find a model by Id');
console.log(res);
})
.catch(err => console.log(err));
}());
// return
{ message: 'user not found' }
The find
method allows you to specify search conditions and get the first model that match.
The method will return a model that match the specified conditon or return a not found error message
model.find({ where: { username: 'johndoe' }})
Example
!(function() {
return users
.find({where: {username: 'johndoe'}})
.then(res => {
console.log('Find a model by condition')
console.log(res);
process.stdout.write('\n');
})
.catch(err => console.log(err));
}());
// return
Find a model by condition
{ name: 'John doe',
email: '[email protected]',
username: 'johndoe',
createdAt: '2021-01-17T20:13:32.599Z',
updatedAt: '2021-01-17T20:13:32.599Z',
id: 1 }
!(function() {
return users
.find({where: {username: 'johndoe'}})
.then(res => {
console.log('Find a model by condition')
console.log(res);
process.stdout.write('\n');
})
.catch(err => console.log(err));
}());
// return
{ message: 'user not found' }
To delete a model from the model collection, you will use the destroy
method and specify conditions to match the model to be deleted.
This method will return a success message if the model is found and deleted or
!(function() {
return users
.destroy({ where: { id: 1 }})
.then(res => {
console.log('Deleting a model')
console.log(res)
process.stdout.write('\n')
})
}())
// return
Deleting a model
{ message: 'user has been deleted' }
When model does not exist
!(function() {
return users
.destroy({ where: { id: 2 }})
.then(res => {
console.log('Deleting a model')
console.log(res)
process.stdout.write('\n')
})
.catch(err => console.log(err));
}())
// return
{ message: 'user not found, not action taken' }
The clear
method allows you to delete all entries from your model collection.
model.clear()
!(function() {
return users
.clear({ where: { id: 1 }})
.then(res => console.log(res))
}())
// return
{ message: 'Successfully cleared users' }
When using database, the rawQuery
method could be used to run queries against the database if API exposed by the other methods does not meet your need. You simple pass the queryString
and the query will be ran against the database assumming a connection is established
model.rawQuery(queryString)
Different combination of where, type and groups is used to search for matching models when using the methods find
, findAll
, update
and delete
. type and groups provide more control when you have two or more properties in the where condition.
Although the samples below is demonstrated using the findAll
method, It works the same way for find
, update
, and delete
.
model.findAll({
where: {
propsToSearch1: 'value'
propsToSearch2: 'value2'
},
type: 'or' || 'and' // default 'and'
})
and
is the default if type is not specified. This return result where all the props match.or
return result where any of the props match.
Example
{
where: {
username: 'john',
email: '[email protected]'
}
type: or,
}
It is possible to group the keys to search for by specifying the groups parameter in the search condition as demonstrated below.
In the sample below, if the or
type condition is specified along with the groups, the search return models that match any of the given groups. If the and
type condition is specify, the search return model that match all the groups.
model.findAll({
where: {
propsToSearch1: 'value',
propsToSearch2: 'value2',
propsToSearch3: 'value3',
},
type: "or" || "and",
groups: [[propsToSearch1, propsToSearch2], [propsToSearch1, propsToSearch3]],
});
Example
{
where: {
id: 1,
username: 'john',
email: '[email protected]'
}
groups: [['id', 'username'], ['id', 'email]],
type: or,
}
You can search for a key that match multiple values by passing an array of values to match instead of passing a single value for the key. The sample below demonstrate this
model.findAll({
where: {
propsToSearch1: 'value',
propsToSearch2: ['prop2value1', 'prop2value2', 'prop2value3' ]
},
type: "or" || "and",
})
In this case search will match models where propsToSearch2
has values that match any of prop2value1
, prop2value2
and prop2value3
, ANDed
or ORed
with propsToSearch1
.
{
where: {
id: 1,
username: ['john', 'jane', 'loki'],
}
type: and
}
- Tutu Godfrey [email protected]