@@ -66,6 +66,13 @@ private class ParamKeySaveOperation < ValueColumnModel::SaveOperation
66
66
end
67
67
68
68
private class UpsertUserOperation < User ::SaveOperation
69
+ include QuerySpy
70
+
71
+ upsert_lookup_columns :name , :nickname
72
+ upsert_unique_on :name , :nickname
73
+ end
74
+
75
+ private class UpsertWithoutUniqueKeys < User ::SaveOperation
69
76
upsert_lookup_columns :name , :nickname
70
77
end
71
78
@@ -307,6 +314,147 @@ describe "Avram::SaveOperation" do
307
314
end
308
315
end
309
316
317
+ describe " .upsert" do
318
+ it " should only proc one query" do
319
+ UpsertUserOperation .times_called = 0
320
+ some_time = Time .utc(2016 , 2 , 15 , 10 , 20 , 30 )
321
+
322
+ updates = [
323
+ {
324
+ name: " Name 1" ,
325
+ nickname: " Nickname 1" ,
326
+ age: 42 ,
327
+ joined_at: some_time,
328
+ created_at: some_time,
329
+ updated_at: some_time,
330
+ },
331
+ {
332
+ name: " Name 2" ,
333
+ nickname: " Nickname 2" ,
334
+ age: 42 ,
335
+ joined_at: some_time,
336
+ created_at: some_time,
337
+ updated_at: some_time,
338
+ },
339
+ ]
340
+
341
+ records = UpsertUserOperation .upsert(updates)
342
+ UpsertUserOperation .times_called.should eq 1
343
+ end
344
+
345
+ context " when a record already exists" do
346
+ before_each do
347
+ UserFactory .create do |u |
348
+ u.name(" Name 1" )
349
+ u.nickname(" Nickname 1" )
350
+ u.age(42 )
351
+ u.year_born(1960 )
352
+ u.joined_at(Time .utc)
353
+ end
354
+ end
355
+
356
+ it " allows manual passing of updated_at, but ignores created_at" do
357
+ some_time = Time .utc(2016 , 2 , 15 , 10 , 20 , 30 )
358
+
359
+ update = {
360
+ name: " Name 1" ,
361
+ nickname: " Nickname 1" ,
362
+ age: 42 ,
363
+ joined_at: some_time,
364
+ created_at: some_time,
365
+ updated_at: some_time,
366
+ }
367
+
368
+ records = UpsertUserOperation .upsert([update])
369
+ records.first.created_at.should_not eq some_time
370
+ records.first.updated_at.should eq some_time
371
+ end
372
+
373
+ it " should create one, and update the other record" do
374
+ update = {
375
+ name: " Name 1" ,
376
+ nickname: " Nickname 1" ,
377
+ year_born: nil ,
378
+ age: 42 ,
379
+ joined_at: Time .utc,
380
+ }
381
+
382
+ insert = {
383
+ name: " Name 2" ,
384
+ nickname: " Nickname 2" ,
385
+ year_born: 1980 _i16 ,
386
+ age: 64 ,
387
+ joined_at: Time .utc,
388
+ }
389
+
390
+ records = UpsertUserOperation .upsert([update, insert])
391
+
392
+ records.first.id.should_not eq nil
393
+ records.last.id.should_not eq nil
394
+ records.first.year_born.should eq nil
395
+ records.last.year_born.should eq 1980 _i16
396
+ end
397
+ end
398
+
399
+ context " when no records exist" do
400
+ it " allows manual passing of id" do
401
+ insert = {
402
+ id: 42 _i64 ,
403
+ name: " Name 1" ,
404
+ nickname: " Nickname 1" ,
405
+ age: 42 ,
406
+ joined_at: Time .utc,
407
+ }
408
+
409
+ records = UpsertUserOperation .upsert([insert])
410
+ records.first.id.should eq 42 _i64
411
+ end
412
+
413
+ it " allows manual passing of updated_at and created_at" do
414
+ some_time = Time .utc(2016 , 2 , 15 , 10 , 20 , 30 )
415
+
416
+ insert = {
417
+ name: " Name 1" ,
418
+ nickname: " Nickname 1" ,
419
+ age: 42 ,
420
+ joined_at: some_time,
421
+ created_at: some_time,
422
+ updated_at: some_time,
423
+ }
424
+
425
+ records = UpsertUserOperation .upsert([insert])
426
+ records.first.id.should_not eq nil
427
+ records.first.created_at.should eq some_time
428
+ records.first.updated_at.should eq some_time
429
+ end
430
+ end
431
+
432
+ context " when the tuple values are passed in different orders" do
433
+ it " should upsert records" do
434
+ record_args = [
435
+ {
436
+ name: " Name 1" ,
437
+ nickname: " Nickname 1" ,
438
+ year_born: nil ,
439
+ age: 42 ,
440
+ joined_at: Time .utc,
441
+ },
442
+ {
443
+ nickname: " Nickname 2" ,
444
+ name: " Name 2" ,
445
+ age: 42 ,
446
+ joined_at: Time .utc,
447
+ year_born: nil ,
448
+ },
449
+ ]
450
+
451
+ records = UpsertUserOperation .upsert(record_args)
452
+ records.last.nickname.should eq " Nickname 2"
453
+ records.last.name.should eq " Name 2"
454
+ end
455
+ end
456
+ end
457
+
310
458
describe " #errors" do
311
459
it " includes errors for all operation attributes" do
312
460
operation = SaveUser .new
0 commit comments