Skip to content

Commit 3d1d026

Browse files
committed
Don't auto save associations after autofetching them.
Closes #398
1 parent 7e3d4b5 commit 3d1d026

File tree

5 files changed

+113
-16
lines changed

5 files changed

+113
-16
lines changed

Readme.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,10 @@ patient.removeDoctors(docs, function...) // Removes specified doctors from join
657657

658658
doctor.getPatients(function..)
659659
etc...
660+
661+
// You can also do:
662+
patient.doctors = [doc1, doc2];
663+
patient.save(...)
660664
```
661665

662666
To associate a doctor to a patient:

lib/Associations/Many.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan
227227
}
228228

229229
association.model.find(conditions, options, cb);
230+
230231
return this;
231232
},
232233
enumerable: false,
@@ -409,6 +410,17 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan
409410
enumerable: false,
410411
writable: true
411412
});
413+
414+
Object.defineProperty(Instance, association.name, {
415+
get: function () {
416+
return Instance.__opts.associations[association.name].value;
417+
},
418+
set: function (val) {
419+
Instance.__opts.associations[association.name].changed = true;
420+
Instance.__opts.associations[association.name].value = val;
421+
},
422+
enumerable: true
423+
});
412424
}
413425

414426
function autoFetchInstance(Instance, association, opts, cb) {
@@ -426,7 +438,8 @@ function autoFetchInstance(Instance, association, opts, cb) {
426438

427439
Instance[association.getAccessor]({}, { autoFetchLimit: opts.autoFetchLimit - 1 }, function (err, Assoc) {
428440
if (!err) {
429-
Instance[association.name] = Assoc;
441+
// Set this way to prevent setting 'changed' status
442+
Instance.__opts.associations[association.name].value = Assoc;
430443
}
431444

432445
return cb();

lib/Instance.js

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ function Instance(Model, opts) {
1111
opts.id = opts.id || "id";
1212
opts.changes = (opts.is_new ? Object.keys(opts.data) : []);
1313
opts.extrachanges = [];
14+
opts.associations = {};
1415

1516
var instance_saving = false;
1617
var events = {};
@@ -297,18 +298,18 @@ function Instance(Model, opts) {
297298

298299

299300
var _saveManyAssociation = function (assoc) {
300-
if (!instance.hasOwnProperty(assoc.name)) return;
301-
if (!Array.isArray(instance[assoc.name])) {
302-
instance[assoc.name] = [ instance[assoc.name] ];
303-
}
301+
var assocVal = instance[assoc.name];
302+
303+
if (!Array.isArray(assocVal)) return;
304+
if (!opts.associations[assoc.name].changed) return;
304305

305-
for (j = 0; j < instance[assoc.name].length; j++) {
306-
if (!instance[assoc.name][j].isInstance) {
307-
instance[assoc.name][j] = new assoc.model(instance[assoc.name][j]);
306+
for (j = 0; j < assocVal.length; j++) {
307+
if (!assocVal[j].isInstance) {
308+
assocVal[j] = new assoc.model(assocVal[j]);
308309
}
309310
}
310311

311-
return saveAssociation(assoc.setAccessor, instance[assoc.name]);
312+
saveAssociation(assoc.setAccessor, assocVal);
312313
};
313314

314315
for (i = 0; i < opts.many_associations.length; i++) {
@@ -619,6 +620,10 @@ function Instance(Model, opts) {
619620
},
620621
enumerable: false
621622
});
623+
Object.defineProperty(instance, "__opts", {
624+
value: opts,
625+
enumerable: false
626+
});
622627
Object.defineProperty(instance, "model", {
623628
value: function (cb) {
624629
return Model;
@@ -632,6 +637,9 @@ function Instance(Model, opts) {
632637
break;
633638
}
634639
}
640+
641+
opts.setupAssociations(instance);
642+
635643
for (i = 0; i < opts.one_associations.length; i++) {
636644
var asc = opts.one_associations[i];
637645

@@ -666,9 +674,14 @@ function Instance(Model, opts) {
666674
}
667675
}
668676
for (i = 0; i < opts.many_associations.length; i++) {
669-
if (opts.data.hasOwnProperty(opts.many_associations[i].name)) {
670-
instance[opts.many_associations[i].name] = opts.data[opts.many_associations[i].name];
671-
delete opts.data[opts.many_associations[i].name];
677+
var aName = opts.many_associations[i].name;
678+
opts.associations[aName] = {
679+
changed: false, data: opts.many_associations[i]
680+
};
681+
682+
if (Array.isArray(opts.data[aName])) {
683+
instance[aName] = opts.data[aName];
684+
delete opts.data[aName];
672685
}
673686
}
674687

lib/Model.js

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,13 @@ function Model(opts) {
8383
autoFetchLimit : inst_opts.autoFetchLimit,
8484
cascadeRemove : inst_opts.cascadeRemove
8585
};
86+
87+
var setupAssociations = function (instance) {
88+
OneAssociation.extend(model, instance, opts.driver, one_associations, assoc_opts);
89+
ManyAssociation.extend(model, instance, opts.driver, many_associations, assoc_opts, createInstance);
90+
ExtendAssociation.extend(model, instance, opts.driver, extend_associations, assoc_opts);
91+
};
92+
8693
var pending = 2, create_err = null;
8794
var instance = new Instance(model, {
8895
uid : inst_opts.uid, // singleton unique id
@@ -101,7 +108,8 @@ function Model(opts) {
101108
one_associations : one_associations,
102109
many_associations : many_associations,
103110
extend_associations : extend_associations,
104-
association_properties : association_properties
111+
association_properties : association_properties,
112+
setupAssociations : setupAssociations
105113
});
106114
instance.on("ready", function (err) {
107115
if (--pending > 0) {
@@ -115,9 +123,6 @@ function Model(opts) {
115123
if (model_fields !== null) {
116124
LazyLoad.extend(instance, model, opts.properties);
117125
}
118-
OneAssociation.extend(model, instance, opts.driver, one_associations, assoc_opts);
119-
ManyAssociation.extend(model, instance, opts.driver, many_associations, assoc_opts, createInstance);
120-
ExtendAssociation.extend(model, instance, opts.driver, extend_associations, assoc_opts);
121126

122127
OneAssociation.autoFetch(instance, one_associations, assoc_opts, function () {
123128
ManyAssociation.autoFetch(instance, many_associations, assoc_opts, function () {

test/integration/association-hasmany.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,5 +541,67 @@ describe("hasMany", function () {
541541
});
542542
});
543543
});
544+
545+
it("should not auto save associations which were autofetched", function (done) {
546+
Pet.all(function (err, pets) {
547+
should.not.exist(err);
548+
should.equal(pets.length, 2);
549+
550+
Person.create({ name: 'Paul' }, function (err, paul) {
551+
should.not.exist(err);
552+
553+
Person.one({ name: 'Paul' }, function (err, paul2) {
554+
should.not.exist(err);
555+
should.equal(paul2.pets.length, 0);
556+
557+
paul.setPets(pets, function (err) {
558+
should.not.exist(err);
559+
560+
// reload paul to make sure we have 2 pets
561+
Person.one({ name: 'Paul' }, function (err, paul) {
562+
should.not.exist(err);
563+
should.equal(paul.pets.length, 2);
564+
565+
// Saving paul2 should NOT auto save associations and hence delete
566+
// the associations we just created.
567+
paul2.save(function (err) {
568+
should.not.exist(err);
569+
570+
// let's check paul - pets should still be associated
571+
Person.one({ name: 'Paul' }, function (err, paul) {
572+
should.not.exist(err);
573+
should.equal(paul.pets.length, 2);
574+
575+
done();
576+
});
577+
});
578+
});
579+
});
580+
});
581+
});
582+
});
583+
});
584+
585+
it("should save associations set by the user", function (done) {
586+
Person.one({ name: 'John' }, function (err, john) {
587+
should.not.exist(err);
588+
should.equal(john.pets.length, 2);
589+
590+
john.pets = [];
591+
592+
john.save(function (err) {
593+
should.not.exist(err);
594+
595+
// reload john to make sure pets were deleted
596+
Person.one({ name: 'John' }, function (err, john) {
597+
should.not.exist(err);
598+
should.equal(john.pets.length, 0);
599+
600+
done();
601+
});
602+
});
603+
});
604+
});
605+
544606
});
545607
});

0 commit comments

Comments
 (0)