About
CORMO is an ORM framework for Node.js.
Currently supports:
- multi-DB: MySQL, MongoDB, SQLite3, PostgreSQL
- constraints
- validations
- associations
- geospatial query
- callbacks
- aggregation
- nested column
See https://github.com/croquiscom/cormo/wiki/Future-Plans for future plans.
Overview
You can see detail guides on http://croquiscom.github.io/cormo/.
Define models
import * as cormo from 'cormo';
const connection = new cormo.Connection('mysql', { database: 'test' });
@cormo.Model()
class User extends cormo.BaseModel {
@cormo.Column({ type: String })
name?: string;
@cormo.Column({ type: cormo.types.Integer })
age?: number;
}
@cormo.Model({ connection })
class Post extends cormo.BaseModel {
@cormo.Column(String)
title?: string;
@cormo.Column('string')
body?: string;
@cormo.Column(Date)
date?: Date;
@cormo.ObjectColumn({type: Author})
author: Author;
}
class Auther extends User {
@cormo.Column(Date)
date_joined? Date;
}
const cormo = require('cormo');
const connection = new cormo.Connection('mysql', { database: 'test' });
const User = connection.model('User', {
name: { type: String },
age: { type: cormo.types.Integer }
});
const Post = connection.model('Post', {
title: String,
body: 'string',
date: Date,
});
cormo = require 'cormo'
connection = new cormo.Connection 'mysql', database: 'test'
# this will create two tables - users, posts - in the database.
class User extends cormo.BaseModel
@column 'name', type: String
@column 'age', type: cormo.types.Integer
class Post extends cormo.BaseModel
@column 'title', String # `String` is the same as `type: String`
@column 'body', 'string' # you can also use `string` to specify a string type
@column 'date', Date
Create records
const user1 = new User({ name: 'John Doe', age: 27 });
await user1.save();
const user2 = await User.create({ name: 'John Doe', age: 27 });
const user1 = new User({ name: 'John Doe', age: 27 });
await user1.save();
const user2 = await User.create({ name: 'John Doe', age: 27 });
user1 = new User name: 'John Doe', age: 27
await user1.save()
user2 = await User.create name: 'John Doe', age: 27
Retreive records
const user = await User.find(1);
const users = await User.where({name: 'John Doe'});
const users = await User.where({age: 27})
.select(['name'])
.order('name')
.limit(5)
.skip(100);
const users = await User.where({$or: [ { age: { $lt: 20 } }, { age: { $gt: 60 } } ]})
.where({name: { $contains: 'smi' }});
const posts = await Post.where({
title: 'Lorem ipsum',
'author.name': 'John Doe',
});
const user = await User.find(1);
const users = await User.where({name: 'John Doe'});
const users = await User.where({age: 27})
.select(['name'])
.order('name')
.limit(5)
.skip(100);
const users = await User.where({$or: [ { age: { $lt: 20 } }, { age: { $gt: 60 } } ]})
.where({name: { $contains: 'smi' }});
user = await User.find 1
users = await User.where name: 'John Doe'
users = await await User.where(age: 27)
.select(['name'])
.order('name')
.limit(5)
.skip(100)
users = await User.where($or: [ { age: $lt: 20 }, { age: $gt: 60 } ])
.where(name: $contains: 'smi')
Count records
const count = await User.count();
const count = await User.count({age: 27});
const count = await User.count();
const count = await User.count({age: 27});
count = await User.count()
count = await User.count age: 27
Update records
const user = await User.find(1);
user.age = 30;
await user.save();
const count = await User.find(1).update({age: 10});
const count = await User.where({age: 27}).update({age: 10});
const count = await User.where({age: 35}).update({age: {$inc: 3}});
const posts = await Post.where({title: 'Lorem Ipsum'}).update({ author: {age: {$inc: 5}}});
const user = await User.find(1);
user.age = 30;
await user.save();
const count = await User.find(1).update({age: 10});
const count = await User.where({age: 27}).update({age: 10});
const count = await User.where({age: 35}).update({age: {$inc: 3}});
user = await User.find 1
user.age = 30
await user.save()
count = await User.find(1).update age: 10
count = await User.where(age: 27).update age: 10
count = await User.where(age: 35).update age: $inc: 3
Delete records
const count = await User.delete({age: 27});
const count = await User.delete({age: 27});
count = await User.delete age: 27
Constraint
@cormo.Model()
class User extends cormo.BaseModel {
@cormo.Column({ type: String, required: true })
name!: string;
@cormo.Column({ type: Number, required: true })
age!: number;
@cormo.Column({ type: String, unique: true, required: true })
email!: string;
}
const User = connection.model('User', {
name: { type: String, required: true },
age: { type: Number, required: true },
email: { type: String, unique: true, required: true }
});
class User extends cormo.BaseModel
@column 'name', type: String, required: true
@column 'age', type: Number, required: true
@column 'email', type: String, unique: true, required: true
Validation
@cormo.Model()
class User extends cormo.BaseModel {
@cormo.Column(String)
name?: string;
@cormo.Column(Number)
age?: number;
@cormo.Column(String)
email?: string;
}
User.addValidator((record) => {
if (record.age<18) {
return 'too young';
}
});
const User = connection.model('User', {
name: String,
age: Number,
email: String
});
User.addValidator((record) => {
if (record.age<18) {
return 'too young';
}
});
class User extends cormo.BaseModel
@column 'name', String
@column 'age', Number
@column 'email', String
@addValidator (record) ->
if record.age < 18
return 'too young'
Callbacks
@cormo.Model()
class User extends cormo.BaseModel {
@cormo.Column(String)
name?: string;
@cormo.Column(Number)
age?: number;
}
User.beforeSave(() => {
this.name = this.name.trim();
});
const User = connection.model('User', {
name: String,
age: Number
});
User.beforeSave(() => {
this.name = this.name.trim();
});
class User extends cormo.BaseModel
@column 'name', String
@column 'age', Number
@beforeSave ->
@name = @name.trim()
Associations
@cormo.Model()
class User extends cormo.BaseModel {
@cormo.Column(String)
name?: string;
@cormo.Column(Number)
age?: number;
@cormo.HasMany()
posts?: Post[];
}
@cormo.Model()
class Post extends cormo.BaseModel {
@cormo.Column(String)
title?: string;
@cormo.Column(String)
body?: string;
@cormo.BelongsTo()
user?: User;
}
var User = connection.model('User', {
name: String,
age: Number
});
var Post = connection.model('Post', {
title: String,
body: String
});
User.hasMany(Post);
Post.belongsTo(User);
class User extends cormo.BaseModel
@column 'name', String
@column 'age', Number
@hasMany 'posts'
class Post extends cormo.BaseModel
@column 'title', String
@column 'body', String
@belongsTo 'user'
Aggregation
const records = await Order.where({price: {$lt: 10}})
.group(null, {count: {$sum: 1}, total: {$sum: '$price'}})
.order('total');
const records = await Order.group('customer', {min_price: {$min: '$price'}, max_price: {$max: '$price'}});
const records = await Order.where({price: {$lt: 10}})
.group(null, {count: {$sum: 1}, total: {$sum: '$price'}})
.order('total');
const records = await Order.group('customer', {min_price: {$min: '$price'}, max_price: {$max: '$price'}});
records = await Order.where price: $lt: 10
.group null, count: {$sum: 1}, total: {$sum: '$price'}
.order 'total'
records = await Order.group 'customer', min_price: { $min: '$price' }, max_price: { $max: '$price' }
Geospatial query
@cormo.Model()
class Place extends cormo.BaseModel {
@cormo.Column(String)
name?: string;
@cormo.Column(cormo.types.GeoPoint)
location?: [number, number];
}
await Place.create({name: 'Carrier Dome', location: [-76.136131, 43.036240]});
const places = await Place.query().near({location: [-5, 45]}).limit(4);
console.log(places);
const Place = connection.model('Place', {
name: String,
location: cormo.types.GeoPoint
});
await Place.create({name: 'Carrier Dome', location: [-76.136131, 43.036240]});
const places = await Place.query().near({location: [-5, 45]}).limit(4);
console.log(places);
class Place extends cormo.BaseModel
@column 'name', String
@column 'location', cormo.types.GeoPoint
# create
await Place.create name: 'Carrier Dome', location: [-76.136131, 43.036240]
# query
places = await Place.query().near(location: [-5, 45]).limit(4)
console.log places
License
MIT licenses. See LICENSE for more details.