Class: Perpetuity::Mapper

Inherits:
Object
  • Object
show all
Includes:
DataInjectable
Defined in:
lib/perpetuity/mapper.rb

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from DataInjectable

#give_id_to, #inject_attribute, #inject_data

Constructor Details

#initialize(registry = Perpetuity.mapper_registry, id_map = IdentityMap.new) ⇒ Mapper

Returns a new instance of Mapper.



16
17
18
19
20
# File 'lib/perpetuity/mapper.rb', line 16

def initialize registry=Perpetuity.mapper_registry, id_map=IdentityMap.new
  @mapper_registry = registry
  @identity_map = id_map
  @dirty_tracker = DirtyTracker.new
end

Class Attribute Details

.collection_nameObject

Returns the value of attribute collection_name.



13
14
15
# File 'lib/perpetuity/mapper.rb', line 13

def collection_name
  @collection_name
end

Instance Attribute Details

#dirty_trackerObject (readonly)

Returns the value of attribute dirty_tracker.



11
12
13
# File 'lib/perpetuity/mapper.rb', line 11

def dirty_tracker
  @dirty_tracker
end

#identity_mapObject (readonly)

Returns the value of attribute identity_map.



11
12
13
# File 'lib/perpetuity/mapper.rb', line 11

def identity_map
  @identity_map
end

#mapper_registryObject (readonly)

Returns the value of attribute mapper_registry.



11
12
13
# File 'lib/perpetuity/mapper.rb', line 11

def mapper_registry
  @mapper_registry
end

Class Method Details

.attribute(name, options = {}) ⇒ Object



32
33
34
35
# File 'lib/perpetuity/mapper.rb', line 32

def self.attribute name, options = {}
  type = options.fetch(:type) { nil }
  attribute_set << Attribute.new(name, type, options)
end

.attribute_setObject



28
29
30
# File 'lib/perpetuity/mapper.rb', line 28

def self.attribute_set
  @attribute_set ||= AttributeSet.new
end

.attributesObject



37
38
39
# File 'lib/perpetuity/mapper.rb', line 37

def self.attributes
  attribute_set.map(&:name)
end

.collection(name) ⇒ Object



274
275
276
# File 'lib/perpetuity/mapper.rb', line 274

def self.collection name
  @collection_name = name.to_s
end

.data_source(configuration = Perpetuity.configuration) ⇒ Object



103
104
105
# File 'lib/perpetuity/mapper.rb', line 103

def self.data_source(configuration=Perpetuity.configuration)
  configuration.data_source
end

.id(type = nil, &block) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
# File 'lib/perpetuity/mapper.rb', line 202

def self.id type=nil, &block
  if block_given?
    @id = block
    if type
      attribute :id, type: type
    end
    nil
  else
    @id ||= -> { nil }
  end
end

.index(attribute_names, options = {}) ⇒ Object



41
42
43
44
45
46
47
48
# File 'lib/perpetuity/mapper.rb', line 41

def self.index attribute_names, options={}
  attributes = Array(attribute_names).map { |name| attribute_set[name] }
  if attributes.one?
    data_source.index collection_name, attributes.first, options
  else
    data_source.index collection_name, attributes, options
  end
end

.map(klass, registry = Perpetuity.mapper_registry) ⇒ Object



22
23
24
25
26
# File 'lib/perpetuity/mapper.rb', line 22

def self.map klass, registry=Perpetuity.mapper_registry
  registry[klass] = self
  @mapped_class = klass
  collection klass.name
end

.mapped_classObject



270
271
272
# File 'lib/perpetuity/mapper.rb', line 270

def self.mapped_class
  @mapped_class
end

Instance Method Details

#allObject



131
132
133
# File 'lib/perpetuity/mapper.rb', line 131

def all
  retrieve
end

#all?(&block) ⇒ Boolean

Returns:

  • (Boolean)


115
116
117
# File 'lib/perpetuity/mapper.rb', line 115

