lore 0.4.8 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
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