massive_record 0.2.1 → 0.2.2.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. data/CHANGELOG.md +58 -2
  2. data/Gemfile.lock +17 -17
  3. data/README.md +98 -41
  4. data/lib/massive_record.rb +2 -1
  5. data/lib/massive_record/adapters/thrift/hbase/hbase.rb +2425 -2154
  6. data/lib/massive_record/adapters/thrift/hbase/hbase_constants.rb +3 -3
  7. data/lib/massive_record/adapters/thrift/hbase/hbase_types.rb +195 -195
  8. data/lib/massive_record/adapters/thrift/row.rb +35 -4
  9. data/lib/massive_record/adapters/thrift/table.rb +49 -12
  10. data/lib/massive_record/orm/attribute_methods.rb +77 -5
  11. data/lib/massive_record/orm/attribute_methods/cast_numbers_on_write.rb +24 -0
  12. data/lib/massive_record/orm/attribute_methods/dirty.rb +18 -0
  13. data/lib/massive_record/orm/attribute_methods/time_zone_conversion.rb +24 -3
  14. data/lib/massive_record/orm/attribute_methods/write.rb +8 -1
  15. data/lib/massive_record/orm/base.rb +62 -8
  16. data/lib/massive_record/orm/column.rb +7 -11
  17. data/lib/massive_record/orm/default_id.rb +1 -1
  18. data/lib/massive_record/orm/embedded.rb +66 -0
  19. data/lib/massive_record/orm/errors.rb +17 -0
  20. data/lib/massive_record/orm/finders.rb +124 -71
  21. data/lib/massive_record/orm/finders/rescue_missing_table_on_find.rb +1 -1
  22. data/lib/massive_record/orm/finders/scope.rb +58 -34
  23. data/lib/massive_record/orm/id_factory.rb +22 -105
  24. data/lib/massive_record/orm/id_factory/atomic_incrementation.rb +117 -0
  25. data/lib/massive_record/orm/id_factory/timestamp.rb +60 -0
  26. data/lib/massive_record/orm/identity_map.rb +256 -0
  27. data/lib/massive_record/orm/log_subscriber.rb +18 -0
  28. data/lib/massive_record/orm/observer.rb +69 -0
  29. data/lib/massive_record/orm/persistence.rb +47 -119
  30. data/lib/massive_record/orm/persistence/operations.rb +100 -0
  31. data/lib/massive_record/orm/persistence/operations/atomic_operation.rb +71 -0
  32. data/lib/massive_record/orm/persistence/operations/destroy.rb +17 -0
  33. data/lib/massive_record/orm/persistence/operations/embedded/destroy.rb +26 -0
  34. data/lib/massive_record/orm/persistence/operations/embedded/insert.rb +27 -0
  35. data/lib/massive_record/orm/persistence/operations/embedded/operation_helpers.rb +66 -0
  36. data/lib/massive_record/orm/persistence/operations/embedded/reload.rb +39 -0
  37. data/lib/massive_record/orm/persistence/operations/embedded/update.rb +29 -0
  38. data/lib/massive_record/orm/persistence/operations/insert.rb +19 -0
  39. data/lib/massive_record/orm/persistence/operations/reload.rb +26 -0
  40. data/lib/massive_record/orm/persistence/operations/suppress.rb +15 -0
  41. data/lib/massive_record/orm/persistence/operations/table_operation_helpers.rb +106 -0
  42. data/lib/massive_record/orm/persistence/operations/update.rb +25 -0
  43. data/lib/massive_record/orm/query_instrumentation.rb +26 -49
  44. data/lib/massive_record/orm/raw_data.rb +47 -0
  45. data/lib/massive_record/orm/relations.rb +4 -0
  46. data/lib/massive_record/orm/relations/interface.rb +134 -0
  47. data/lib/massive_record/orm/relations/metadata.rb +58 -12
  48. data/lib/massive_record/orm/relations/proxy.rb +17 -12
  49. data/lib/massive_record/orm/relations/proxy/embedded_in.rb +54 -0
  50. data/lib/massive_record/orm/relations/proxy/embedded_in_polymorphic.rb +15 -0
  51. data/lib/massive_record/orm/relations/proxy/embeds_many.rb +215 -0
  52. data/lib/massive_record/orm/relations/proxy/references_many.rb +112 -88
  53. data/lib/massive_record/orm/relations/proxy/references_one.rb +1 -1
  54. data/lib/massive_record/orm/relations/proxy/references_one_polymorphic.rb +1 -1
  55. data/lib/massive_record/orm/relations/proxy_collection.rb +84 -0
  56. data/lib/massive_record/orm/schema/column_family.rb +3 -2
  57. data/lib/massive_record/orm/schema/{column_interface.rb → embedded_interface.rb} +38 -4
  58. data/lib/massive_record/orm/schema/field.rb +2 -0
  59. data/lib/massive_record/orm/schema/table_interface.rb +19 -2
  60. data/lib/massive_record/orm/single_table_inheritance.rb +37 -2
  61. data/lib/massive_record/orm/timestamps.rb +17 -7
  62. data/lib/massive_record/orm/validations.rb +4 -0
  63. data/lib/massive_record/orm/validations/associated.rb +50 -0
  64. data/lib/massive_record/rails/railtie.rb +31 -0
  65. data/lib/massive_record/version.rb +1 -1
  66. data/lib/massive_record/wrapper/cell.rb +8 -1
  67. data/massive_record.gemspec +4 -4
  68. data/spec/adapter/thrift/atomic_increment_spec.rb +16 -0
  69. data/spec/adapter/thrift/table_find_spec.rb +14 -2
  70. data/spec/adapter/thrift/table_spec.rb +6 -6
  71. data/spec/adapter/thrift/utf8_encoding_of_id_spec.rb +71 -0
  72. data/spec/orm/cases/attribute_methods_spec.rb +215 -22
  73. data/spec/orm/cases/auto_generate_id_spec.rb +1 -1
  74. data/spec/orm/cases/change_id_spec.rb +62 -0
  75. data/spec/orm/cases/default_id_spec.rb +25 -6
  76. data/spec/orm/cases/default_values_spec.rb +6 -3
  77. data/spec/orm/cases/dirty_spec.rb +150 -102
  78. data/spec/orm/cases/embedded_spec.rb +250 -0
  79. data/spec/orm/cases/{finder_default_scope.rb → finder_default_scope_spec.rb} +4 -0
  80. data/spec/orm/cases/finder_scope_spec.rb +96 -29
  81. data/spec/orm/cases/finders_spec.rb +57 -10
  82. data/spec/orm/cases/id_factory/atomic_incrementation_spec.rb +72 -0
  83. data/spec/orm/cases/id_factory/timestamp_spec.rb +61 -0
  84. data/spec/orm/cases/identity_map/identity_map_spec.rb +357 -0
  85. data/spec/orm/cases/identity_map/middleware_spec.rb +74 -0
  86. data/spec/orm/cases/log_subscriber_spec.rb +15 -2
  87. data/spec/orm/cases/observing_spec.rb +61 -0
  88. data/spec/orm/cases/persistence_spec.rb +151 -60
  89. data/spec/orm/cases/raw_data_spec.rb +58 -0
  90. data/spec/orm/cases/single_table_inheritance_spec.rb +58 -2
  91. data/spec/orm/cases/table_spec.rb +3 -3
  92. data/spec/orm/cases/time_zone_awareness_spec.rb +27 -0
  93. data/spec/orm/cases/timestamps_spec.rb +23 -109
  94. data/spec/orm/cases/validation_spec.rb +9 -0
  95. data/spec/orm/models/address.rb +5 -1
  96. data/spec/orm/models/address_with_timestamp.rb +12 -0
  97. data/spec/orm/models/car.rb +5 -0
  98. data/spec/orm/models/person.rb +13 -1
  99. data/spec/orm/models/person_with_timestamp.rb +4 -2
  100. data/spec/orm/models/test_class.rb +1 -0
  101. data/spec/orm/persistence/operations/atomic_operation_spec.rb +58 -0
  102. data/spec/orm/persistence/operations/destroy_spec.rb +22 -0
  103. data/spec/orm/persistence/operations/embedded/destroy_spec.rb +71 -0
  104. data/spec/orm/persistence/operations/embedded/insert_spec.rb +59 -0
  105. data/spec/orm/persistence/operations/embedded/operation_helpers_spec.rb +92 -0
  106. data/spec/orm/persistence/operations/embedded/reload_spec.rb +67 -0
  107. data/spec/orm/persistence/operations/embedded/update_spec.rb +60 -0
  108. data/spec/orm/persistence/operations/insert_spec.rb +31 -0
  109. data/spec/orm/persistence/operations/reload_spec.rb +48 -0
  110. data/spec/orm/persistence/operations/suppress_spec.rb +17 -0
  111. data/spec/orm/persistence/operations/table_operation_helpers_spec.rb +98 -0
  112. data/spec/orm/persistence/operations/update_spec.rb +25 -0
  113. data/spec/orm/persistence/operations_spec.rb +58 -0
  114. data/spec/orm/relations/interface_spec.rb +188 -0
  115. data/spec/orm/relations/metadata_spec.rb +92 -15
  116. data/spec/orm/relations/proxy/embedded_in_polymorphic_spec.rb +37 -0
  117. data/spec/orm/relations/proxy/embedded_in_spec.rb +66 -0
  118. data/spec/orm/relations/proxy/embeds_many_spec.rb +651 -0
  119. data/spec/orm/relations/proxy/references_many_spec.rb +466 -2
  120. data/spec/orm/schema/column_family_spec.rb +21 -0
  121. data/spec/orm/schema/embedded_interface_spec.rb +181 -0
  122. data/spec/orm/schema/field_spec.rb +7 -0
  123. data/spec/orm/schema/table_interface_spec.rb +31 -1
  124. data/spec/shared/orm/id_factories.rb +44 -0
  125. data/spec/shared/orm/model_with_timestamps.rb +132 -0
  126. data/spec/shared/orm/persistence/a_persistence_embedded_operation_class.rb +3 -0
  127. data/spec/shared/orm/persistence/a_persistence_operation_class.rb +11 -0
  128. data/spec/shared/orm/persistence/a_persistence_table_operation_class.rb +11 -0
  129. data/spec/shared/orm/relations/proxy.rb +9 -2
  130. data/spec/spec_helper.rb +9 -0
  131. data/spec/support/mock_massive_record_connection.rb +2 -1
  132. metadata +106 -21
  133. data/spec/orm/cases/column_spec.rb +0 -49
  134. data/spec/orm/cases/id_factory_spec.rb +0 -92
  135. data/spec/orm/schema/column_interface_spec.rb +0 -136
