yarn add requelize joijoi is a peer dependency to create schemas
const requelize = require('requelize')({ host: 'localhost', db: 'myApp' })Options are passed to rethinkdbdash options
requelize uses debug to debug your apps.
You can use the DEBUG environment variable as follows:
DEBUG=requelize:* yarn startconst joi = require('joi')
const User = requelize.model('User', {
email: joi.string()
firstname: joi.string(),
lastname: joi.string()
})
User.index('email')You might also pass a third argument to requelize.model that looks like this: { primaryKey: string }
Primary keys allowed are: guid and integers
requelize.sync()
.then(() => User.getAll('john.doe@example.com', { index: 'email' }))
.then((users) => {
console.log(users)
})First you need to sync database with requelize.sync. To query documents, you can use any rql commands.
User is a sugar syntax for r.db('...').table('User').
You can instanciate models to create documents
const user = new User({
email: 'john.doe@example.com',
firstname: 'John',
lastname: 'Doe'
})
user
.save()
.then(() => console.log(user.id))You can update users with subsequent save calls
user.email = 'john@doe.com'
user.save()You can delete documents with the delete model method.
user
.delete()
.then(() => assert.equal(null, user.id))User.hasOne('Role', 'role', 'User_id')Arguments are:
- Relation Model name (the first argument of
requelize.model) - The virutal field on the instance (so that you have
user.role.id) - The foreign key to use. requelize defaults to
SelfModel_id
User.hasMany('Post', 'posts', 'User_id')Arguments are:
- Relation Model name (the first argument of
requelize.model) - The virutal field on the instance (so that you have
user.posts[0].id) - The foreign key to use. requelize defaults to
SelfModel_id
The foreign key have to be equal to the local key used on belongsTo method
Role.belongsTo('User', 'user', 'User_id')
Post.belongsTo('User', 'user', 'User_id')Arguments are:
- Relation Model name (the first argument of
requelize.model) - The virutal field on the instance (so that you have
role.user.idorpost.user.id) - The local key to use (usually:
model_idormodelIdorModel_id). requelize defaults toModel_id
User.belongsToMany('Right', 'rights')
Right.belongsToMany('User', 'users')Arguments are:
- Relation Model name (the first argument of
requelize.model) - The virutal field on the instance (so that you have
right.users[0].idoruser.rights[0].id) - An optional join table name. Default is
ModelA_ModelBwith ModelA and ModelB being sorted
To query an instance with its relationships, you can use embed:
User
.get('someId')
.embed({
role: true,
rights: true,
group: {
admin: true
}
})
.then((user) => {
console.log(user.role.id)
assert.equal(true, user.role instanceof Role)
})You may have nested relations with sub object (as in group: { admin: true })
To save an instance with its relationships, you can use saveAll:
user.role = roleA
user.rights = [ rightA, rightB ]
user.saveAll({
role: true,
rights: true
})You can also save an array of ids with hasMany or belongsToMany:
user.role = roleA
user.rights = [ rightA.id, rightB.id ]
user.saveAll({
role: true,
rights: true
})Note: be careful that user.rights will be repopulated with rightA and rightB, but those objects will not
be the same as the original rightA and rightB.
That means rightA.User_id is undefined (because saveAll knows nothing about it), but user.rights[0].User_id will be set.
Tree has the same possibilities that you have in embed
If you want to save pivot data (data you store in a belongsToMany relationship), use setPivot and getPivot
user.rights = [ rightA, rightB ]
rightA.setPivot('User', { period: 'infinity' })
rightB.setPivot('User', { period: 'this month' })
user.saveAll({ rights: true })The data will be stored in the joint table. It is shared between the user instance and the right instance
Right
.get('rightAId')
.embed({ users: true })
.then((rightA) => {
console.log(rightA.users[0].getPivot()) // should be equal
})
User
.get('userId')
.embed({ rights: true })
.then((user) => {
console.log(user.rights[0].getPivot()) // should be equal
})Note: a race condition exists here because of users[0] and rights[0].
A proper way to do it would be to use: rights.find(right => right.id === rightA.id)
You can provide your own model to join tables:
User = requelize.model('User', { name: Joi.string() })
Role = requelize.model('Role', { name: Joi.string() })
Period = requelize.model('Period', { name: Joi.string() })
UserRole = requelize.model('UserRole')
// This is important (creates indexes for relation fields)
UserRole.customJoinTable('User', 'Role')
Period.hasMany('UserRole', 'userroles')
UserRole.belongsTo('Period', 'period')
User.belongsToMany('Role', 'roles', 'UserRole')
Role.belongsToMany('User', 'users', 'UserRole')To save a three-way document:
user = new User({ name: 'John Doe' })
role = new Role({ name: 'Admin' })
period = new Period({ name: 'Infinity' })
userRole = new UserRole()
user.roles = [
{
// this is the related document
document: role,
// this is the join document
through: userRole,
// this will be used when saving the join document
saveAll: { period: true }
}
]
userRole.period = period
return user.saveAll({
roles: true
})To retrieve a three-way document:
User
.embed({ roles: { _through: { period: true } } })
.nth(0)
.then((res) => {
console.log(res.roles[0]._through.period)
})requelize provide a changefeed structure with the library rxjs and Observables.
You are free to use original cursors if you want (by using changes((err, cursor) => { ... }) and not .feed())
let feed = User.feed()
feed
.filter(event => event.type === 'create')
.subscribe(
(event) => console.log(event),
(err) => console.error(err)
)event is a simple object that contains:
- type (string): 'create', 'update' or 'delete'
- from (Object): the original value (null when event.type === 'create')
- to (Object): the target value (null when event.type === 'delete')
You should unsubscribe when you do not have any use of it by using the custom Observable method close():
let feed = User.feed()
let subscription = feed
.filter(event => event.type === 'create')
.subscribe(
(event) => console.log(event),
(err) => console.error(err)
)
somePromise()
.then(() => {
feed.close()
subscription.unsubscribe()
})Note: in the example above, the subscription is also closed
A few hooks are available in requelize: validating, validated, saving, saved, creating, created, updating and updated.
User.on('saving', (user) => {
user.editedAt = new Date()
})
User.on('creating', (user) => {
user.createdAt = new Date()
})Hooks also support promises
User.on('saving', (user) => {
return somePromise()
.then(() => {
user.foo = 'bar'
})
})If you plan to use queries that do not resolve to a Model instance, but starts from a model, use parse() :
User
.parse(false)
.getAll()
.map((user) => 1)
.reduce((a, b) => a.add(b))
.run()
.then((res) => {
assert.equal('number', typeof res)
})Note: you need to call run()
You can also disable validation when saving a document. Documents are only validated at insert, not at retrieval
user.someInvalidField = 'foo'
user.validate(false).save()If you need virtual fields, you can use virtual method from model:
const User = requelize.model('User', {
email: joi.string()
firstname: joi.string(),
lastname: joi.string()
})
User.virtual('fullname', user => `${user.firstname} ${user.lastname}`)
let user = new User({ firstname: 'John', lastname: 'Doe' })
assert.equal('John Doe', user.fullname)If you need r for any use (r.row, etc.) you can find it under requelize: requelize.r