Make [.find|.where|.all] synonyms & chain multiple times by dxg · Pull Request #758 · dresende/node-orm2 · GitHub
Skip to content
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
2 changes: 1 addition & 1 deletion .travis.yml
4 changes: 4 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
### v3.2.0
- Make [.find|.where|.all] synonyms & allow them to chain multiple times
- Update dependencies

### v3.1.0
- Add `enumerable` flag to exclude instance properties from enumeration ([#724](../../issues/724))

Expand Down
4 changes: 3 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ Person.aggregate(["age"], { country: "someCountry" }).avg("weight").groupBy("age

There are more aggregate functions depending on the driver (Math functions for example).

#### Chaining
### Chaining

If you prefer less complicated syntax you can chain `.find()` by not giving a callback parameter.

Expand All @@ -410,6 +410,8 @@ It's bad practice to manually escape SQL parameters as it's error prone and expo
The `?` syntax takes care of escaping for you, by safely substituting the question mark in the query with the parameters provided.
You can also chain multiple `where` clauses as needed.

`.find`, `.where` & `.all` do the same thing; they are all interchangeable and chainable.

You can also `order` or `orderRaw`:
```js
Person.find({ age: 18 }).order('-name').all( ... );
Expand Down
153 changes: 77 additions & 76 deletions lib/ChainFind.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,77 @@ function ChainFind(Model, opts) {
);
};

var chainRun = function (cb) {
var order, conditions;

conditions = Utilities.transformPropertyNames(
opts.conditions, opts.properties
);
order = Utilities.transformOrderPropertyNames(
opts.order, opts.properties
);

opts.driver.find(opts.only, opts.table, conditions, {
limit : opts.limit,
order : order,
merge : opts.merge,
offset : opts.offset,
exists : opts.exists
}, function (err, data) {
if (err) {
return cb(err);
}
if (data.length === 0) {
return cb(null, []);
}
var pending = data.length;

var createInstance = function (idx) {
opts.newInstance(data[idx], function (err, instance) {
data[idx] = instance;

if (--pending === 0) {
return (opts.__eager && opts.__eager.length ? eagerLoading : cb)(null, data);
}
});
};

var eagerLoading = function (err, data) {
var pending = opts.__eager.length;
var idMap = {};
var count = 0;

var keys = _.map(data, function (instance) {
var key = instance[opts.keys[0]];
// Create the association arrays
for (var i = 0, association; association = opts.__eager[i]; i++) {
instance[association.name] = [];
}

idMap[key] = count++;
return key;
});

_.map(opts.__eager, function (association) {
opts.driver.eagerQuery(association, opts, keys, function (err, instances) {
for (var i = 0, instance; instance = instances[i]; i++) {
// Perform a parent lookup with $p, and initialize it as an instance.
data[idMap[instance.$p]][association.name].push(association.model(instance));
}

if (--pending === 0) {
return cb(null, data);
}
});
});
};

for (var i = 0; i < data.length; i++) {
createInstance(i);
}
});
}

var promise = null;
var chain = {
find: function () {
Expand All @@ -38,7 +109,7 @@ function ChainFind(Model, opts) {
}

if (cb) {
return this.all(cb);
chainRun(cb);
}
return this;
},
Expand Down Expand Up @@ -149,7 +220,8 @@ function ChainFind(Model, opts) {
return new ChainInstance(this, cb);
},
run: function (cb) {
return this.all(cb);
chainRun(cb);
return this;
},
success: function (cb) {
if (!promise) {
Expand Down Expand Up @@ -178,81 +250,10 @@ function ChainFind(Model, opts) {
return ~associations.indexOf(association.name);
});

return this;
},
all: function (cb) {
var order, conditions;

conditions = Utilities.transformPropertyNames(
opts.conditions, opts.properties
);
order = Utilities.transformOrderPropertyNames(
opts.order, opts.properties
);

opts.driver.find(opts.only, opts.table, conditions, {
limit : opts.limit,
order : order,
merge : opts.merge,
offset : opts.offset,
exists : opts.exists
}, function (err, data) {
if (err) {
return cb(err);
}
if (data.length === 0) {
return cb(null, []);
}
var pending = data.length;

var createInstance = function (idx) {
opts.newInstance(data[idx], function (err, instance) {
data[idx] = instance;

if (--pending === 0) {
return (opts.__eager && opts.__eager.length ? eagerLoading : cb)(null, data);
}
});
};

var eagerLoading = function (err, data) {
var pending = opts.__eager.length;
var idMap = {};
var count = 0;

var keys = _.map(data, function (instance) {
var key = instance[opts.keys[0]];
// Create the association arrays
for (var i = 0, association; association = opts.__eager[i]; i++) {
instance[association.name] = [];
}

idMap[key] = count++;
return key;
});

_.map(opts.__eager, function (association) {
opts.driver.eagerQuery(association, opts, keys, function (err, instances) {
for (var i = 0, instance; instance = instances[i]; i++) {
// Perform a parent lookup with $p, and initialize it as an instance.
data[idMap[instance.$p]][association.name].push(association.model(instance));
}

if (--pending === 0) {
return cb(null, data);
}
});
});
};

for (var i = 0; i < data.length; i++) {
createInstance(i);
}
});
return this;
}
};
chain.where = chain.find;
chain.all = chain.where = chain.find;

if (opts.associations) {
for (var i = 0; i < opts.associations.length; i++) {
Expand All @@ -262,12 +263,12 @@ function ChainFind(Model, opts) {
for (var k in Model) {
if ([
"hasOne", "hasMany",
"drop", "sync", "get", "find", "all", "count", "clear", "create",
"drop", "sync", "get", "clear", "create",
"exists", "settings", "aggregate"
].indexOf(k) >= 0) {
continue;
}
if (typeof Model[k] !== "function") {
if (typeof Model[k] !== "function" || chain[k]) {
continue;
}

Expand Down
9 changes: 4 additions & 5 deletions lib/Model.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,14 +426,13 @@ function Model(opts) {

if (typeof cb !== "function") {
return chain;
} else {
chain.run(cb);
return this;
}

chain.run(cb);

return this;
};

model.all = model.find;
model.where = model.all = model.find;

model.one = function () {
var args = Array.prototype.slice.apply(arguments);
Expand Down
20 changes: 10 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"sqlite",
"mongodb"
],
"version" : "3.1.0",
"version" : "3.2.0",
"license" : "MIT",
"homepage" : "http://dresende.github.io/node-orm2",
"repository" : "http://github.com/dresende/node-orm2.git",
Expand All @@ -38,20 +38,20 @@
"dependencies": {
"enforce" : "0.1.6",
"sql-query" : "0.1.26",
"sql-ddl-sync" : "0.3.11",
"sql-ddl-sync" : "0.3.12",
"hat" : "0.0.3",
"lodash" : "4.11.2",
"path-is-absolute" : "1.0.0"
"lodash" : "4.17.2",
"path-is-absolute" : "1.0.1"
},
"devDependencies": {
"mysql" : "2.10.2",
"pg" : "4.5.5",
"sqlite3" : "3.1.3",
"mysql" : "2.12.0",
"pg" : "6.1.0",
"sqlite3" : "3.1.8",
"async" : "1.5.2",
"mocha" : "2.4.5",
"should" : "8.3.1",
"mocha" : "3.2.0",
"should" : "11.1.1",
"mongodb" : "1.4.10",
"glob" : "7.0.3"
"glob" : "7.1.1"
},
"optionalDependencies": {}
}
40 changes: 40 additions & 0 deletions test/integration/model-find-chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,46 @@ describe("Model.find() chaining", function() {
});
});

describe("finders should be chainable & interchangeable including", function () {
before(setup());

before(function (done) {
Person.create([
{ name: "Mel", surname: "Gabbs", age: 12 },
{ name: "Mel", surname: "Gibbs", age: 22 },
{ name: "Mel", surname: "Gobbs", age: 32 }
], function (err, items) {
should.not.exist(err);
done()
}
);
});

['find', 'where', 'all'].forEach(function (func) {
it("." + func + "()", function (done) {
Person[func]({ name: "Mel" })[func]({ age: ORM.gt(20) })[func](function (err, items) {
should.not.exist(err);
should.equal(items.length, 2);

should.equal(items[0].surname, "Gibbs");
should.equal(items[1].surname, "Gobbs");
done();
});
});
});

it("a mix", function (done) {
Person.all({ name: "Mel" }).where({ age: ORM.gt(20) }).find(function (err, items) {
should.not.exist(err);
should.equal(items.length, 2);

should.equal(items[0].surname, "Gibbs");
should.equal(items[1].surname, "Gobbs");
done();
});
});
});

describe(".each()", function () {
before(setup());

Expand Down
14 changes: 14 additions & 0 deletions test/integration/model-find.js