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,6 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe MassiveRecord::ORM::Schema::ColumnFamily do
4
+
5
+ let(:families) { MassiveRecord::ORM::Schema::ColumnFamilies.new }
6
+ subject { MassiveRecord::ORM::Schema::ColumnFamily.new :name => "family_name", :column_families => families }
7
+
4
8
  describe "initializer" do
5
9
  it "should take a name" do
6
10
  column_family = MassiveRecord::ORM::Schema::ColumnFamily.new :name => "family_name"
@@ -128,4 +132,21 @@ describe MassiveRecord::ORM::Schema::ColumnFamily do
128
132
  end
129
133
  end
130
134
  end
135
+
136
+ describe "#autoload_fields" do
137
+ it "sets self to be autoloaded" do
138
+ subject.instance_eval do
139
+ autoload_fields
140
+ end
141
+ subject.should be_autoload_fields
142
+ end
143
+
144
+ it "takes options for created fields when autoloading" do
145
+ options = {:type => :integer}
146
+ subject.instance_eval do
147
+ autoload_fields options
148
+ end
149
+ subject.options_for_autoload_created_fields.should eq options
150
+ end
151
+ end
131
152
  end
@@ -0,0 +1,181 @@
1
+ require 'spec_helper'
2
+
3
+ class TestEmbeddedInterface
4
+ include MassiveRecord::ORM::Schema::EmbeddedInterface
5
+ end
6
+
7
+ describe MassiveRecord::ORM::Schema::EmbeddedInterface do
8
+ after do
9
+ TestEmbeddedInterface.fields = nil
10
+ end
11
+
12
+ it "should respond_to default_attributes_from_schema" do
13
+ TestEmbeddedInterface.should respond_to :default_attributes_from_schema
14
+ end
15
+
16
+ it "should have fields set to nil if no fields are defined" do
17
+ TestEmbeddedInterface.fields.should be_nil
18
+ end
19
+
20
+ it "should have one field if one field is added" do
21
+ class TestEmbeddedInterface
22
+ field :field_name, :string
23
+ end
24
+
25
+ TestEmbeddedInterface.should have(1).fields
26
+ TestEmbeddedInterface.fields.first.name.should == "field_name"
27
+ end
28
+
29
+ it "should not be possible to have to fields with the same name" do
30
+ lambda {
31
+ class TestEmbeddedInterface
32
+ field :will_raise_error
33
+ field :will_raise_error
34
+ end
35
+ }.should raise_error MassiveRecord::ORM::Schema::InvalidField
36
+ end
37
+
38
+ it "should return attributes schema based on DSL" do
39
+ class TestEmbeddedInterface
40
+ field :name
41
+ field :age, :integer, :default => 1
42
+ end
43
+
44
+ TestEmbeddedInterface.attributes_schema["name"].type.should == :string
45
+ TestEmbeddedInterface.attributes_schema["age"].type.should == :integer
46
+ TestEmbeddedInterface.attributes_schema["age"].default.should == 1
47
+ end
48
+
49
+ it "should make attributes_schema readable from instances" do
50
+ class TestEmbeddedInterface
51
+ field :name
52
+ end
53
+
54
+ TestEmbeddedInterface.new.attributes_schema["name"].type.should == :string
55
+ end
56
+
57
+ it "should have a list of known attribute names" do
58
+ class TestEmbeddedInterface
59
+ field :name, :string
60
+ field :age, :integer
61
+ end
62
+
63
+ TestEmbeddedInterface.should have(2).known_attribute_names
64
+ TestEmbeddedInterface.known_attribute_names.should include("name", "age")
65
+ end
66
+
67
+ it "should make known_attribute_names readable for instances" do
68
+ class TestEmbeddedInterface
69
+ field :name, :string
70
+ end
71
+
72
+ TestEmbeddedInterface.new.known_attribute_names.should include('name')
73
+ end
74
+
75
+
76
+ it "should give us default attributes from schema" do
77
+ class TestEmbeddedInterface
78
+ field :name
79
+ field :age, :integer, :default => 1
80
+ end
81
+
82
+ defaults = TestEmbeddedInterface.default_attributes_from_schema
83
+ defaults["name"].should be_nil
84
+ defaults["age"].should == 1
85
+ end
86
+
87
+ describe "timestamps" do
88
+ before do
89
+ class TestEmbeddedInterface
90
+ timestamps
91
+ end
92
+ end
93
+
94
+ it "should have a created_at time field" do
95
+ TestEmbeddedInterface.attributes_schema['created_at'].type.should == :time
96
+ end
97
+ end
98
+
99
+
100
+ describe "dynamically adding a field" do
101
+ it "should be possible to dynamically add a field" do
102
+ TestEmbeddedInterface.add_field :name, :default => "NA"
103
+
104
+ TestEmbeddedInterface.should have(1).fields
105
+
106
+ field = TestEmbeddedInterface.fields.first
107
+
108
+ field.name.should == "name"
109
+ field.default.should == "NA"
110
+ end
111
+
112
+ it "should be possible to set field's type just like the DSL" do
113
+ TestEmbeddedInterface.add_field :age, :integer, :default => 0
114
+
115
+ TestEmbeddedInterface.fields.first.name.should == "age"
116
+ TestEmbeddedInterface.fields.first.type.should == :integer
117
+ TestEmbeddedInterface.fields.first.default.should == 0
118
+ end
119
+
120
+ it "should call class' undefine_attribute_methods to make sure it regenerates for newly added" do
121
+ TestEmbeddedInterface.should_receive(:undefine_attribute_methods)
122
+ TestEmbeddedInterface.add_field :name, :default => "NA"
123
+ end
124
+
125
+ it "should return the new field" do
126
+ field = TestEmbeddedInterface.add_field :age, :integer, :default => 0
127
+ field.should == TestEmbeddedInterface.fields.first
128
+ end
129
+
130
+ it "should insert the new field's default value right away" do
131
+ test_interface = TestEmbeddedInterface.new
132
+ test_interface.should_receive("age=").with(1)
133
+ test_interface.add_field :age, :integer, :default => 1
134
+ end
135
+ end
136
+
137
+ describe "#attributes_db_raw_data_hash" do
138
+ subject { Address.new("id", :street => "Asker", :number => 2, :nice_place => true, :zip => '1384') }
139
+
140
+ it "returns hash with correct key-value pairs" do
141
+ subject.attributes_db_raw_data_hash.should eq({
142
+ "street" => "Asker",
143
+ "number" => 2,
144
+ "nice_place" => "true",
145
+ "postal_code" => "1384"
146
+ })
147
+ end
148
+ end
149
+
150
+ describe ".transpose_raw_data_to_record_attributes_and_raw_data" do
151
+ let(:id) { "id" }
152
+ let(:raw_data) do
153
+ MassiveRecord::ORM::RawData.new(value: {
154
+ "street" => "Oslo",
155
+ "number" => 3,
156
+ "nice_place" => "false",
157
+ "postal_code" => "1111"
158
+ })
159
+ end
160
+
161
+ it "returns attributes" do
162
+ attributes, raw = Address.transpose_raw_data_to_record_attributes_and_raw_data id, raw_data
163
+ attributes.should eq({:id=>"id", "street"=>"Oslo", "number"=>3, "nice_place"=>false, "zip"=>"1111", "updated_at" => nil})
164
+ end
165
+
166
+ it "returns raw data" do
167
+ attributes, raw = Address.transpose_raw_data_to_record_attributes_and_raw_data id, raw_data
168
+ raw.should eq Hash[raw_data.value.collect do |attr, value|
169
+ [attr, MassiveRecord::ORM::RawData.new(value: value, created_at: raw_data.created_at)]
170
+ end]
171
+ end
172
+
173
+ it "returns correct attributes from serialized db values hash" do
174
+ attributes, raw = Address.transpose_raw_data_to_record_attributes_and_raw_data(
175
+ id,
176
+ MassiveRecord::ORM::RawData.new(value: MassiveRecord::ORM::Base.coder.dump(raw_data.value))
177
+ )
178
+ attributes.should eq({:id=>"id", "street"=>"Oslo", "number"=>3, "nice_place"=>false, "zip"=>"1111", "updated_at" => nil})
179
+ end
180
+ end
181
+ end
@@ -162,6 +162,13 @@ describe MassiveRecord::ORM::Schema::Field do
162
162
  @subject.decode("\x00\x00\x00\x00\x00\x00\x00\x1E").should eq 30
