jmdobry/reheat

View on GitHub
guide/relations/relations.md

Summary

Maintainability
Test Coverage
@doc overview
@id index
@name Relations Guide
@description

# Relations

<page-list></page-list>

@doc overview
@id overview
@name Overview
@description

Currently Reheat supports querying Models and one-level deep relations. You can define `belongsTo`, `hasOne` and `hasMany` relationships.

Reheat will create the necessary secondary indices for you if they don't already exist. Let's get to the examples:

```js
var User = reheat.defineModel('User', {
  tableName: 'user',
  connection: connection,
  relations: {
    hasMany: {
      Post: {
        localField: 'posts',
        foreignKey: 'userId'
      },
      Comment: {
        localField: 'comments',
        foreignKey: 'userId'
      }
    },
    hasOne: {
      Profile: {
        localField: 'profile',
        foreignKey: 'userId'
      }
    }
  }
});

var Profile = reheat.defineModel('Profile', {
  tableName: 'profile',
  connection: connection,
  relations: {
    belongsTo: {
      User: {
        localKey: 'userId',
        localField: 'user'
      }
    }
  }
});

var Post = reheat.defineModel('Post', {
  tableName: 'post',
  connection: connection,
  relations: {
    belongsTo: {
      User: {
        localKey: 'userId',
        localField: 'user'
      }
    },
    hasMany: {
      Comment: {
        localField: 'comments',
        foreignKey: 'postId'
      }
    }
  }
});

var Comment = reheat.defineModel('Comment', {
  tableName: 'comment',
  connection: connection,
  relations: {
    belongsTo: {
      User: {
        localKey: 'userId',
        localField: 'user'
      },
      Post: {
        localKey: 'postId',
        localField: 'post'
      }
    }
  }
});
```

`localField` refers to attribute on the model instance where the relation will go. For example:

```js
User.get('1234', { with: ['Post'] }).then(function (user) {

  User.relations.hasMany.Post.localField; // "posts"

  // therefore
  console.log(user.get('posts') instanceof Post.collection); // true
});
```

`foreignKey` refers to the field on which the secondary index should be created in the relation's table. (Used with `hasOne` and `hasMany` relations.)

`localKey` refers to the field on which the secondary index should be created in the model's table. (Used with `belongsTo` relations.)

Examples:
```js
var Post = reheat.defineModel('Post', {
  tableName: 'post',
  connection: connection,
  relations: {
    belongsTo: {
      User: {
        localKey: 'userId', // secondary index on "userId" in the "post" table
        localField: 'user'
      }
    },
    hasMany: {
      Comment: {
        localField: 'comments',
        foreignKey: 'postId' // secondary index on "postId" in the "comment" table
      }
    }
  }
});
```

@doc overview
@id options
@name Querying Relations
@description

Methods that support quering relations:

- [Model#get(primaryKey[ options][, cb])](http://reheat/documentation/api/api/Model.static_methods:get)
- [Collection#findAll(predicate[, options][, cb])](http://reheat/documentation/api/api/Collection.static_methods:findAll)
- [Collection#getAll(keys, index[, options][, cb])](http://reheat/documentation/api/api/Collection.static_methods:getAll)

Examples:

```js
User.get('1234', { with: ['Profile'] }).then(function (user) {
  user.get('profile');
});

Posts.findAll({ author: 'John Anderson' }, { with: ['Comment'] }).then(function (posts) {
  posts.forEach(function (post) {
    post.get('comments');
  });
});

Users.getAll(['12345', '67890'], { with: ['Profile', 'Post', 'Comment'] }).then(function (users) {
  users.forEach(function (user) {
    user.get('profile');
    user.get('posts');
    user.get('comments');
  });
});
```

See the tests for more examples:

- [findOne.relations.test.js](https://github.com/jmdobry/reheat/blob/master/test/integration/model/static/findOne.relations.test.js)
- [findAll.relations.test.js](https://github.com/jmdobry/reheat/blob/master/test/integration/collection/static/findAll.relations.test.js)
- [getAll.relations.test.js](https://github.com/jmdobry/reheat/blob/master/test/integration/collection/static/getAll.relations.test.js)

@doc overview
@id instances
@name Saving/Destroy Relations
@description

When you call `Model#save` or `Model#destroy` you can pass an option (`deepSave` or `deepDestroy`) which cause `save` or `destroy` to be called
on any hasOne or hasMany relations loaded into model instance.

```js
var profileId;

User.get('12345', { with: ['Profile'] })
  .then(function (user) {
    profileId = user.get('profile').get('id');
    return user.destroy({ deepDestroy: true });
  })
  .then(function () {
    return User.get('12345');
  })
  .then(function (user) {
    user; // null

    return Profile.get(profileId);
  })
  .then(function (profile) {
    profile; // null
  });
```

`Model.destroyOne`, a static method, is a more efficient way to destroy a single row, along with any hasOne or hasMany relations.

```js
Model.destroyOne('12345', { with: ['Profile'] })
  .then(function (result) {
    result.deleted; // 1
    return User.get('12345');
  })
  .then(function (user) {
    user; // null

    return Profile.get(profileId);
  })
  .then(function (profile) {
    profile; // null
  });
```