UNPKG

nqm-minimongo

Version:

Client-side mongo database with server sync over http

371 lines (301 loc) 12.1 kB
_ = require 'lodash' chai = require 'chai' assert = chai.assert error = (err) -> console.log err assert.fail(JSON.stringify(err)) # Runs queries on @col which must be a collection (with a:<string>, b:<integer>, c:<json>, geo:<geojson>, stringarr: <json array of strings>) # When present: # c.arrstr is an array of string values # c.arrint is an array of integer values # @reset(done) must truncate the collection module.exports = -> before -> # Test a filter to return specified rows (in order) @testFilter = (filter, ids, done) -> @col.find(filter, { sort:["_id"]}).fetch (results) -> assert.deepEqual _.pluck(results, '_id'), ids done() context 'With sample rows', -> beforeEach (done) -> @reset => @col.upsert { _id:"1", a:"Alice", b:1, c: { d: 1, e: 2 } }, => @col.upsert { _id:"2", a:"Charlie", b:2, c: { d: 2, e: 3 } }, => @col.upsert { _id:"3", a:"Bob", b:3 }, -> done() it 'finds all rows', (done) -> @col.find({}).fetch (results) -> assert.equal results.length, 3 done() it 'finds all rows with options', (done) -> @col.find({}, {}).fetch (results) -> assert.equal 3, results.length done() it 'filters by id', (done) -> @testFilter { _id: "1" }, ["1"], done it 'filters by string', (done) -> @testFilter { a: "Alice" }, ["1"], done it 'filters by $in string', (done) -> @testFilter { a: { $in: ["Alice", "Charlie"]} }, ["1", "2"], done it 'filters by number', (done) -> @testFilter { b: 2 }, ["2"], done it 'filters by $in number', (done) -> @testFilter { b: { $in: [2, 3]} }, ["2", "3"], done it 'filters by $regex', (done) -> @testFilter { a: { $regex: "li"} }, ["1", "2"], done it 'filters by $regex case-sensitive', (done) -> @testFilter { a: { $regex: "A"} }, ["1"], done it 'filters by $regex case-insensitive', (done) -> @testFilter { a: { $regex: "A", $options: 'i' } }, ["1", "2"], done it 'filters by $or', (done) -> @testFilter { "$or": [{b:1}, {b:2}]}, ["1","2"], done it 'filters by path', (done) -> @testFilter { "c.d": 2 }, ["2"], done it 'filters by $ne', (done) -> @testFilter { "b": { $ne: 2 }}, ["1","3"], done it 'filters by $gt', (done) -> @testFilter { "b": { $gt: 1 }}, ["2","3"], done it 'filters by $lt', (done) -> @testFilter { "b": { $lt: 3 }}, ["1","2"], done it 'filters by $gte', (done) -> @testFilter { "b": { $gte: 2 }}, ["2","3"], done it 'filters by $lte', (done) -> @testFilter { "b": { $lte: 2 }}, ["1","2"], done it 'filters by $not', (done) -> @testFilter { "b": { $not: { $lt: 3 }}}, ["3"], done it 'filters by $or', (done) -> @testFilter { $or: [{b: 3},{b: 1}]}, ["1", "3"], done it 'filters by $exists: true', (done) -> @testFilter { c: { $exists: true }}, ["1", "2"], done it 'filters by $exists: false', (done) -> @testFilter { c: { $exists: false }}, ["3"], done it 'includes fields', (done) -> @col.find({ _id: "1" }, { fields: { a:1 }}).fetch (results) -> assert.deepEqual results[0], { _id: "1", a: "Alice" } done() it 'includes subfields', (done) -> @col.find({ _id: "1" }, { fields: { "c.d":1 }}).fetch (results) -> assert.deepEqual results[0], { _id: "1", c: { d: 1 } } done() it 'ignores non-existent subfields', (done) -> @col.find({ _id: "1" }, { fields: { "x.y":1 }}).fetch (results) -> assert.deepEqual results[0], { _id: "1" } done() it 'excludes fields', (done) -> @col.find({ _id: "1" }, { fields: { a:0 }}).fetch (results) -> assert.isUndefined results[0].a assert.equal results[0].b, 1 done() it 'excludes subfields', (done) -> @col.find({ _id: "1" }, { fields: { "c.d": 0 }}).fetch (results) -> assert.deepEqual results[0].c, { e: 2 } done() it 'finds one row', (done) -> @col.findOne { _id: "2" }, (result) -> assert.equal 'Charlie', result.a done() it 'removes item', (done) -> @col.remove "2", => @col.find({}).fetch (results) -> assert.equal 2, results.length assert "1" in (result._id for result in results) assert "2" not in (result._id for result in results) done() , error , error it 'removes non-existent item', (done) -> @col.remove "999", => @col.find({}).fetch (results) -> assert.equal 3, results.length done() it 'sorts ascending', (done) -> @col.find({}, {sort: ['a']}).fetch (results) -> assert.deepEqual _.pluck(results, '_id'), ["1","3","2"] done() it 'sorts descending', (done) -> @col.find({}, {sort: [['a','desc']]}).fetch (results) -> assert.deepEqual _.pluck(results, '_id'), ["2","3","1"] done() it 'limits', (done) -> @col.find({}, {sort: ['a'], limit:2}).fetch (results) -> assert.deepEqual _.pluck(results, '_id'), ["1","3"] done() it 'skips', (done) -> @col.find({}, {sort: ['a'], skip:2}).fetch (results) -> assert.deepEqual _.pluck(results, '_id'), ["2"] done() # MemoryDb is much faster if we relax this constraint it 'fetches independent copies', (done) -> @col.findOne { _id: "2" }, (result1) => @col.findOne { _id: "2" }, (result2) -> assert result1 != result2 done() # MemoryDb is much faster if we relax this constraint it 'upsert keeps independent copies', (done) -> doc = { _id: "2" } @col.upsert doc, (item) => doc.a = "xyz" item.a = "xyz" @col.findOne { _id:"2" }, (doc2) -> assert doc != doc2 assert doc2.a != "xyz" done() it 'adds _id to rows', (done) -> @col.upsert { a: "1" }, (item) -> assert.property item, '_id' assert.lengthOf item._id, 32 done() it 'returns array if called with array', (done) -> @col.upsert [{ a: "1" }], (items) -> assert.equal items[0].a, "1" done() it 'updates by id', (done) -> @col.upsert { _id:"1", a:"1" }, (item) => @col.upsert { _id:"1", a:"2", b: 1 }, (item) => assert.equal item.a, "2" @col.find({ _id: "1" }).fetch (results) -> assert.equal 1, results.length, "Should be only one document" done() it 'call upsert with upserted row', (done) -> @col.upsert { _id:"1", a:"1" }, (item) -> assert.equal item._id, "1" assert.equal item.a, "1" done() it 'upserts multiple rows', (done) -> @timeout(10000) @reset => docs = [] for i in [0...100] docs.push { b: i } @col.upsert docs, => @col.find({}).fetch (results) -> assert.equal results.length, 100 done() , error , error context 'With sample with capitalization', -> beforeEach (done) -> @reset => @col.upsert { _id:"1", a:"Alice", b:1, c: { d: 1, e: 2 } }, => @col.upsert { _id:"2", a:"AZ", b:2, c: { d: 2, e: 3 } }, -> done() it 'finds sorts in Javascript order', (done) -> @col.find({}, {sort: ['a']}).fetch (results) -> assert.deepEqual _.pluck(results, '_id'), ["2","1"] done() context 'With integer array in json rows', -> beforeEach (done) -> @reset => @col.upsert { _id:"1", c: { arrint: [1, 2] }}, => @col.upsert { _id:"2", c: { arrint: [2, 3] }}, => @col.upsert { _id:"3", c: { arrint: [1, 3] }}, -> done() it 'filters by $in', (done) -> @testFilter { "c.arrint": { $in: [3] }}, ["2", "3"], done it 'filters by list $in with multiple', (done) -> @testFilter { "c.arrint": { $in: [1, 3] }}, ["1", "2", "3"], done context 'With object array rows', -> beforeEach (done) -> @reset => @col.upsert { _id:"1", c: [{ x: 1, y: 1 }, { x:1, y:2 }] }, => @col.upsert { _id:"2", c: [{ x: 2, y: 1 }] }, => @col.upsert { _id:"3", c: [{ x: 2, y: 2 }] }, -> done() it 'filters by $elemMatch', (done) -> @testFilter { "c": { $elemMatch: { y:1 }}}, ["1", "2"], => @testFilter { "c": { $elemMatch: { x:1 }}}, ["1"], done context 'With array rows with inner string arrays', -> beforeEach (done) -> @reset => @col.upsert { _id:"1", c: [{ arrstr: ["a", "b"]}, { arrstr: ["b", "c"]}] }, => @col.upsert { _id:"2", c: [{ arrstr: ["b"]}] }, => @col.upsert { _id:"3", c: [{ arrstr: ["c", "d"]}, { arrstr: ["e", "f"]}] }, -> done() it 'filters by $elemMatch', (done) -> @testFilter { "c": { $elemMatch: { "arrstr": { $in: ["b"]} }}}, ["1", "2"], => @testFilter { "c": { $elemMatch: { "arrstr": { $in: ["d", "e"]} }}}, ["3"], done context 'With text array rows', -> beforeEach (done) -> @reset => @col.upsert { _id:"1", textarr: ["a", "b"]}, => @col.upsert { _id:"2", textarr: ["b", "c"]}, => @col.upsert { _id:"3", textarr: ["c", "d"]}, -> done() , error , error , error it 'filters by $in', (done) -> @testFilter { "textarr": { $in: ["b"] }}, ["1", "2"], done it 'filters by direct reference', (done) -> @testFilter { "textarr": "b" }, ["1", "2"], done it 'filters by both item and complete array', (done) -> @testFilter { "textarr": { $in: ["a", ["b", "c"]] } }, ["1", "2"], done geopoint = (lng, lat) -> return { type: 'Point' coordinates: [lng, lat] } context 'With geolocated rows', -> beforeEach (done) -> @col.upsert { _id:"1", geo:geopoint(90, 45) }, => @col.upsert { _id:"2", geo:geopoint(90, 46) }, => @col.upsert { _id:"3", geo:geopoint(91, 45) }, => @col.upsert { _id:"4", geo:geopoint(91, 46) }, -> done() it 'finds points near', (done) -> selector = geo: $near: $geometry: geopoint(90, 45) @col.find(selector).fetch (results) -> assert.deepEqual _.pluck(results, '_id'), ["1","3","2","4"] done() it 'finds points near maxDistance', (done) -> selector = geo: $near: $geometry: geopoint(90, 45) $maxDistance: 111180 @col.find(selector).fetch (results) -> assert.deepEqual _.pluck(results, '_id'), ["1","3"] done() it 'finds points near maxDistance just above', (done) -> selector = geo: $near: $geometry: geopoint(90, 45) $maxDistance: 111410 @col.find(selector).fetch (results) -> assert.deepEqual _.pluck(results, '_id'), ["1","3","2"] done() it 'finds points within simple box', (done) -> selector = geo: $geoIntersects: $geometry: type: 'Polygon' coordinates: [[ [89.5, 45.5], [89.5, 46.5], [90.5, 46.5], [90.5, 45.5], [89.5, 45.5] ]] @col.find(selector).fetch (results) -> assert.deepEqual _.pluck(results, '_id'), ["2"] done() it 'finds points within big box', (done) -> selector = geo: $geoIntersects: $geometry: type: 'Polygon' coordinates: [[ [0, -89], [0, 89], [179, 89], [179, -89], [0, -89] ]] @col.find(selector, {sort:['_id']}).fetch (results) -> assert.deepEqual _.pluck(results, '_id'), ["1", "2", "3", "4"] done() it 'handles undefined', (done) -> selector = geo: $geoIntersects: $geometry: type: 'Polygon' coordinates: [[ [89.5, 45.5], [89.5, 46.5], [90.5, 46.5], [90.5, 45.5], [89.5, 45.5] ]] @col.upsert { _id:5 }, => @col.find(selector).fetch (results) -> assert.deepEqual _.pluck(results, '_id'), ["2"] done()