desc: Tests insertion into tables table_variable_name: tbl tests: # Set up our secondary test table - cd: r.db('test').table_create('test2') ot: partial({'tables_created':1}) - def: tbl2 = r.db('test').table('test2') # Single doc insert - cd: tbl.insert({'id':0,'a':0}) ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':1} - cd: tbl.count() ot: 1 # Hard durability insert - py: tbl.insert({'id':1, 'a':1}, durability='hard') js: tbl.insert({id:1, a:1}, {durability:'hard'}) rb: tbl.insert({ :id => 1, :a => 1 }, { :durability => 'hard' }) ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':1} - cd: tbl.count() ot: 2 # Soft durability insert - py: tbl.insert({'id':2, 'a':2}, durability='soft') js: tbl.insert({id:2, a:2}, {durability:'soft'}) rb: tbl.insert({ :id => 2, :a => 2 }, { :durability => 'soft' }) ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':1} - cd: tbl.count() ot: 3 # Wrong durability insert - py: tbl.insert({'id':3, 'a':3}, durability='wrong') js: tbl.insert({id:3, a:3}, {durability:'wrong'}) rb: tbl.insert({ :id => 3, :a => 3 }, { :durability => 'wrong' }) ot: err('ReqlQueryLogicError', 'Durability option `wrong` unrecognized (options are "hard" and "soft").', [0]) - cd: tbl.count() ot: 3 # Cleanup. - cd: tbl.get(2).delete() ot: {'deleted':1,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':0} # Multi doc insert - cd: tbl.insert([{'id':2,'a':2}, {'id':3,'a':3}]) ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':2} # Stream insert - cd: tbl2.insert(tbl) ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':4} # test pkey clash error - cd: tbl.insert({'id':2,'b':20}) ot: {'first_error':"Duplicate primary key `id`:\n{\n\t\"a\":\t2,\n\t\"id\":\t2\n}\n{\n\t\"b\":\t20,\n\t\"id\":\t2\n}",'deleted':0,'replaced':0,'unchanged':0,'errors':1,'skipped':0,'inserted':0} # test error conflict option (object exists) - py: tbl.insert({'id':2,'b':20}, conflict='error') js: tbl.insert({'id':2,'b':20}, {conflict:'error'}) rb: tbl.insert({:id => 2, :b => 20}, { :conflict => 'error' }) ot: {'first_error':"Duplicate primary key `id`:\n{\n\t\"a\":\t2,\n\t\"id\":\t2\n}\n{\n\t\"b\":\t20,\n\t\"id\":\t2\n}",'deleted':0,'replaced':0,'unchanged':0,'errors':1,'skipped':0,'inserted':0} # test error conflict option (object doesn't exist) - py: tbl.insert({'id':15,'b':20}, conflict='error') js: tbl.insert({'id':15,'b':20}, {conflict:'error'}) rb: tbl.insert({:id => 15, :b => 20}, { :conflict => 'error' }) ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':1} - cd: tbl.get(15) ot: {'id':15,'b':20} # test replace conflict option (object exists) - py: tbl.insert({'id':2,'b':20}, conflict='replace') js: tbl.insert({'id':2,'b':20}, {conflict:'replace'}) rb: tbl.insert({:id => 2, :b => 20}, { :conflict => 'replace' }) ot: {'deleted':0,'replaced':1,'unchanged':0,'errors':0,'skipped':0,'inserted':0} - cd: tbl.get(2) ot: {'id':2,'b':20} # test replace conflict option (object doesn't exist) - py: tbl.insert({'id':20,'b':20}, conflict='replace') js: tbl.insert({'id':20,'b':20}, {conflict:'replace'}) rb: tbl.insert({:id => 20, :b => 20}, { :conflict => 'replace' }) ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':1} - cd: tbl.get(20) ot: {'id':20,'b':20} # test update conflict option (object exists) - py: tbl.insert({'id':2,'c':30}, conflict='update') js: tbl.insert({'id':2,'c':30}, {conflict:'update'}) rb: tbl.insert({:id => 2, :c => 30}, { :conflict => 'update' }) ot: {'deleted':0,'replaced':1,'unchanged':0,'errors':0,'skipped':0,'inserted':0} - cd: tbl.get(2) ot: {'id':2, 'b':20, 'c':30} # test update conflict option (object doesn't exist) - py: tbl.insert({'id':30,'b':20}, conflict='update') js: tbl.insert({'id':30,'b':20}, {conflict:'update'}) rb: tbl.insert({:id => 30, :b => 20}, { :conflict => 'update' }) ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':1} - cd: tbl.get(30) ot: {'id':30,'b':20} # test incorrect conflict option - py: tbl.insert({'id':3, 'a':3}, conflict='wrong') js: tbl.insert({id:3, a:3}, {conflict:'wrong'}) rb: tbl.insert({ :id => 3, :a => 3 }, { :conflict => 'wrong' }) ot: err('ReqlQueryLogicError', 'Conflict option `wrong` unrecognized (options are "error", "replace" and "update").', [0]) # test auto pkey generation - py: r.db('test').table_create('testpkey', primary_key='foo') js: r.db('test').tableCreate('testpkey', {primaryKey:'foo'}) rb: r.db('test').table_create('testpkey', { :primary_key => 'foo' }) ot: partial({'tables_created':1}) def: tblpkey = r.db('test').table('testpkey') - cd: tblpkey.insert({}) ot: {'deleted':0,'replaced':0,'generated_keys':arrlen(1,uuid()),'unchanged':0,'errors':0,'skipped':0,'inserted':1} - cd: tblpkey ot: [{'foo':uuid()}] # test replace conflict pkey generation - py: tblpkey.insert({'b':20}, conflict='replace') js: tblpkey.insert({'b':20}, {conflict:'replace'}) rb: tblpkey.insert({:b => 20}, { :conflict => 'replace' }) ot: {'deleted':0,'replaced':0,'generated_keys':arrlen(1,uuid()),'unchanged':0,'errors':0,'skipped':0,'inserted':1} # test update conflict pkey generation - py: tblpkey.insert({'b':20}, conflict='update') js: tblpkey.insert({'b':20}, {conflict:'update'}) rb: tblpkey.insert({:b => 20}, { :conflict => 'update' }) ot: {'deleted':0,'replaced':0,'generated_keys':arrlen(1,uuid()),'unchanged':0,'errors':0,'skipped':0,'inserted':1} - cd: r.db('test').table_drop('testpkey') ot: partial({'tables_dropped':1}) # Insert within for each - py: tbl.for_each(lambda row: tbl2.insert(row.merge({'id':row['id'] + 100 })) ) js: tbl.forEach(function(row) { return tbl2.insert(row.merge({'id':row('id').add(100)})); }) rb: tbl.for_each(proc { |row| tbl2.insert(row.merge({'id'=>row['id'] + 100 })) }) ot: {'deleted':0,'replaced':0,'unchanged':0,'errors':0,'skipped':0,'inserted':7} # Insert unwritable data - cd: tbl.insert({'value':r.minval}) rb: tbl.insert({:value => r.minval}) ot: partial({'errors':1,'first_error':'`r.minval` and `r.maxval` cannot be written to disk.'}) - cd: tbl.insert({'value':r.maxval}) rb: tbl.insert({:value => r.maxval}) ot: partial({'errors':1,'first_error':'`r.minval` and `r.maxval` cannot be written to disk.'}) # Crash 5683 - py: tbl.insert([{'id':666}, {'id':666}], return_changes="always") ot: {'changes': [{'new_val': {'id': 666}, 'old_val': None},{'error': 'Duplicate primary key `id`:\n{\n\t"id":\t666\n}\n{\n\t"id":\t666\n}','new_val': {'id': 666},'old_val': {'id': 666}}],'deleted': 0,'errors': 1,'first_error': 'Duplicate primary key `id`:\n{\n\t"id":\t666\n}\n{\n\t"id":\t666\n}','inserted': 1,'replaced': 0,'skipped': 0,'unchanged': 0} # Confirm inserts are ordered in return_changes always - py: tbl.insert([{'id':100+i, 'ordered-num':i} for i in range(1,100)], return_changes="always") ot: partial({'changes':[{'old_val': None, 'new_val': {'id': 100+i, 'ordered-num': i}} for i in range(1,100)] }) # Confirm inserts are ordered in return_changes always with complicated key - py: tbl.insert([{'id':[1, "blah", 200+i], 'ordered-num':i} for i in range(1,100)], return_changes="always") ot: partial({'changes':[{'old_val': None, 'new_val': {'id': [1,"blah", 200+i], 'ordered-num': i}} for i in range(1,100)] }) # Confirm inserts are ordered in return_changes always with return_changes=true - py: tbl.insert([{'id':[1, "blah", 300+i], 'ordered-num':i} for i in range(1,100)], return_changes=true) ot: partial({'changes':[{'old_val': None, 'new_val': {'id': [1,"blah", 300+i], 'ordered-num': i}} for i in range(1,100)] }) # Confirm errors are property returned with return_changes="always" - py: tbl.insert([{'id':100 + i, 'ordered-num':i} for i in range(1,100)], return_changes="always") ot: partial({'changes':[{'old_val': {'id':100+i, 'ordered-num':i}, 'new_val': {'id':100+i, 'ordered-num':i}, 'error':'Duplicate primary key `id`:\n{\n\t"id":\t'+str(100+i)+',\n\t"ordered-num":\t'+str(i)+'\n}\n{\n\t"id":\t'+str(100+i)+',\n\t"ordered-num":\t'+str(i)+'\n}'} for i in range(1,100)]}) # Trivial errors with return_changes="always", this has to be long test, testing order and message for this type - py: tbl.insert([{'id':123}, {'id':'a'*500}, {'id':321}], return_changes="always") ot: {'changes': [{'error': 'Duplicate primary key `id`:\n{\n\t"id":\t123,\n\t"ordered-num":\t23\n}\n{\n\t"id":\t123\n}', 'new_val': {'id': 123, 'ordered-num': 23}, 'old_val': {'id': 123, 'ordered-num': 23}}, {'error': 'Primary key too long (max 127 characters): "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"', 'new_val': None, 'old_val': None}, {'new_val': {'id': 321}, 'old_val': None}], 'deleted': 0, 'errors': 2, 'first_error': 'Primary key too long (max 127 characters): "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"', 'inserted': 1, 'replaced': 0, 'skipped': 0, 'unchanged': 0} # No errors returned with return_changes=true - py: tbl.insert([{'id':100 + i, 'ordered-num':i} for i in range(1,100)], return_changes=true) ot: partial({'changes':[]}) - py: tbl.insert({'a':r.minval}, return_changes="always") ot: partial({'changes': [{'old_val': None, 'new_val': None, 'error': '`r.minval` and `r.maxval` cannot be written to disk.'}]}) # Tests for insert conflict resolution function # Using a conflict function - cd: tbl.insert({'id':42, 'foo':1, 'bar':1}) ot: partial({'inserted':1}) - py: tbl.insert({'id':42, 'foo':5, 'bar':5}, conflict=lambda id, old_row, new_row: old_row.merge(new_row.pluck("bar"))) ot: partial({'replaced':1}) - py: tbl.get(42) ot: {'id':42, 'foo':1, 'bar':5} - rb: tbl.insert({:id=>42, :foo=>6, :bar=>6}, conflict: lambda {|id, old_row, new_row| return old_row.merge(new_row.pluck("bar"))}) ot: partial({'replaced':1}) - rb: tbl.get(42) ot: {'id':42, 'foo':1, 'bar':6} - js: tbl.insert({'id':42, 'foo':7, 'bar':7}, {conflict: function(id, old_row, new_row) {return old_row.merge(new_row.pluck("bar"))}}) ot: partial({'replaced':1}) - js: tbl.get(42) ot: {'id':42, 'foo':1, 'bar':7} # Inserting and deleting an item - js: tbl.insert({id: "toggle"},{conflict: function(x,y,z) { return null},returnChanges: true}) ot: partial({'inserted': 1}) - js: tbl.insert({id: "toggle"},{conflict: function(x,y,z) { return null},returnChanges: true}) ot: partial({'deleted': 1}) # Returning the wrong thing from the conflict function - py: tbl.insert({'id':42, 'foo':1, 'bar':1}, conflict=lambda a,b,c: 2) ot: partial({'first_error': 'Inserted value must be an OBJECT (got NUMBER):\n2'}) # Incorrect Arity - py: tbl.insert({'id':42}, conflict=lambda a,b: a) ot: err("ReqlQueryLogicError", "The conflict function passed to `insert` should expect 3 arguments.") # Non atomic operation - py: tbl.insert({'id':42}, conflict=lambda a,b,c: tbl.get(42)) ot: err("ReqlQueryLogicError", "The conflict function passed to `insert` must be deterministic.") - py: tbl.insert({'id':42}, conflict=lambda a,b,c: {'id':42, 'num':'424'}) ot: partial({'replaced': 1}) - py: tbl.get(42) ot: {'id':42, 'num':'424'} # Get unreturnable data - cd: r.minval ot: err('ReqlQueryLogicError','Cannot convert `r.minval` to JSON.') - cd: r.maxval ot: err('ReqlQueryLogicError','Cannot convert `r.maxval` to JSON.') # clean up - cd: r.db('test').table_drop('test2') ot: partial({'tables_dropped':1})