Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rows to hasMany join table in order provided #862

Merged
merged 1 commit into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
### v8.0.0
- [POSSIBLY BREAKING] Add rows to hasMany join table in order provided (previously, they were added in reverse order) ([862](../../pull/862))

### v7.1.1
- Resolve most development-only security vulnerabilities (no production ones present) ([861](../../pull/861))
- Don't run test on node 10 & 12 - dev deps don't work
Expand Down
40 changes: 16 additions & 24 deletions lib/Associations/Many.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var _ = require("lodash");
var async = require("async");
var Hook = require("../Hook");
var Settings = require("../Settings");
var Property = require("../Property");
Expand Down Expand Up @@ -369,17 +370,13 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan
value: function () {
var Associations = [];
var opts = {};
var cb = noOperation;
var next = noOperation;

var run = function () {
var savedAssociations = [];
var saveNextAssociation = function () {
if (Associations.length === 0) {
return cb(null, savedAssociations);
}
var saveAssociation = function (Association, cb) {
const hookOpts = Object.keys(association.props).length > 0 ? opts : undefined;

var Association = Associations.pop();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the offending line. Rather than switch to .shift I decided to simplify by leveraging async.eachSeries.

var saveAssociation = function (err) {
Hook.wait(Association, association.hooks.beforeSave, function (err) {
if (err) {
return cb(err);
}
Expand All @@ -405,9 +402,7 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan
return cb(err);
}

savedAssociations.push(Association);

return saveNextAssociation();
return cb();
});
}

Expand All @@ -419,27 +414,24 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan
return cb(err);
}

savedAssociations.push(Association);

return saveNextAssociation();
return cb();
});
});
};

if (Object.keys(association.props).length) {
Hook.wait(Association, association.hooks.beforeSave, saveAssociation, opts);
} else {
Hook.wait(Association, association.hooks.beforeSave, saveAssociation);
}
}, hookOpts);
};

return saveNextAssociation();
async.eachSeries(Associations, saveAssociation, function (err) {
if (err) {
return next(err);
}
next(null, Associations);
});
};

for (var i = 0; i < arguments.length; i++) {
switch (typeof arguments[i]) {
case "function":
cb = arguments[i];
next = arguments[i];
break;
case "object":
if (Array.isArray(arguments[i])) {
Expand All @@ -462,7 +454,7 @@ function extendInstance(Model, Instance, Driver, association, opts, createInstan
} else {
this.save(function (err) {
if (err) {
return cb(err);
return next(err);
}

return run();
Expand Down
34 changes: 11 additions & 23 deletions lib/Associations/One.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var _ = require("lodash");
var async = require("async");
var util = require("../Utilities");
var ORMError = require("../Error");
var Accessors = { "get": "get", "set": "set", "has": "has", "del": "remove" };
Expand Down Expand Up @@ -214,52 +215,39 @@ function extendInstance(Model, Instance, Driver, association) {
writable: true
});
Object.defineProperty(Instance, association.setAccessor, {
value: function (OtherInstance, cb) {
value: function (OtherInstance, next) {
if (association.reversed) {
Instance.save(function (err) {
if (err) {
return cb(err);
return next(err);
}

if (!Array.isArray(OtherInstance)) {
util.populateConditions(Model, Object.keys(association.field), Instance, OtherInstance, true);

return OtherInstance.save({}, { saveAssociations: false }, cb);
return OtherInstance.save({}, { saveAssociations: false }, next);
}

var associations = _.clone(OtherInstance);

var saveNext = function () {
if (!associations.length) {
return cb();
}

var other = associations.pop();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also changed the order in which hasOne associations are saved from reverse to provided order.
No tests for this as it doesn't really affect anything.

var saveAssociation = function (otherInstance, cb) {
util.populateConditions(Model, Object.keys(association.field), Instance, otherInstance, true);

util.populateConditions(Model, Object.keys(association.field), Instance, other, true);

other.save({}, { saveAssociations: false }, function (err) {
if (err) {
return cb(err);
}

saveNext();
});
otherInstance.save({}, { saveAssociations: false }, cb);
};

return saveNext();
var associations = _.clone(OtherInstance);
async.eachSeries(associations, saveAssociation, next);
});
} else {
OtherInstance.save({}, { saveAssociations: false }, function (err) {
if (err) {
return cb(err);
return next(err);
}

Instance[association.name] = OtherInstance;

util.populateConditions(association.model, Object.keys(association.field), OtherInstance, Instance);

return Instance.save({}, { saveAssociations: false }, cb);
return Instance.save({}, { saveAssociations: false }, next);
});
}

Expand Down
40 changes: 20 additions & 20 deletions lib/Hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,30 @@ exports.trigger = function () {
}
};

exports.wait = function () {
var args = Array.prototype.slice.apply(arguments);
var self = args.shift();
var hook = args.shift();
var next = args.shift();
exports.wait = function (self, hook, next, opts) {
if (typeof hook !== "function") {
return next();
}

args.push(next);
Copy link
Collaborator Author

@dxg dxg Jun 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a bit complicated and it wasn't clear what it's actually doing (there's an optional opts parameter which gets passed to the hook).
Rewritten to make it more explicit.

if (typeof hook === "function") {
var hookValue = hook.apply(self, args);
var hookDoesntExpectCallback = hook.length < 1;
var hookValue;
if (opts) {
hookValue = hook.call(self, opts, next);
hookDoesntExpectCallback = hook.length < 2;
} else {
hookValue = hook.call(self, next);
}

var hookDoesntExpectCallback = hook.length < args.length;
var isPromise = hookValue && typeof(hookValue.then) === "function";
var isPromise = hookValue && typeof(hookValue.then) === "function";

if (hookDoesntExpectCallback) {
if (isPromise) {
return hookValue
.then(function () {
next();
})
.catch(next);
}
return next();
if (hookDoesntExpectCallback) {
if (isPromise) {
return hookValue
.then(function () {
next();
})
.catch(next);
}
} else {
return next();
}
};
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"sqlite",
"mongodb"
],
"version": "7.1.1",
"version": "8.0.0",
"license": "MIT",
"homepage": "http://dresende.github.io/node-orm2",
"repository": "http://github.com/dresende/node-orm2.git",
Expand Down
18 changes: 18 additions & 0 deletions test/integration/association-hasmany.js
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,24 @@ describe("hasMany", function () {
});
});

it("should add rows to join tables in order provided", async function () {
const pets = await Pet.createAsync([{ name: 'Fluffy' }, { name: 'Quacky' }, { name: 'Horsey' }]);
const Justin = await Person.oneAsync({ name: "Justin" });
const justinsPetsBefore = await Justin.getPetsAsync();
await Justin.addPetsAsync(pets);
const justinsPetsAfter = await Justin.getPetsAsync();

should.equal(justinsPetsBefore.length, justinsPetsAfter.length - 3);

const joinRows = await db.driver.execQueryAsync("SELECT * FROM person_pets");

should.deepEqual(
// Mysql returns array of RowDataPacket. Concert to plain object.
joinRows.slice(-pets.length).map((item) => Object.assign({}, item)),
pets.map(function (pet) { return { person_id: Justin.id, pets_id: pet.id }; }),
);
});

it("should throw if no items passed", function (done) {
Person.one(function (err, person) {
should.equal(err, null);
Expand Down