massive_record 0.2.1 → 0.2.2.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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