def all? &block
  count(&block) == count
end

#any?(&block) ⇒ Boolean

Returns:

  • (Boolean)


111
112
113
# File 'lib/perpetuity/mapper.rb', line 111

def any? &block
  count(&block) > 0
end

#attribute_setObject



75
76
77
# File 'lib/perpetuity/mapper.rb', line 75

def attribute_set
  self.class.attribute_set
end

#attributesObject



71
72
73
# File 'lib/perpetuity/mapper.rb', line 71

def attributes
  self.class.attributes
end

#collection_nameObject



282
283
284
# File 'lib/perpetuity/mapper.rb', line 282

def collection_name
  self.class.collection_name
end

#count(&block) ⇒ Object



107
108
109
# File 'lib/perpetuity/mapper.rb', line 107

def count &block
  data_source.count collection_name, &block
end

#data_sourceObject



250
251
252
# File 'lib/perpetuity/mapper.rb', line 250

def data_source
  self.class.data_source
end

#decrement(object, attribute, count = 1) ⇒ Object



233
234
235
236
# File 'lib/perpetuity/mapper.rb', line 233

def decrement object, attribute, count=1
  id = id_for(object) || object
  data_source.increment collection_name, id, attribute, -count
end

#delete(object_or_array) ⇒ Object



178
179
180
181
182
183
# File 'lib/perpetuity/mapper.rb', line 178

def delete object_or_array
  ids = Array(object_or_array).map { |object|
    persisted?(object) ? id_for(object) : object
  }
  data_source.delete ids, collection_name
end

#delete_allObject



79
80
81
# File 'lib/perpetuity/mapper.rb', line 79

def delete_all
  data_source.delete_all collection_name
end

#find(id = nil, &block) ⇒ Object Also known as: detect



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# File 'lib/perpetuity/mapper.rb', line 141

def find id=nil, &block
  return select(&block).first if block_given?

  result = if id.is_a? Array
             find_all_by_ids id
           else
             identity_map[mapped_class, id] ||
             select { |object| object.id == id }.first
           end

  Array(result).each do |r|
    identity_map << r
    dirty_tracker << r
  end

  result
end

#find_all_by_ids(ids) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/perpetuity/mapper.rb', line 161

def find_all_by_ids ids
  ids_in_map    = ids & identity_map.ids_for(mapped_class)
  ids_to_select = ids - ids_in_map
  retrieved     = if ids_to_select.any?
                    select { |object| object.id.in ids_to_select }.to_a
                  else
                    []
                  end
  from_map      = ids_in_map.map { |id| identity_map[mapped_class, id] }

  retrieved.concat from_map
end

#firstObject



127
128
129
# File 'lib/perpetuity/mapper.rb', line 127

def first
  retrieve.limit(1).first
end

#generate_id_for(object) ⇒ Object



99
100
101
# File 'lib/perpetuity/mapper.rb', line 99

def generate_id_for object
  object.instance_exec(&self.class.id)
end

#id_for(object) ⇒ Object



246
247
248
# File 'lib/perpetuity/mapper.rb', line 246

def id_for object
  object.instance_variable_get(:@id)
end

#increment(object, attribute, count = 1) ⇒ Object



228
229
230
231
# File 'lib/perpetuity/mapper.rb', line 228

def increment object, attribute, count=1
  id = id_for(object) || object
  data_source.increment collection_name, id, attribute, count
end

#indexesObject



54
55
56
# File 'lib/perpetuity/mapper.rb', line 54

def indexes
  data_source.indexes(collection_name)
end

#insert(object) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/perpetuity/mapper.rb', line 83

def insert object
  objects = Array(object)
  serialized_objects = objects.map { |obj| serialize(obj) }

  new_ids = data_source.insert(collection_name, serialized_objects, attribute_set)
  objects.each_with_index do |obj, index|
    give_id_to obj, new_ids[index]
  end

  if object.is_a? Array
    new_ids
  else
    new_ids.first
  end