@@ -1,5 +1,6 @@
1
1
  class TestClass < MassiveRecord::ORM::Table
2
2
 
3
+ embeds_many :addresses, :inverse_of => :addressable
3
4
  references_one :attachable, :polymorphic => true, :store_in => :test_family
4
5
 
5
6
  column_family :test_family do
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+
3
+ describe MassiveRecord::ORM::Persistence::Operations::AtomicOperation do
4
+ include MockMassiveRecordConnection
5
+
6
+ let(:record) { Person.new("id-1") }
7
+ let(:options) { {:operation => :increment, :attr_name => 'age', :by => 1} }
8
+
9
+ subject { described_class.new(record, options) }
10
+
11
+ it_should_behave_like "a persistence table operation class"
12
+
13
+
14
+ describe "#execute" do
15
+ it "raises NotNumericalFieldError if field is not numerical" do
16
+ options[:attr_name] = :name
17
+ expect { subject.execute }.to raise_error MassiveRecord::ORM::NotNumericalFieldError
18
+ end
19
+
20
+ it "ensures that we have table and column families" do
21
+ subject.should_receive(:ensure_that_we_have_table_and_column_families!)
22
+ subject.execute
23
+ end
24
+
25
+ it "ensures that we have binary representation of integer value" do
26
+ subject.should_receive(:ensure_proper_binary_integer_representation)
27
+ subject.execute
28
+ end
29
+
30
+ it "asks adapter's row to do the atomic operation" do
31
+ row = mock(Object)
32
+ row.should_receive(:atomic_increment).and_return(1)
33
+ subject.should_receive(:row_for_record).and_return row
34
+ subject.execute
35
+ end
36
+
37
+ it "assigns the attribute in record with whatever row for record atomic operation returns" do
38
+ row = mock(Object)
39
+ row.should_receive(:atomic_increment).and_return(111)
40
+ subject.should_receive(:row_for_record).and_return row
41
+ subject.execute
42
+ record.age.should eq 111
43
+ end
44
+
45
+ it "sets record's @new_record flag to false" do
46
+ record.instance_variable_set(:@new_record, true)
47
+ subject.execute
48
+ record.instance_variable_get(:@new_record).should be_false
49
+ end
50
+
51
+ it "returns the new state of attribute updated" do
52
+ row = mock(Object)
53
+ row.should_receive(:atomic_increment).and_return(123)
54
+ subject.should_receive(:row_for_record).and_return row
55
+ subject.execute.should eq 123
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe MassiveRecord::ORM::Persistence::Operations::Destroy do
4
+ include MockMassiveRecordConnection
5
+
6
+ let(:record) { TestClass.new("id-1") }
7
+ let(:options) { {:this => 'hash', :has => 'options'} }
8
+
9
+ subject { described_class.new(record, options) }
10
+
11
+ it_should_behave_like "a persistence table operation class"
12
+
13
+
14
+ describe "#execute" do
15
+ it "asks row_for_record to destroy itself" do
16
+ row = mock(Object)
17
+ row.should_receive(:destroy).and_return true
18
+ subject.should_receive(:row_for_record).and_return(row)
19
+ subject.execute
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+
3
+ describe MassiveRecord::ORM::Persistence::Operations::Embedded::Destroy do
4
+ include SetUpHbaseConnectionBeforeAll
5
+ include SetTableNamesToTestTable
6
+
7
+ let(:another_address) { Address.new("addresss-id-2", :street => "Asker too", :number => 5) }
8
+ let(:record) { Address.new("addresss-id", :street => "Asker", :number => 5) }
9
+ let(:person) { Person.new "person-id", :name => "Thorbjorn", :age => "22" }
10
+ let(:options) { {:this => 'hash', :has => 'options'} }
11
+
12
+ subject { described_class.new(record, options) }
13
+
14
+ describe "generic behaviour" do
15
+ before { record.person = person }
16
+ it_should_behave_like "a persistence embedded operation class"
17
+ end
18
+
19
+
20
+ describe "#execute" do
21
+ before do
22
+ record.person = person
23
+ person.save
24
+ end
25
+
26
+ context "not embedded" do
27
+ before { record.person = nil }
28
+
29
+ it "returns true" do
30
+ subject.execute.should eq true
31
+ end
32
+
33
+ it "does not call destroy" do
34
+ subject.execute
35
+ subject.should_not_receive(:update_embedded)
36
+ end
37
+ end
38
+
39
+ context "embedded" do
40
+ context "collection owner new record" do
41
+ before { record.person = person }
42
+
43
+ it "returns true" do
44
+ subject.execute.should eq true
45
+ end
46
+
47
+ it "does not call destroy" do
48
+ subject.execute
49
+ subject.should_not_receive(:update_embedded)
50
+ end
51
+ end
52
+
53
+ context "collection owner persisted" do
54
+ before do
55
+ record.person = person
56
+ person.save!
57
+ end
58
+
59
+ it "removes record from collection owher" do
60
+ subject.execute
61
+ person.addresses.should be_empty
62
+ end
63
+
64
+ it "persists the removal of record from collection owner" do
65
+ subject.execute
66
+ person.reload.addresses.should be_empty
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe MassiveRecord::ORM::Persistence::Operations::Embedded::Insert do
4
+ include SetUpHbaseConnectionBeforeAll
5
+ include SetTableNamesToTestTable
6
+
7
+ let(:record) { Address.new("addresss-id", :street => "Asker", :number => 5) }
8
+ let(:person) { Person.new "person-id", :name => "Thorbjorn", :age => "22" }
9
+ let(:options) { {:this => 'hash', :has => 'options'} }
10
+
11
+ subject { described_class.new(record, options) }
12
+
13
+ describe "generic behaviour" do
14
+ before { record.person = person }
15
+ it_should_behave_like "a persistence embedded operation class"
16
+ end
17
+
18
+
19
+ describe "#execute" do
20
+ before { record.person = nil }
21
+
22
+ context "not embedded" do
23
+ it "raises an error" do
24
+ expect { subject.execute }.to raise_error MassiveRecord::ORM::NotAssignedToEmbeddedCollection
25
+ end
26
+ end
27
+
28
+ context "embedded" do
29
+ context "but embedded in is not saved" do
30
+ before { record.person = person }
31
+
32
+ it "calls save on embedded owner when it is a new record" do
33
+ person.should_receive(:save).and_return true
34
+ subject.execute
35
+ end
36
+
37
+ it "returns false if none of the embedded_in_proxy_targets returned true" do
38
+ person.should_receive(:save).and_return false
39
+ subject.execute.should be_false
40
+ end
41
+
42
+ it "is changed when reloading" do
43
+ subject.execute
44
+ Person.find(person.id).addresses.first.should eq record
45
+ end
46
+ end
47
+
48
+ context "and embedded in is already saved and now needs to be updated" do
49
+ # Not gonna get into this situation as far as I can see now.
50
+ # Reason for it is we are auto-saving when pushing new records
51
+ # on to an embeds many collection where it's owner has been persisted.
52
+ # But, it might be something we want to handle in the future if we have
53
+ # an auto_save option on the relation. In which case I think we should
54
+ # ensure that only the one embedded record which receives save are actually
55
+ # updated in the embeds many collection owner's record.
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,92 @@
1
+ require 'spec_helper'
2
+
3
+ module MassiveRecord
4
+ module ORM
5
+ module Persistence
6
+ module Operations
7
+ module Embedded
8
+ class TestEmbeddedOperationHelpers
9
+ include Operations, OperationHelpers
10
+ end
11
+
12
+ describe TestEmbeddedOperationHelpers do
13
+ include SetUpHbaseConnectionBeforeAll
14
+ include SetTableNamesToTestTable
15
+
16
+ let(:address) { Address.new("addresss-id", :street => "Asker", :number => 5) }
17
+ let(:person) { Person.new "person-id", :name => "Thorbjorn", :age => "22" }
18
+ let(:options) { {:this => 'hash', :has => 'options'} }
19
+
20
+
21
+ let(:proxy_for_person) { address.send(:relation_proxy, :person) }
22
+
23
+ let(:row) do
24
+ MassiveRecord::Wrapper::Row.new({
25
+ :id => person.id,
26
+ :table => person.class.table
27
+ })
28
+ end
29
+
30
+
31
+ subject { TestEmbeddedOperationHelpers.new(address, options) }
32
+
33
+ before { address.person = person }
34
+
35
+
36
+ describe "#embedded_in_proxies" do
37
+ it "returns some proxies" do
38
+ subject.embedded_in_proxies.should_not be_empty
39
+ end
40
+
41
+ it "returns proxies which represents embedded in relations" do
42
+ subject.embedded_in_proxies.all? { |p| p.metadata.embedded_in? }.should be_true
43
+ end
44
+ end
45
+
46
+ describe "#embedded_in_proxy_targets" do
47
+ its(:embedded_in_proxy_targets) { should include person }
48
+ end
49
+
50
+ describe "#row_for_record" do
51
+ it "returns row for given record" do
52
+ row = subject.row_for_record(person)
53
+ row.id.should eq person.id
54
+ row.table.should eq person.class.table
55
+ end
56
+ end
57
+
58
+
59
+
60
+ describe "update_embedded" do
61
+ before { subject.stub(:row_for_record).and_return(row) }
62
+
63
+ it "ask for record's row" do
64
+ subject.should_receive(:row_for_record).with(person).and_return(row)
65
+ subject.update_embedded(proxy_for_person, "new_value")
66
+ end
67
+
68
+ it "sets value on row" do
69
+ row.should_receive(:values=).with(
70
+ 'addresses' => {
71
+ address.database_id => "new_value"
72
+ }
73
+ )
74
+ subject.update_embedded(proxy_for_person, "new_value")
75
+ end
76
+
77
+ it "asks row to be saved" do
78
+ row.should_receive(:save)
79
+ subject.update_embedded(proxy_for_person, "new_value")
80
+ end
81
+ end
82
+ end
83
+
84
+
85
+
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+
@@ -0,0 +1,67 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ describe MassiveRecord::ORM::Persistence::Operations::Embedded::Reload do
5
+ include SetUpHbaseConnectionBeforeAll
6
+ include SetTableNamesToTestTable
7
+
8
+ let(:record) { Address.new("addresss-id", :street => "Asker", :number => 5) }
9
+ let(:person) { Person.new "person-id", :name => "Thorbjorn", :age => "22" }
10
+ let(:options) { {:this => 'hash', :has => 'options'} }
11
+
12
+ subject { described_class.new(record, options) }
13
+
14
+ before { record.person = person; record.save! }
15
+
16
+ describe "generic behaviour" do
17
+ it_should_behave_like "a persistence embedded operation class"
18
+ end
19
+
20
+
21
+ describe "#execute" do
22
+ context "new record" do
23
+ before { record.stub(:persisted?).and_return false }
24
+
25
+ its(:execute) { should be_false }
26
+ end
27
+
28
+ context "persisted" do
29
+ let(:inverse_proxy) { mock(Object, :reload => true, :find => record) }
30
+ let(:embedded_in_proxy) { subject.embedded_in_proxies.first }
31
+
32
+ before do
33
+ subject.stub(:inverse_proxy_for).and_return(inverse_proxy)
34
+ end
35
+
36
+ it "just returns false if no not embedded in any proxies" do
37
+ subject.should_receive(:embedded_in_proxies).any_number_of_times.and_return []
38
+ subject.execute.should be_false
39
+ end
40
+
41
+ it "asks for inverse proxy" do
42
+ subject.should_receive(:inverse_proxy_for).with(embedded_in_proxy).and_return(inverse_proxy)
43
+ subject.execute
44
+ end
45
+
46
+ it "reloads inverse proxy" do
47
+ inverse_proxy.should_receive :reload
48
+ subject.execute
49
+ end
50
+
51
+ it "finds the record asked to be reloaded" do
52
+ inverse_proxy.should_receive(:find).with(record.id).and_return record
53
+ subject.execute
54
+ end
55
+
56
+ it "reinit record with found record's attributes and raw_data" do
57
+ record.should_receive(:attributes).and_return('attributes' => {})
58
+ record.should_receive(:raw_data).and_return('raw_data' => {})
59
+ record.should_receive(:reinit_with).with({
60
+ 'attributes' => {'attributes' => {}},
61
+ 'raw_data' => {'raw_data' => {}}
62
+ })
63
+ subject.execute
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe MassiveRecord::ORM::Persistence::Operations::Embedded::Update do
4
+ include SetUpHbaseConnectionBeforeAll
5
+ include SetTableNamesToTestTable
6
+
7
+ let(:another_address) { Address.new("addresss-id-2", :street => "Asker too", :number => 5) }
8
+ let(:record) { Address.new("addresss-id", :street => "Asker", :number => 5) }
9
+ let(:person) { Person.new "person-id", :name => "Thorbjorn", :age => "22" }
10
+ let(:options) { {:this => 'hash', :has => 'options'} }
11
+
12
+ subject { described_class.new(record, options) }
13
+
14
+ describe "generic behaviour" do
15
+ before { record.person = person }
16
+ it_should_behave_like "a persistence embedded operation class"
17
+ end
18
+
19
+
20
+ describe "#execute" do
21
+ before do
22
+ record.person = person
23
+ person.save
24
+ end
25
+
26
+ context "not embedded" do
27
+ it "raises an error" do
28
+ record.person = nil
29
+ expect { subject.execute }.to raise_error MassiveRecord::ORM::NotAssignedToEmbeddedCollection
30
+ end
31
+ end
32
+
33
+ context "embedded" do
34
+ it "do persist the changes" do
35
+ record.street = "Oslogata"
36
+ subject.execute
37
+ person.reload.addresses.first.street.should eq "Oslogata"
38
+ end
39
+
40
+ it "does not update other embedded records" do
41
+ person.addresses << another_address
42
+ record.street = "Oslogata"
43
+ another_address.street = "FooBar"
44
+
45
+ subject.execute
46
+
47
+ person.reload.addresses.find(another_address.id).street.should eq "Asker too"
48
+ end
49
+
50
+ it "does not update attributes on the record it is embedded in" do
51
+ person.name += "_NEW"
52
+ record.street = "Oslogata"
53
+
54
+ subject.execute
55
+
56
+ person.reload.name.should eq "Thorbjorn"
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe MassiveRecord::ORM::Persistence::Operations::Insert do
4
+ include MockMassiveRecordConnection
5
+
6
+ let(:record) { TestClass.new("id-1") }
7
+ let(:options) { {:this => 'hash', :has => 'options'} }
8
+
9
+ subject { described_class.new(record, options) }
10
+
11
+ it_should_behave_like "a persistence table operation class"
12
+
13
+
14
+ describe "#execute" do
15
+ it "ensures that we have table and column families" do
16
+ subject.should_receive(:ensure_that_we_have_table_and_column_families!)
17
+ subject.execute
18
+ end
19
+
20
+ it "raises a RecordNotUnique error if we should check it" do
21
+ record.class.should_receive(:check_record_uniqueness_on_create).and_return true
22
+ record.class.should_receive(:exists?).with(record.id).and_return true
23
+ expect { subject.execute }.to raise_error MassiveRecord::ORM::RecordNotUnique
24
+ end
25
+
26
+ it "calls upon store_record_to_database for help with actually insert job" do
27
+ subject.should_receive(:store_record_to_database).with('create')
28
+ subject.execute
29
+ end
30
+ end
31
+ end