Class: JetSet::Mapper

Inherits:
Object
  • Object
show all
Defined in:
lib/jet_set/mapper.rb

Overview

A converter of a data rows to object model according to a mapping.

Instance Method Summary collapse

Constructor Details

#initialize(entity_builder, mapping, container) ⇒ Mapper

Parameters:

+entity_builder+:: an instance of +JetSet::EntityBuilder+
+mapping+:: an instance of +JetSet::Mapping+
+container+:: IoC container (+Hypo::Container+) for resolving entity dependencies


12
13
14
15
16
17
18
19
20
21
# File 'lib/jet_set/mapper.rb', line 12

def initialize(entity_builder, mapping, container)
  @entity_builder = entity_builder
  @mapping = mapping
  @container = container

  @mapping.entity_mappings.values.each do |entity_mapping|
    entity_name = "jet_set__#{entity_mapping.type.name.underscore}".to_sym
    container.register(entity_mapping.type, entity_name)
  end
end

Instance Method Details

#map(type, row_hash, session, prefix = type.name.underscore) ⇒ Object

Converts a table row to an object Parameters:

+type+:: entity type defined in the mapping
+row_hash+:: hash representation of table row
+session+:: instance of +JetSet::Session+
+prefix+:: (optional) custom prefix for extracting the type attributes,
  i.e."customer" for query:
    "SELECT u.name AS customer__name from users u"


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/jet_set/mapper.rb', line 31

def map(type, row_hash, session, prefix = type.name.underscore)
  entity_name = type.name.underscore.to_sym
  resolve_name = "jet_set__#{type.name.underscore}".to_sym
  entity_mapping = @mapping.get(entity_name)
  row = Row.new(row_hash, entity_mapping.fields, prefix)

  reference_hash = {}
  row.reference_names.each do |reference_name|
    if entity_mapping.references.key? reference_name.to_sym
      reference_id_name = reference_name + '__id'
      unless row_hash[reference_id_name.to_sym].nil?
        type = entity_mapping.references[reference_name.to_sym].type
        reference_hash[reference_name.to_sym] = map(type, row_hash, session, reference_name)
      end
    end
  end

  object = @container.resolve(resolve_name, row.attributes_hash.merge(reference_hash))
  entity = @entity_builder.create(object)
  entity.load_attributes!(row.attributes)

  reference_hash.each do |key, value|
    entity.set_reference! key.to_s, value
  end

  session.attach(entity)
  entity
end

#map_association(target, name, rows, session) ⇒ Object

Constructs object model relationships between of complex objects. Parameters:

+target+:: an instance or an array of entity instances
+name+:: name of the target attribute to bind
+rows+:: an array of database rows (hashes)
+session+:: an instance of +JetSet::Session+


66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/jet_set/mapper.rb', line 66

def map_association(target, name, rows, session)
  singular_name = name.to_s.singularize.to_sym
  entity_mapping = @mapping.get(singular_name)

  if target.is_a? Array
    relations = {}
    target_name = target[0].class.name.underscore
    back_relations = {}

    if rows.length > 0
      target_id_name = "#{target_name.underscore}_id"
      target_reference = entity_mapping.references[target_name.to_sym]

      rows.each do |row|
        relation = map(entity_mapping.type, row, session, singular_name.to_s)
        target_id = row[target_id_name.to_sym]

        if target_id.nil?
          raise MapperError, "Field \"#{target_id_name}\" is not defined in the query but it's required to construct \"#{name} to #{target_name}\" association. Just add it to SELECT clause."
        end

        relations[target_id] ||= []
        relations[target_id] << relation
        back_relations[relation.id] = target.select{|t| t.id == target_id}
      end

      target.each do |entry|
        target_id = entry.id
        relation_objects = relations[target_id]

        if relation_objects
          if target_reference
            relation_objects.each {|obj| obj.set_reference!(target_reference.name, entry)}
          end

          # set forward collection relation
          entry.set_collection!(name, relations[target_id])

          # set reverse collection relation if it's present
          if entity_mapping.collections[target_name.pluralize.to_sym]
            relation_objects.each{|obj| obj.set_collection!(target_name.pluralize.to_sym, back_relations[obj.id])}
          end
        end
      end
    end

    ids = []
    relations.values.each do |associations|
      ids << associations.map{|a| a.id}
    end

    {result: relations, ids: ids.flatten.uniq}
  else
    result = rows.map do |row|
      map(entity_mapping.type, row, session, singular_name.to_s)
    end

    target.set_collection!(name, result)

    {result: result, ids: result.map {|i| i.id}}
  end

end