Wrote tests for the local mongo querier

This commit is contained in:
Ruben Vereecken 2014-05-13 22:46:56 +02:00
parent 99927d1345
commit f2f4fef1e0
9 changed files with 188 additions and 62 deletions

View file

@ -1,15 +1,18 @@
LocalMongo = module.exports
#or = (list) -> _.reduce list (res, val)
LocalMongo.doQuerySelector = (value, operatorObj) ->
for operator, body of operatorObj
switch operator
when '$gt' then return false unless value > body
when '$gte' then return false unless value >= body
when '$in' then return false unless value in body
when '$in' then return false unless value in body or
_.reduce value, ((result, val) -> result or val in body), false
when '$lt' then return false unless value < body
when '$lte' then return false unless value <= body
when '$ne' then return false unless value != body
when '$nin' then return false if value in body
when '$nin' then return false if value of body
true
@ -23,7 +26,8 @@ LocalMongo.doLogicalOperator = (target, operatorObj) ->
LocalMongo.matchesQuery = (target, query) ->
for key, value of query
return false unless key in target
return false unless key of target
if typeof value != 'object'
return false unless target[key] == value
else return false unless doQuerySelector value query[key]
return false unless target[key] == value or (target[key] in value if _.isArray value)
else return false unless doQuerySelector value query[key]
true

View file

@ -1,70 +1,43 @@
c = require './../schemas'
module.exports =
AchievementSchema :
AchievementSchema =
type: 'object'
properties:
name: c.shortString({title: 'Display Name'})
query: { $ref: 'mongoFindQuery' } # TODO make this happen
worth:
type: 'number'
collection:
type: 'string'
worth: { type: 'number' }
collection: { type: 'string' }
description: { type: 'string' }
proportionalTo:
type: 'string'
description: 'For repeatables only. Denotes the field a repeatable achievement needs for its calculations'
ratio:
type: 'integer'
description: 'For repeatables only. Denotes how many proportionalTo\'s trigger an achievement. Usually 1.'
minimum: 1
required: ['name', 'query', 'worth', 'collection']
EarnedAchievementSchema :
type: 'object'
properties:
user: c.objectId
links:
[
{
rel: 'extra'
href: "/db/user/{($)}"
}
]
achievement: c.objectId
links:
[
{
rel: 'extra'
href: '/db/user/{($)}'
}
]
achievedAmount:
type: 'number'
MongoFindQuerySchema =
title: 'MongoDB Query'
id: 'mongoFindQuery'
type: 'object'
patternProperties:
'^[a-zA-Z0-9_\-\$]*$':
type: [ 'string', 'object' ]
oneOf: [
{ $ref: 'mongoQueryOperator' }, # TODO make this happen
{ type: 'string' }
]
additionalProperties: false
MongoFindQuerySchema :
title: 'MongoDB Query'
id: 'mongoFindQuery'
type: 'object'
patternProperties:
'^[a-zA-Z0-9_\-\$]*$':
type: [ 'string', 'object' ]
oneOf: [
{ $ref: 'mongoQueryOperator' }, # TODO make this happen
{ type: 'string' }
]
additionalProperties: false
# TODO add these: http://docs.mongodb.org/manual/reference/operator/query/
MongoQueryOperatorSchema :
title: 'MongoDB Query operator'
id: 'mongoQueryOperator'
type: 'object'
properties:
'$gt': type: 'number'
'$gte': type: 'number'
'$in': type: 'array'
'$lt': type: 'number'
'$lte': type: 'number'
'$ne': type: [ 'number', 'string' ]
'$nin': type: 'array'
additionalProperties: true # TODO set to false when the schema's done
# TODO add these: http://docs.mongodb.org/manual/reference/operator/query/
MongoQueryOperatorSchema =
title: 'MongoDB Query operator'
id: 'mongoQueryOperator'
type: 'object'
properties:
'$gt': type: 'number'
'$gte': type: 'number'
'$in': type: 'array'
'$lt': type: 'number'
'$lte': type: 'number'
'$ne': type: [ 'number', 'string' ]
'$nin': type: 'array'
additionalProperties: true # TODO set to false when the schema's done

View file

@ -0,0 +1,26 @@
c = require './../schemas'
module.exports =
EarnedAchievementSchema =
type: 'object'
properties:
user: c.objectId
links:
[
{
rel: 'extra'
href: "/db/user/{($)}"
}
]
achievement: c.objectId
links:
[
{
rel: 'extra'
href: '/db/user/{($)}'
}
]
achievedAmount:
type: 'number'
notified:
type: 'boolean'

View file

@ -0,0 +1,13 @@
mongoose = require('mongoose')
jsonschema = require('../../app/schemas/models/achievement')
# `pre` and `post` are not called for update operations executed directly on the database,
# including `Model.update`,`.findByIdAndUpdate`,`.findOneAndUpdate`, `.findOneAndRemove`,and `.findByIdAndRemove`.order
# to utilize `pre` or `post` middleware, you should `find()` the document, and call the `init`, `validate`, `save`,
# or `remove` functions on the document. See [explanation](http://github.com/LearnBoost/mongoose/issues/964).
AchievementSchema = new mongoose.Schema({
query: Object
}, {strict: false})
module.exports = Achievement = mongoose.model('achievements', AchievementSchema)

View file

@ -0,0 +1,8 @@
mongoose = require 'mongoose'
jsonschema = require '../../../app/schemas/models/achievement_earned'
AchievementEarnedSchema = new mongoose.Schema({
user: Object
}, {strict:false})
module.exports = AchievementEarned = mongoose.model('achievements.earned', AchievementEarnedSchema)

View file

