Merge branch 'release/2.13.0' into production
This commit is contained in:
commit
dfd26e4c23
118
CHANGES.md
118
CHANGES.md
|
@ -1,4 +1,42 @@
|
||||||
2014-12-09, Version 2.12.0
|
2015-01-07, Version 2.13.0
|
||||||
|
==========================
|
||||||
|
|
||||||
|
* added test for sorting undefined values (Christian Vette)
|
||||||
|
|
||||||
|
* Fix the floating number comparison (Raymond Feng)
|
||||||
|
|
||||||
|
* Fix bad CLA URL in CONTRIBUTING.md (Ryan Graham)
|
||||||
|
|
||||||
|
* replace deprecated function __defineGetter__ (bitmage)
|
||||||
|
|
||||||
|
* add a flag to callback of findOrCreate to indicate find or create (Clark Wang)
|
||||||
|
|
||||||
|
* fix sorting of undefined values with multiple columns (Christian Vette)
|
||||||
|
|
||||||
|
* code style (cvette)
|
||||||
|
|
||||||
|
* fix sorting with undefined in memory connector (cvette)
|
||||||
|
|
||||||
|
* Added support for inline parameters like: new GeoPoint(-34, 150) (Simo Moujami)
|
||||||
|
|
||||||
|
* fix default include in default scope fails findById (Clark Wang)
|
||||||
|
|
||||||
|
* Added test for toString() (Simo Moujami)
|
||||||
|
|
||||||
|
* Additional formatting (Simo Moujami)
|
||||||
|
|
||||||
|
* Fixed constructor parameters and added bdd tests for constructor validation (Simo Moujami)
|
||||||
|
|
||||||
|
* Fixed indentation (Simo Moujami)
|
||||||
|
|
||||||
|
* Added mocha tests for GeoPoint (Simo Moujami)
|
||||||
|
|
||||||
|
* renamed intermediary variable (Simo Moujami)
|
||||||
|
|
||||||
|
* Fixed the haversine formula to calculate distance between 2 points properly (Simo Moujami)
|
||||||
|
|
||||||
|
|
||||||
|
2014-12-08, Version 2.12.0
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
* Relax the id comparison (Raymond Feng)
|
* Relax the id comparison (Raymond Feng)
|
||||||
|
@ -391,19 +429,16 @@
|
||||||
|
|
||||||
* Cleanup mixin tests (Fabien Franzen)
|
* Cleanup mixin tests (Fabien Franzen)
|
||||||
|
|
||||||
* Fix a name conflict in scope metadata (Raymond Feng)
|
|
||||||
|
|
||||||
|
|
||||||
2014-08-08, Version 2.3.0
|
|
||||||
=========================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2014-08-08, Version 2.3.1
|
2014-08-08, Version 2.3.1
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
* Fix a name conflict in scope metadata (Raymond Feng)
|
* Fix a name conflict in scope metadata (Raymond Feng)
|
||||||
|
|
||||||
|
|
||||||
|
2014-08-08, Version 2.3.0
|
||||||
|
=========================
|
||||||
|
|
||||||
* Fix the test case so that it works with other DBs (Raymond Feng)
|
* Fix the test case so that it works with other DBs (Raymond Feng)
|
||||||
|
|
||||||
* Bump version (Raymond Feng)
|
* Bump version (Raymond Feng)
|
||||||
|
@ -516,6 +551,8 @@
|
||||||
|
|
||||||
* Implemented embedsMany relation (Fabien Franzen)
|
* Implemented embedsMany relation (Fabien Franzen)
|
||||||
|
|
||||||
|
* Fix a regression where undefined id should not match any record (Raymond Feng)
|
||||||
|
|
||||||
* Minor tweaks; pass-through properties/scope for hasAndBelongsToMany (Fabien Franzen)
|
* Minor tweaks; pass-through properties/scope for hasAndBelongsToMany (Fabien Franzen)
|
||||||
|
|
||||||
* Implemented polymorphic hasMany through inverse (Fabien Franzen)
|
* Implemented polymorphic hasMany through inverse (Fabien Franzen)
|
||||||
|
@ -531,6 +568,11 @@
|
||||||
* Implemented polymorphic hasMany (Fabien Franzen)
|
* Implemented polymorphic hasMany (Fabien Franzen)
|
||||||
|
|
||||||
|
|
||||||
|
2014-07-27, Version 2.1.0
|
||||||
|
=========================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2014-07-27, Version 2.1.1
|
2014-07-27, Version 2.1.1
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
@ -538,12 +580,6 @@
|
||||||
|
|
||||||
* Fix a regression where undefined id should not match any record (Raymond Feng)
|
* Fix a regression where undefined id should not match any record (Raymond Feng)
|
||||||
|
|
||||||
|
|
||||||
2014-07-27, Version 2.1.0
|
|
||||||
=========================
|
|
||||||
|
|
||||||
* Bump version (Raymond Feng)
|
|
||||||
|
|
||||||
* datasource: support connectors without `getTypes` (Miroslav Bajtoš)
|
* datasource: support connectors without `getTypes` (Miroslav Bajtoš)
|
||||||
|
|
||||||
* relation: add `scope._target` for `hasOne` (Miroslav Bajtoš)
|
* relation: add `scope._target` for `hasOne` (Miroslav Bajtoš)
|
||||||
|
@ -628,6 +664,10 @@
|
||||||
|
|
||||||
* Add missing inflection dep back (Raymond Feng)
|
* Add missing inflection dep back (Raymond Feng)
|
||||||
|
|
||||||
|
|
||||||
|
2014-07-15, Version 2.0.0-beta3
|
||||||
|
===============================
|
||||||
|
|
||||||
* Bump version (Raymond Feng)
|
* Bump version (Raymond Feng)
|
||||||
|
|
||||||
* 2.0.0-beta2 (Miroslav Bajtoš)
|
* 2.0.0-beta2 (Miroslav Bajtoš)
|
||||||
|
@ -664,17 +704,12 @@
|
||||||
2014-07-15, Version 1.7.0
|
2014-07-15, Version 1.7.0
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2014-07-15, Version 2.0.0-beta3
|
|
||||||
===============================
|
|
||||||
|
|
||||||
* Bump version (Raymond Feng)
|
|
||||||
|
|
||||||
* Make sure related properties are defined for RDBMS (Raymond Feng)
|
* Make sure related properties are defined for RDBMS (Raymond Feng)
|
||||||
|
|
||||||
* Test instance or id by the model type (Raymond Feng)
|
* Test instance or id by the model type (Raymond Feng)
|
||||||
|
|
||||||
|
* Bump version (Raymond Feng)
|
||||||
|
|
||||||
* Allow before hooks to pass arguments to next() (Raymond Feng)
|
* Allow before hooks to pass arguments to next() (Raymond Feng)
|
||||||
|
|
||||||
* Remoting methods for hasMany through (Raymond Feng)
|
* Remoting methods for hasMany through (Raymond Feng)
|
||||||
|
@ -699,36 +734,6 @@
|
||||||
|
|
||||||
* DAO.prototype.exists should return 'boolean' type. (Samuel Reed)
|
* DAO.prototype.exists should return 'boolean' type. (Samuel Reed)
|
||||||
|
|
||||||
* 2.0.0-beta2 (Miroslav Bajtoš)
|
|
||||||
|
|
||||||
* validations: support non-V8 browsers (Miroslav Bajtoš)
|
|
||||||
|
|
||||||
* Remove remoting metadata (Raymond Feng)
|
|
||||||
|
|
||||||
* Fix the forEach closure (Raymond Feng)
|
|
||||||
|
|
||||||
* ModelBuilder: add `prototype.defineValueType` (Miroslav Bajtoš)
|
|
||||||
|
|
||||||
* Replace connector base with loopback-connector (Miroslav Bajtoš)
|
|
||||||
|
|
||||||
* Remove unsupported connectors (Miroslav Bajtoš)
|
|
||||||
|
|
||||||
* 2.0.0-beta1 (Ritchie Martori)
|
|
||||||
|
|
||||||
* Keep undefined/null values for the array type (Raymond Feng)
|
|
||||||
|
|
||||||
* Remove JSDocs for scopeMethods.add(acInst) and scopeMethods.remove(acInst) (crandmck)
|
|
||||||
|
|
||||||
* Copy info from api-model.md to JSDoc (crandmck)
|
|
||||||
|
|
||||||
* !fixup Remove additional remoting (Ritchie Martori)
|
|
||||||
|
|
||||||
* !fixup Require ._delegate for fn override (Ritchie Martori)
|
|
||||||
|
|
||||||
* Remove relation remoting (Ritchie Martori)
|
|
||||||
|
|
||||||
* Remove remoting metadata (Ritchie Martori)
|
|
||||||
|
|
||||||
|
|
||||||
2014-07-03, Version 1.6.3
|
2014-07-03, Version 1.6.3
|
||||||
=========================
|
=========================
|
||||||
|
@ -1091,8 +1096,6 @@
|
||||||
|
|
||||||
* Simplify the test case (Raymond Feng)
|
* Simplify the test case (Raymond Feng)
|
||||||
|
|
||||||
* Revert the inflection version due to regression in camelize (Raymond Feng)
|
|
||||||
|
|
||||||
* Add unit test for datatype handling in updateAttributes. (arlaneenalra)
|
* Add unit test for datatype handling in updateAttributes. (arlaneenalra)
|
||||||
|
|
||||||
* Move new var into thunk. (arlaneenalra)
|
* Move new var into thunk. (arlaneenalra)
|
||||||
|
@ -1100,11 +1103,6 @@
|
||||||
* Use type converted data when writing back to database. (arlaneenalra)
|
* Use type converted data when writing back to database. (arlaneenalra)
|
||||||
|
|
||||||
|
|
||||||
2014-02-11, Version 1.3.0
|
|
||||||
=========================
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2014-02-11, Version 1.3.1
|
2014-02-11, Version 1.3.1
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
|
@ -1112,6 +1110,10 @@
|
||||||
|
|
||||||
* Revert the inflection version due to regression in camelize (Raymond Feng)
|
* Revert the inflection version due to regression in camelize (Raymond Feng)
|
||||||
|
|
||||||
|
|
||||||
|
2014-02-11, Version 1.3.0
|
||||||
|
=========================
|
||||||
|
|
||||||
* Bump version and update deps (Raymond Feng)
|
* Bump version and update deps (Raymond Feng)
|
||||||
|
|
||||||
* Add a test case (Raymond Feng)
|
* Add a test case (Raymond Feng)
|
||||||
|
|
|
@ -14,7 +14,7 @@ Contributing to `loopback-datasource-juggler` is easy. In a few simple steps:
|
||||||
* Adhere to code style outlined in the [Google C++ Style Guide][] and
|
* Adhere to code style outlined in the [Google C++ Style Guide][] and
|
||||||
[Google Javascript Style Guide][].
|
[Google Javascript Style Guide][].
|
||||||
|
|
||||||
* Sign the [Contributor License Agreement](https://cla.strongloop.com/strongloop/loopback-datasource-juggler)
|
* Sign the [Contributor License Agreement](https://cla.strongloop.com/agreements/strongloop/loopback-datasource-juggler)
|
||||||
|
|
||||||
* Submit a pull request through Github.
|
* Submit a pull request through Github.
|
||||||
|
|
||||||
|
|
8
index.js
8
index.js
|
@ -4,11 +4,11 @@ exports.ModelBaseClass = require('./lib/model.js');
|
||||||
exports.GeoPoint = require('./lib/geo.js').GeoPoint;
|
exports.GeoPoint = require('./lib/geo.js').GeoPoint;
|
||||||
exports.ValidationError = require('./lib/validations.js').ValidationError;
|
exports.ValidationError = require('./lib/validations.js').ValidationError;
|
||||||
|
|
||||||
exports.__defineGetter__('version', function () {
|
Object.defineProperty(exports, 'version', {
|
||||||
return require('./package.json').version;
|
get: function() {return require('./package.json').version;}
|
||||||
});
|
});
|
||||||
|
|
||||||
var commonTest = './test/common_test';
|
var commonTest = './test/common_test';
|
||||||
exports.__defineGetter__('test', function () {
|
Object.defineProperty(exports, 'test', {
|
||||||
return require(commonTest);
|
get: function() {return require(commonTest);}
|
||||||
});
|
});
|
||||||
|
|
|
@ -347,13 +347,19 @@ Memory.prototype.all = function all(model, filter, callback) {
|
||||||
});
|
});
|
||||||
|
|
||||||
function sorting(a, b) {
|
function sorting(a, b) {
|
||||||
|
var undefinedA, undefinedB;
|
||||||
|
|
||||||
for (var i = 0, l = this.length; i < l; i++) {
|
for (var i = 0, l = this.length; i < l; i++) {
|
||||||
if (a[this[i].key] > b[this[i].key]) {
|
undefinedB = b[this[i].key] === undefined && a[this[i].key] !== undefined;
|
||||||
|
undefinedA = a[this[i].key] === undefined && b[this[i].key] !== undefined;
|
||||||
|
|
||||||
|
if (undefinedB || a[this[i].key] > b[this[i].key]) {
|
||||||
return 1 * this[i].reverse;
|
return 1 * this[i].reverse;
|
||||||
} else if (a[this[i].key] < b[this[i].key]) {
|
} else if (undefinedA || a[this[i].key] < b[this[i].key]) {
|
||||||
return -1 * this[i].reverse;
|
return -1 * this[i].reverse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -58,7 +58,6 @@ function byIdQuery(m, id) {
|
||||||
var pk = idName(m);
|
var pk = idName(m);
|
||||||
var query = { where: {} };
|
var query = { where: {} };
|
||||||
query.where[pk] = id;
|
query.where[pk] = id;
|
||||||
m.applyScope(query);
|
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +316,7 @@ DataAccessObject.updateOrCreate = DataAccessObject.upsert = function upsert(data
|
||||||
* @param {Object} query Search conditions. See [find](#dataaccessobjectfindquery-callback) for query format.
|
* @param {Object} query Search conditions. See [find](#dataaccessobjectfindquery-callback) for query format.
|
||||||
* For example: `{where: {test: 'me'}}`.
|
* For example: `{where: {test: 'me'}}`.
|
||||||
* @param {Object} data Object to create.
|
* @param {Object} data Object to create.
|
||||||
* @param {Function} cb Callback called with (err, instance)
|
* @param {Function} cb Callback called with (err, instance, created)
|
||||||
*/
|
*/
|
||||||
DataAccessObject.findOrCreate = function findOrCreate(query, data, callback) {
|
DataAccessObject.findOrCreate = function findOrCreate(query, data, callback) {
|
||||||
if (query === undefined) {
|
if (query === undefined) {
|
||||||
|
@ -335,8 +334,10 @@ DataAccessObject.findOrCreate = function findOrCreate(query, data, callback) {
|
||||||
var t = this;
|
var t = this;
|
||||||
this.findOne(query, function (err, record) {
|
this.findOne(query, function (err, record) {
|
||||||
if (err) return callback(err);
|
if (err) return callback(err);
|
||||||
if (record) return callback(null, record);
|
if (record) return callback(null, record, false);
|
||||||
t.create(data, callback);
|
t.create(data, function (err, record) {
|
||||||
|
callback(err, record, record != null);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
48
lib/geo.js
48
lib/geo.js
|
@ -111,7 +111,11 @@ exports.GeoPoint = GeoPoint;
|
||||||
*
|
*
|
||||||
* @options {Object} Options Object with two Number properties: lat and long.
|
* @options {Object} Options Object with two Number properties: lat and long.
|
||||||
* @property {Number} lat The latitude point in degrees. Range: -90 to 90.
|
* @property {Number} lat The latitude point in degrees. Range: -90 to 90.
|
||||||
* @property {Number} lng The longitude point in degrees. Range: -90 to 90.
|
* @property {Number} lng The longitude point in degrees. Range: -180 to 180.
|
||||||
|
*
|
||||||
|
* @options {Array} Options Array with two Number entries: [lat,long].
|
||||||
|
* @property {Number} lat The latitude point in degrees. Range: -90 to 90.
|
||||||
|
* @property {Number} lng The longitude point in degrees. Range: -180 to 180.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function GeoPoint(data) {
|
function GeoPoint(data) {
|
||||||
|
@ -119,14 +123,23 @@ function GeoPoint(data) {
|
||||||
return new GeoPoint(data);
|
return new GeoPoint(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(arguments.length === 2) {
|
||||||
|
data = {
|
||||||
|
lat: arguments[0],
|
||||||
|
lng: arguments[1]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(Array.isArray(data) || typeof data === 'object' || typeof data === 'string', 'must provide valid geo-coordinates array [lat, lng] or object or a "lat, lng" string');
|
||||||
|
|
||||||
if (typeof data === 'string') {
|
if (typeof data === 'string') {
|
||||||
data = data.split(/,\s*/);
|
data = data.split(/,\s*/);
|
||||||
assert(data.length === 2, 'must provide a string "lng,lat" creating a GeoPoint with a string');
|
assert(data.length === 2, 'must provide a string "lat,lng" creating a GeoPoint with a string');
|
||||||
}
|
}
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
data = {
|
data = {
|
||||||
lng: Number(data[0]),
|
lat: Number(data[0]),
|
||||||
lat: Number(data[1])
|
lng: Number(data[1])
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
data.lng = Number(data.lng);
|
data.lng = Number(data.lng);
|
||||||
|
@ -177,7 +190,7 @@ GeoPoint.distanceBetween = function distanceBetween(a, b, options) {
|
||||||
var y2 = b.lng;
|
var y2 = b.lng;
|
||||||
|
|
||||||
return geoDistance(x1, y1, x2, y2, options);
|
return geoDistance(x1, y1, x2, y2, options);
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the spherical distance to the given point.
|
* Determine the spherical distance to the given point.
|
||||||
|
@ -202,26 +215,22 @@ GeoPoint.distanceBetween = function distanceBetween(a, b, options) {
|
||||||
|
|
||||||
GeoPoint.prototype.distanceTo = function (point, options) {
|
GeoPoint.prototype.distanceTo = function (point, options) {
|
||||||
return GeoPoint.distanceBetween(this, point, options);
|
return GeoPoint.distanceBetween(this, point, options);
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple serialization.
|
* Simple serialization.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GeoPoint.prototype.toString = function () {
|
GeoPoint.prototype.toString = function () {
|
||||||
return this.lng + ',' + this.lat;
|
return this.lat + ',' + this.lng;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @property {Number} PI - Ratio of a circle's circumference to its diameter.
|
|
||||||
* @property {Number} DEG2RAD - Factor to convert degrees to radians.
|
* @property {Number} DEG2RAD - Factor to convert degrees to radians.
|
||||||
* @property {Number} RAD2DEG - Factor to convert radians to degrees.
|
* @property {Number} RAD2DEG - Factor to convert radians to degrees.
|
||||||
* @property {Object} EARTH_RADIUS - Radius of the earth.
|
* @property {Object} EARTH_RADIUS - Radius of the earth.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// ratio of a circle's circumference to its diameter
|
|
||||||
var PI = 3.1415926535897932384626433832795;
|
|
||||||
|
|
||||||
// factor to convert degrees to radians
|
// factor to convert degrees to radians
|
||||||
var DEG2RAD = 0.01745329252;
|
var DEG2RAD = 0.01745329252;
|
||||||
|
|
||||||
|
@ -239,18 +248,23 @@ var EARTH_RADIUS = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function geoDistance(x1, y1, x2, y2, options) {
|
function geoDistance(x1, y1, x2, y2, options) {
|
||||||
|
|
||||||
|
var type = (options && options.type) || 'miles';
|
||||||
|
|
||||||
// Convert to radians
|
// Convert to radians
|
||||||
x1 = x1 * DEG2RAD;
|
x1 = x1 * DEG2RAD;
|
||||||
y1 = y1 * DEG2RAD;
|
y1 = y1 * DEG2RAD;
|
||||||
x2 = x2 * DEG2RAD;
|
x2 = x2 * DEG2RAD;
|
||||||
y2 = y2 * DEG2RAD;
|
y2 = y2 * DEG2RAD;
|
||||||
|
|
||||||
var a = Math.pow(Math.sin(( y2 - y1 ) / 2.0), 2);
|
// use the haversine formula to calculate distance for any 2 points on a sphere.
|
||||||
var b = Math.pow(Math.sin(( x2 - x1 ) / 2.0), 2);
|
// ref http://en.wikipedia.org/wiki/Haversine_formula
|
||||||
var c = Math.sqrt(a + Math.cos(y2) * Math.cos(y1) * b);
|
var haversine = function(a) {
|
||||||
|
return Math.pow(Math.sin(a / 2.0), 2);
|
||||||
|
};
|
||||||
|
|
||||||
var type = (options && options.type) || 'miles';
|
var f = Math.sqrt(haversine(x2 - x1) + Math.cos(x2) * Math.cos(x1) * haversine(y2 - y1));
|
||||||
|
|
||||||
return 2 * Math.asin(c) * EARTH_RADIUS[type];
|
return 2 * Math.asin(f) * EARTH_RADIUS[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "loopback-datasource-juggler",
|
"name": "loopback-datasource-juggler",
|
||||||
"version": "2.12.0",
|
"version": "2.13.0",
|
||||||
"description": "LoopBack DataSoure Juggler",
|
"description": "LoopBack DataSoure Juggler",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"StrongLoop",
|
"StrongLoop",
|
||||||
|
|
|
@ -1122,12 +1122,14 @@ function testOrm(dataSource) {
|
||||||
|
|
||||||
it('should find or create', function (test) {
|
it('should find or create', function (test) {
|
||||||
var email = 'some email ' + Math.random();
|
var email = 'some email ' + Math.random();
|
||||||
User.findOrCreate({where: {email: email}}, function (err, u) {
|
User.findOrCreate({where: {email: email}}, function (err, u, created) {
|
||||||
test.ok(u);
|
test.ok(u);
|
||||||
test.ok(!u.age);
|
test.ok(!u.age);
|
||||||
User.findOrCreate({where: {email: email}}, {age: 21}, function (err, u2) {
|
test.ok(created);
|
||||||
|
User.findOrCreate({where: {email: email}}, {age: 21}, function (err, u2, created) {
|
||||||
test.equals(u.id.toString(), u2.id.toString(), 'Same user ids');
|
test.equals(u.id.toString(), u2.id.toString(), 'Same user ids');
|
||||||
test.ok(!u2.age);
|
test.ok(!u2.age);
|
||||||
|
test.ok(!created);
|
||||||
test.done();
|
test.done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
var should = require('./init.js');
|
var should = require('./init.js');
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
|
|
||||||
var db, Category, Product, Tool, Widget, Thing;
|
var db, Category, Product, Tool, Widget, Thing, Person;
|
||||||
|
|
||||||
// This test requires a connector that can
|
// This test requires a connector that can
|
||||||
// handle a custom collection or table name
|
// handle a custom collection or table name
|
||||||
|
@ -86,6 +86,10 @@ describe('default scope', function () {
|
||||||
mongodb: { collection: 'Product' },
|
mongodb: { collection: 'Product' },
|
||||||
memory: { collection: 'Product' }
|
memory: { collection: 'Product' }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Person = db.define('Person', { name: String }, {
|
||||||
|
scope: { include: 'things' }
|
||||||
|
});
|
||||||
|
|
||||||
// inst is only valid for instance methods
|
// inst is only valid for instance methods
|
||||||
// like save, updateAttributes
|
// like save, updateAttributes
|
||||||
|
@ -115,6 +119,9 @@ describe('default scope', function () {
|
||||||
Tool.belongsTo(Category);
|
Tool.belongsTo(Category);
|
||||||
Widget.belongsTo(Category);
|
Widget.belongsTo(Category);
|
||||||
Thing.belongsTo(Category);
|
Thing.belongsTo(Category);
|
||||||
|
|
||||||
|
Person.hasMany(Thing);
|
||||||
|
Thing.belongsTo(Person);
|
||||||
|
|
||||||
db.automigrate(done);
|
db.automigrate(done);
|
||||||
});
|
});
|
||||||
|
@ -802,7 +809,33 @@ describe('default scope', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('with include option', function() {
|
||||||
|
|
||||||
|
before(function (done) {
|
||||||
|
db.automigrate(done);
|
||||||
|
});
|
||||||
|
|
||||||
|
before(function (done) {
|
||||||
|
Person.create({ id: 1, name: 'Person A' }, function(err, person) {
|
||||||
|
person.things.create({ name: 'Thing A' }, done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should find a scoped instance with included relation - things', function(done) {
|
||||||
|
Person.findById(1, function(err, person) {
|
||||||
|
should.not.exist(err);
|
||||||
|
should.exist(person);
|
||||||
|
var things = person.things();
|
||||||
|
should.exist(things);
|
||||||
|
things.should.be.an.instanceOf(Array);
|
||||||
|
things.should.have.length(1);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*global describe,it*/
|
||||||
|
/*jshint expr:true */
|
||||||
|
|
||||||
|
require('should');
|
||||||
|
|
||||||
|
var GeoPoint = require('../lib/geo').GeoPoint;
|
||||||
|
var DELTA = 0.0000001;
|
||||||
|
|
||||||
|
describe('GeoPoint', function () {
|
||||||
|
|
||||||
|
describe('constructor', function() {
|
||||||
|
|
||||||
|
it('should support a valid array', function () {
|
||||||
|
var point = new GeoPoint([-34, 150]);
|
||||||
|
|
||||||
|
point.lat.should.equal(-34);
|
||||||
|
point.lng.should.equal(150);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support a valid object', function () {
|
||||||
|
var point = new GeoPoint({ lat: -34, lng: 150 });
|
||||||
|
|
||||||
|
point.lat.should.equal(-34);
|
||||||
|
point.lng.should.equal(150);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support valid string geo coordinates', function () {
|
||||||
|
var point = new GeoPoint('-34,150');
|
||||||
|
|
||||||
|
point.lat.should.equal(-34);
|
||||||
|
point.lng.should.equal(150);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support coordinates as inline parameters', function () {
|
||||||
|
var point = new GeoPoint(-34, 150);
|
||||||
|
|
||||||
|
point.lat.should.equal(-34);
|
||||||
|
point.lng.should.equal(150);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject invalid parameters', function () {
|
||||||
|
/*jshint -W024 */
|
||||||
|
var fn = function() {
|
||||||
|
new GeoPoint('150,-34');
|
||||||
|
};
|
||||||
|
fn.should.throw();
|
||||||
|
|
||||||
|
fn = function() {
|
||||||
|
new GeoPoint('invalid_string');
|
||||||
|
};
|
||||||
|
fn.should.throw();
|
||||||
|
|
||||||
|
fn = function() {
|
||||||
|
new GeoPoint([150, -34]);
|
||||||
|
};
|
||||||
|
fn.should.throw();
|
||||||
|
|
||||||
|
fn = function() {
|
||||||
|
new GeoPoint({
|
||||||
|
lat: 150,
|
||||||
|
lng: null
|
||||||
|
});
|
||||||
|
};
|
||||||
|
fn.should.throw();
|
||||||
|
|
||||||
|
fn = function() {
|
||||||
|
new GeoPoint(150, -34);
|
||||||
|
};
|
||||||
|
fn.should.throw();
|
||||||
|
|
||||||
|
fn = function() {
|
||||||
|
new GeoPoint();
|
||||||
|
};
|
||||||
|
fn.should.throw();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('toString()', function() {
|
||||||
|
|
||||||
|
it('should return a string in the form "lat,lng"', function() {
|
||||||
|
|
||||||
|
var point = new GeoPoint({ lat: -34, lng: 150 });
|
||||||
|
point.toString().should.equal('-34,150');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('distance calculation between two points', function () {
|
||||||
|
|
||||||
|
var here = new GeoPoint({ lat: 40.77492964101182, lng: -73.90950187151662 });
|
||||||
|
var there = new GeoPoint({ lat: 40.7753227, lng: -73.909217 });
|
||||||
|
|
||||||
|
it('should return value in miles by default', function () {
|
||||||
|
|
||||||
|
var distance = GeoPoint.distanceBetween(here, there);
|
||||||
|
distance.should.be.a.Number;
|
||||||
|
distance.should.be.approximately(0.03097916611592679, DELTA);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return value using specified unit', function () {
|
||||||
|
|
||||||
|
/* Supported units:
|
||||||
|
* - `radians`
|
||||||
|
* - `kilometers`
|
||||||
|
* - `meters`
|
||||||
|
* - `miles`
|
||||||
|
* - `feet`
|
||||||
|
* - `degrees`
|
||||||
|
*/
|
||||||
|
|
||||||
|
var distance = here.distanceTo(there, { type: 'radians'});
|
||||||
|
distance.should.be.a.Number;
|
||||||
|
distance.should.be.approximately(0.000007825491914348416, DELTA);
|
||||||
|
|
||||||
|
distance = here.distanceTo(there, { type: 'kilometers'});
|
||||||
|
distance.should.be.a.Number;
|
||||||
|
distance.should.be.approximately(0.04985613511367009, DELTA);
|
||||||
|
|
||||||
|
distance = here.distanceTo(there, { type: 'meters'});
|
||||||
|
distance.should.be.a.Number;
|
||||||
|
distance.should.be.approximately(49.856135113670085, DELTA);
|
||||||
|
|
||||||
|
distance = here.distanceTo(there, { type: 'miles'});
|
||||||
|
distance.should.be.a.Number;
|
||||||
|
distance.should.be.approximately(0.03097916611592679, DELTA);
|
||||||
|
|
||||||
|
distance = here.distanceTo(there, { type: 'feet'});
|
||||||
|
distance.should.be.a.Number;
|
||||||
|
distance.should.be.approximately(163.56999709209347, DELTA);
|
||||||
|
|
||||||
|
distance = here.distanceTo(there, { type: 'degrees'});
|
||||||
|
distance.should.be.a.Number;
|
||||||
|
distance.should.be.approximately(0.0004483676593058972, DELTA);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -183,7 +183,7 @@ describe('Memory connector', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('support order with multiple fields', function (done) {
|
it('should support order with multiple fields', function (done) {
|
||||||
User.find({order: 'vip ASC, seq DESC'}, function (err, posts) {
|
User.find({order: 'vip ASC, seq DESC'}, function (err, posts) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
posts[0].seq.should.be.eql(4);
|
posts[0].seq.should.be.eql(4);
|
||||||
|
@ -192,6 +192,17 @@ describe('Memory connector', function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should sort undefined values to the end when ordered DESC', function (done) {
|
||||||
|
User.find({order: 'vip ASC, order DESC'}, function (err, posts) {
|
||||||
|
console.log(posts);
|
||||||
|
should.not.exist(err);
|
||||||
|
|
||||||
|
posts[4].seq.should.be.eql(1);
|
||||||
|
posts[5].seq.should.be.eql(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should throw if order has wrong direction', function (done) {
|
it('should throw if order has wrong direction', function (done) {
|
||||||
User.find({order: 'seq ABC'}, function (err, posts) {
|
User.find({order: 'seq ABC'}, function (err, posts) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
|
@ -200,11 +211,11 @@ describe('Memory connector', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should support neq operator for number', function (done) {
|
it('should support neq operator for number', function (done) {
|
||||||
User.find({where: {order: {neq: 6}}}, function (err, users) {
|
User.find({where: {seq: {neq: 4}}}, function (err, users) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
users.length.should.be.equal(5);
|
users.length.should.be.equal(5);
|
||||||
for (var i = 0; i < users.length; i++) {
|
for (var i = 0; i < users.length; i++) {
|
||||||
users[i].order.should.not.be.equal(6);
|
users[i].seq.should.not.be.equal(4);
|
||||||
}
|
}
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
@ -242,7 +253,6 @@ describe('Memory connector', function () {
|
||||||
email: 'john@b3atl3s.co.uk',
|
email: 'john@b3atl3s.co.uk',
|
||||||
role: 'lead',
|
role: 'lead',
|
||||||
birthday: new Date('1980-12-08'),
|
birthday: new Date('1980-12-08'),
|
||||||
order: 2,
|
|
||||||
vip: true
|
vip: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue