Class: Perpetuity::Mapper

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

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) ⇒ Mapper

Returns a new instance of Mapper.



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

def initialize registry=Perpetuity.mapper_registry
  @mapper_registry = registry
  @identity_map = IdentityMap.new
end

Instance Attribute Details

#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



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

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

.attribute_setObject



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

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

.attributesObject



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

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

.data_source(configuration = Perpetuity.configuration) ⇒ Object



94
95
96
# File 'lib/perpetuity/mapper.rb', line 94

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

.id(&block) ⇒ Object



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

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

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



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

def self.index attribute, options={}
  data_source.index mapped_class, attribute_set[attribute], options
end

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



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

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

.mapped_classObject



253
254
255
# File 'lib/perpetuity/mapper.rb', line 253

def self.mapped_class
  @mapped_class
end

.validate(&block) ⇒ Object



225
226
227
# File 'lib/perpetuity/mapper.rb', line 225

def self.validate &block
  validations.instance_exec(&block)
end

.validationsObject



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

def self.validations
  @validations ||= ValidationSet.new
end

Instance Method Details

#allObject



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

def all
  retrieve
end

#all?(&block) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#any?(&block) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#attribute_setObject



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

def attribute_set
  self.class.attribute_set
end

#attributesObject



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

def attributes
  self.class.attributes
end

#count(&block) ⇒ Object



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

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

#data_sourceObject



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

def data_source
  self.class.data_source
end

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



207
208
209
210
211
# File 'lib/perpetuity/mapper.rb', line 207

def decrement object, attribute, count=1
  data_source.increment mapped_class, id_for(object), attribute, -count
rescue Moped::Errors::OperationFailure
  raise ArgumentError.new('Attempted to decrement a non-numeric value')
end

#delete(object) ⇒ Object



155
156
157
158
# File 'lib/perpetuity/mapper.rb', line 155

def delete object
  id = persisted?(object) ? id_for(object) : object
  data_source.delete id, mapped_class
end

#delete_allObject



69
70
71
# File 'lib/perpetuity/mapper.rb', line 69

def delete_all
  data_source.delete_all mapped_class
end

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



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/perpetuity/mapper.rb', line 132

def find id=nil, cache_result=true, &block
  if block_given?
    select(&block).first
  else
    cached_value = identity_map[mapped_class, id]
    return cached_value if cached_value

    result = select { |object| object.id == id }.first

    if cache_result and !result.nil?
      identity_map << result
    end

    result
  end
end

#firstObject



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

def first
  retrieve.limit(1).first
end

#generate_id_for(object) ⇒ Object



90
91
92
# File 'lib/perpetuity/mapper.rb', line 90

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

#id_for(object) ⇒ Object



221
222
223
# File 'lib/perpetuity/mapper.rb', line 221

def id_for object
  object.instance_variable_get(:@id) if persisted?(object)
end

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



201
202
203
204
205
# File 'lib/perpetuity/mapper.rb', line 201

def increment object, attribute, count=1
  data_source.increment mapped_class, id_for(object), attribute, count
rescue Moped::Errors::OperationFailure
  raise ArgumentError.new('Attempted to increment a non-numeric value')
end

#indexesObject



44
45
46
# File 'lib/perpetuity/mapper.rb', line 44

def indexes
  data_source.indexes(mapped_class)
end

#insert(object) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/perpetuity/mapper.rb', line 73

def insert object
  raise "#{object} is invalid and cannot be persisted." unless self.class.validations.valid?(object)
  objects = Array(object)
  serialized_objects = objects.map { |obj| serialize(obj) }

  new_ids = data_source.insert(mapped_class, serialized_objects)
  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



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

def load_association! object, attribute
  objects = Array(object)
  dereferencer = Dereferencer.new(mapper_registry)
  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



257
258
259
# File 'lib/perpetuity/mapper.rb', line 257

def mapped_class
  self.class.mapped_class
end

#none?(&block) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#one?(&block) ⇒ Boolean

Returns:

  • (Boolean)


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

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

#persisted?(object) ⇒ Boolean

Returns:

  • (Boolean)


217
218
219
# File 'lib/perpetuity/mapper.rb', line 217

def persisted? object
  object.instance_variable_defined?(:@id)
end

#reindex!Object



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

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



151
152
153
# File 'lib/perpetuity/mapper.rb', line 151

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

#remove_index!(index) ⇒ Object



40
41
42
# File 'lib/perpetuity/mapper.rb', line 40

def remove_index! index
  data_source.remove_index index
end

#sampleObject



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

def sample
  all.sample
end

#save(object) ⇒ Object



192
193
194
195
196
197
198
199
# File 'lib/perpetuity/mapper.rb', line 192

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

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



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

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

#serialize(object) ⇒ Object



237
238
239
240
241
242
243
244
# File 'lib/perpetuity/mapper.rb', line 237

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



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

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

#unspecified_indexesObject



55
56
57
58
59
# File 'lib/perpetuity/mapper.rb', line 55

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

#update(object, new_data, update_in_memory = true) ⇒ Object



185
186
187
188
189
190
# File 'lib/perpetuity/mapper.rb', line 185

def update object, new_data, update_in_memory = true
  id = object.is_a?(mapped_class) ? id_for(object) : object

  inject_data object, new_data if update_in_memory
  data_source.update mapped_class, id, new_data
end