yarn add requelize joi
joi 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