lore 0.4.8 → 0.9.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 (111) hide show
  1. data/Manifest.txt +16 -7
  2. data/README.rdoc +91 -0
  3. data/benchmark/benchmark.sql +11 -0
  4. data/benchmark/results.txt +28 -0
  5. data/benchmark/select.rb +352 -0
  6. data/lib/lore.rb +22 -8
  7. data/lib/lore/adapters/context.rb +64 -0
  8. data/lib/lore/adapters/postgres-pr.rb +6 -0
  9. data/lib/lore/adapters/postgres-pr/connection.rb +93 -0
  10. data/lib/lore/adapters/postgres-pr/result.rb +63 -0
  11. data/lib/lore/{types.rb → adapters/postgres-pr/types.rb} +36 -0
  12. data/lib/lore/adapters/postgres.rb +24 -0
  13. data/lib/lore/adapters/postgres/connection.rb +81 -0
  14. data/lib/lore/adapters/postgres/result.rb +82 -0
  15. data/lib/lore/adapters/postgres/types.rb +91 -0
  16. data/lib/lore/bits.rb +18 -0
  17. data/lib/lore/cache/abstract_entity_cache.rb +2 -1
  18. data/lib/lore/cache/cacheable.rb +12 -177
  19. data/lib/lore/cache/memcache_entity_cache.rb +89 -0
  20. data/lib/lore/cache/memory_entity_cache.rb +77 -0
  21. data/lib/lore/cache/mmap_entity_cache.rb +2 -2
  22. data/lib/lore/cache/mmap_entity_cache_bork.rb +86 -0
  23. data/lib/lore/clause.rb +107 -35
  24. data/lib/lore/{exception → exceptions}/ambiguous_attribute.rb +2 -2
  25. data/lib/lore/{exception → exceptions}/cache_exception.rb +1 -1
  26. data/lib/lore/exceptions/database_exception.rb +16 -0
  27. data/lib/lore/{exception/invalid_parameter.rb → exceptions/invalid_field.rb} +7 -4
  28. data/lib/lore/exceptions/unknown_type.rb +18 -0
  29. data/lib/lore/exceptions/validation_failure.rb +71 -0
  30. data/lib/lore/gui/form_generator.rb +109 -60
  31. data/lib/lore/gui/lore_model_select_field.rb +1 -0
  32. data/lib/lore/migration.rb +84 -25
  33. data/lib/lore/model.rb +3 -18
  34. data/lib/lore/{aspect.rb → model/aspect.rb} +0 -0
  35. data/lib/lore/model/associations.rb +225 -0
  36. data/lib/lore/model/attribute_settings.rb +233 -0
  37. data/lib/lore/model/filters.rb +34 -0
  38. data/lib/lore/model/mockable.rb +62 -0
  39. data/lib/lore/{model_factory.rb → model/model_factory.rb} +68 -39
  40. data/lib/lore/model/model_instance.rb +382 -0
  41. data/lib/lore/{model_shortcuts.rb → model/model_shortcuts.rb} +7 -0
  42. data/lib/lore/model/polymorphic.rb +53 -0
  43. data/lib/lore/model/prepare.rb +97 -0
  44. data/lib/lore/model/table_accessor.rb +1016 -0
  45. data/lib/lore/query.rb +71 -0
  46. data/lib/lore/query_shortcuts.rb +43 -11
  47. data/lib/lore/strategies/table_delete.rb +115 -0
  48. data/lib/lore/strategies/table_insert.rb +146 -0
  49. data/lib/lore/strategies/table_select.rb +299 -0
  50. data/lib/lore/strategies/table_update.rb +155 -0
  51. data/lib/lore/validation/parameter_validator.rb +85 -26
  52. data/lib/lore/validation/type_validator.rb +34 -78
  53. data/{custom_models.rb → lore-0.9.2.gem} +0 -0
  54. data/lore.gemspec +26 -17
  55. data/spec/clause.rb +37 -0
  56. data/spec/fixtures/blank_models.rb +37 -0
  57. data/{test/model.rb → spec/fixtures/models.rb} +64 -41
  58. data/spec/fixtures/polymorphic_models.rb +68 -0
  59. data/spec/model_associations.rb +86 -0
  60. data/spec/model_create.rb +47 -0
  61. data/spec/model_definition.rb +151 -0
  62. data/spec/model_delete.rb +31 -0
  63. data/spec/model_inheritance.rb +50 -0
  64. data/spec/model_polymorphic.rb +85 -0
  65. data/spec/model_select.rb +101 -0
  66. data/spec/model_select_eager.rb +42 -0
  67. data/spec/model_union_select.rb +33 -0
  68. data/spec/model_update.rb +45 -0
  69. data/spec/model_validation.rb +20 -0
  70. data/spec/spec_db.sql +808 -0
  71. data/spec/spec_env.rb +19 -0
  72. data/spec/spec_helpers.rb +77 -0
  73. metadata +93 -82
  74. data/lib/lore/README.txt +0 -84
  75. data/lib/lore/behaviours/lockable.rb +0 -55
  76. data/lib/lore/behaviours/movable.rb +0 -72
  77. data/lib/lore/behaviours/paginated.rb +0 -31
  78. data/lib/lore/behaviours/versioned.rb +0 -36
  79. data/lib/lore/connection.rb +0 -152
  80. data/lib/lore/exception/invalid_klass_parameters.rb +0 -63
  81. data/lib/lore/exception/unknown_typecode.rb +0 -19
  82. data/lib/lore/result.rb +0 -119
  83. data/lib/lore/symbol.rb +0 -58
  84. data/lib/lore/table_accessor.rb +0 -1790
  85. data/lib/lore/table_deleter.rb +0 -116
  86. data/lib/lore/table_inserter.rb +0 -170
  87. data/lib/lore/table_instance.rb +0 -389
  88. data/lib/lore/table_selector.rb +0 -285
  89. data/lib/lore/table_updater.rb +0 -157
  90. data/lib/lore/validation.rb +0 -65
  91. data/lib/lore/validation/message.rb +0 -60
  92. data/lib/lore/validation/reason.rb +0 -52
  93. data/lore_test.log +0 -2366
  94. data/test/README +0 -31
  95. data/test/custom_models.rb +0 -18
  96. data/test/env.rb +0 -5
  97. data/test/prepare.rb +0 -37
  98. data/test/tc_aspect.rb +0 -58
  99. data/test/tc_cache.rb +0 -83
  100. data/test/tc_clause.rb +0 -104
  101. data/test/tc_deep_inheritance.rb +0 -49
  102. data/test/tc_factory.rb +0 -57
  103. data/test/tc_filter.rb +0 -37
  104. data/test/tc_form.rb +0 -32
  105. data/test/tc_model.rb +0 -140
  106. data/test/tc_prepare.rb +0 -44
  107. data/test/tc_refined_query.rb +0 -88
  108. data/test/tc_table_accessor.rb +0 -267
  109. data/test/tc_thread.rb +0 -100
  110. data/test/test_db.sql +0 -400
  111. data/test/test_lore.rb +0 -50
