MasterRecord
Relationships
Connect your entities with expressive, code-first associations.
Relationships are declared like any other field — a method that calls a relationship builder. MasterRecord wires up the foreign keys, eager/lazy loading, and cascading for you.
belongsTo & hasMany#
A belongsTo creates and owns the foreign-key column; the inverse hasMany reads through it. belongsTo('User') automatically creates a user_id column.
models
// User.js
export default class User {
id(db) { db.integer().primary().auto(); }
name(db) { db.string(); }
Posts(db) { db.hasMany('Post'); } // one User → many Posts
}
// Post.js
export default class Post {
id(db) { db.integer().primary().auto(); }
title(db) { db.string(); }
User(db) { db.belongsTo('User'); } // creates user_id, links to User
}Using the association#
usage.js
// Create a post for a user
const post = db.Post.new();
post.title = 'Eternia News';
post.user_id = user.id;
await post.save();
// Read related records
const author = await db.Post.where((p) => p.id == $$, post.id).include('User').single();
console.log(author.User.name);hasOne#
A one-to-one association. The related record is required unless the column is nullable.
javascript
export default class User {
id(db) { db.integer().primary().auto(); }
Profile(db) { db.hasOne('Profile'); }
}hasManyThrough#
A many-to-many through a join entity. Pass the join table and its foreign key:
javascript
export default class Post {
id(db) { db.integer().primary().auto(); }
Tags(db) { db.hasManyThrough('Tagging', 'tag_id'); }
}Cascading deletes#
hasMany cascades deletes by default — removing a parent removes its children. Opt out per association with .stopCascadeOnDelete():
javascript
Posts(db) { db.hasMany('Post').stopCascadeOnDelete(); } Custom foreign keys
Both
hasMany and belongsTo accept an explicit key as a second argument, e.g. db.hasMany('Post', 'author_id')— handy when your column doesn’t follow the <model>_id convention.