lore 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. data/LICENSE +19 -0
  2. data/README +74 -0
  3. data/aspect.rb +80 -0
  4. data/behaviours/lockable.rb +41 -0
  5. data/behaviours/movable.rb +54 -0
  6. data/behaviours/versioned.rb +24 -0
  7. data/benchmark.rb +193 -0
  8. data/bits.rb +52 -0
  9. data/cache/abstract_entity_cache.rb +82 -0
  10. data/cache/bits.rb +22 -0
  11. data/cache/cacheable.rb +202 -0
  12. data/cache/cached_entities.rb +116 -0
  13. data/cache/file_index.rb +35 -0
  14. data/cache/mmap_entity_cache.rb +67 -0
  15. data/clause.rb +528 -0
  16. data/connection.rb +155 -0
  17. data/custom_functions.sql +14 -0
  18. data/exception/ambiguous_attribute.rb +14 -0
  19. data/exception/cache_exception.rb +30 -0
  20. data/exception/invalid_klass_parameters.rb +63 -0
  21. data/exception/invalid_parameter.rb +42 -0
  22. data/exception/unknown_typecode.rb +19 -0
  23. data/file_index.sql +56 -0
  24. data/gui/erb_template.rb +79 -0
  25. data/gui/erb_template_helpers.rhtml +19 -0
  26. data/gui/form.rb +314 -0
  27. data/gui/form_element.rb +676 -0
  28. data/gui/form_generator.rb +151 -0
  29. data/gui/templates/button.rhtml +2 -0
  30. data/gui/templates/checkbox.rhtml +3 -0
  31. data/gui/templates/checkbox_row.rhtml +1 -0
  32. data/gui/templates/file.rhtml +2 -0
  33. data/gui/templates/file_readonly.rhtml +3 -0
  34. data/gui/templates/form_element.rhtml +5 -0
  35. data/gui/templates/form_element_horizontal.rhtml +3 -0
  36. data/gui/templates/form_element_listed.rhtml +8 -0
  37. data/gui/templates/form_table.rhtml +3 -0
  38. data/gui/templates/form_table_blank.rhtml +3 -0
  39. data/gui/templates/form_table_horizontal.rhtml +8 -0
  40. data/gui/templates/password.rhtml +2 -0
  41. data/gui/templates/password_readonly.rhtml +3 -0
  42. data/gui/templates/radio.rhtml +1 -0
  43. data/gui/templates/radio_row.rhtml +1 -0
  44. data/gui/templates/select.rhtml +23 -0
  45. data/gui/templates/text.rhtml +2 -0
  46. data/gui/templates/text_readonly.rhtml +3 -0
  47. data/gui/templates/textarea.rhtml +3 -0
  48. data/gui/templates/textarea_readonly.rhtml +4 -0
  49. data/lore.gemspec +40 -0
  50. data/lore.rb +94 -0
  51. data/migration.rb +48 -0
  52. data/model.rb +139 -0
  53. data/model_factory.rb +202 -0
  54. data/model_shortcuts.rb +16 -0
  55. data/query_shortcuts.rb +367 -0
  56. data/reserved_methods.txt +3 -0
  57. data/result.rb +100 -0
  58. data/symbol.rb +58 -0
  59. data/table_accessor.rb +1926 -0
  60. data/table_deleter.rb +115 -0
  61. data/table_inserter.rb +168 -0
  62. data/table_instance.rb +384 -0
  63. data/table_selector.rb +314 -0
  64. data/table_updater.rb +155 -0
  65. data/test/README +31 -0
  66. data/test/env.rb +5 -0
  67. data/test/lore_test.log +8218 -0
  68. data/test/model.rb +142 -0
  69. data/test/prepare.rb +37 -0
  70. data/test/tc_aspect.rb +58 -0
  71. data/test/tc_cache.rb +80 -0
  72. data/test/tc_clause.rb +104 -0
  73. data/test/tc_deep_inheritance.rb +49 -0
  74. data/test/tc_factory.rb +57 -0
  75. data/test/tc_filter.rb +37 -0
  76. data/test/tc_form.rb +32 -0
  77. data/test/tc_model.rb +86 -0
  78. data/test/tc_prepare.rb +45 -0
  79. data/test/tc_refined_query.rb +88 -0
  80. data/test/tc_table_accessor.rb +265 -0
  81. data/test/test.log +181 -0
  82. data/test/test_db.sql +400 -0
  83. data/test/ts_lore.rb +49 -0
  84. data/types.rb +55 -0
  85. data/validation/message.rb +60 -0
  86. data/validation/parameter_validator.rb +104 -0
  87. data/validation/reason.rb +54 -0
  88. data/validation/type_validator.rb +91 -0
  89. data/validation.rb +65 -0
  90. metadata +170 -0
