require 'massive_record/orm/schema/common_interface' module MassiveRecord module ORM module Schema module EmbeddedInterface extend ActiveSupport::Concern included do include CommonInterface class_attribute :fields, :instance_writer => false self.fields = nil end module ClassMethods # # DSL method exposed into class. Makes it possible to do: # # class Person < MassiveRecord::ORM::Embedded # field :name # field :age, :integer, :default => 0 # field :points, :integer, :column => :number_of_points # end # # def field(*args) ensure_fields_exists fields << Field.new_with_arguments_from_dsl(*args) end def timestamps add_field :created_at, :time end # # If you need to add fields dynamically, use this method. # It wraps functionality needed to keep the class in a consistent state. # There is also an instance method defined which will inject default value # to the object itself after defining the field. # def add_field(*args) ensure_fields_exists field = Field.new_with_arguments_from_dsl(*args) fields << field undefine_attribute_methods if respond_to? :undefine_attribute_methods field end # # Returns attributes in embedded object from raw data. Raw # data's keys might different from a field name, if :column # option has been used. # def transpose_raw_data_to_record_attributes_and_raw_data(id, raw_data) attributes = {:id => id} attributes['updated_at'] = raw_data.created_at raw_attributes = if raw_data.value.is_a? String Base.coder.load(raw_data.value) else raw_data.value end raw_data = Hash[raw_attributes.collect do |attr, value| [attr, RawData.new(value: value, created_at: raw_data.created_at)] end] attributes_schema.each do |attr_name, orm_field| value = raw_attributes.has_key?(orm_field.column) ? raw_attributes[orm_field.column] : nil attributes[attr_name] = value.nil? ? nil : orm_field.decode(raw_attributes[orm_field.column]) end [attributes, raw_data] end private # # Entrypoint for the CommonInterface # def schema_source fields end def ensure_fields_exists self.fields = Fields.new if fields.nil? end end # # Same as defined in class method, but also sets the default value # in current object it was called from. # def add_field(*args) new_field = self.class.add_field(*args) method = "#{new_field.name}=" send(method, new_field.default) if respond_to? method end # # Returns attributes as a hash which has correct keys # based on it's field definition. For instance, you can # have a class with a field :attr_name, :column => :stored_as_this # def attributes_db_raw_data_hash(only_attr_names = []) values = Hash.new attributes_schema.each do |attr_name, orm_field| next unless only_attr_names.empty? || only_attr_names.include?(attr_name) values[orm_field.column] = orm_field.encode(send(attr_name)) end values end def attributes_to_row_values_hash(only_attr_names = []) ActiveSupport::Deprecation.warn("attributes_to_row_values_hash is deprecated. Please use attributes_db_raw_data_hash") attributes_db_raw_data_hash(only_attr_names) end end end end end