Skip to content

Commit

Permalink
Hyperion: Avoid 'No matching document found' version errors while exe…
Browse files Browse the repository at this point in the history
…cuting rule: disabled versionning cause conflict can't be property handled, and data erasure is acceptable
  • Loading branch information
feugy committed Jul 14, 2014
1 parent 09905b1 commit 26eec43
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 12 deletions.
5 changes: 3 additions & 2 deletions docs/TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
- heroku: reload game.repo from s3 at dyno startup, save periodically
- Documentation
- Rule engine
- [!] Handle 'No matching document found' version errors while executing rule and revert execution
- provide rule triggering inside rules, with reloading when imported ruless changed (IA ?)

- Rheia
Expand Down Expand Up @@ -41,7 +40,9 @@
- remove item type property does not update existing items
- bug with map value when retrieving items with search
- fix from handling at event creation
- save new item on a new map : mapId stored in DB, but map object not affected to item (modelWatcher does not send the map)
- save new item on a new map : mapId stored in DB, but map object not affected to item (modelWatcher does not send
the map)
- Avoid 'No matching document found' version errors while executing rule: disabled versionning cause conflict can't be property handled, and data erasure is acceptable
- ImageService to upload and associate images to types
- remove all images when removing a type
- Field type CRUD
Expand Down
7 changes: 5 additions & 2 deletions hyperion/src/model/typeFactory.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,6 @@ module.exports = (typeName, spec, options = {}) ->
when 'deletion'
delete caches[typeName][changes.id]

spec.versionKey = false

if options.typeProperties
# event properties definition, stored by names
Expand Down Expand Up @@ -224,7 +223,11 @@ module.exports = (typeName, spec, options = {}) ->

options._id = false
spec._id = String

# Disable versionning on array properties.
# Versionning avoid data erasure, but the single-thread architecture of Hyperion already enforece this.
# In case of cached values reuse, as we can't handle conflict, we rather prefer to erase data
options.versionKey = false

# Abstract schema, that can contains i18n attributes
AbstractType = new mongoose.Schema spec, options

Expand Down
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
"express": "3.10.3",
"fs-extra": "0.9.1",
"gift": "0.4.2",
"gulp": "3.7.0",
"gulp-clean": "0.3.0",
"gulp-coffee": "2.0.1",
"gulp-plumber": "0.6.2",
"gulp-stylus": "1.0.2",
"gulp-util": "2.2.16",
"isemail": "1.0.1",
"js-yaml": "3.0.2",
"jshint": "2.5.1",
Expand All @@ -37,12 +43,6 @@
},
"devDependencies": {
"chai": "1.9.1",
"gulp": "3.7.0",
"gulp-clean": "0.3.0",
"gulp-coffee": "2.0.1",
"gulp-plumber": "0.6.2",
"gulp-stylus": "1.0.2",
"gulp-util": "2.2.16",
"mocha": "1.20.1",
"phantom-proxy": "0.1.792",
"request": "2.36.0",
Expand All @@ -51,8 +51,8 @@
},
"scripts": {
"start": "node hyperion/bin/start",
"postinstall": "gulp cleanBuild",
"test": "gulp test"
"postinstall": "node node_modules/gulp/bin/gulp.js cleanBuild",
"test": "node node_modules/gulp/bin/gulp.js test"
},
"licence": "LGPL v3",
"engines": {
Expand Down
47 changes: 47 additions & 0 deletions test/testRuleService.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

_ = require 'underscore'
async = require 'async'
{MongoClient, Server} = require 'mongodb'
Executable = require '../hyperion/src/model/Executable'
Item = require '../hyperion/src/model/Item'
Event = require '../hyperion/src/model/Event'
Expand Down Expand Up @@ -610,6 +611,52 @@ describe 'RuleService tests', ->
expect(result).to.satisfy (obj) -> player.equals obj
done()

it 'should data erasure occurs during save', (done) ->
# given an item
new ItemType(id: 'chopper').save (err, type) ->
return done err if err?
new Item(type: type).save (err, item) ->
return done err if err?
# given a rule modifing player
script.content = """Rule = require 'hyperion/model/Rule'
Player = require 'hyperion/model/Player'
class MyRule extends Rule
canExecute: (actor, target, context, callback) =>
callback null, if actor._className is 'Item' then [] else null
execute: (actor, target, params, context, callback) =>
# reuse cached values
Player.findCached ["#{player.id}"], (err, [player]) =>
player.characters.push actor
@saved.push player
callback null, null
module.exports = new MyRule()"""
script.save (err) ->
return done err if err?
# given a client to mongoDB
new MongoClient(new Server utils.confKey('mongo.host'), utils.confKey 'mongo.port', 27017).open (err, client) ->
return done "Unable to open second connection to Mongo #{err}" if err?
db = client.db utils.confKey('mongo.db')
db.collection 'players', (err, collection) ->
return done "Unable to open second connection to Mongo #{err}" if err?

# given a modification into db
collection.update {_id: player._id}, {$push:{characters: event1.id}}, (err) ->
return done "Unable to modify player in DB #{err}" if err?

collection.find(_id: player._id).toArray (err, [player]) ->
return done "Unable to consult cached player #{err}" if err?
expect(player).to.have.property('characters').that.has.lengthOf(1).and.that.include event1.id

# when executing this rule on the player
service.execute 'rule0', item.id, item.id, null, player.email, (err, result)->
expect(err).not.to.exist

# then player in db has rule values
collection.find(_id: player._id).toArray (err, [result]) ->
return done err if err?
expect(result).to.have.property('characters').that.has.lengthOf(1).and.that.include item.id
done()

describe 'given items, events, fields and a dumb rule', ->

beforeEach (done) ->
Expand Down

0 comments on commit 26eec43

Please sign in to comment.