data/table_deleter.rb ADDED
@@ -0,0 +1,115 @@
1
+
2
+ require('lore/connection')
3
+ require('lore/bits')
4
+
5
+ module Lore
6
+
7
+ module Table_Deleter # :nodoc:
8
+
9
+ @logger = Lore.logger
10
+
11
+ private
12
+
13
+ def self.atomic_delete_query(table_name, primary_keys, value_keys)
14
+
15
+ query_string = 'DELETE FROM '+table_name+' WHERE '
16
+
17
+ field_counter=0
18
+ primary_keys.each { |field|
19
+
20
+ query_string << field + '=\''
21
+ internal_attribute_name = field[0..27]
22
+ value = value_keys[internal_attribute_name].to_s
23
+ if value == '' then
24
+ value = value_keys[table_name+'.'+internal_attribute_name].to_s
25
+ end
26
+
27
+ # attrib = Lore.resolve_passed_value(value_keys, table_name, field)
28
+ # value = attrib[:value]
29
+ # internal_attribute_name = attrib[:field]
30
+ query_string << value + '\' '
31
+ if field_counter < primary_keys.length-1
32
+ query_string += 'AND '
33
+ end
34
+ field_counter += 1
35
+ }
36
+ query_string += ';'
37
+
38
+ query_string
39
+
40
+ end #def
41
+
42
+ def self.block_delete(accessor,
43
+ &block)
44
+
45
+ query_string = 'DELETE FROM '+accessor.get_table_name
46
+
47
+ if block_given? then
48
+ yield_obj = Lore::Clause_Parser.new(accessor.table_name)
49
+ clause = yield *yield_obj
50
+ end
51
+
52
+ query_string += clause.where_part
53
+
54
+ Context.enter(accessor.get_context) unless accessor.get_context.nil?
55
+ begin
56
+ Lore::Connection.perform(query_string)
57
+ ensure
58
+ Context.leave unless accessor.get_context.nil?
59
+ end
60
+
61
+ end
62
+
63
+ def self.delete_query(table_name, is_a_hierarchy, primary_keys, value_keys, query_string='')
64
+
65
+ is_a_hierarchy.each_pair { |table, base_tables|
66
+
67
+ # pass base tables first, recursively, as IS_A-based creation has
68
+ # to be done bottom-up:
69
+ query_string += delete_query(table,
70
+ base_tables,
71
+
72
+ primary_keys,
73
+ value_keys,
74
+
75
+ query_string
76
+ ).to_s
77
+ }
78
+ # finally, add query string for this table:
79
+ query_string += atomic_delete_query(table_name,
80
+ primary_keys[table_name],
81
+ value_keys[table_name]
82
+ ).to_s
83
+
84
+ query_string
85
+
86
+ end # def
87
+
88
+ public
89
+
90
+
91
+
92
+ protected
93
+
94
+ def self.perform_delete(accessor,
95
+ value_keys)
96
+
97
+ query_string = delete_query(accessor.get_table_name,
98
+ accessor.get_is_a,
99
+ accessor.get_primary_keys,
100
+ value_keys)
101
+
102
+ Context.enter(accessor.get_context) unless accessor.get_context.nil?
103
+ begin
104
+ Lore::Connection.perform("BEGIN;\n#{query_string}\nCOMMIT;")
105
+ ensure
106
+ Context.leave unless accessor.get_context.nil?
107
+ end
108
+
109
+ accessor.flush_entity_cache()
110
+
111
+ end #def
112
+
113
+ end # module
114
+ end # module
115
+
data/table_inserter.rb ADDED
@@ -0,0 +1,168 @@
1
+
2
+ require('lore/connection')
3
+
4
+ module Lore
5
+
6
+ module Table_Inserter # :nodoc:
7
+
8
+ @logger = Lore.logger
9
+
10
+ protected
11
+
12
+ def self.load_sequence_values(sequences)
13
+
14
+ sequence_values = Hash.new
15
+
16
+ sequences.each_pair { |table_name, field|
17
+ field.each_pair { |field_name, sequence_name|
18
+
19
+ pure_schema_name = table_name.split('.')[0]
20
+ pure_table_name = table_name.split('.')[1]
21
+ temp_sequence_name = sequence_name+'_temp'
22
+
23
+ sequence_query_string = 'SELECT nextval(\''+pure_schema_name+'.'+sequence_name+'\'::text) as '+temp_sequence_name+'; '
24
+ sequence_value_result = Lore::Connection.perform(sequence_query_string)
25
+
26
+ sequence_values[table_name] = Hash.new if sequence_values[table_name] == nil
27
+ sequence_values[table_name][field_name.to_s] = sequence_value_result.get_field_value(0, temp_sequence_name)
28
+ }
29
+ }
30
+
31
+ return sequence_values
32
+
33
+ end
34
+
35
+ def self.atomic_insert_query(table_name, value_keys)
36
+
37
+ query_string = "\n"
38
+ query_string += 'INSERT INTO '+table_name
39
+
40
+ value_string = String.new
41
+ field_string = String.new
42
+ key_counter = 0
43
+ value_keys.each_pair { |field, value|
44
+
45
+ field_string += field
46
+ value_string += '\''+value.to_s+'\''
47
+ if key_counter < value_keys.length-1
48
+ field_string += ', '
49
+ value_string += ', '
50
+ end
51
+ key_counter += 1
52
+ }
53
+ query_string += '('+field_string+') VALUES '
54
+ query_string += '('+value_string+'); '
55
+
56
+ query_string
57
+
58
+ end #def
59
+
60
+ def self.insert_query(table_name,
61
+ is_a_hierarchy,
62
+ sequence_values,
63
+ value_keys,
64
+ query_string='')
65
+
66
+ is_a_hierarchy.each_pair { |table, base_tables|
67
+
68
+ # pass base tables first, recursively, as IS_A-based creation has
69
+ # to be done bottom-up:
70
+ query_string += insert_query(table, base_tables, sequence_values, value_keys).to_s
71
+ }
72
+ # finally, add query string for this table:
73
+ if(value_keys[table_name] != nil)
74
+ query_string += atomic_insert_query(table_name, value_keys[table_name]).to_s
75
+ else
76
+ @logger.debug { "No initial attribute for IS_A related table #{table_name} given. " }
77
+ end
78
+
79
+ query_string
80
+
81
+ end # def
82
+
83
+ def self.update_sequence_values_deps( table_names,
84
+ is_a_hierarchy,
85
+ foreign_keys,
86
+ sequence_values,
87
+ value_keys,
88
+ allowed_attributes)
89
+
90
+ is_a_hierarchy.each_pair { |table, basetables|
91
+ table_names.each { |table_name|
92
+ # extend each value_key with primary keys of its base table:
93
+ if sequence_values.has_key?(table) then
94
+ # We only want a inherited sequence value update if this table (table_name)
95
+ # has a field for it at all:
96
+ sequence_values[table].each_pair { |attrib, seq_val|
97
+ # Set own foreign keys to value of primary key in
98
+ # referenced table.
99
+ # Example: public.car.*vehicle_id* => public.vehicle.id
100
+ # (Note that own and foreign attribute names differ)
101
+ if foreign_keys[table].first && allowed_attributes[table_name].include?(foreign_keys[table].first.to_s) then
102
+ # puts 'setting seq val: ' << table_name.to_s + '.' << foreign_keys[table].first.to_s + ' = ' << seq_val
103
+ value_keys[table_name][foreign_keys[table].first.to_s] = seq_val
104
+ end
105
+ }
106
+ end
107
+ }
108
+ table_names << table
109
+ value_keys = update_sequence_values_deps(table_names, basetables, foreign_keys, sequence_values, value_keys, allowed_attributes)
110
+ }
111
+
112
+ return value_keys
113
+
114
+ end #def
115
+
116
+ def self.perform_insert(accessor, value_keys)
117
+
118
+ table_name = accessor.get_table_name
119
+ is_a_hierarchy = accessor.get_is_a.dup
120
+ foreign_keys = accessor.get_foreign_keys
121
+ sequences = accessor.get_sequences
122
+
123
+ accessor.get_aggregates.each_pair { |table, subtable|
124
+ is_a_hierarchy.delete(table)
125
+ }
126
+
127
+ Context.enter(accessor.get_context) unless accessor.get_context.nil?
128
+ @logger.debug('PERFORM INSERT on '+table_name)
129
+
130
+ sequence_values = load_sequence_values(sequences)
131
+
132
+ # Parse sequence_values into value_keys where entries match the exact table:
133
+ # (thus, there is an explicit call like primary_key :this_field, :this_sequence)
134
+ sequence_values.each_pair { |table, fields|
135
+
136
+ # TODO: Support different attribute names here, like:
137
+ # value_keys[table_name][my_field_name] = Hash.new(sequence_values[table][foreign_field_name]
138
+ # Currently it's
139
+ # value_keys[table_name][foreign_field_name] = Hash.new(sequence_values[table][foreign_field_name]
140
+ value_keys[table].update(sequence_values[table])
141
+ }
142
+ # Parse sequence_values into value_keys where a table depends from a
143
+ # sequence field by IS_A
144
+ value_keys = update_sequence_values_deps([table_name],
145
+ is_a_hierarchy,
146
+ foreign_keys,
147
+ sequence_values,
148
+ value_keys,
149
+ accessor.get_attributes)
150
+ query_string = insert_query(table_name,
151
+ is_a_hierarchy,
152
+ sequence_values,
153
+ value_keys)
154
+
155
+ begin
156
+ Lore::Connection.perform("BEGIN;\n#{query_string}\nCOMMIT;")
157
+ ensure
158
+ Lore::Context.leave unless accessor.get_context.nil?
159
+ end
160
+
161
+ accessor.flush_entity_cache()
162
+
163
+ # value_keys now are extended by sequence values:
164
+ return value_keys
165
+ end # def
166
+
167
+ end # module
168
+ end # module
data/table_instance.rb ADDED
@@ -0,0 +1,384 @@
1
+
2
+ require('lore/exception/ambiguous_attribute')
3
+ require('lore/behaviours/movable')
4
+ require('lore/behaviours/versioned')
5
+ require('lore/behaviours/lockable')
6
+
7
+ module Lore
8
+
9
+ class Attribute_Hash < Hash # :nodoc:
10
+
11
+ alias random_access_op []
12
+ alias random_access_assign_op []=
13
+ def [](key)
14
+ if !random_access_op(key).nil? then
15
+ return random_access_op(key)
16
+ elsif !random_access_op(key.to_s).nil? then
17
+ return random_access_op(key.to_s)
18
+ else
19
+ skey = key.to_s[0..24].intern
20
+ return random_access_op(skey)
21
+ end
22
+ end
23
+
24
+ def []=(key, value)
25
+ begin
26
+ key = key.to_s[0..24].intern
27
+ rescue ::Exception => excep
28
+ Lore.logger.debug { 'Error when trying to access key ' << key.inspect }
29
+ raise excep
30
+ end
31
+ self.random_access_assign_op(key, value)
32
+ end
33
+
34
+ def method_missing(key)
35
+ self[key]
36
+ end
37
+
38
+ end # class
39
+
40
+ # Used as mixin for Table_Accessor.
41
+ # This module holds methods provided by Table_Accessor instances.
42
+ module Table_Instance
43
+
44
+
45
+ # retreive class instance variables from concrete
46
+ # Table_Accessor this object is an instance of:
47
+ def setup_instance() # :nodoc:
48
+
49
+ @touched = false
50
+
51
+ @primary_key_values = Hash.new
52
+ self.class.get_primary_keys.each_pair { |table, attrib_array|
53
+ @primary_key_values[table] = Hash.new
54
+ attrib_array.each { |field|
55
+ begin
56
+ pk_attrib_value = @attribute_values[table][field]
57
+ # NOTE: Field length in Postgres is limited to 25 characters normally.
58
+ pk_attrib_value = @attribute_values[table][field.to_s[0..24]] unless pk_attrib_value
59
+ @primary_key_values[table][field] = pk_attrib_value
60
+ rescue ::Exception => excep
61
+ # We end here if a coder tried to hack a query. We let him
62
+ # continue in his plans, it might make sense after all.
63
+ end
64
+ }
65
+ }
66
+
67
+ # Applying filter to *all* attribute values, including derived attributes.
68
+ # This way, an output filter can be added in a derived type that does not
69
+ # exist in a base type.
70
+ output_filters = self.class.get_output_filters
71
+ if output_filters then
72
+ @attribute_values.each_pair { |table,keys|
73
+ keys.each_pair { |key, value|
74
+ @attribute_values[table][key] = output_filters[key.intern].call(value) if output_filters[key.intern]
75
+ }
76
+ }
77
+ end
78
+
79
+ end # def
80
+
81
+ def table_accessor
82
+ self.class
83
+ end
84
+
85
+ # Create a marshalled dump of this model instance.
86
+ # Returns attribute values as The only difference
87
+ # between model instances is their value set.
88
+ def marshal_dump
89
+ {
90
+ :klass => self.class.to_s,
91
+ :values => get_attribute_values
92
+ }
93
+ end
94
+
95
+ # Returns primary key values of own table
96
+ def key
97
+ @primary_key_values[table_accessor.get_table_name]
98
+ end
99
+
100
+ def get_label_string
101
+ value = ''
102
+ Lore.logger.debug { 'LABEL ATTRIBS: ' << @attribute_values.inspect }
103
+ table_accessor.get_labels.each { |label_attrib|
104
+ Lore.logger.debug { 'LABEL_STRING: ' << label_attrib }
105
+ label_parts = label_attrib.split('.')
106
+ value << @attribute_values[label_parts[0..1].join('.')][label_parts[2]].to_s + ' '
107
+ }
108
+ value = '[no label given]' if value == ''
109
+ return value
110
+ end
111
+
112
+ # Creates an instance of self from marshalled value set.
113
+ def marshal_load(dump)
114
+ klass = eval(dump[:klass])
115
+ return initialize(dump[:values], :cached)
116
+ end
117
+
118
+ # Whether this instance has been loaded from
119
+ # cache or live from DB.
120
+ def is_cached_entity?
121
+ # Set in initialize via marshal_load
122
+ @loaded_from_cache
123
+ end
124
+
125
+ def touched?
126
+ @touched
127
+ end
128
+
129
+ def method_missing(meth)
130
+ begin
131
+ return attr[meth]
132
+ rescue ::Exception => excep
133
+ raise excep
134
+ end
135
+ end
136
+
137
+ def move(sortpos, criteria)
138
+ Lore::Movable.move(self, table_accessor.get_order_attr, sortpos, criteria)
139
+ end # def
140
+
141
+ # Set value for given attribute, e.g. for later commit.
142
+ # It is recommended to use random access assignment instead:
143
+ #
144
+ # instance.set_attribute_value(:name, 'Wombat')
145
+ # is same as
146
+ # instance[:name] = 'Wombat'
147
+ #
148
+ def set_attribute_value(attrib_name, attrib_value)
149
+ # {{{
150
+
151
+ if @input_filters && (@input_filters.has_key?(attrib_name.intern)) then
152
+ attrib_value = @input_filters[attrib_name.intern].call(attrib_value)
153
+ end
154
+
155
+ @touched = true
156
+ # Delete cached value of @flat_attr:
157
+ @flat_attr = nil
158
+ save_attribute_values = @attribute_values.dup
159
+ attrib_name = attrib_name.to_s
160
+ attrib_name_array = attrib_name.split('.')
161
+
162
+ # Attrib name is implicit (no table name given).
163
+ # Check for ambiguous attribute name:
164
+ if attrib_name_array[2].nil? then
165
+ changed_table = false
166
+ @attribute_values.each { |table, attributes|
167
+
168
+ if attributes.has_key?(attrib_name) then
169
+ @attribute_values[table][attrib_name] = attrib_value
170
+ changed_table = true
171
+ elsif attributes.has_key?(attrib_name) && changed_table then
172
+ raise Lore::Exception::Ambiguous_Attribute.new(table,
173
+ changed_table,
174
+ attrib_name)
175
+ end
176
+ }
177
+
178
+ # Attrib name is explicit (also includes table name).
179
+ # No need to check for ambiguous attribute:
180
+ else
181
+ attrib_name_index = attrib_name_array[2]
182
+ attrib_table = attrib_name_array[0]+'.'+attrib_name_array[1]
183
+
184
+ @attribute_values[attrib_table][attrib_name_index] = attrib_value
185
+ end
186
+
187
+ begin
188
+
189
+ # Lore::Validation::Parameter_Validator.invalid_params(
190
+ # self.class,
191
+ # @attribute_values)
192
+
193
+ rescue Lore::Exception::Invalid_Klass_Parameters => ikp
194
+
195
+ # load saved (stable, validated) attribute_values:
196
+ @attribute_values = save_attribute_values
197
+ # log'n'throw:
198
+ ikp.log
199
+ raise ikp
200
+
201
+ rescue Lore::Exception::Ambiguous_Attribute => aa
202
+
203
+ # load saved (stable, validated) attribute_values:
204
+ @attribute_values = save_attribute_values
205
+ # log'n'throw:
206
+ raise aa
207
+
208
+ end
209
+
210
+ end # def }}}
211
+
212
+ # Sets attribute value. Example:
213
+ # instance[:name] = 'Wombat'
214
+ # instance.commit
215
+ def []=(key, value)
216
+ set_attribute_value(key, value)
217
+ end
218
+
219
+ # Explicit attribute request.
220
+ # Example:
221
+ # Car[Vehicle.name]
222
+ # In case name is attribute field in Car and Vehicle.
223
+ def [](clause)
224
+ abs_attr(clause)
225
+ end
226
+
227
+ # Returns true if instance points to same records as other instance.
228
+ # Only compares primary key values.
229
+ def ==(other)
230
+ result = true
231
+ return false if self.class.to_s != other.class.to_s
232
+ return id() == other.id()
233
+ end
234
+
235
+ # Return primary key value. In case primary key is composed, return it as array.
236
+ def id
237
+ key = []
238
+ table = table_accessor.table_name
239
+ table_accessor.get_primary_keys[table].each { |attrib_array|
240
+ attrib_array.each { |field|
241
+ key << get_attribute_values[table][field]
242
+ }
243
+ }
244
+ return key.first if key.length < 2
245
+ return key
246
+ end
247
+
248
+ # Returns true if instance points to same records as other instance,
249
+ # also compares non-key attribute values.
250
+ def ===(other)
251
+ return false unless (self == other)
252
+
253
+ end
254
+ # See ==
255
+ def <=>(other)
256
+ return !(self.==(other))
257
+ end
258
+
259
+ # Returns all attribute values as hash.
260
+ def get_attribute_values() # :nodoc:
261
+ @attribute_values
262
+ end # def
263
+
264
+ # Returns value hash of instance attributes like:
265
+ #
266
+ # {
267
+ # 'schema.table.id' => 123,
268
+ # 'schema.atable.name' => 'example'
269
+ # }
270
+ #
271
+ # Common usage:
272
+ #
273
+ # table_instance.attr[:id] -> 123
274
+ #
275
+ # But it is recommended to use
276
+ #
277
+ # table_instance.id -> 123
278
+ #
279
+ def attr
280
+
281
+ if @flat_attr.nil? then
282
+ @flat_attr = Attribute_Hash.new
283
+ get_attribute_values.each_pair { |table, attribs|
284
+ attribs.each_pair { |attrib_name, value|
285
+ @flat_attr[attrib_name] = value unless value.nil?
286
+ }
287
+ }
288
+ end
289
+ @flat_attr
290
+
291
+ end # def
292
+
293
+ # Returns value hash of instance attributes
294
+ # of a given subtype like:
295
+ #
296
+ # {
297
+ # 'id' => 123,
298
+ # 'name' => 'example'
299
+ # }
300
+ #
301
+ # Common usage:
302
+ #
303
+ # table_accessor.abs_attr(Klass_A)[:id] -> 123
304
+ #
305
+ def abs_attr(klass=nil)
306
+ klass = klass.to_s if klass.instance_of? Symbol
307
+ return get_attribute_values if klass.nil?
308
+ return get_attribute_values[klass.table_name] if klass.kind_of? Lore::Table_Accessor
309
+ return get_attribute_values[klass] if klass.instance_of? String
310
+ return get_attribute_values[klass.to_s.split('.')[0..1].join('.').to_s][klass.to_s.split('.').at(-1)] if klass.instance_of? Lore::Clause
311
+
312
+ end # def
313
+
314
+ def get_primary_key_values
315
+ @primary_key_values
316
+ end
317
+
318
+
319
+ # Commit changes on Table_Accessor instance to DB.
320
+ # Results in an / several SQL update calls.
321
+ #
322
+ # Common usage:
323
+ #
324
+ # unit['name'] = 'changed'
325
+ # unit.commit()
326
+ #
327
+ def commit
328
+ # {{{
329
+
330
+ return unless @touched
331
+
332
+ input_filters = self.class.get_input_filters
333
+ if input_filters then
334
+ @attribute_values.each_pair { |table,keys|
335
+ keys.each_pair { |key, value|
336
+ @attribute_values[table][key] = input_filters[key.intern].call(value) if input_filters[key.intern]
337
+ }
338
+ }
339
+ end
340
+
341
+ begin
342
+ Lore::Validation::Parameter_Validator.invalid_params(self.class,
343
+ @attribute_values)
344
+ rescue Lore::Exception::Invalid_Klass_Parameters => ikp
345
+ # log'n'throw:
346
+ ikp.log
347
+ raise ikp
348
+ end
349
+
350
+ table_accessor.before_commit(self)
351
+
352
+ Table_Updater.perform_update(table_accessor,
353
+ self)
354
+
355
+ table_accessor.after_commit(self)
356
+
357
+ @touched = false
358
+
359
+ end # def }}}
360
+ alias save commit
361
+
362
+ # Delete this instance from DB.
363
+ # Common usage:
364
+ #
365
+ # unit = Some_Table_Accessor.select { ... }.first
366
+ # unit.delete
367
+ #
368
+ #
369
+ def delete
370
+
371
+ # Called before entity_instance.delete
372
+ table_accessor.before_instance_delete(self)
373
+
374
+ Table_Deleter.perform_delete(table_accessor,
375
+ @attribute_values)
376
+ # Called after entity_instance.delete
377
+ table_accessor.after_instance_delete(self)
378
+
379
+ end # def
380
+
381
+ end # module
382
+
383
+
384
+ end # module