Skip to content

Commit

Permalink
start of relationship logic
Browse files Browse the repository at this point in the history
  • Loading branch information
MyMediaMagnet committed Mar 26, 2018
1 parent cf2bf98 commit 21f051d
Show file tree
Hide file tree
Showing 7 changed files with 271 additions and 6 deletions.
37 changes: 36 additions & 1 deletion dist/models/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ var _Query2 = require('./Query');

var _Query3 = _interopRequireDefault(_Query2);

var _Relationship = require('./Relationship');

var _Relationship2 = _interopRequireDefault(_Relationship);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
Expand Down Expand Up @@ -52,7 +56,13 @@ var Model = function (_Query) {
value: function set(data) {
for (var key in data) {
if (data.hasOwnProperty(key)) {
this[key] = data[key];
if (typeof this[key] == "function") {
// Setup the data for method access
this['_' + key] = data[key];
} else {
// Add the data as a property
this[key] = data[key];
}
}
}

Expand All @@ -61,6 +71,31 @@ var Model = function (_Query) {

// Create a collection consisting of this model

}, {
key: 'hasOne',


// Relationship Methods
// Use the relationship class to extend other model classes and give shorthand functionality

// Belongs To
value: function hasOne(instance) {
var data = this['_' + instance.constructor.name.toLowerCase()];

return instance.set(data);
}

// Has Many

}, {
key: 'hasMany',
value: function hasMany(instance) {
// We want to figure out information dynamically here about the caller of this method
// For example: user.posts().create({...}) we want to be able to send in who the user is so we are aware of it when creating the post
var items = this['_' + instance.route()];

return new _Relationship2.default(instance, items);
}
}], [{
key: 'collect',
value: function collect(items) {
Expand Down
5 changes: 5 additions & 0 deletions dist/models/Query.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ var Query = function () {
value: function collect(data) {
throw new Error('The collect method has not been properly implemented in the Query child class');
}
}, {
key: 'route',
value: function route() {
return pluralize.plural(this.constructor.name).toLowerCase();
}
}], [{
key: 'baseUrl',
value: function baseUrl() {
Expand Down
68 changes: 68 additions & 0 deletions dist/models/Relationship.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
"use strict";

Object.defineProperty(exports, "__esModule", {
value: true
});

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Relationship = function () {

// Setup a new Model instance
function Relationship(instance, items) {
_classCallCheck(this, Relationship);

this.instance = instance;
this.items = items;
this.collection = null;
}

_createClass(Relationship, [{
key: "first",
value: function first() {
return this.getCollection().first();
}
}, {
key: "last",
value: function last() {
return this.getCollection().last();
}
}, {
key: "nth",
value: function nth(i) {
return this.getCollection().nth(i);
}
}, {
key: "get",
value: function get() {
return this.getCollection().items;
}
}, {
key: "create",
value: function create(data) {
// This should dynamically get the id of the extending class...
// For example: user.posts().create({...}) should automagically send in the user_id with the post content
return Promise.resolve(this.instance.constructor.create(data));
}
}, {
key: "collect",
value: function collect() {
return this.getCollection();
}
}, {
key: "getCollection",
value: function getCollection() {
if (!this.collection) {
this.collection = this.instance.constructor.collect(this.items);
}

return this.collection;
}
}]);

return Relationship;
}();

exports.default = Relationship;
28 changes: 27 additions & 1 deletion src/models/Model.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Collection from '../classes/collection/Collection'
import Query from './Query'
import Relationship from './Relationship'
class Model extends Query{

// Setup a new Model instance
Expand All @@ -21,7 +22,13 @@ class Model extends Query{
set(data) {
for (var key in data) {
if (data.hasOwnProperty(key)) {
this[key] = data[key];
if(typeof this[key] == "function") {
// Setup the data for method access
this['_' + key] = data[key]
} else {
// Add the data as a property
this[key] = data[key];
}
}
}

Expand All @@ -42,6 +49,25 @@ class Model extends Query{
return new Collection()
}

// Relationship Methods
// Use the relationship class to extend other model classes and give shorthand functionality

// Belongs To
hasOne(instance) {
let data = this['_' + instance.constructor.name.toLowerCase()]

return instance.set(data)
}

// Has Many
hasMany(instance) {
// We want to figure out information dynamically here about the caller of this method
// For example: user.posts().create({...}) we want to be able to send in who the user is so we are aware of it when creating the post
let items = this['_' + instance.route()]

return new Relationship(instance, items)
}

}

export default Model;
4 changes: 4 additions & 0 deletions src/models/Query.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ class Query {
return 'api'
}

route() {
return pluralize.plural(this.constructor.name).toLowerCase()
}

static route() {
return pluralize.plural(this.name).toLowerCase()
}
Expand Down
45 changes: 45 additions & 0 deletions src/models/Relationship.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class Relationship{

// Setup a new Model instance
constructor(instance, items) {
this.instance = instance
this.items = items
this.collection = null
}

first () {
return this.getCollection().first()
}

last () {
return this.getCollection().last()
}

nth (i) {
return this.getCollection().nth(i)
}

get () {
return this.getCollection().items
}

create (data) {
// This should dynamically get the id of the extending class...
// For example: user.posts().create({...}) should automagically send in the user_id with the post content
return Promise.resolve(this.instance.constructor.create(data))
}

collect () {
return this.getCollection()
}

getCollection() {
if(!this.collection) {
this.collection = this.instance.constructor.collect(this.items)
}

return this.collection
}
}

export default Relationship;
90 changes: 86 additions & 4 deletions test/model.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
'use strict';

var expect = require('chai').expect;
let Collection = require('../dist/classes/collection/Collection').default
let Model = require('../dist/models/Model').default
let Query = require('../dist/models/Query').default
let Relationship = require('../dist/models/Relationship').default

describe('#Model', function() {

Expand Down Expand Up @@ -46,15 +48,95 @@ describe('#Model', function() {

it('it creates api routes based on the extending model', function() {
let object = {id: 1, name: 'Jack', email: 'jack@jones.ca'}
let user = new User()
user.set(object)
expect(User.route()).to.equal('users');
expect(User.getFullPath()).to.equal('/api/users/');
let user = new User(object)
expect(User.route()).to.equal('users')
expect(User.getFullPath()).to.equal('/api/users/')
});

it('it is able to get a hasMany relationship', function() {
let object = {id: 1, name: 'Jack', email: 'jack@jones.ca', posts: [{id: 1, title: 'Something Great'}, {id: 2, title: 'Something New'}]}
let user = new User(object)
expect(user.posts()).to.instanceof(Relationship);
expect(user.posts().get()).to.instanceof(Array);
expect(user.posts().first()).to.instanceof(Post);
expect(user.posts().collect()).to.instanceof(Collection);

expect(user.posts().first().title).to.equal("Something Great");
expect(user.posts().collect().last().title).to.equal("Something New");
});

it('it is able to create from a hasMany relationship', function() {
let object = {id: 99, name: 'Jack', email: 'jack@jones.ca', posts: [{id: 1, title: 'Something Great'}, {id: 2, title: 'Something New'}]}
let user = new User(object)

user.posts().create({id: 3, title: 'The Newest'}).catch(e => {
expect(e.config.data.user_id).to.equal(99)
expect(e.config.url).to.equal('/api/posts/create')
})
});

it('it is able to get from a belongsTo relationship', function() {
let object = {id: 1, title: "A Great Post", user: {id: 100, name: "Jack", email: 'test@tester.com'}}
let post = new Post(object)

expect(post.user()).to.instanceof(User);
expect(post.user().name).to.equal('Jack')
});

it('it is able to handle a chain of relationships', function() {
let object = {
id: 1,
title: "A Great Post",
user: {id: 100, name: "Jack", email: 'test@tester.com'},
comments: [
{id:1000, body: 'some comment', user:{id: 100, name: 'Jack', email: 'test@tester.com'}},
{id:1001, body: 'some other comment', user:{id: 101, name: 'Jones', email: 'jones@tester.com'}},
]
}
let post = new Post(object)

expect(post.comments()).to.instanceof(Relationship);
expect(post.comments().first().user().name).to.equal('Jack')
expect(post.comments().last().user().name).to.equal('Jones')
});


});

class User extends Model {
constructor(data) {
super(data)
}

posts() {
return this.hasMany(new Post)
}
}

class Post extends Model {
constructor(data) {
super(data)
}

user() {
return this.hasOne(new User)
}

comments() {
return this.hasMany(new Comment)
}
}

class Comment extends Model {
constructor(data) {
super(data)
}

user() {
return this.hasOne(new User)
}

post() {
return this.hasOne(new Post)
}
}

0 comments on commit 21f051d

Please sign in to comment.