Module: Lore::Model_Instance

Includes:
Polymorphic_Instance_Methods
Included in:
Table_Accessor
Defined in:
lib/lore/model/model_instance.rb

Overview

Used as mixin for Table_Accessor. This module holds methods provided by Table_Accessor instances.

Instance Method Summary collapse

Methods included from Polymorphic_Instance_Methods

#get_concrete_model

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, *args) ⇒ Object



159
160
161
# File 'lib/lore/model/model_instance.rb', line 159

def method_missing(meth, *args)
  return @attribute_values_flat[meth]
end

Instance Method Details

#<=>(other) ⇒ Object

See ==



241
242
243
# File 'lib/lore/model/model_instance.rb', line 241

def <=>(other)
  return !(self.==(other))
end

#==(other) ⇒ Object

Returns true if instance points to same records as other instance. Only compares primary key values.



216
217
218
219
# File 'lib/lore/model/model_instance.rb', line 216

def ==(other)
  return false if self.class.to_s != other.class.to_s
  return pkeys() == other.pkeys()
end

#===(other) ⇒ Object

Returns true if instance points to same records as other instance, also compares non-key attribute values.



236
237
238
239
# File 'lib/lore/model/model_instance.rb', line 236

def ===(other)
  return false unless (self == other)
  
end

#[](clause) ⇒ Object

Explicit attribute request. Example:

Car[Vehicle.name]

In case name is attribute field in Car and Vehicle.



210
211
212
# File 'lib/lore/model/model_instance.rb', line 210

def [](clause)
  abs_attr(clause)
end

#abs_attr(klass = nil) ⇒ Object

Returns value hash of instance attributes of a given subtype like:

{
  'id' => 123, 
  'name' => 'example'
}

Common usage:

self.class.abs_attr(Klass_A)[:id]  ->  123


297
298
299
300
301
302
303
304
305
# File 'lib/lore/model/model_instance.rb', line 297

def abs_attr(klass=nil)
  Lore.logger.warn { 'abs_attr() is deprecated' }

  klass = klass.to_s if klass.instance_of? Symbol
  return @attribute_values if klass.nil?
  return @attribute_values[klass.table_name] if klass.kind_of? Lore::Table_Accessor
  return @attribute_values[klass] if klass.instance_of? String
  return @attribute_values[klass.to_s.split('.')[0..1].join('.').to_s][klass.to_s.split('.').at(-1)] if klass.instance_of? Lore::Clause
end

#attrObject

Returns value hash of instance attributes like:

{
  'schema.table.id' => 123, 
  'schema.atable.name' => 'example'
}

Common usage:

table_instance.attr[:id]  ->  123

But it is recommended to use

table_instance.id  -> 123


272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/lore/model/model_instance.rb', line 272

def attr
  return @attribute_values_flat
  if @flat_attr.nil? then
    @flat_attr = Attribute_Hash.new
    @attribute_values.each_pair { |table, attribs| 
      attribs.each_pair { |attrib_name, value|
        @flat_attr[attrib_name] = value unless value.nil?
      }
    }
  end
  @flat_attr
end

#attribute_valuesObject

def



307
308
309
310
# File 'lib/lore/model/model_instance.rb', line 307

def attribute_values
  @attribute_values ||= self.class.distribute_attrib_values(@attribute_values_flat)
  @attribute_values
end

#commitObject Also known as: save

Commit changes on Table_Accessor instance to DB. Results in one or more SQL update calls.

Common usage:

unit.name = 'changed'
unit.commit()


320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/lore/model/model_instance.rb', line 320

def commit
# {{{
  return unless @touched
  
  Lore.logger.debug { "Updating #{self.to_s}. " }
  Lore.logger.debug { "Touched values are: #{@touched_fields.inspect}" }

  # TODO: Optimize this! 
  @attribute_values = self.class.distribute_attrib_values(@attribute_values_flat)
  foreign_pkey_values = false
  @update_values = {}
  @update_pkey_values = {}
  @attribute_values.each_pair { |table,attributes|
    @touched_fields.each { |name|
      value  = @attribute_values[table][name]
      filter = self.class.__filters__.input_filters[name]
      value = filter.call(value) if filter
      if attributes[name] then
        update_values[table] ||= {}
        @update_values[table][name] = value 
      end
    }
    foreign_pkey_values = get_primary_key_value_map[table]
    
    @update_pkey_values[table] = foreign_pkey_values if foreign_pkey_values
  }

  Validation::Parameter_Validator.validate_update(self.class, update_values)

  self.class.before_commit(self)
  self.class.__update_strategy__.perform_update(self)
  self.class.after_commit(self)

  @touched = false
