Skip to content

Commit c258914

Browse files
committed
Merge pull request #73 from digitalsadhu/resource_creation_update_relationships
Resource creation update relationships
2 parents 006e099 + 5d66dc9 commit c258914

File tree

9 files changed

+699
-256
lines changed

9 files changed

+699
-256
lines changed

lib/create.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ module.exports = function (app, options) {
1111

1212
//in this case we are only interested in handling create operations.
1313
if (ctx.method.name === 'create') {
14-
1514
//JSON API specifies that created resources should have the
1615
//http status code of 201
1716
ctx.res.statusCode = 201;

lib/deserialize.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use strict';
22
var deserializer = require('./deserializer');
3+
34
var utils = require('./utils');
45

56
module.exports = function (app) {

lib/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ var create = require('./create');
1010
var update = require('./update');
1111
var del = require('./delete');
1212
var errors = require('./errors');
13+
var relationships = require('./relationships');
1314
var debug = require('debug')('loopback-component-jsonapi');
1415

1516
module.exports = function (app, options) {
@@ -27,6 +28,7 @@ module.exports = function (app, options) {
2728
debug('Started');
2829
options.debug = debug;
2930
headers(app, options);
31+
relationships(app, options);
3032
removeRemoteMethods(app, options);
3133
patch(app, options);
3234
serialize(app, options);
@@ -35,4 +37,5 @@ module.exports = function (app, options) {
3537
update(app, options);
3638
errors(app, options);
3739
del(app, options);
40+
3841
};

lib/relationships.js

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
'use strict';
2+
3+
var _ = require('lodash');
4+
var utils = require('./utils');
5+
6+
module.exports = function (app, options) {
7+
//get remote methods.
8+
//set strong-remoting for more information
9+
//https://github.com/strongloop/strong-remoting
10+
var remotes = app.remotes();
11+
var id, data, model;
12+
13+
remotes.before('**', function (ctx, next) {
14+
15+
id = ctx.req.params.id;
16+
data = ctx.args.data;
17+
model = utils.getModelFromContext(ctx, app);
18+
relationships(id, data, model);
19+
20+
next();
21+
});
22+
23+
// for create
24+
remotes.after('**', function (ctx, next) {
25+
26+
if (ctx.result) {
27+
id = ctx.result.id;
28+
data = ctx.req.body;
29+
model = utils.getModelFromContext(ctx, app);
30+
relationships(id, data, model);
31+
};
32+
33+
next();
34+
});
35+
36+
};
37+
38+
function relationships (id, data, model) {
39+
40+
if (!data || !data.data || !id || !model || !data.data.relationships) {
41+
return;
42+
}
43+
44+
_.each(data.data.relationships, function (relationship, name) {
45+
46+
var serverRelation = model.relations[name];
47+
var type = serverRelation.type;
48+
var modelTo = serverRelation.modelTo;
49+
50+
var fkName = serverRelation.keyTo;
51+
52+
if (type === 'belongsTo') {
53+
fkName = serverRelation.keyFrom;
54+
modelTo = serverRelation.modelFrom;
55+
}
56+
57+
if (!modelTo) {
58+
return false;
59+
}
60+
61+
var setTo = {};
62+
setTo[fkName] = null;
63+
var where = {};
64+
where[fkName] = id;
65+
66+
// remove all relations to the model (eg .: post/1)
67+
if (type !== 'belongsTo') {
68+
modelTo.updateAll(where, setTo, function (err, info) {
69+
if (err) {console.log(err);}
70+
});
71+
}
72+
73+
var idToFind = null;
74+
75+
if (_.isArray(relationship.data)) {
76+
// find all instance from the relation data eg
77+
// [{type: "comments", id: 1}, {type: "comments", id: 2}]
78+
_.each(relationship.data, function (item) {
79+
idToFind = item.id;
80+
81+
if (type === 'belongsTo') {
82+
where[fkName] = item.id;
83+
idToFind = id;
84+
}
85+
86+
updateRelation(modelTo, idToFind, where);
87+
});
88+
} else {
89+
90+
if (relationship.data === null) {
91+
where[fkName] = null;
92+
updateRelation(model, id, where);
93+
return;
94+
}
95+
96+
idToFind = relationship.data.id;
97+
98+
if (type === 'belongsTo') {
99+
idToFind = id;
100+
where[fkName] = relationship.data.id;
101+
}
102+
// relationship: {data: {type: "comments": id: 1}}
103+
updateRelation(modelTo, idToFind, where);
104+
}
105+
106+
});
107+
108+
return;
109+
}
110+
111+
// if the instance exist, then update it (create relationship),
112+
// according to JSON API spec we MUST NOT create new ones
113+
function updateRelation (model, id, data) {
114+
115+
model.findById(id, function (err, instance) {
116+
if (err) {console.log(err);}
117+
118+
if (instance !== null) {
119+
instance.updateAttributes(data);
120+
}
121+
122+
});
123+
}

test/belongsTo.test.js

Lines changed: 0 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -327,78 +327,6 @@ describe('loopback json api belongsTo relationships', function () {
327327
});
328328
});
329329

330-
describe.skip('link related models as part of a create operation', function () {
331-
it('should create and link models', function (done) {
332-
request(app).post('/posts')
333-
.send({
334-
data: {type: 'posts', attributes: {title: 'my post', content: 'my post content' }},
335-
relationships: {comments: {data: [
336-
{type: 'comments', id: 1}
337-
]}}
338-
})
339-
.set('Accept', 'application/vnd.api+json')
340-
.set('Content-Type', 'application/json')
341-
.end(function (err, res) {
342-
expect(err).to.equal(null);
343-
Comment.findById(1, function (err, comment) {
344-
expect(err).to.equal(null);
345-
expect(comment).not.to.equal(null);
346-
expect(comment.postId).to.equal(2);
347-
done();
348-
});
349-
});
350-
});
351-
});
352-
353-
describe.skip('delete linkages to models as part of an update operation', function () {
354-
it('should update model linkages', function (done) {
355-
request(app).patch('/posts/1')
356-
.send({
357-
data: {type: 'posts', attributes: {title: 'my post', content: 'my post content' }},
358-
relationships: {comments: {data: []}}
359-
})
360-
.set('Accept', 'application/vnd.api+json')
361-
.set('Content-Type', 'application/json')
362-
.end(function (err, res) {
363-
expect(err).to.equal(null);
364-
Comment.findById(1, function (err, comment) {
365-
expect(err).to.equal(null);
366-
expect(comment).not.to.equal(null);
367-
expect(comment.postId).to.equal(null);
368-
done();
369-
});
370-
});
371-
});
372-
});
373-
374-
describe.skip('replace linkages as part of an update operation', function () {
375-
beforeEach(function (done) {
376-
Comment.create({
377-
title: 'my comment 2',
378-
comment: 'my post comment 2'
379-
}, done);
380-
});
381-
it('should update model linkages', function (done) {
382-
request(app).patch('/posts/1').send({
383-
data: {type: 'posts', attributes: {title: 'my post', content: 'my post content' }},
384-
relationships: {comments: {data: [
385-
{type: 'comments', id: 1},
386-
{type: 'comments', id: 2}
387-
]}}
388-
})
389-
.set('Accept', 'application/vnd.api+json')
390-
.set('Content-Type', 'application/json')
391-
.end(function (err, res) {
392-
expect(err).to.equal(null);
393-
Comment.find({postId: 1}, function (err, comments) {
394-
expect(err).to.equal(null);
395-
expect(comments.length).to.equal(2);
396-
done();
397-
});
398-
});
399-
});
400-
});
401-
402330
describe.skip('link related models using relationship url', function () {
403331
beforeEach(function (done) {
404332
Post.create({name: 'my post', content: 'my post content'}, done);
@@ -425,53 +353,5 @@ describe('loopback json api belongsTo relationships', function () {
425353
});
426354
});
427355

428-
describe.skip('delete linkages to models as part of an update operation', function () {
429-
it('should update model linkages', function (done) {
430-
request(app).patch('/posts/1')
431-
.send({
432-
data: {type: 'posts', attributes: {title: 'my post', content: 'my post content' }},
433-
relationships: {comments: {data: []}}
434-
})
435-
.set('Accept', 'application/vnd.api+json')
436-
.set('Content-Type', 'application/json')
437-
.end(function (err, res) {
438-
expect(err).to.equal(null);
439-
Comment.findById(1, function (err, comment) {
440-
expect(err).to.equal(null);
441-
expect(comment).not.to.equal(null);
442-
expect(comment.postId).to.equal(null);
443-
done();
444-
});
445-
});
446-
});
447-
});
448-
449-
describe.skip('replace linkages as part of an update operation', function () {
450-
beforeEach(function (done) {
451-
Post.create({
452-
name: 'my post',
453-
content: 'my post content'
454-
}, done);
455-
});
456-
it('should update model linkages', function (done) {
457-
request(app).patch('/posts/1').send({
458-
data: {type: 'posts', attributes: {title: 'my post', content: 'my post content' }},
459-
relationships: {comments: {data: [
460-
{type: 'comments', id: 1},
461-
{type: 'comments', id: 2}
462-
]}}
463-
})
464-
.set('Accept', 'application/vnd.api+json')
465-
.set('Content-Type', 'application/json')
466-
.end(function (err, res) {
467-
expect(err).to.equal(null);
468-
Comment.find({postId: 1}, function (err, comments) {
469-
expect(err).to.equal(null);
470-
expect(comments.length).to.equal(2);
471-
done();
472-
});
473-
});
474-
});
475-
});
476356
});
477357
});

test/hasMany.test.js

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -276,76 +276,5 @@ describe('loopback json api hasMany relationships', function () {
276276
});
277277
});
278278

