lore 0.4.8 → 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +16 -7
- data/README.rdoc +91 -0
- data/benchmark/benchmark.sql +11 -0
- data/benchmark/results.txt +28 -0
- data/benchmark/select.rb +352 -0
- data/lib/lore.rb +22 -8
- data/lib/lore/adapters/context.rb +64 -0
- data/lib/lore/adapters/postgres-pr.rb +6 -0
- data/lib/lore/adapters/postgres-pr/connection.rb +93 -0
- data/lib/lore/adapters/postgres-pr/result.rb +63 -0
- data/lib/lore/{types.rb → adapters/postgres-pr/types.rb} +36 -0
- data/lib/lore/adapters/postgres.rb +24 -0
- data/lib/lore/adapters/postgres/connection.rb +81 -0
- data/lib/lore/adapters/postgres/result.rb +82 -0
- data/lib/lore/adapters/postgres/types.rb +91 -0
- data/lib/lore/bits.rb +18 -0
- data/lib/lore/cache/abstract_entity_cache.rb +2 -1
- data/lib/lore/cache/cacheable.rb +12 -177
- data/lib/lore/cache/memcache_entity_cache.rb +89 -0
- data/lib/lore/cache/memory_entity_cache.rb +77 -0
- data/lib/lore/cache/mmap_entity_cache.rb +2 -2
- data/lib/lore/cache/mmap_entity_cache_bork.rb +86 -0
- data/lib/lore/clause.rb +107 -35
- data/lib/lore/{exception → exceptions}/ambiguous_attribute.rb +2 -2
- data/lib/lore/{exception → exceptions}/cache_exception.rb +1 -1
- data/lib/lore/exceptions/database_exception.rb +16 -0
- data/lib/lore/{exception/invalid_parameter.rb → exceptions/invalid_field.rb} +7 -4
- data/lib/lore/exceptions/unknown_type.rb +18 -0
- data/lib/lore/exceptions/validation_failure.rb +71 -0
- data/lib/lore/gui/form_generator.rb +109 -60
- data/lib/lore/gui/lore_model_select_field.rb +1 -0
- data/lib/lore/migration.rb +84 -25
- data/lib/lore/model.rb +3 -18
- data/lib/lore/{aspect.rb → model/aspect.rb} +0 -0
- data/lib/lore/model/associations.rb +225 -0
- data/lib/lore/model/attribute_settings.rb +233 -0
- data/lib/lore/model/filters.rb +34 -0
- data/lib/lore/model/mockable.rb +62 -0
- data/lib/lore/{model_factory.rb → model/model_factory.rb} +68 -39
- data/lib/lore/model/model_instance.rb +382 -0
- data/lib/lore/{model_shortcuts.rb → model/model_shortcuts.rb} +7 -0
- data/lib/lore/model/polymorphic.rb +53 -0
- data/lib/lore/model/prepare.rb +97 -0
- data/lib/lore/model/table_accessor.rb +1016 -0
- data/lib/lore/query.rb +71 -0
- data/lib/lore/query_shortcuts.rb +43 -11
- data/lib/lore/strategies/table_delete.rb +115 -0
- data/lib/lore/strategies/table_insert.rb +146 -0
- data/lib/lore/strategies/table_select.rb +299 -0
- data/lib/lore/strategies/table_update.rb +155 -0
- data/lib/lore/validation/parameter_validator.rb +85 -26
- data/lib/lore/validation/type_validator.rb +34 -78
- data/{custom_models.rb → lore-0.9.2.gem} +0 -0
- data/lore.gemspec +26 -17
- data/spec/clause.rb +37 -0
- data/spec/fixtures/blank_models.rb +37 -0
- data/{test/model.rb → spec/fixtures/models.rb} +64 -41
- data/spec/fixtures/polymorphic_models.rb +68 -0
- data/spec/model_associations.rb +86 -0
- data/spec/model_create.rb +47 -0
- data/spec/model_definition.rb +151 -0
- data/spec/model_delete.rb +31 -0
- data/spec/model_inheritance.rb +50 -0
- data/spec/model_polymorphic.rb +85 -0
- data/spec/model_select.rb +101 -0
- data/spec/model_select_eager.rb +42 -0
- data/spec/model_union_select.rb +33 -0
- data/spec/model_update.rb +45 -0
- data/spec/model_validation.rb +20 -0
- data/spec/spec_db.sql +808 -0
- data/spec/spec_env.rb +19 -0
- data/spec/spec_helpers.rb +77 -0
- metadata +93 -82
- data/lib/lore/README.txt +0 -84
- data/lib/lore/behaviours/lockable.rb +0 -55
- data/lib/lore/behaviours/movable.rb +0 -72
- data/lib/lore/behaviours/paginated.rb +0 -31
- data/lib/lore/behaviours/versioned.rb +0 -36
- data/lib/lore/connection.rb +0 -152
- data/lib/lore/exception/invalid_klass_parameters.rb +0 -63
- data/lib/lore/exception/unknown_typecode.rb +0 -19
- data/lib/lore/result.rb +0 -119
- data/lib/lore/symbol.rb +0 -58
- data/lib/lore/table_accessor.rb +0 -1790
- data/lib/lore/table_deleter.rb +0 -116
- data/lib/lore/table_inserter.rb +0 -170
- data/lib/lore/table_instance.rb +0 -389
- data/lib/lore/table_selector.rb +0 -285
- data/lib/lore/table_updater.rb +0 -157
- data/lib/lore/validation.rb +0 -65
- data/lib/lore/validation/message.rb +0 -60
- data/lib/lore/validation/reason.rb +0 -52
- data/lore_test.log +0 -2366
- data/test/README +0 -31
- data/test/custom_models.rb +0 -18
- data/test/env.rb +0 -5
- data/test/prepare.rb +0 -37
- data/test/tc_aspect.rb +0 -58
- data/test/tc_cache.rb +0 -83
- data/test/tc_clause.rb +0 -104
- data/test/tc_deep_inheritance.rb +0 -49
- data/test/tc_factory.rb +0 -57
- data/test/tc_filter.rb +0 -37
- data/test/tc_form.rb +0 -32
- data/test/tc_model.rb +0 -140
- data/test/tc_prepare.rb +0 -44
- data/test/tc_refined_query.rb +0 -88
- data/test/tc_table_accessor.rb +0 -267
- data/test/tc_thread.rb +0 -100
- data/test/test_db.sql +0 -400
- data/test/test_lore.rb +0 -50
data/lib/lore/table_deleter.rb
DELETED
@@ -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
|
-
|
data/lib/lore/table_inserter.rb
DELETED
@@ -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
|
data/lib/lore/table_instance.rb
DELETED
@@ -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
|