163
163
  end
164
164
 
165
+ it "it forces encoding on the value to be BINARY if value is integer" do
166
+ value = "\x00\x00\x00\x00\x00\x00\x00\x01"
167
+ value.should_receive(:force_encoding).and_return(value)
168
+ @subject = MassiveRecord::ORM::Schema::Field.new(:name => :status, :type => :integer)
169
+ @subject.decode(value)
170
+ end
171
+
165
172
  it "should decode an float value" do
166
173
  @subject = MassiveRecord::ORM::Schema::Field.new(:name => :code, :type => :float)
167
174
  @subject.decode("12.345").should == 12.345
@@ -30,6 +30,11 @@ describe MassiveRecord::ORM::Schema::TableInterface do
30
30
  TestInterface.column_families.collect(&:name).should include("misc")
31
31
  end
32
32
 
33
+ it "adds a column family" do
34
+ TestInterface.add_column_family(:foo)
35
+ TestInterface.column_families.collect(&:name).should include("foo")
36
+ end
37
+
33
38
  it "should be possible to add fields to a column families" do
34
39
  class TestInterface
35
40
  column_family :info do
@@ -40,6 +45,20 @@ describe MassiveRecord::ORM::Schema::TableInterface do
40
45
  TestInterface.known_attribute_names.should == ["name"]
