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
@@ -5,6 +5,27 @@ module MassiveRecord
5
5
 
6
6
  attr_accessor :connection, :name, :column_families
7
7
 
8
+ #
9
+ # TODO
10
+ # Helper method to inform about changed options. Remove this in next version..
11
+ # Also note that this method is used other places to wrap same functionality.
12
+ #
13
+ def self.warn_and_change_deprecated_finder_options(options)
14
+ deprecations = {
15
+ :start => :starts_with
16
+ }
17
+
18
+ deprecations.each do |deprecated, current|
19
+ if options.has_key? deprecated
20
+ # TODO remove this for next version
21
+ ActiveSupport::Deprecation.warn("finder option '#{deprecated}' is deprecated. Please use: '#{current}'")
22
+ options[current] = options.delete deprecated
23
+ end
24
+ end
25
+
26
+ options
27
+ end
28
+
8
29
  def initialize(connection, table_name)
9
30
  @connection = connection
10
31
  @name = table_name.to_s
@@ -87,9 +108,14 @@ module MassiveRecord
87
108
  end
88
109
 
89
110
  def format_options_for_scanner(opts = {})
111
+ opts = self.class.warn_and_change_deprecated_finder_options(opts)
112
+
113
+ start = opts[:starts_with] && opts[:starts_with].dup.force_encoding(Encoding::BINARY)
114
+ offset = opts[:offset] && opts[:offset].dup.force_encoding(Encoding::BINARY)
115
+
90
116
  {
91
- :start_key => opts[:start],
92
- :offset_key => opts[:offset],
117
+ :start_key => start,
118
+ :offset_key => offset,
93
119
  :created_at => opts[:created_at],
94
120
  :columns => opts[:select], # list of column families to fetch from hbase
95
121
  :limit => opts[:limit] || opts[:batch_size]
@@ -115,8 +141,16 @@ module MassiveRecord
115
141
  # table.get("my_id", :info, :name) # => "Bob"
116
142
  #
117
143
  def get(id, column_family_name, column_name)
118
- if value = connection.get(name, id, "#{column_family_name.to_s}:#{column_name.to_s}").first.try(:value)
119
- MassiveRecord::Wrapper::Cell.new(:value => value).value # might seems a bit strange.. Just to "enforice" that the value is a supported type
144
+ get_cell(id, column_family_name, column_name).try :value
145
+ end
146
+
147
+
148
+ #
149
+ # Fast way of fetching one cell
150
+ #
151
+ def get_cell(id, column_family_name, column_name)
152
+ if cell = connection.get(name, id.dup.force_encoding(Encoding::BINARY), "#{column_family_name.to_s}:#{column_name.to_s}").first
153
+ MassiveRecord::Wrapper::Cell.populate_from_tcell(cell)
120
154
  end
121
155
  end
122
156
 
@@ -126,17 +160,20 @@ module MassiveRecord
126
160
  # Returns nil if id is not found
127
161
  #
128
162
  def find(*args)
129
- what_to_find = args.first
130
163
  options = args.extract_options!.symbolize_keys
164
+ what_to_find = args.first
131
165
 
132
- if what_to_find.is_a?(Array)
133
- what_to_find.collect { |id| find(id, options) }
134
- else
135
- if column_families_to_find = options[:select]
136
- column_families_to_find = column_families_to_find.collect { |c| c.to_s }
137
- end
166
+ if column_families_to_find = options[:select]
167
+ column_families_to_find = column_families_to_find.collect { |c| c.to_s }
168
+ end
138
169
 
139
- if t_row_result = connection.getRowWithColumns(name, what_to_find, column_families_to_find).first
170
+ if what_to_find.is_a? Array
171
+ what_to_find.collect! { |id| id.dup.force_encoding(Encoding::BINARY) }
172
+ connection.getRowsWithColumns(name, what_to_find, column_families_to_find).collect do |t_row_result|
173
+ Row.populate_from_trow_result(t_row_result, connection, name, column_families_to_find)
174
+ end
175
+ else
176
+ if t_row_result = connection.getRowWithColumns(name, what_to_find.dup.force_encoding(Encoding::BINARY), column_families_to_find).first
140
177
  Row.populate_from_trow_result(t_row_result, connection, name, column_families_to_find)
141
178
  end
142
179
  end
@@ -37,14 +37,22 @@ module MassiveRecord
37
37
  def attributes=(new_attributes)
38
38
  return unless new_attributes.is_a?(Hash)
39
39
 
40
+ multiparameter_attributes = []
41
+
40
42
  sanitize_for_mass_assignment(new_attributes).each do |attr, value|
41
- writer_method = "#{attr}="
42
- if respond_to? writer_method
43
- send(writer_method, value)
43
+ if multiparameter? attr
44
+ multiparameter_attributes << [attr, value]
44
45
  else
45
- raise UnknownAttributeError.new("Unkown attribute: #{attr}")
46
+ writer_method = "#{attr}="
47
+ if respond_to? writer_method
48
+ send(writer_method, value)
49
+ else
50
+ raise UnknownAttributeError.new("Unkown attribute: #{attr}")
51
+ end
46
52
  end
47
53
  end
54
+
55
+ assign_multiparameter_attributes(multiparameter_attributes)
48
56
  end
49
57
 
50
58
 
@@ -84,10 +92,74 @@ module MassiveRecord
84
92
  end
85
93
 
86
94
  def fill_attributes_with_default_values_where_nil_is_not_allowed
87
- attributes_schema.reject { |attr_name, field| field.allow_nil? || self[attr_name].present? }.each do |attr_name, field|
95
+ attributes_to_fill = attributes_schema.reject do |attr_name, field|
96
+ field.allow_nil? || self[attr_name].present? || (field.type == :boolean && self[attr_name] == false)
97
+ end
98
+
99
+ attributes_to_fill.each do |attr_name, field|
88
100
  self[attr_name] = field.default
89
101
  end
90
102
  end
103
+
104
+
105
+
106
+
107
+
108
+
109
+ def multiparameter?(attr)
110
+ attr.to_s.include?('(')
111
+ end
112
+
113
+ def assign_multiparameter_attributes(attribute_pairs)
114
+ convert_multiparameter_pairs_to_hash_with_initializer_arguments(attribute_pairs).each do |attr_name, initialize_values|
115
+ if field = attributes_schema[attr_name]
116
+ value = begin
117
+ if initialize_values.any?
118
+ case field.type
119
+ when :date
120
+ initialize_values = initialize_values[0, 3]
121
+ initialize_values.collect! { |v| v.nil? ? 1 : v }
122
+ Date.new(*initialize_values)
123
+ when :time
124
+ initialize_values = initialize_values[0, 6]
125
+ initialize_values.collect! { |v| v.nil? ? 0 : v }
126
+ Time.new(*initialize_values)
127
+ end
128
+ end
129
+ rescue ArgumentError
130
+ nil
131
+ end
132
+
133
+ self[attr_name] = value
134
+ end
135
+ end
136
+ end
137
+
138
+ def convert_multiparameter_pairs_to_hash_with_initializer_arguments(attribute_pairs)
139
+ out = Hash.new { |h, k| h[k] = [] }.tap do |hash|
140
+ attribute_pairs.each do |pair|
141
+ name, value = pair
142
+ attr_name = name.split('(').first
143
+ hash[attr_name] << [multiparameter_position(name), type_cast_multiparameter_value(name, value)]
144
+ end
145
+ end
146
+
147
+ out.each do |attr_name, positions_and_values|
148
+ out[attr_name] = positions_and_values.sort_by(&:first).collect(&:last)
149
+ end
150
+
151
+ out
152
+ end
153
+
154
+ def type_cast_multiparameter_value(name, value)
155
+ unless value.empty?
156
+ name =~ /\([0-9]*([if])\)/ ? value.send("to_" + $1) : value
157
+ end
158
+ end
159
+
160
+ def multiparameter_position(name)
161
+ name.scan(/\(([0-9]*).*\)/).first.first
162
+ end
91
163
  end
92
164
  end
93
165
  end
@@ -0,0 +1,24 @@
1
+ module MassiveRecord
2
+ module ORM
3
+ module AttributeMethods
4
+ module CastNumbersOnWrite
5
+ extend ActiveSupport::Concern
6
+
7
+ def write_attribute(attr_name, value)
8
+ if value.present?
9
+ if field = attributes_schema[attr_name]
10
+ case field.type
11
+ when :integer
12
+ value = value.to_i
13
+ when :float
14
+ value = value.to_f
15
+ end
16
+ end
17
+ end
18
+
19
+ super
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -45,6 +45,24 @@ module MassiveRecord
45
45
  end
46
46
 
47
47
 
48
+ def changed?
49
+ super || relation_proxies_for_embedded.any?(&:changed?)
50
+ end
51
+
52
+ def changed
53
+ super + relation_proxies_for_embedded.select(&:changed?).collect { |proxy| proxy.metadata.name }
54
+ end
55
+
56
+ def changes
57
+ changes_in_embedded_proxies = {}
58
+
59
+ relation_proxies_for_embedded.select(&:changed?).each do |proxy|
60
+ changes_in_embedded_proxies[proxy.metadata.name] = proxy.changes
61
+ end
62
+
63
+ super.update(changes_in_embedded_proxies)
64
+ end
65
+
48
66
  private
49
67
 
50
68
  def update(*)
@@ -56,16 +56,37 @@ module MassiveRecord
56
56
  time.in_time_zone
57
57
  end
58
58
  end
59
+ alias_method attr_name, internal_read_method
59
60
  end
60
61
  else
61
62
  super
62
63
  end
63
64
  end
64
65
 
65
- # Redefine writer method if we are to do time zone configuration on field
66
66
  def define_method_attribute=(attr_name)
67
- # Nothing special goes on here, at the moment
68
- super
67
+ if time_zone_conversion_on_field?(attributes_schema[attr_name])
68
+ internal_write_method = "_#{attr_name}="
69
+
70
+ if attr_name =~ ActiveModel::AttributeMethods::COMPILABLE_REGEXP
71
+ generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__
72
+ def #{internal_write_method}(time)
73
+ time = Time.zone.parse(time) if time.is_a? String
74
+ #{attr_name}_will_change! if will_change_attribute? #{attr_name}, time
75
+ @attributes['#{attr_name}'] = time
76
+ end
77
+ alias #{attr_name}= #{internal_write_method}
78
+ RUBY
79
+ else
80
+ generated_attribute_methods.send(:define_method, internal_write_method) do |time|
81
+ time = Time.zone.parse(time) if time.is_a? String
82
+ send("#{attr_name}_will_change!") if will_change_attribute? attr_name, time
83
+ @attributes[attr_name] = time
84
+ end
85
+ alias_method "#{attr_name}=", internal_write_method
86
+ end
87
+ else
88
+ super
89
+ end
69
90
  end
70
91
 
71
92
 
@@ -28,7 +28,14 @@ module MassiveRecord
28
28
  end
29
29
 
30
30
  def write_attribute(attr_name, value)
31
- @attributes[attr_name.to_s] = value
31
+ attr_name = attr_name.to_s
32
+ internal_write_method = "_#{attr_name}="
33
+
34
+ if respond_to? internal_write_method
35
+ send(internal_write_method, value)
36
+ else
37
+ @attributes[attr_name.to_s] = value
38
+ end
32
39
  end
33
40
 
34
41
  private
@@ -18,15 +18,19 @@ require 'massive_record/orm/finders/rescue_missing_table_on_find'
18
18
  require 'massive_record/orm/attribute_methods'
19
19
  require 'massive_record/orm/attribute_methods/time_zone_conversion'
20
20
  require 'massive_record/orm/attribute_methods/write'
21
+ require 'massive_record/orm/attribute_methods/cast_numbers_on_write'
21
22
  require 'massive_record/orm/attribute_methods/read'
22
23
  require 'massive_record/orm/attribute_methods/dirty'
23
24
  require 'massive_record/orm/single_table_inheritance'
24
25
  require 'massive_record/orm/validations'
26
+ require 'massive_record/orm/validations/associated'
25
27
  require 'massive_record/orm/callbacks'
26
28
  require 'massive_record/orm/timestamps'
27
29
  require 'massive_record/orm/persistence'
28
30
  require 'massive_record/orm/default_id'
29
31
  require 'massive_record/orm/query_instrumentation'
32
+ require 'massive_record/orm/observer'
33
+ require 'massive_record/orm/identity_map'
30
34
 
31
35
 
32
36
  module MassiveRecord
@@ -75,8 +79,21 @@ module MassiveRecord
75
79
  class_attribute :check_record_uniqueness_on_create, :instance_writer => false
76
80
  self.check_record_uniqueness_on_create = false
77
81
 
78
- class_attribute :auto_increment_id, :instance_writer => false
79
- self.auto_increment_id = true
82
+
83
+ #
84
+ # Default id and id facyory settings
85
+ # Should we set automatically the id, and which factory should we ask?
86
+ #
87
+ # The default id factory is set when massive record is fully loaded, as
88
+ # it uses MassiveRecord itself to communicate with the database.
89
+ # Take a look inside of orm/id_factory.rb; we are utilizing the on_load hook.
90
+ #
91
+ class_attribute :id_factory, :instance_writer => false
92
+ class_attribute :set_id_from_factory_before_create, :instance_writer => false
93
+ self.set_id_from_factory_before_create = true
94
+
95
+
96
+
80
97
 
81
98
  class << self
82
99
  def table_name
@@ -146,11 +163,13 @@ module MassiveRecord
146
163
  @new_record = true
147
164
  @destroyed = @readonly = false
148
165
  @relation_proxy_cache = {}
166
+ @raw_data = Hash.new { |h,k| h[k] = {} }
167
+
168
+ clear_dirty_states!
149
169
 
150
170
  self.attributes_raw = attributes_from_field_definition.merge('id' => id)
151
171
  self.attributes = attributes
152
172
 
153
- clear_dirty_states!
154
173
 
155
174
  _run_initialize_callbacks
156
175
  end
@@ -176,7 +195,7 @@ module MassiveRecord
176
195
  @destroyed = @readonly = false
177
196
  @relation_proxy_cache = {}
178
197
 
179
- self.attributes_raw = coder['attributes']
198
+ reinit_with(coder)
180
199
  fill_attributes_with_default_values_where_nil_is_not_allowed
181
200
 
182
201
  _run_find_callbacks
@@ -185,6 +204,12 @@ module MassiveRecord
185
204
  self
186
205
  end
187
206
 
207
+ def reinit_with(coder) # :nodoc:
208
+ @raw_data = Hash.new { |h,k| h[k] = {} }
209
+ @raw_data.update(coder['raw_data']) if coder.has_key? 'raw_data'
210
+ self.attributes_raw = coder['attributes']
211
+ end
212
+
188
213
 
189
214
  def ==(other)
190
215
  other.equal?(self) || other.instance_of?(self.class) && id == other.id
@@ -197,6 +222,7 @@ module MassiveRecord
197
222
 
198
223
  def freeze
199
224
  @attributes.freeze
225
+ self
200
226
  end
201
227
 
202
228
  def frozen?
@@ -242,6 +268,31 @@ module MassiveRecord
242
268
  object.init_with('attributes' => attributes.select{|k| !['id', 'created_at', 'updated_at'].include?(k)})
243
269
  object
244
270
  end
271
+
272
+
273
+ #
274
+ # The raw data is raw values returned by the adapter.
275
+ # It is a nested hash like:
276
+ #
277
+ # {
278
+ # 'family' => {
279
+ # 'attr1' => 'value'
280
+ # 'attr2' => 'value'
281
+ # },
282
+ #
283
+ # 'addresses' => {
284
+ # 'address-1' => {'serialized' => 'attributes', 'for' => 'address-2'}
285
+ # }
286
+ # ...
287
+ # }
288
+ #
289
+ def raw_data
290
+ @raw_data.dup
291
+ end
292
+
293
+ def update_raw_data_for_column_family(column_family, new_values) # :nodoc:
294
+ @raw_data[column_family] = new_values
295
+ end
245
296
 
246
297
 
247
298
  private
@@ -271,7 +322,7 @@ module MassiveRecord
271
322
 
272
323
 
273
324
  def next_id
274
- IdFactory.next_for(self.class).to_s
325
+ id_factory.next_for(self.class).to_s
275
326
  end
276
327
  end
277
328
 
@@ -279,19 +330,21 @@ module MassiveRecord
279
330
  Base.class_eval do
280
331
  include Config
281
332
  include Persistence
282
- include Relations::Interface
283
333
  include Finders
334
+ include IdentityMap
284
335
  extend RescueMissingTableOnFind
285
336
  include AttributeMethods
337
+ include Relations::Interface
286
338
  include AttributeMethods::Write, AttributeMethods::Read
287
339
  include AttributeMethods::TimeZoneConversion
288
340
  include AttributeMethods::Dirty
341
+ include AttributeMethods::CastNumbersOnWrite
289
342
  include Validations
290
- include Callbacks
343
+ include Callbacks, ActiveModel::Observing
291
344
  include Timestamps
292
345
  include SingleTableInheritance
293
346
  include DefaultId
294
- include QueryInstrumentation
347
+ include QueryInstrumentation::Table
295
348
 
296
349
 
297
350
  alias [] read_attribute
@@ -302,6 +355,7 @@ end
302
355
 
303
356
  require 'massive_record/orm/table'
304
357
  require 'massive_record/orm/column'
358
+ require 'massive_record/orm/embedded'
305
359
  require 'massive_record/orm/id_factory'
306
360
  require 'massive_record/orm/log_subscriber'
307
361