desc: Tests updates of selections
tests:

    # Set up some data
    - cd: r.db('test').table_create('test1')
      ot: ({'created':1})

    - def: tbl = r.db('test').table('test1')

    - cd: r.db('test').table_create('test2')
      ot: ({'created':1})

    - def: tbl2 = r.db('test').table('test2')

    - py: tbl.insert([{'id':i} for i in xrange(100)])
      js: |
        tbl.insert(function(){
            var res = []
            for (var i = 0; i < 100; i++) {
                res.push({id:i});
            }
            return res;
        }())
      rb: tbl.insert((0...100).map{ |i| { :id => i } })
      ot: ({'deleted':0.0,'replaced':0.0,'unchanged':0.0,'errors':0.0,'skipped':0.0,'inserted':100})

    - cd: tbl.count()
      ot: 100

    - py: tbl2.insert([{'id':i, 'foo':{'bar':i}} for i in xrange(100)])
      js: |
        tbl2.insert(function(){
            var res = []
            for (var i = 0; i < 100; i++) {
                res.push({id:i,foo:{bar:i}});
            }
            return res;
        }())
      rb: tbl2.insert((0...100).map{ |i| { :id => i, :foo => { :bar => i } } })
      ot: ({'deleted':0.0,'replaced':0.0,'unchanged':0.0,'errors':0.0,'skipped':0.0,'inserted':100})

    - cd: tbl2.count()
      ot: 100

    # Identity
    - py: tbl.get(12).update(lambda row:row)
      js: tbl.get(12).update(function(row) { return row; })
      rb: tbl.get(12).update{ |row| row}
      ot: ({'deleted':0.0,'replaced':0.0,'unchanged':1,'errors':0.0,'skipped':0.0,'inserted':0.0})

    # Soft durability point update
    - py: tbl.get(12).update(lambda row:{'a':row['id'] + 1}, durability='soft')
      js: tbl.get(12).update(function(row) { return {'a':row('id').add(1)}; }, {durability:'soft'})
      rb: tbl.get(12).update({ :durability => 'soft' }) { |row| { :a => row[:id] + 1 } }
      ot: ({'deleted':0.0,'replaced':1,'unchanged':0.0,'errors':0.0,'skipped':0.0,'inserted':0.0})

    - cd: tbl.get(12)
      ot: ({'id':12, 'a':13})

    # Hard durability point update
    - py: tbl.get(12).update(lambda row:{'a':row['id'] + 2}, durability='hard')
      js: tbl.get(12).update(function(row) { return {'a':row('id').add(2)}; }, {durability:'hard'})
      rb: tbl.get(12).update({ :durability => 'hard' }) { |row| { :a => row[:id] + 2 } }
      ot: ({'deleted':0.0,'replaced':1,'unchanged':0.0,'errors':0.0,'skipped':0.0,'inserted':0.0})

    - cd: tbl.get(12)
      ot: ({'id':12, 'a':14})

    # Wrong durability point update
    - py: tbl.get(12).update(lambda row:{'a':row['id'] + 3}, durability='wrong')
      js: tbl.get(12).update(function(row) { return {'a':row('id').add(3)}; }, {durability:'wrong'})
      rb: tbl.get(12).update({ :durability => 'wrong' }) { |row| { :a => row[:id] + 3 } }
      ot: err('RqlRuntimeError', 'Durability option `wrong` unrecognized (options are "hard" and "soft").', [0])

    - cd: tbl.get(12)
      ot: ({'id':12, 'a':14})

    # Point update
    - py: tbl.get(12).update(lambda row:{'a':row['id']})
      js: tbl.get(12).update(function(row) { return {'a':row('id')}; })
      rb: tbl.get(12).update{ |row| { :a => row[:id] } }
      ot: ({'deleted':0.0,'replaced':1,'unchanged':0.0,'errors':0.0,'skipped':0.0,'inserted':0.0})

    - cd: tbl.get(12)
      ot: ({'id':12, 'a':12})

    # undo the point update
    - cd: tbl.get(12).update({'a':r.literal()})
      ot: ({'deleted':0.0,'replaced':1,'unchanged':0.0,'errors':0.0,'skipped':0.0,'inserted':0.0})

    # Update selection of table

    - py: tbl.between(10, 20).update(lambda row:{'a':row['id']})
      js: tbl.between(10, 20).update(function(row) { return {'a':row('id')}; })
      rb: tbl.between(10, 20).update{ |row| { :a => row[:id] } }
      ot: ({'deleted':0.0,'replaced':10,'unchanged':0,'errors':0.0,'skipped':0.0,'inserted':0.0})

    - py: tbl.filter(lambda row:(row['id'] >= 10) & (row['id'] < 20)).update(lambda row:{'a':row['id']})
      js: tbl.filter(function(row) { return row('id').ge(10).and(row('id').lt(20))}).update(function(row) { return {'a':row('id')}; })
      rb: tbl.filter{ |row| (row[:id] >= 10).and(row[:id] < 20) }.update{ |row| { :a => row[:id] } }
      ot: ({'deleted':0.0,'replaced':0.0,'unchanged':10,'errors':0.0,'skipped':0.0,'inserted':0.0})

    - py: tbl.filter(lambda row:(row['id'] >= 10) & (row['id'] < 20)).update(lambda row:{'b':row['id']})
      js: tbl.filter(function(row) { return row('id').ge(10).and(row('id').lt(20))}).update(function(row) { return {'b':row('id')}; })
      rb: tbl.filter{ |row| (row[:id] >= 10).and(row[:id] < 20) }.update{ |row| { :b => row[:id] } }
      ot: ({'deleted':0.0,'replaced':10,'unchanged':0.0,'errors':0.0,'skipped':0.0,'inserted':0.0})

    # now undo that update
    - cd: tbl.between(10, 20).update({'a':r.literal()})
      ot: ({'deleted':0.0,'replaced':10,'unchanged':0,'errors':0.0,'skipped':0.0,'inserted':0.0})

    # trying to change pkey of a document
    - cd: tbl.get(1).update({'id':2,'d':1})
      rb: [] # the ruby test driver cannot parse the expected error message
      ot: ({'first_error':'Primary key `id` cannot be changed (`{\n\t"id":\t1\n}` -> `{\n\t"d":\t1,\n\t"id":\t2\n}`).','deleted':0.0,'replaced':0.0,'unchanged':0.0,'errors':1,'skipped':0.0,'inserted':0.0})

    # check r.row, static value and otherwise
    - py: tbl.get(1).update({'id':r.row['id'],'d':'b'})
      js: tbl.get(1).update({'id':r.row('id'),'d':'b'})
      rb: tbl.get(1).update{ |row| { :id => row[:id], :d => 'b' } }
      ot: ({'deleted':0.0,'replaced':1,'unchanged':0.0,'errors':0.0,'skipped':0.0,'inserted':0.0})

    # I don't we don't need the merge, just testing r.row just in case
    - cd: tbl.get(1).update(r.row.merge({'d':'b'}))
      rb: tbl.get(1).update{ |row| row.merge({'d':'b'}) }
      ot: ({'deleted':0.0,'replaced':0.0,'unchanged':1,'errors':0.0,'skipped':0.0,'inserted':0.0})

    # test atomicity constraints (positive and negative test)
    - cd: tbl.get(1).update({'d':r.js('5')})
      ot: err('RqlRuntimeError', 'Could not prove function deterministic.  Maybe you want to use the non_atomic flag?', [0])

    - cd: tbl.get(1).update({'d':tbl.nth(0)})
      ot: err('RqlRuntimeError', 'Could not prove function deterministic.  Maybe you want to use the non_atomic flag?', [0])

    - py: tbl.get(1).update({'d':r.js('5')}, non_atomic=True)
      js: tbl.get(1).update({'d':r.js('5')}, {'nonAtomic':true})
      rb: tbl.get(1).update({ :d => r.js('5') }, { :non_atomic => true })
      ot: ({'deleted':0.0,'replaced':1,'unchanged':0.0,'errors':0.0,'skipped':0.0,'inserted':0.0})

    - js: tbl.get(1).update({}, 'foo')
      cd: []
      ot: err('RqlDriverError', 'Expected 1 argument(s) but found 2.')

    - js: tbl.get(1).update({}, {'foo':'bar'})
      cd: []
      ot: err('RqlCompileError', 'Unrecognized optional argument `foo`.')

    # Update whole table
    - py: tbl.update(lambda row:{'a':row['id']})
      js: tbl.update(function(row) { return {'a':row('id')}; })
      rb: tbl.update{ |row| { :a => row['id'] } }
      ot: ({'deleted':0.0,'replaced':100,'unchanged':0,'errors':0.0,'skipped':0.0,'inserted':0.0})

    # undo the update on the whole table
    - cd: tbl.update({'a':r.literal()})
      ot: ({'deleted':0.0,'replaced':100,'unchanged':0,'errors':0.0,'skipped':0.0,'inserted':0.0})

    # recursive merge
    - cd: tbl2.update({'foo':{'bar':2}})
      ot: ({'deleted':0.0,'replaced':99,'unchanged':1,'errors':0.0,'skipped':0.0,'inserted':0.0})

    - cd: tbl2.order_by('id').nth(0)
      ot: ({'id':0,'foo':{'bar':2}})

    - cd: tbl2.update({'foo':{'buzz':2}})
      ot: ({'deleted':0.0,'replaced':100,'unchanged':0,'errors':0.0,'skipped':0.0,'inserted':0.0})

    - cd: tbl2.order_by('id').nth(0)
      ot: ({'id':0,'foo':{'bar':2,'buzz':2}})

    - cd: tbl2.update({'foo':r.literal(1)})
      ot: ({'deleted':0.0,'replaced':100,'unchanged':0,'errors':0.0,'skipped':0.0,'inserted':0.0})

    - cd: tbl2.order_by('id').nth(0)
      ot: ({'id':0,'foo':1})

    # clean up
    - cd: r.db('test').table_drop('test1')
      ot: ({'dropped':1})
    - cd: r.db('test').table_drop('test2')
      ot: ({'dropped':1})

