mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 15:48:11 -05:00
Added support for the operator in LocalMongo
This commit is contained in:
parent
bd2b289943
commit
509be067c3
3 changed files with 67 additions and 55 deletions
|
@ -18,6 +18,7 @@ doQuerySelector = (value, operatorObj) ->
|
|||
when '$ne' then return false if mapred value, body, (l, r) -> l == r
|
||||
when '$in' then return false unless _.reduce value, ((result, val) -> result or val in body), false
|
||||
when '$nin' then return false if _.reduce value, ((result, val) -> result or val in body), false
|
||||
when '$exists' then return false if value[0]? isnt body[0]
|
||||
else return false
|
||||
true
|
||||
|
||||
|
@ -34,11 +35,13 @@ matchesQuery = (target, queryObj) ->
|
|||
pieces = prop.split('.')
|
||||
obj = target
|
||||
for piece in pieces
|
||||
return false unless piece of obj
|
||||
unless piece of obj
|
||||
obj = null
|
||||
break
|
||||
obj = obj[piece]
|
||||
if typeof query != 'object' or _.isArray query
|
||||
return false unless obj == query or (query in obj if _.isArray obj)
|
||||
else return false unless doQuerySelector obj, query
|
||||
true
|
||||
|
||||
LocalMongo.matchesQuery = matchesQuery
|
||||
LocalMongo.matchesQuery = matchesQuery
|
||||
|
|
|
@ -17,45 +17,45 @@ class EarnedAchievementHandler extends Handler
|
|||
recalculate: (req, res) ->
|
||||
onSuccess = (data) => @sendSuccess(res, data)
|
||||
if 'achievements' of req.query # Support both slugs and IDs separated by commas
|
||||
achievementSlugsOrIDs = req.query.id.split(',')
|
||||
achievementSlugsOrIDs = req.query.achievements.split(',')
|
||||
EarnedAchievementHandler.recalculate achievementSlugsOrIDs, onSuccess
|
||||
else
|
||||
EarnedAchievementHandler.recalculate onSuccess
|
||||
@sendSuccess res
|
||||
@sendSuccess res
|
||||
|
||||
# Returns success: boolean
|
||||
@recalculate: (callbackOrSlugsOrIDs, callback) ->
|
||||
if _.isArray callbackOrSlugsOrIDs
|
||||
achievementSlugs = (thing unless Handler.isID(thing) for thing in callbackOrSlugsOrIDs)
|
||||
achievementIDs = (thing if Handler.isID(thing) for thing in callbackOrSlugsOrIDs)
|
||||
achievementSlugs = (thing for thing in callbackOrSlugsOrIDs when not Handler.isID(thing))
|
||||
achievementIDs = (thing for thing in callbackOrSlugsOrIDs when Handler.isID(thing))
|
||||
else
|
||||
callback = callbackOrSlugsOrIDs
|
||||
|
||||
filter = {}
|
||||
filter.$or = [
|
||||
_id: $in: achievementIDs
|
||||
slug: $in: achievementSlugs
|
||||
{_id: $in: achievementIDs},
|
||||
{slug: $in: achievementSlugs}
|
||||
] if achievementSlugs? or achievementIDs?
|
||||
|
||||
Achievement.find filter, (err, achievements) ->
|
||||
return false and log.error err if err?
|
||||
User.find {}, (err, users) ->
|
||||
_.each users, (user) ->
|
||||
# Keep track of a user's already achieved so as to set the notified values correctly
|
||||
# Keep track of a user's already achieved in order to set the notified values correctly
|
||||
userID = user.get('_id').toHexString()
|
||||
EarnedAchievement.find {user: userID}, (err, alreadyEarned) ->
|
||||
alreadyEarnedIDs = []
|
||||
previousPoints = 0
|
||||
_.each alreadyEarned, (earned) ->
|
||||
alreadyEarnedIDs.push earned.get('achievement')
|
||||
previousPoints += earned.get 'earnedPoints'
|
||||
if (_.find achievements, (single) -> earned.get('achievement') is single.get('_id').toHexString())
|
||||
alreadyEarnedIDs.push earned.get('achievement')
|
||||
previousPoints += earned.get 'earnedPoints'
|
||||
|
||||
# TODO maybe also delete earned? Make sure you don't delete too many
|
||||
|
||||
newTotalPoints = 0
|
||||
|
||||
earnedAchievementSaverGenerator = (achievement) -> (callback) ->
|
||||
log.debug 'Checking out tha fancy achievement'
|
||||
isRepeatable = achievement.get('proportionalTo')?
|
||||
model = mongoose.model(achievement.get('collection'))
|
||||
if not model?
|
||||
|
@ -78,9 +78,12 @@ class EarnedAchievementHandler extends Handler
|
|||
earned.previouslyAchievedAmount = 0
|
||||
|
||||
expFunction = achievement.getExpFunction()
|
||||
newTotalPoints += expFunction(earned.achievedAmount) * achievement.get('worth')
|
||||
newPoints = expFunction(earned.achievedAmount) * achievement.get('worth')
|
||||
else
|
||||
newTotalPoints += achievement.get 'worth'
|
||||
newPoints = achievement.get 'worth'
|
||||
|
||||
earned.earnedPoints = newPoints
|
||||
newTotalPoints += newPoints
|
||||
|
||||
EarnedAchievement.update {achievement:earned.achievement, user:earned.user}, earned, {upsert: true}, (err) ->
|
||||
log.error err if err?
|
||||
|
@ -93,11 +96,13 @@ class EarnedAchievementHandler extends Handler
|
|||
if _.isEmpty filter # Completely clean
|
||||
User.update {_id: userID}, {$set: points: newTotalPoints}, {}, (err) -> log.error err if err?
|
||||
else
|
||||
log.debug "Incrementing score for these achievements with #{newTotalPoints - previousPoints}"
|
||||
User.update {_id: userID}, {$inc: points: newTotalPoints - previousPoints}, {}, (err) -> log.error err if err?
|
||||
|
||||
earnedAchievementSavers = (earnedAchievementSaverGenerator(achievement) for achievement in achievements)
|
||||
earnedAchievementSavers.push saveUserPoints
|
||||
|
||||
# We need to have all these database updates chained so we know the final score
|
||||
async.series earnedAchievementSavers
|
||||
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ describe 'Local Mongo queries', ->
|
|||
LocalMongo = require 'lib/LocalMongo'
|
||||
|
||||
beforeEach ->
|
||||
this.fixture1 =
|
||||
@fixture1 =
|
||||
'id': 'somestring'
|
||||
'value': 9000
|
||||
'levels': [3, 8, 21]
|
||||
|
@ -10,68 +10,72 @@ describe 'Local Mongo queries', ->
|
|||
'type': 'unicorn'
|
||||
'likes': ['poptarts', 'popsicles', 'popcorn']
|
||||
|
||||
this.fixture2 = this: is: so: 'deep'
|
||||
@fixture2 = this: is: so: 'deep'
|
||||
|
||||
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()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'gender': 'unicorn')).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type':'unicorn')).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type':'zebra')).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type':'unicorn', 'id':'somestring')).toBeTruthy()
|
||||
|
||||
it 'array match of a property', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'likes':'poptarts')).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'likes':'walks on the beach')).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'likes':'poptarts')).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'likes':'walks on the beach')).toBeFalsy()
|
||||
|
||||
it 'nested match', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture2, 'this.is.so':'deep')).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture2, 'this.is.so':'deep')).toBeTruthy()
|
||||
|
||||
it '$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, 'levels': '$gt': [10, 20, 30])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': '$gt': 9000)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': {'$gt': 8000}, 'worth': {'$gt': 5})).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$gt': 8000)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$gt': [8000, 10000])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'levels': '$gt': [10, 20, 30])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$gt': 9000)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': {'$gt': 8000}, 'worth': {'$gt': 5})).toBeTruthy()
|
||||
|
||||
it '$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()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'levels': '$gte': [21, 30])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$gte': 9001)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$gte': 9000)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$gte': [9000, 10000])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'levels': '$gte': [21, 30])).toBeTruthy()
|
||||
|
||||
it '$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, 9000])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'levels': '$lt': [10, 20, 30])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'value': {'$lt': 9001}, 'worth': {'$lt': 7})).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$lt': 9001)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$lt': 9000)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$lt': [9001, 9000])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'levels': '$lt': [10, 20, 30])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': {'$lt': 9001}, 'worth': {'$lt': 7})).toBeTruthy()
|
||||
|
||||
it '$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}, 'worth': {'$lte': [6, 5]})).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$lte': 9000)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$lte': 8000)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': {'$lte': 9000}, 'worth': {'$lte': [6, 5]})).toBeTruthy()
|
||||
|
||||
it '$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()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, 'likes': '$ne': ['popcorn', 'chicken'])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'value': '$ne': 9000)).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'id': '$ne': 'otherstring')).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'id': '$ne': ['otherstring', 'somestring'])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'likes': '$ne': ['popcorn', 'chicken'])).toBeFalsy()
|
||||
|
||||
it '$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()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type': '$in': ['unicorn', 'zebra'])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type': '$in': ['cats', 'dogs'])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'likes': '$in': ['popcorn', 'chicken'])).toBeTruthy()
|
||||
|
||||
it '$nin 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()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type': '$nin': ['unicorn', 'zebra'])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'type': '$nin': ['cats', 'dogs'])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, 'likes': '$nin': ['popcorn', 'chicken'])).toBeFalsy()
|
||||
|
||||
it '$or operator', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, $or: [{value:9000}, {type:'zebra'}])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, $or: [{value:9001}, {worth:$lt:10}])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, $or: [{value:9000}, {type:'zebra'}])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, $or: [{value:9001}, {worth:$lt:10}])).toBeTruthy()
|
||||
|
||||
it '$and operator', ->
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, $and: [{value:9000}, {type:'zebra'}])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, $and: [{value:9000}, {type:'unicorn'}])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(this.fixture1, $and: [{value:$gte:9000}, {worth:$lt:10}])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, $and: [{value:9000}, {type:'zebra'}])).toBeFalsy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, $and: [{value:9000}, {type:'unicorn'}])).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, $and: [{value:$gte:9000}, {worth:$lt:10}])).toBeTruthy()
|
||||
|
||||
it '$exists operator', ->
|
||||
expect(LocalMongo.matchesQuery(@fixture1, type: $exists: true)).toBeTruthy()
|
||||
expect(LocalMongo.matchesQuery(@fixture1, interesting: $exists: false)).toBeTruthy()
|
||||
|
||||
|
|
Loading…
Reference in a new issue