end

#deleteObject

Delete this instance from DB. Common usage:

unit = Some_Table_Accessor.select { ... }.first
unit.delete

Calls hooks Table_Accessor.before_instance_delete(self) and Table_Accessor.after_instance_delete(self).



366
367
368
369
370
371
372
373
# File 'lib/lore/model/model_instance.rb', line 366

def delete
  # Called before entity_instance.delete
  self.class.before_instance_delete(self)

  self.class.__delete_strategy__.perform_delete(@attribute_values_flat)
  # Called after entity_instance.delete
  self.class.after_instance_delete(self)
end

#get_attribute_value_mapObject

Returns attribute values mapped to table names.



251
252
253
254
255
# File 'lib/lore/model/model_instance.rb', line 251

def get_attribute_value_map
  return @attribute_values if @attribute_values
  @attribute_values = self.class.distribute_attrib_values(@attribute_values_flat)
  return @attribute_values
end

#get_attribute_valuesObject

Returns all attribute values as hash.



246
247
248
# File 'lib/lore/model/model_instance.rb', line 246

def get_attribute_values() # :nodoc:
  @attribute_values_flat
end

#get_label_stringObject



128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/lore/model/model_instance.rb', line 128

def get_label_string
  if !@label_string || @touched then
    value = ''
    self.class.get_labels.each { |label_attrib|
      label_parts = label_attrib.split('.')
      value << @attribute_values[label_parts[0..1].join('.')][label_parts[2]].to_s + ' '
    }
    value = '[no label given]' if value == ''
    @label_string = value
  end
  return @label_string
end

#get_primary_key_value_mapObject

Returns primary key values mapped to table names.



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
# File 'lib/lore/model/model_instance.rb', line 91

def get_primary_key_value_map
# {{{
  return @primary_key_value_map if (@primary_key_value_map && !@touched)
  
  accessor    = self.class
  base_models = accessor.__associations__.base_klasses()
  table_name  = accessor.table_name
  pkey_fields = accessor.get_primary_keys
  
  if !pkey_fields[table_name] then
    raise ::Exception.new("Unable to resolve pkey fields for #{self.class.to_s}. Known fields are: #{pkey_fields.inspect}")
  end

  @primary_key_value_map = { table_name => {} }
  pkey_fields[table_name].each { |own_pkey|
    @primary_key_value_map[table_name][own_pkey] = @attribute_values_flat[own_pkey]
  }
  
  # Map own foreign key values back to foreign primary key 
  # values. This is necessary as joined primary key field names are 
  # shadowed. 
  accessor.__associations__.pkey_value_lookup.each { |mapping|
    foreign_pkeys = {}
    mapping.at(1).each_with_index { |fkey,idx|
      value = @attribute_values_flat[fkey]
      foreign_pkeys[mapping.at(2).at(idx)] = value 
    }
    @primary_key_value_map[mapping.at(0)] = foreign_pkeys
  }
  return @primary_key_value_map
end

#get_primary_key_valuesObject



80
81
82
83
84
85
86
87
88
# File 'lib/lore/model/model_instance.rb', line 80

def get_primary_key_values
  return @primary_key_values if @primary_key_values

  keys = self.class.get_primary_keys[self.class.table_name]
  @primary_key_values = keys.map { |pkey|
    @attribute_values_flat[pkey]
  }
  @primary_key_values
end

#idObject



164
165
166
# File 'lib/lore/model/model_instance.rb', line 164

def id
  @attribute_values_flat[:id] || obj_id
end

#inspectObject

def



375
376
377
378
# File 'lib/lore/model/model_instance.rb', line 375

def inspect
# {{{
  'Lore::Table_Accessor entity: ' << @attribute_values_flat.inspect
end

#is_cached_entity?Boolean

