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.