end

#load_association!(object, attribute) ⇒ Object



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/perpetuity/mapper.rb', line 185

def load_association! object, attribute
  objects = Array(object)
  dereferencer = Dereferencer.new(mapper_registry, identity_map)
  dereferencer.load objects.map { |obj| obj.instance_variable_get("@#{attribute}") }

  objects.each do |obj|
    reference = obj.instance_variable_get("@#{attribute}")
    if reference.is_a? Array
      refs = reference
      real_objects = refs.map { |ref| dereferencer[ref] }
      inject_attribute obj, attribute, real_objects
    else
      inject_attribute obj, attribute, dereferencer[reference]
    end
  end
end

#mapped_classObject



278
279
280
# File 'lib/perpetuity/mapper.rb', line 278

def mapped_class
  self.class.mapped_class
end

#none?(&block) ⇒ Boolean

Returns:

  • (Boolean)


123
124
125
# File 'lib/perpetuity/mapper.rb', line 123

def none? &block
  !any?(&block)
end

#one?(&block) ⇒ Boolean

Returns:

  • (Boolean)


119
120
121
# File 'lib/perpetuity/mapper.rb', line 119

def one? &block
  count(&block) == 1
end

#persisted?(object) ⇒ Boolean

Returns:

  • (Boolean)


242
243
244
# File 'lib/perpetuity/mapper.rb', line 242

def persisted? object
  !!id_for(object)
end

#reindex!Object



58
59
60
61
62
63
# File 'lib/perpetuity/mapper.rb', line 58

def reindex!
  indexes.each { |index| data_source.activate_index! index }
  unspecified_indexes.each do |index|
    data_source.remove_index index
  end
end

#reject(&block) ⇒ Object



174
175
176
# File 'lib/perpetuity/mapper.rb', line 174

def reject &block
  retrieve data_source.negate_query(&block)
end

#remove_index!(index) ⇒ Object



50
51
52
# File 'lib/perpetuity/mapper.rb', line 50

def remove_index! index
  data_source.remove_index index
end

#sampleObject



238
239
240
# File 'lib/perpetuity/mapper.rb', line 238

def sample
  all.sample
end

#save(object) ⇒ Object



219
220
221
222
223
224
225
226
# File 'lib/perpetuity/mapper.rb', line 219

def save object
  changed_attributes = serialize_changed_attributes(object)
  if changed_attributes && changed_attributes.any?
    update object, changed_attributes
  else
    update object, serialize(object)
  end
end

#select(&block) ⇒ Object Also known as: find_all



135
136
137
# File 'lib/perpetuity/mapper.rb', line 135

def select &block
  retrieve data_source.query(&block)
end

#serialize(object) ⇒ Object



254
255
256
257
258
259
260
261
# File 'lib/perpetuity/mapper.rb', line 254

def serialize object
  attributes = data_source.serialize(object, self)
  if o_id = generate_id_for(object)
    attributes['id'] = o_id
  end

  attributes
end

#serialize_changed_attributes(object) ⇒ Object



263
264
265
266
267
268
# File 'lib/perpetuity/mapper.rb', line 263

def serialize_changed_attributes object
  cached = dirty_tracker[object.class, id_for(object)]
  if cached
    data_source.serialize_changed_attributes(object, cached, self)
  end
end

#unspecified_indexesObject



65
66
67
68
69
# File 'lib/perpetuity/mapper.rb', line 65

def unspecified_indexes
  active_indexes = data_source.active_indexes(collection_name)
  active_but_unspecified_indexes = (active_indexes - indexes)
  active_but_unspecified_indexes.reject { |index| index.attribute =~ /id/ }
end

#update(object, new_data) ⇒ Object



214
215
216
217
# File 'lib/perpetuity/mapper.rb', line 214

def update object, new_data
  id = object.is_a?(mapped_class) ? id_for(object) : object
  data_source.update collection_name, id, new_data
end