@ -2,6 +2,7 @@
mongoose = require('mongoose')
plugins = require('../../plugins/plugins')
AchievablePlugin = require '../../plugins/achievements'
jsonschema = require('../../../app/schemas/models/level_session')
LevelSessionSchema = new mongoose.Schema({
@ -10,6 +11,7 @@ LevelSessionSchema = new mongoose.Schema({
'default': Date.now
}, {strict: false})
LevelSessionSchema.plugin(plugins.PermissionsPlugin)
LevelSessionSchema.plugin(AchievablePlugin)
LevelSessionSchema.pre 'init', (next) ->
# TODO: refactor this into a set of common plugins for all models?

View file

@ -0,0 +1,41 @@
mongoose = require('mongoose')
Achievement = require('../achievements/Achievement')
AchievementEarned = require '../achievements/earned/AchievementEarned'
achievements = {}
loadAchievements = ->
achievements = {}
query = Achievement.find({})
query.exec (err, docs) ->
_.each docs, (achievement) ->
achievements[achievement.get 'collection'] = [] unless achievement.collection in achievements
achievements[achievement.get 'collection'].push achievement
loadAchievements()
# TODO make a difference between '$userID' and '$userObjectID' ?
module.exports = AchievablePlugin = (schema, options) ->
checkForAchievement = (doc) ->
collectionName = doc.constructor.modelName
console.log achievements
for achievement in achievements[collectionName]
console.log achievement.get 'name'
fetched = {}
schema.post 'init', (doc) ->
fetched[doc.id] = doc
collectionName = doc.constructor.modelName
for achievement in achievements[collectionName]
console.log achievement.get 'name'
schema.post 'save', (doc) ->
collectionName = doc.constructor.modelName
docBefore = fetched?.doc.id
for achievement in achievements[collectionName]
"placeholder"
# continue if init'd and already achieved
# else if new doc validates, new achievement! make the fucker

View file

@ -4,6 +4,7 @@ crypto = require('crypto')
{salt, isProduction} = require('../../server_config')
mail = require '../commons/mail'
log = require 'winston'
plugins = require '../plugins/achievements'
sendwithus = require '../sendwithus'

View file

@ -0,0 +1,58 @@
describe 'Local Mongo queries', ->
LocalMongo = require 'lib/LocalMongo'
console.warn 'matchesQuery' in LocalMongo
beforeEach ->
this.fixture1 =
'id': 'somestring'
'value': 9000
'worth': 6
'type': 'unicorn'
'likes': ['poptarts', 'popsicles', 'popcorn']
it 'regular match of a property', ->
expect(LocalMongo.matchesQuery(this.fixture1, 'gender': 'unicorn')).toBeFalsy()
expect(LocalMongo.matchesQuery(this.fixture1, 'type':'unicorn')).toBeTruthy()
expect(LocalMongo.matchesQuery(this.fixture1, 'type':'zebra')).toBeFalsy()
expect(LocalMongo.matchesQuery(this.fixture1, 'type':'unicorn', 'id':'somestring')).toBeTruthy()
xit 'array match of a property', ->
expect(LocalMongo.matchesQuery(this.fixture1, 'likes':'poptarts')).toBeTruthy()
expect(LocalMongo.matchesQuery(this.fixture1, 'likes':'walks on the beach')).toBeFalsy()
xit '$gt selector', ->
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$gt': 8000)).toBeTruthy()
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$gt': [8000, 10000])).toBeTruthy()
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$gt': 9000)).toBeFalsy()
expect(LocalMongo.matchesQuery(this.fixture1, 'value': {'$gt': 8000}, 'worth': {'$gt': 5})).toBeTruthy()
xit '$gte selector', ->
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$gte': 9001)).toBeFalsy()
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$gte': 9000)).toBeTruthy()
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$gte': [9000, 10000])).toBeTruthy()
xit '$in selector', ->
expect(LocalMongo.matchesQuery(this.fixture1, 'type': '$in': ['unicorn', 'zebra'])).toBeTruthy()
expect(LocalMongo.matchesQuery(this.fixture1, 'type': '$in': ['cats', 'dogs'])).toBeFalsy()
expect(LocalMongo.matchesQuery(this.fixture1, 'likes': '$in': ['popcorn', 'chicken'])).toBeTruthy()
xit '$lt selector', ->
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$lt': 9001)).toBeTruthy()
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$lt': 9000)).toBeFalsy()
expect(LocalMongo.matchesQuery(this.fixture1, 'value': {'$lt': 9001}, 'worth': {'$lt': 7})).toBeTruthy()
xit '$lte selector', ->
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$lte': 9000)).toBeTruthy()
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$lte': 8000)).toBeFalsy()
expect(LocalMongo.matchesQuery(this.fixture1, 'value': {'$lte': 9000}, 'value': {'$lte': [6, 5]})).toBeTruthy()
xit '$ne selector', ->
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$ne': 9000)).toBeFalsy()
expect(LocalMongo.matchesQuery(this.fixture1, 'id': '$ne': 'otherstring')).toBeTruthy()
expect(LocalMongo.matchesQuery(this.fixture1, 'id': '$ne': ['otherstring', 'somestring'])).toBeFalsy()
xit '$in selector', ->
expect(LocalMongo.matchesQuery(this.fixture1, 'type': '$nin': ['unicorn', 'zebra'])).toBeFalsy()
expect(LocalMongo.matchesQuery(this.fixture1, 'type': '$nin': ['cats', 'dogs'])).toBeTruthy()
expect(LocalMongo.matchesQuery(this.fixture1, 'likes': '$nin': ['popcorn', 'chicken'])).toBeFalsy()