41
46
  end
42
47
 
48
+ it "should return a list of known collum families" do
49
+ class TestInterface
50
+ column_family :info do
51
+ field :name
52
+ end
53
+ end
54
+
55
+ TestInterface.known_column_family_names.should == ["info"]
56
+ end
57
+
58
+ it "returns no known column family names if no one are defined" do
59
+ TestInterface.known_column_family_names.should == []
60
+ end
61
+
43
62
  it "should return attributes schema based on DSL" do
44
63
  class TestInterface
45
64
  column_family :info do
@@ -170,12 +189,16 @@ describe MassiveRecord::ORM::Schema::TableInterface do
170
189
  autoload_fields
171
190
  end
172
191
 
192
+ column_family :integers_only do
193
+ autoload_fields :type => :integer
194
+ end
195
+
173
196
  column_family :misc do
174
197
  field :text
175
198
  end
176
199
  end
177
200
 
178
- @column_names = %w(info:name misc:other)
201
+ @column_names = %w(info:name misc:other integers_only:number)
179
202
  end
180
203
 
181
204
  it "should not add fields to misc" do
@@ -188,6 +211,13 @@ describe MassiveRecord::ORM::Schema::TableInterface do
188
211
  TestInterface.autoload_column_families_and_fields_with(@column_names)
189
212
  end
190
213
 
214
+ it "creates fields with same options as you give to autoload fields" do
215
+ TestInterface.autoload_column_families_and_fields_with(@column_names)
216
+ family = TestInterface.column_families.family_by_name("integers_only")
217
+ autoloaded_field = family.field_by_name(:number)
218
+ autoloaded_field.type.should eq :integer
219
+ end
220
+
191
221
  it "should be possible to run twice" do
192
222
  2.times { TestInterface.autoload_column_families_and_fields_with(@column_names) }
193
223
  end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for 'an id factory' do