279-
describe.skip('link related models as part of a create operation', function () {
280-
it('should create and link models', function (done) {
281-
request(app).post('/posts')
282-
.send({
283-
data: {type: 'posts', attributes: {title: 'my post', content: 'my post content' }},
284-
relationships: {comments: {data: [
285-
{type: 'comments', id: 1}
286-
]}}
287-
})
288-
.set('Accept', 'application/vnd.api+json')
289-
.set('Content-Type', 'application/json')
290-
.end(function (err, res) {
291-
expect(err).to.equal(null);
292-
Comment.findById(1, function (err, comment) {
293-
expect(err).to.equal(null);
294-
expect(comment).not.to.equal(null);
295-
expect(comment.postId).to.equal(2);
296-
done();
297-
});
298-
});
299-
});
300-
});
301-
302-
describe.skip('delete linkages to models as part of an update operation', function () {
303-
it('should update model linkages', function (done) {
304-
request(app).patch('/posts/1')
305-
.send({
306-
data: {type: 'posts', attributes: {title: 'my post', content: 'my post content' }},
307-
relationships: {comments: {data: []}}
308-
})
309-
.set('Accept', 'application/vnd.api+json')
310-
.set('Content-Type', 'application/json')
311-
.end(function (err, res) {
312-
expect(err).to.equal(null);
313-
Comment.findById(1, function (err, comment) {
314-
expect(err).to.equal(null);
315-
expect(comment).not.to.equal(null);
316-
expect(comment.postId).to.equal(null);
317-
done();
318-
});
319-
});
320-
});
321-
});
322-
323-
describe.skip('replace linkages as part of an update operation', function () {
324-
beforeEach(function (done) {
325-
Comment.create({
326-
title: 'my comment 2',
327-
comment: 'my post comment 2'
328-
}, done);
329-
});
330-
it('should update model linkages', function (done) {
331-
request(app).patch('/posts/1').send({
332-
data: {type: 'posts', attributes: {title: 'my post', content: 'my post content' }},
333-
relationships: {comments: {data: [
334-
{type: 'comments', id: 1},
335-
{type: 'comments', id: 2}
336-
]}}
337-
})
338-
.set('Accept', 'application/vnd.api+json')
339-
.set('Content-Type', 'application/json')
340-
.end(function (err, res) {
341-
expect(err).to.equal(null);
342-
Comment.find({postId: 1}, function (err, comments) {
343-
expect(err).to.equal(null);
344-
expect(comments.length).to.equal(2);
345-
done();
346-
});
347-
});
348-
});
349-
});
350279
});
351280
});

0 commit comments

Comments
 (0)