@@ -1,116 +0,0 @@
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
- query_string += atomic_delete_query(table_name,
66
- primary_keys[table_name],
67
- value_keys[table_name]
68
- ).to_s
69
- is_a_hierarchy.each_pair { |table, base_tables|
70
-
71
- # pass base tables afterwards, recursively, as IS_A-based deletion has
72
- # to be done top-down (derived tabled first):
73
- query_string = delete_query(table,
74
- base_tables,
75
-
76
- primary_keys,
77
- value_keys,
78
-
79
- query_string
80
- ).to_s
81
- }
82
-
83
- query_string
84
-
85
- end # def
86
-
87
- public
88
-
89
-
90
-
91
- protected
92
-
93
- def self.perform_delete(accessor,
94
- value_keys)
95
-
96
- query_string = delete_query(accessor.get_table_name,
97
- accessor.get_is_a,
98
- accessor.get_primary_keys,
99
- value_keys)
100
-
101
- Context.enter(accessor.get_context) unless accessor.get_context.nil?
102
- begin
103
- Lore::Connection.perform("BEGIN;\n#{query_string}\nCOMMIT;")
104
- rescue ::Exception => excep
105
- Lore::Connection.perform("ROLLBACK;")
106
- ensure
107
- Context.leave unless accessor.get_context.nil?
108
- end
109
-
110
- accessor.flush_entity_cache()
111
-
112
- end #def
113
-
114
- end # module
115
- end # module
116
-
@@ -1,170 +0,0 @@
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
- rescue ::Exception => excep
158
- Lore::Connection.perform("ROLLBACK;")
159
- ensure
160
- Lore::Context.leave unless accessor.get_context.nil?
161
- end
162
-
163
- accessor.flush_entity_cache()
164
-
165
- # value_keys now are extended by sequence values:
166
- return value_keys
167
- end # def
168
-
169
- end # module
170
- end # module
@@ -1,389 +0,0 @@
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
- # retreive class instance variables from concrete
45
- # Table_Accessor this object is an instance of:
46
- def setup_instance() # :nodoc:
47
-
48
- @touched = false
49
-
50
- @primary_key_values = Hash.new
51
- self.class.get_primary_keys.each_pair { |table, attrib_array|
52
- @primary_key_values[table] = Hash.new
53
- attrib_array.each { |field|
54
- begin
55
- pk_attrib_value = @attribute_values[table][field]
56
- # NOTE: Field length in Postgres is limited to 25 characters normally.
57
- pk_attrib_value = @attribute_values[table][field.to_s[0..24]] unless pk_attrib_value
58
- @primary_key_values[table][field] = pk_attrib_value
59
- rescue ::Exception => excep
60
- # We end here if a coder tried to hack a query. We let him
61
- # continue in his plans, it might make sense after all.
62
- end
63
- }
64
- }
65
-
66
- # Applying filter to *all* attribute values, including derived attributes.
67
- # This way, an output filter can be added in a derived type that does not
68
- # exist in a base type.
69
- output_filters = self.class.get_output_filters
70
- if output_filters then
71
- @attribute_values.each_pair { |table,keys|
72
- keys.each_pair { |key, value|
73
- @attribute_values[table][key] = output_filters[key.intern].call(value) if output_filters[key.intern]
74
- }
75
- }
76
- end
77
-
78
- end # def
79
-
80
- def table_accessor
81
- self.class
82
- end
83
-
84
- # Create a marshalled dump of this model instance.
85
- # Returns attribute values as The only difference
86
- # between model instances is their value set.
87
- def marshal_dump
88
- {
89
- :klass => self.class.to_s,
90
- :values => get_attribute_values,
91
- :joined => @joined_models
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
- dump[:joined].map { |m| m = eval(m) }
116
- return initialize(dump[:values], dump[:joined], :cached)
117
- end
118
-
119
- # Whether this instance has been loaded from
120
- # cache or live from DB.
121
- def is_cached_entity?
122
- # Set in initialize via marshal_load
123
- @loaded_from_cache
124
- end
125
-
126
- def touched?
127
- @touched
128
- end
129
-
130
- def method_missing(meth)
131
- begin
132
- return attr[meth]
133
- rescue ::Exception => excep
134
- raise excep
135
- end
136
- end
137
-
138
- def move(sortpos, criteria)
139
- Lore::Movable.move(self, table_accessor.get_order_attr, sortpos, criteria)
140
- end # def
141
-
142
- # Set value for given attribute, e.g. for later commit.
143
- # It is recommended to use random access assignment instead:
144
- #
145
- # instance.set_attribute_value(:name, 'Wombat')
146
- # is same as
147
- # instance[:name] = 'Wombat'
148
- #
149
- def set_attribute_value(attrib_name, attrib_value)
150
- # {{{
151
-
152
- if @input_filters && (@input_filters.has_key?(attrib_name.intern)) then
153
- attrib_value = @input_filters[attrib_name.intern].call(attrib_value)
154
- end
155
-
156
- @touched = true
157
- # Delete cached value of @flat_attr:
158
- @flat_attr = nil
159
- save_attribute_values = @attribute_values.dup
160
- attrib_name = attrib_name.to_s
161
- attrib_name_array = attrib_name.split('.')
162
-
163
- # Attrib name is implicit (no table name given).
164
- # Check for ambiguous attribute name:
165
- if attrib_name_array[2].nil? then
166
- changed_table = false
167
- @attribute_values.each { |table, attributes|
168
-
169
- if attributes.has_key?(attrib_name) then
170
- @attribute_values[table][attrib_name] = attrib_value
171
- changed_table = true
172
- elsif attributes.has_key?(attrib_name) && changed_table then
173
- raise Lore::Exception::Ambiguous_Attribute.new(table,
174
- changed_table,
175
- attrib_name)
176
- end
177
- }
178
-
179
- # Attrib name is explicit (also includes table name).
180
- # No need to check for ambiguous attribute:
181
- else
182
- attrib_name_index = attrib_name_array[2]
183
- attrib_table = attrib_name_array[0]+'.'+attrib_name_array[1]
184
-
185
- @attribute_values[attrib_table][attrib_name_index] = attrib_value
186
- end
187
-
188
- begin
189
-
190
- # Lore::Validation::Parameter_Validator.invalid_params(
191
- # self.class,
192
- # @attribute_values)
193
-
194
- rescue Lore::Exception::Invalid_Klass_Parameters => ikp
195
-
196
- # load saved (stable, validated) attribute_values:
197
- @attribute_values = save_attribute_values
198
- # log'n'throw:
199
- ikp.log
200
- raise ikp
201
-
202
- rescue Lore::Exception::Ambiguous_Attribute => aa
203
-
204
- # load saved (stable, validated) attribute_values:
205
- @attribute_values = save_attribute_values
206
- # log'n'throw:
207
- raise aa
208
-
209
- end
210
-
211
- end # def }}}
212
-
213
- # Sets attribute value. Example:
214
- # instance[:name] = 'Wombat'
215
- # instance.commit
216
- def []=(key, value)
217
- set_attribute_value(key, value)
218
- end
219
-
220
- # Explicit attribute request.
221
- # Example:
222
- # Car[Vehicle.name]
223
- # In case name is attribute field in Car and Vehicle.
224
- def [](clause)
225
- abs_attr(clause)
226
- end
227
-
228
- # Returns true if instance points to same records as other instance.
229
- # Only compares primary key values.
230
- def ==(other)
231
- result = true
232
- return false if self.class.to_s != other.class.to_s
233
- return id() == other.id()
234
- end
235
-
236
- # Return primary key value. In case primary key is composed, return it as array.
237
- def id
238
- key = []
239
- table = table_accessor.table_name
240
- table_accessor.get_primary_keys[table].each { |attrib_array|
241
- attrib_array.each { |field|
242
- key << get_attribute_values[table][field]
243
- }
244
- }
245
- return key.first if key.length < 2
246
- return key
247
- end
248
-
249
- # Returns true if instance points to same records as other instance,
250
- # also compares non-key attribute values.
251
- def ===(other)
252
- return false unless (self == other)
253
-
254
- end
255
- # See ==
256
- def <=>(other)
257
- return !(self.==(other))
258
- end
259
-
260
- # Returns all attribute values as hash.
261
- def get_attribute_values() # :nodoc:
262
- @attribute_values
263
- end # def
264
-
265
- # Returns value hash of instance attributes like:
266
- #
267
- # {
268
- # 'schema.table.id' => 123,
269
- # 'schema.atable.name' => 'example'
270
- # }
271
- #
272
- # Common usage:
273
- #
274
- # table_instance.attr[:id] -> 123
275
- #
276
- # But it is recommended to use
277
- #
278
- # table_instance.id -> 123
279
- #
280
- def attr
281
-
282
- if @flat_attr.nil? then
283
- @flat_attr = Attribute_Hash.new
284
- get_attribute_values.each_pair { |table, attribs|
285
- attribs.each_pair { |attrib_name, value|
286
- @flat_attr[attrib_name] = value unless value.nil?
287
- }
288
- }
289
- end
290
- @flat_attr
291
-
292
- end # def
293
-
294
- # Returns value hash of instance attributes
295
- # of a given subtype like:
296
- #
297
- # {
298
- # 'id' => 123,
299
- # 'name' => 'example'
300
- # }
301
- #
302
- # Common usage:
303
- #
304
- # table_accessor.abs_attr(Klass_A)[:id] -> 123
305
- #
306
- def abs_attr(klass=nil)
307
- klass = klass.to_s if klass.instance_of? Symbol
308
- return get_attribute_values if klass.nil?
309
- return get_attribute_values[klass.table_name] if klass.kind_of? Lore::Table_Accessor
310
- return get_attribute_values[klass] if klass.instance_of? String
311
- 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
312
-
313
- end # def
314
-
315
- def get_primary_key_values
316
- @primary_key_values
317
- end
318
-
319
-
320
- # Commit changes on Table_Accessor instance to DB.
321
- # Results in an / several SQL update calls.
322
- #
323
- # Common usage:
324
- #
325
- # unit['name'] = 'changed'
326
- # unit.commit()
327
- #
328
- def commit
329
- # {{{
330
-
331
- return unless @touched
332
-
333
- input_filters = self.class.get_input_filters
334
- if input_filters then
335
- @attribute_values.each_pair { |table,keys|
336
- keys.each_pair { |key, value|
337
- @attribute_values[table][key] = input_filters[key.intern].call(value) if input_filters[key.intern]
338
- }
339
- }
340
- end
341
-
342
- begin
343
- Lore::Validation::Parameter_Validator.invalid_params(self.class,
344
- @attribute_values)
345
- rescue Lore::Exception::Invalid_Klass_Parameters => ikp
346
- # log'n'throw:
347
- ikp.log
348
- raise ikp
349
- end
350
-
351
- table_accessor.before_commit(self)
352
-
353
- Table_Updater.perform_update(table_accessor,
354
- self)
355
-
356
- table_accessor.after_commit(self)
357
-
358
- @touched = false
359
-
360
- end # def }}}
361
- alias save commit
362
-
363
- # Delete this instance from DB.
364
- # Common usage:
365
- #
366
- # unit = Some_Table_Accessor.select { ... }.first
367
- # unit.delete
368
- #
369
- #
370
- def delete
371
-
372
- # Called before entity_instance.delete
373
- table_accessor.before_instance_delete(self)
374
-
375
- Table_Deleter.perform_delete(table_accessor,
376
- @attribute_values)
377
- # Called after entity_instance.delete
378
- table_accessor.after_instance_delete(self)
379
-
380
- end # def
381
-
382
- def inspect
383
- get_attribute_values.inspect
384
- end # def
385
-
386
- end # module
387
-
388
-
389
- end # module