Dovima is a high-quality, stand-alone ORM written in ES6. We call it a "supermodel" because it gracefully does everything you expect an ORM to do, plus a whole lot of time-saving, code-cleaning extra features that make it an absolute pleasure to work with.
$ npm install dovima --save
You may wish to run the automated test suite to ensure that Dovima is fully compatible in your environment:
$ cd node_modules/dovima
$ npm test
// ES6
import Model from "dovima";
// ES5
var Model = require("dovima");
Dovima doesn't require centralized schema files for associations, validations, or anything else. You simply define a model, add the features you want to it, and use it.
// models/user.js
import Model from "dovima";
class User extends Model {}
// test.js
import User from "./models/user.js";
const userAttributes = {
name: "Bob Builder"
};
const user = new User(userAttributes);
user.name.should.eql(userAttributes.name);
// models/user.js
import Model, {isNotEmpty} from "dovima";
class User extends Model {
validations() {
this.validate("name", isNotEmpty);
}
}
// test.js
import User from "./models/user.js";
const user = new User();
// Check if the model is valid or not
user.isValid((isValid) => {
isValid.should.be.false;
});
// Get a list of all invalid attributes
// and the reasons they are invalid
user.invalidAttributes((invalidAttributes) => {
invalidAttributes.should.eql({
"name": ["cannot be empty"]
});
});
// models/user.js
import Model from "dovima";
import Article from "./models/article.js";
import Comment from "./models/comment.js";
class User extends Model {
associations() {
this.hasMany("articles", Article);
this.hasMany("comments", Comment);
this.hasMany("articleComments", Comment)
.through("articles");
}
}
// models/article.js
import Model from "dovima";
import User from "./models/user.js";
import Comment from "./models/comment.js";
class Article extends Model {
associations() {
this.belongsTo("user", User);
this.hasMany("comments", Comment);
}
}
// models/comment.js
import Model from "dovima";
import User from "./models/user.js";
import Article from "./models/article.js";
class Comment extends Model {
associations() {
this.belongsTo("user", User);
this.belongsTo("article", Article);
}
}
// test.js
import User from "./models/user.js";
import Article from "./models/article.js";
import Comment from "./models/comment.js";
const user = new User({
name: "Bob Builder"
});
const article = new Article({
title: "How to Build Things!",
user: user
});
const commentAttributes = {
user: user,
article: article,
text: "I really like this article."
};
const comment = new Comment(commentAttributes);
user.articles.push(article);
article.comments.push(comment);
const articleComment = user.articleComments[0];
articleComment.text.should.eql(commentAttributes.text);
// models/user.js
import Model, {isPresent} from "dovima";
import ProfilePicture from "./models/profilePicture.js";
class User extends Model {
associations() {
this.hasOne("profilePicture", ProfilePicture);
}
validations() {
this.validate("profilePicture", isPresent);
}
}
// test.js
import User from "./models/user.js";
const user = new User();
// Check if the model is valid or not
user.isValid((isValid) => {
isValid.should.be.false;
});
// Get a list of all invalid attributes
// and the reasons they are invalid
user.invalidAttributes((invalidAttributes) => {
invalidAttributes.should.eql({
"profilePicture": ["must be present"]
});
});
// models/user.js
import Model from "dovima";
class User extends Model {
instantiate(attributes = {}, options = {}) {
if (options.convertToDogYears) {
this.age = attributes.age * 7;
}
}
}
// test.js
import User from "./models/user.js";
const user = new User({
age: 8
}, {
convertToDogYears: true
});
user.age.should.eql(56);
Note: Dovima utilizes a database adapter called almaden
to make calls to the database.
// models/user.js
import Model from "dovima";
import Article from "./models/article.js";
class User extends Model {
associations() {
this.hasMany("articles", Article);
}
}
// models/article.js
import Model from "dovima";
import User from "./models/user.js";
class Article extends Model {
associations() {
this.belongsTo("user", User);
}
}
// test.js
import Database from "almaden";
import Model from "dovima";
import User from "./models/user.js";
import Article from "./models/article.js";
const databaseCredentials = {
client: "mysql",
connection: {
host : "127.0.0.1",
user : "myUser",
password : "123456789",
database : "test"
}
};
const database = new Database(databaseCredentials);
/**
* Setting Model.database will cause all models to use it by default.
*/
Model.database = database;
/**
* Set up the models
*/
const user = new User({
name: "Norman"
});
const article = new Article({
title: "Things Happening Around Town"
});
user.articles.push(article);
/**
* Now, all models can .save(callback)
*/
user.save((error) => {
if (error) { throw error; }
// user was saved, and now has an id
(user.id === undefined).should.be.false;
// article was saved as well and has an id due to .save
// propagating to all hasOne and hasMany associations
(article.id === undefined).should.be.false;
});
almaden
is built on knex
, so if you have an existing knex connection you'd like to use instead of creating a new one, just use the following instead of passing credentials:
import knex from "knex";
import Database from "almaden";
import Model from "dovima";
const databaseCredentials = {
client: "mysql",
connection: {
host : "127.0.0.1",
user : "myUser",
password : "123456789",
database : "test"
}
};
const database = knex(databaseCredentials);
/**
* Use existing knex connection
*/
Model.database = new Database({
knex: database
});
// models/user.js
import Model from "dovima";
import Article from "./models/article.js";
class User extends Model {
associations() {
this.hasMany("articles", Article);
}
}
// models/article.js
import Model from "dovima";
import User from "./models/user.js";
class Article extends Model {
associations() {
this.belongsTo("user", User);
}
}
// test.js
import Database from "almaden";
import Model from "dovima";
import User from "./models/user.js";
import Article from "./models/article.js";
const databaseCredentials = {
client: "mysql",
connection: {
host : "127.0.0.1",
user : "myUser",
password : "123456789",
database : "test"
}
};
Model.database = new Database(databaseCredentials);
User
.find.one
.where("id", 1)
.include("articles")
.results((error, user) => {
user.name.should.eql("Norman");
user.articles[0].title.should.eql("Things Happening Around Town");
});
// models/user.js
import Model from "dovima";
class User extends Model {}
// test.js
import User from "./models/user.js";
User.mock.find.one.where("id", 1).results({
id: 1,
name: "Bob"
});
User.find.one.where("id", 1).results((error, user) => {
user.name.should.eql("Bob");
});
// models/user.js
import Model from "dovima";
class User extends Model {}
// test.js
import User from "./models/user.js";
const user = new User({id: 1});
user.mock.instance({
id: 1,
name: "Bob"
});
user.fetch(() => {
user.id.should.eql(1);
user.name.should.eql("Bob");
});