4
+ it "is a singleton" do
5
+ MassiveRecord::ORM::IdFactory::AtomicIncrementation.included_modules.should include(Singleton)
6
+ end
7
+
8
+ describe "#next_for" do
9
+ it "responds_to next_for" do
10
+ subject.should respond_to :next_for
11
+ end
12
+
13
+ it "uses incomming table name if it's a string" do
14
+ subject.should_receive(:next_id).with(hash_including(:table => "test_table"))
15
+ subject.next_for "test_table"
16
+ end
17
+
18
+ it "usees incomming table name if it's a symbol" do
19
+ subject.should_receive(:next_id).with(hash_including(:table => "test_table"))
20
+ subject.next_for :test_table
21
+ end
22
+
23
+ it "asks object for it's table name if it responds to that" do
24
+ Person.should_receive(:table_name).any_number_of_times.and_return("people")
25
+ subject.should_receive(:next_id).with(hash_including(:table => "people"))
26
+ subject.next_for(Person)
27
+ end
28
+
29
+ it "returns uniq ids" do
30
+ ids = 10.times.inject([]) do |ids|
31
+ ids << subject.next_for(Person)
32
+ end
33
+
34
+ ids.should eq ids.uniq
35
+ end
36
+ end
37
+
38
+ describe ".next_for" do
39
+ it "delegates to it's instance" do
40
+ subject.should_receive(:next_for).with("cars")
41
+ described_class.next_for("cars")
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,132 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for "a model with timestamps" do
4
+ include TimeZoneHelper
5
+
6
+ describe "#created_at" do
7
+ it "is instructed to create it on create :-)" do
8
+ subject.should be_set_created_at_on_create
9
+ end
10
+
11
+ it "is nil on new records" do
12
+ described_class.new.created_at.should be_nil
13
+ end
14
+
15
+ it "is not possible to set" do
16
+ expect { subject.created_at = Time.now }.to raise_error MassiveRecord::ORM::CantBeManuallyAssigned
17
+ expect { subject['created_at'] = Time.now }.to raise_error MassiveRecord::ORM::CantBeManuallyAssigned
18
+ expect { subject.write_attribute(:created_at, Time.now) }.to raise_error MassiveRecord::ORM::CantBeManuallyAssigned
19
+ end
20
+
21
+ it "is set on persisted records" do
22
+ subject.created_at.should be_a_kind_of Time
23
+ end
24
+
25
+ it "is not changed on update" do
26
+ created_at_was = subject.created_at
27
+
28
+ sleep(1)
29
+
30
+ subject.update_attribute attribute_to_be_changed, subject[attribute_to_be_changed] + "NEW"
31
+ subject.created_at.should == created_at_was
32
+ end
33
+
34
+ it "is included in list of #known_attribute_names_for_inspect" do
35
+ subject.send(:known_attribute_names_for_inspect).should include 'created_at'
36
+ end
37
+
38
+ it "is included in inspect" do
39
+ subject.inspect.should include(%q{created_at:})
40
+ end
41
+
42
+ it "raises error if created_at is not time" do
43
+ described_class.attributes_schema['created_at'].type = :string
44
+ expect { described_class.new.save(:validate => false) }.to raise_error "created_at must be of type time"
45
+ described_class.attributes_schema['created_at'].type = :time
46
+ end
47
+ end
48
+ end
49
+
50
+
51
+
52
+
53
+
54
+ shared_examples_for "a model without timestamps" do
55
+ include TimeZoneHelper
56
+
57
+ describe "#created_at" do
58
+ it "is instructed not to create it on create :-)" do
59
+ subject.should_not be_set_created_at_on_create
60
+ end
61
+
62
+ it "does not raise cant-set-error" do
63
+ expect { subject.created_at = Time.now }.to_not raise_error MassiveRecord::ORM::CantBeManuallyAssigned
64
+ end
65
+
66
+ it "does not include created_at in the list of known attributes" do
67
+ subject.send(:known_attribute_names_for_inspect).should_not include 'created_at'
68
+ end
69
+ end
70
+
71
+ # Might be a bit strange, but HBase gives you time stamps on cells
72
+ # regardless, so we'll always make it available to the client
73
+ describe "#updated_at" do
74
+ it "is nil on new records" do
75
+ described_class.new.updated_at.should be_nil
76
+ end
77
+
78
+ it "is not possible to set" do
79
+ expect { subject.updated_at = Time.now }.to raise_error MassiveRecord::ORM::CantBeManuallyAssigned
80
+ expect { subject['updated_at'] = Time.now }.to raise_error MassiveRecord::ORM::CantBeManuallyAssigned
81
+ expect { subject.write_attribute(:updated_at, Time.now) }.to raise_error MassiveRecord::ORM::CantBeManuallyAssigned
82
+ end
83
+
84
+ it "is set on persisted records" do
85
+ subject.updated_at.should be_a_kind_of Time
86
+ end
87
+
88
+ it "is included in list of #known_attribute_names_for_inspect" do
89
+ subject.send(:known_attribute_names_for_inspect).should include 'updated_at'
90
+ end
91
+
92
+ it "includes updated_at in inspect" do
93
+ subject.inspect.should include(%q{updated_at:})
94
+ end
95
+
96
+ it "is updated after save" do
97
+ sleep(1)
98
+
99
+ updated_at_was = subject.updated_at
100
+ subject.update_attribute attribute_to_be_changed, "Should Give Me New Updated At"
101
+
102
+ subject.updated_at.should_not eq updated_at_was
103
+ end
104
+
105
+ it "is not updated when save fails" do
106
+ sleep(1)
107
+
108
+ updated_at_was = subject.updated_at
109
+ subject[attribute_to_be_changed] = nil
110
+
111
+ subject.should_not be_valid
112
+
113
+ subject.updated_at.should eq updated_at_was
114
+ end
115
+
116
+ context "with time zone awarenesswith zone enabled" do
117
+ it "should return time with zone" do
118
+ in_time_zone "Europe/Stockholm" do
119
+ subject.updated_at.should be_instance_of ActiveSupport::TimeWithZone
120
+ end
121
+ end
122
+
123
+ it "should be nil on new records" do
124
+ in_time_zone "Europe/Stockholm" do
125
+ Person.new.updated_at.should be_nil
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+