Whether this instance has been loaded from cache or live from DB.

Returns:

  • (Boolean)


75
76
77
78
# File 'lib/lore/model/model_instance.rb', line 75

def is_cached_entity?
  # Set in initialize via marshal_load
  @loaded_from_cache
end

#keyObject

Returns primary key values of own table



124
125
126
# File 'lib/lore/model/model_instance.rb', line 124

def key
  get_primary_key_value_map[self.class.table_name]
end

#marshal_dumpObject

Create a marshalled dump of this model instance. Returns attribute values as The only difference between model instances is their value set.



60
61
62
63
64
65
66
# File 'lib/lore/model/model_instance.rb', line 60

def marshal_dump
  { 
    :klass => self.class.to_s, 
    :values => @attribute_values_flat, 
    :joined => @joined_models
  }
end

#marshal_load(dump) ⇒ Object

Creates an instance of self from marshalled value set.



69
70
71
# File 'lib/lore/model/model_instance.rb', line 69

def marshal_load(dump)
  return initialize(dump[:values], dump[:joined], :cached)
end

#obj_idObject



163
# File 'lib/lore/model/model_instance.rb', line 163

alias :obj_id :id

#pkeyObject

Return primary key value. In case primary key is composed, return it as array.



222
223
224
225
226
227
# File 'lib/lore/model/model_instance.rb', line 222

def pkey
  table = self.class.table_name
  key = get_primary_key_values
  return key.first if key.length < 2
  return key
end

#pkeysObject



229
230
231
232
# File 'lib/lore/model/model_instance.rb', line 229

def pkeys
  table = self.class.table_name
  return get_primary_key_values
end

#set_attribute_value(attrib_name, attrib_value) ⇒ Object Also known as: []=

Set value for given attribute, e.g. for later commit. It is recommended to use random access assignment instead:

instance.set_attribute_value(:name, 'Wombat')

is same as

instance[:name] = 'Wombat'


175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/lore/model/model_instance.rb', line 175

def set_attribute_value(attrib_name, attrib_value)
# {{{

  if @input_filters && (@input_filters.has_key?(attrib_name.intern)) then
    attrib_value = @input_filters[attrib_name.intern].call(attrib_value)
  end

  # touch(attrib_name)
  @touched = true
  @touched_fields ||= []
  @touched_fields << attrib_name if attrib_name

  @attribute_values_flat[attrib_name.to_sym] = attrib_value
end

#set_attribute_values(value_hash) ⇒ Object

def }}}



190
191
192
193
194
195
196
197
198
199
# File 'lib/lore/model/model_instance.rb', line 190

def set_attribute_values(value_hash)
  value_hash.each_pair { |attrib_name,value|
    if @input_filters && @input_filters.has_key?(attrib_name.intern) then
      value_hash[attrib_name] = @input_filters[attrib_name.intern].call(attrib_value)
    end
    @attribute_values_flat[attrib_name.to_sym] = attrib_value
    @touched_fields << attrib_name.intern
  }
  touch
end

#table_accessorObject



46
47
48
# File 'lib/lore/model/model_instance.rb', line 46

def table_accessor
  self.class
end

#touch(attrib_name = nil) ⇒ Object



146
147
148
149
150
151
152
# File 'lib/lore/model/model_instance.rb', line 146

def touch(attrib_name=nil)
  @touched = true
  @touched_fields ||= []
  @touched_fields << attrib_name if attrib_name
  @primary_key_value_map = false
  @primary_key_values    = false
end

#touched?Boolean

Returns:

  • (Boolean)


142
143
144
# File 'lib/lore/model/model_instance.rb', line 142

def touched?
  (@touched === true)
end

#untouch(attrib_name = nil) ⇒ Object



154
155
156
157
# File 'lib/lore/model/model_instance.rb', line 154

def untouch(attrib_name=nil)
  @touched = false
  @touched_fields.delete(attrib_name) if attrib_name
end

#update_pkey_valuesObject



53
54
55
# File 'lib/lore/model/model_instance.rb', line 53

def update_pkey_values
  @update_pkey_values
end

#update_valuesObject



50
51
52
# File 'lib/lore/model/model_instance.rb', line 50

def update_values
  @update_values
end