diff --git a/README.md b/README.md index ca59376..27132f5 100644 --- a/README.md +++ b/README.md @@ -188,6 +188,8 @@ use filters for that. You can ask the service for equality, or values greater or | **in** | `in` | `/users?gender__in=female,male` | returns all female and male users | | **nin** | `nin` | `/users?age__nin=18,30` | returns all users with age other than 18 or 30 | | **Regex** | `regex` | `/users?username__regex=/^baugarten/i` | returns all users with a username starting with baugarten | +| **within** | `geoWithin box` | `/users?loc__within=1,1&loc__within=2,2` | returns all users with a loc inside of specified box | +| **within** | `geoWithin polygon` | `/users?loc__within=1,1&loc__within==1,3&loc__within=2,2` | returns all users with a loc inside of specified polygon | ### Populating a sub-entity diff --git a/examples/movies/index.js b/examples/movies/index.js index 86bb2c6..46a902b 100644 --- a/examples/movies/index.js +++ b/examples/movies/index.js @@ -45,7 +45,8 @@ var movie = app.movie = restful.model("movies", mongoose.Schema({ productionco: 'string', director: { type: 'ObjectId', ref: 'users' } }, - secret: { type: 'string', select: false } + secret: { type: 'string', select: false }, + loc: [] })); movie.methods([ diff --git a/lib/model.js b/lib/model.js index 1919c27..5cd4046 100644 --- a/lib/model.js +++ b/lib/model.js @@ -45,6 +45,7 @@ var methods = ['get', 'post', 'put', 'delete'], // All HTTP methods, PATCH not c }, 'in': query('in'), 'nin': query('nin'), + 'within': query('within'), }); defaults = function() { return { @@ -357,9 +358,15 @@ function preprocess(req, res, next) { } function query(key) { - return function(val, query) { - return query[key](val); - }; + if (key === 'within') { + return function(val, query) { + return query[key].apply(query, val); + }; + } else { + return function(val, query) { + return query[key](val); + }; + } } function haveOneModel(req) { @@ -465,6 +472,18 @@ function filterable(props, subfilters) { data = data.split(','); } + if (filter_func === 'within') { + if (!Array.isArray(data)) { + data = [data]; + } + + data = _.map(data, function(item) { + return _.map(item.split(','), function(item) { + return parseFloat(item); + }); + }); + } + return subfilters[filter_func](data, quer.where(field[0])); }, contains: function(key, quer) { diff --git a/test/fixtures/config.js b/test/fixtures/config.js index 31cfda4..c50d6bc 100644 --- a/test/fixtures/config.js +++ b/test/fixtures/config.js @@ -13,7 +13,7 @@ exports.user = app.user; mongoose = app.mongoose; fixtures = fixtures.connect(mongoose.connection.name); -fixtures.load(data, function(err) { +fixtures.clearAndLoad(data, function(err) { exports.users = data.users; exports.movies = data.movies; done = true; diff --git a/test/fixtures/data.js b/test/fixtures/data.js index 607353e..05d9f76 100644 --- a/test/fixtures/data.js +++ b/test/fixtures/data.js @@ -18,6 +18,7 @@ exports.movies = [ _id: new ObjectId(), title: "Title1", year: 2012, + loc: [1, 2], meta: { productionco: "idk", director: exports.users[1]._id, @@ -28,27 +29,32 @@ exports.movies = [ { _id: new ObjectId(), title: "Title2", - year: 2011 + year: 2011, + loc: [12, 1] }, { _id: new ObjectId(), title: "Title3", - year: 2013 + year: 2013, + loc: [1, 1] }, { _id: new ObjectId(), title: "Title4", - year: 2013 + year: 2013, + loc: [2, 2] }, { _id: new ObjectId(), title: "Title5", - year: 2013 + year: 2013, + loc: [3, 3] }, { _id: new ObjectId(), title: "Title6", - year: 2010 + year: 2010, + loc: [0, 0] }, { _id: new ObjectId(), diff --git a/test/model.filters.js b/test/model.filters.js index 5cab60d..e79132f 100644 --- a/test/model.filters.js +++ b/test/model.filters.js @@ -187,5 +187,20 @@ describe('Model', function() { done(); }); }); + it('should filter using within', function(done) { + request(app) + .get('/api/movies?loc__within=0.5,1.5&loc__within=1.5,2.5') + .end(function(err, res) { + res.body.length.should.be.above(0) + res.body.forEach(function(movie) { + movie.loc.should.be.instanceof(Array).and.have.lengthOf(2); + movie.loc[0].should.be.greaterThan(.5); + movie.loc[0].should.be.lessThan(1.5); + movie.loc[1].should.be.greaterThan(1.5); + movie.loc[1].should.be.lessThan(2.5); + }); + done(); + }); + }); }); });