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,285 +0,0 @@
1
-
2
- require('lore/cache/cached_entities')
3
- require('lore/connection')
4
- require('lore/clause')
5
-
6
- module Lore
7
-
8
- module Table_Selector # :nodoc:
9
-
10
- @@logger = Lore.logger
11
-
12
- public
13
-
14
- # Extracted, recursive method for building the JOIN-part of
15
- # a SELECT query.
16
- def self.build_joined_query(accessor, query_string='', joined_tables=[])
17
-
18
- top_table = accessor.table_name
19
- is_a_hierarchy = accessor.get_joins()
20
- own_primary_keys = accessor.get_primary_keys()
21
- own_foreign_keys = accessor.get_foreign_keys()
22
-
23
- joined_accessors = (accessor.get_is_a_klasses).dup
24
- joined_accessors.update(accessor.get_aggregate_klasses)
25
-
26
- # predefine
27
- own_p_keys = Hash.new
28
- foreign_p_keys = Hash.new
29
- on_string = String.new
30
- field_counter = 0
31
-
32
- is_a_hierarchy.each_pair { |foreign_table, foreign_base_tables|
33
- # JOIN base.table ON (
34
- if !(joined_tables.include?(foreign_table)) then
35
-
36
- foreign_p_keys = own_primary_keys[foreign_table]
37
-
38
- own_p_keys = own_foreign_keys[foreign_table]
39
-
40
- if !own_p_keys.nil? then
41
-
42
- joined_tables << foreign_table
43
- query_string << "\n JOIN #{foreign_table} on ("
44
-
45
- field_counter = 0
46
- on_string = ''
47
- foreign_p_keys.uniq.each { |foreign_field|
48
-
49
- # base.table.foreign_field =
50
- on_string << "#{foreign_table}.#{foreign_field} = #{top_table}.#{own_p_keys[field_counter]}"
51
- # this.table.own_field
52
-
53
- if field_counter > 0 then query_string << ", #{on_string}"
54
- else query_string << on_string
55
- end
56
-
57
- field_counter += 1
58
- }
59
-
60
- query_string << ')'
61
-
62
- end
63
-
64
- # sub-joins of joined table:
65
- query_string = build_joined_query(joined_accessors["#{top_table}.#{own_p_keys.first}"],
66
- query_string,
67
- joined_tables)
68
- end
69
- }
70
- return query_string
71
- end # def
72
-
73
- protected
74
-
75
- def self.build_select_query(accessor,
76
- value_keys)
77
- # this is to be wrapped in an adapter to provide DB abstraction:
78
-
79
- table_name = accessor.get_table_name
80
- query_string = 'SELECT * '
81
- query_string << ' FROM ' << table_name + ' '
82
- query_string << build_joined_query(accessor)
83
- query_string << "\n WHERE "
84
-
85
- operator = '='
86
- field = String.new
87
- value_keys[0].each_pair { |field, value|
88
- # Filtering values is not necessary when feeded with
89
- # Lore::Attributes instance
90
- field = field.to_s
91
- if value.instance_of? Hash then
92
- value.each_pair { |attrib_name, attrib_value|
93
- query_string << "#{field}.#{attrib_name} #{operator} '#{attrib_value.to_s.lore_escape}' AND "
94
- }
95
- else
96
- query_string << "#{table_name}." if field.split('.')[2].nil?
97
- query_string << "#{field} #{operator} '#{value.to_s.lore_escape}' AND "
98
- end
99
- }
100
- # remove trailing AND:
101
- query_string.chomp!(' AND ')
102
-
103
- return query_string
104
-
105
- end # def
106
-
107
-
108
- protected
109
-
110
- def self.select_query(what,
111
- accessor,
112
- clause = nil,
113
- &block)
114
-
115
- query_string = 'SELECT '
116
-
117
- # Example:
118
- # select(Car.name) -> SELECT public.car.name AS "value"
119
- if what.instance_of? Lore::Clause then
120
- what = what.to_s + ' AS "value" '
121
- end
122
-
123
- if(what.nil? || what == '*' || what == '') then
124
- query_as_part = '*'
125
- else
126
- query_as_part = what.to_s
127
- end
128
- query_from_part = " FROM #{accessor.get_table_name} "
129
- # Add JOIN part for system defined type (user defined
130
- # joins will be set in Clause_Parser object in later
131
- # yield):
132
- query_join_part = build_joined_query(accessor)
133
-
134
- clause_string = ''
135
- if block_given? then
136
- yield_obj = Lore::Clause_Parser.new(accessor)
137
- clause = yield *yield_obj
138
- end
139
- # Extend AS part by attributes that have been added in clause
140
- query_parts = clause.parts
141
- query_as_part << ' ' << query_parts[:as].to_s
142
- # Extend JOIN part by joins that have been added in clause
143
- query_join_part << ' ' << query_parts[:join].to_s
144
- # Set WHERE part to conditions defined in clause
145
- query_where_part = ' ' << query_parts[:where].to_s
146
- # Set GROUP BY part
147
- query_group_by_part = ' ' << query_parts[:group_by].to_s
148
- # Set HAVING part
149
- query_having_part = ' ' << query_parts[:having].to_s
150
- # Set LIMIT, OFFSET
151
- query_filter_part = ' ' << query_parts[:filter].to_s
152
- query_order_by_part = ' ' << query_parts[:order_by].to_s
153
- query_limit_part = ' ' << query_parts[:limit].to_s
154
- query_limit_part << ' ' << query_parts[:offset].to_s
155
-
156
- query_string << query_as_part << query_from_part << query_join_part << query_where_part << query_group_by_part << query_having_part << query_filter_part << query_order_by_part << query_limit_part
157
-
158
- # TODO:
159
- # Implement class Plan_Clause, offering exactly the same methods as Clause,
160
- # but generating a Plan instead the query.
161
- # Pass block& to Plan_Clause, too, only in case a plan is needed.
162
-
163
- return { :query => query_string, :joined_models => clause.parts[:joined] }
164
-
165
- end
166
-
167
- def self.plan_select_query(what, accessor, &block)
168
-
169
- auto_plan = Lore::Plan.new(clause, select_query(what, accessor, &block), accessor)
170
-
171
- end
172
-
173
- protected
174
-
175
- def self.select(what,
176
- accessor,
177
- &block)
178
-
179
- query_string = select_query(what,
180
- accessor,
181
- &block)
182
-
183
- return perform_select(accessor, query_string[:query])
184
-
185
- end # def
186
-
187
- def self.select_cached(what,
188
- accessor,
189
- &block)
190
-
191
- query_string = select_query(what,
192
- accessor,
193
- &block)
194
-
195
- Lore.log { 'Select on ' << accessor.to_s }
196
-
197
- result = Array.new
198
- if Lore.cache_enabled? && accessor.entity_cache && accessor.entity_cache.include?(accessor, query_string) then
199
- result = accessor.entity_cache.read(accessor, query_string)
200
- result = nil if result == ''
201
- @@logger.debug { "cache contents for #{accessor.table_name} found: #{result.to_s != ''}" }
202
- else
203
- db_result = perform_select(accessor, query_string[:query]).get_rows()
204
- db_result[:values].each { |row|
205
- result.push(accessor.new(row, query_string[:joined_models]))
206
- }
207
- if Lore.cache_enabled? && accessor.entity_cache then
208
- accessor.entity_cache.create(accessor, query_string, result)
209
- end
210
- end
211
- return result
212
- end # def
213
-
214
- # DELETE ME
215
- def self.select_on_keys(accessor,
216
- value_keys)
217
-
218
- query_string = build_select_query(accessor,
219
- value_keys)
220
-
221
- return perform_select(accessor, query_string)
222
-
223
- end #def
224
-
225
- def self.prepare(plan_name, accessor, args, &block)
226
- args_string = ''
227
- args.map { |a| a = Lore::TYPE_NAMES[a] }
228
- if args.to_s != '' && args.length > 0 then args_string = "(#{args.join(',')})" end
229
- query_string = "PREPARE #{accessor.table_name.gsub('.','_')}__#{plan_name.to_s}#{args_string} AS " << select_query(nil, accessor, &block)[:query]
230
- begin
231
- result = Lore::Connection.perform(query_string)
232
- rescue ::Exception => excep
233
- @@logger.debug("Exception when preparing #{plan_name.to_s}: #{excep.message}. Already prepared before?")
234
- end
235
- end
236
-
237
- def self.select_prepared(plan_name, accessor, *args)
238
- args_string = ''
239
- if args.to_s != '' && args.length > 0 then args_string = "(#{args.join(',')})" end
240
- query_string = "EXECUTE #{plan_name.to_s} #{args_string}; "
241
- result = Array.new
242
- if Lore.cache_enabled? && accessor.entity_cache && accessor.entity_cache.include?(accessor, query_string) then
243
- result = accessor.read_entity_cache(query_string)
244
- result = nil if result == ''
245
- @@logger.debug { "cache contents for prepared #{accessor.table_name}: #{result.to_s.inspect}" }
246
- else
247
- db_result = perform_select(accessor, query_string).get_rows()
248
- db_result[:values].each { |row|
249
- result.push(accessor.new(row))
250
- }
251
- if Lore.cache_enabled? && accessor.entity_cache then
252
- accessor.create_entity_cache(query_string, result)
253
- end
254
- end
255
- return result
256
- end
257
-
258
-
259
- def self.deallocate(plan_name, accessor)
260
- begin
261
- query_string = "DEALLOCATE #{accessor.table_name.gsub('.','_')}__#{plan_name.to_s}; "
262
- result = Lore::Connection.perform(query_string)
263
- rescue ::Exception => excep
264
- end
265
- end
266
-
267
- private
268
-
269
- def self.perform_select(accessor, query_string)
270
-
271
- Context.enter(accessor.get_context) unless accessor.get_context.nil?
272
- begin
273
- result = Lore::Connection.perform(query_string)
274
- return result
275
- rescue PGError => pge
276
- raise pge
277
- ensure
278
- Context.leave unless accessor.get_context.nil?
279
- # GC.start
280
- end
281
- end
282
-
283
-
284
- end # module
285
- end # module
@@ -1,157 +0,0 @@
1
-
2
- require('lore/connection')
3
- require('lore/bits')
4
-
5
- module Lore
6
-
7
- module Table_Updater # :nodoc:
8
-
9
- @logger = Logger.new(Lore.logfile)
10
-
11
- def self.atomic_update_query(table_name,
12
- attributes,
13
- primary_key_values,
14
- value_keys,
15
- explicit_fields)
16
-
17
- @logger.debug('EXPLICIT FIELDS: ' << explicit_fields.inspect)
18
-
19
- query_string = "\n"
20
- query_string += 'UPDATE '+table_name+' SET '
21
-
22
- set_string = String.new
23
-
24
- key_counter = 0
25
- attributes.each { |attribute_name|
26
-
27
- internal_attribute_name = attribute_name[0..24]
28
- value = value_keys[internal_attribute_name].to_s
29
- if value == '' then
30
- value = value_keys[table_name+'.'+internal_attribute_name].to_s
31
- end
32
-
33
- # attrib = Lore.resolve_passed_value(value_keys, table_name, attribute_name)
34
- # value = attrib[:value]
35
- # internal_attribute_name = attrib[:field]
36
-
37
- # only include attribute to update query if
38
- # this attribute is not marked for explicit updating or
39
- # marked as explicit but non-empty:
40
- if(
41
- !(explicit_fields && explicit_fields.include?(internal_attribute_name) && value.empty?) &&
42
- !(primary_key_values[attribute_name] && value.empty?)
43
- )
44
-
45
- if key_counter > 0
46
- set_string += ', '
47
- end # if
48
- set_string += attribute_name + '=\'' + value.to_s + '\' '
49
-
50
- key_counter = 1
51
-
52
- end # if
53
- }
54
- query_string += set_string
55
-
56
- query_string += 'WHERE '
57
-
58
- field_counter=0
59
- primary_key_values.each_pair { |field, value|
60
- query_string += field + '=\'' + value.to_s + '\' '
61
- if field_counter < primary_key_values.keys.length-1
62
- query_string += 'AND '
63
- end
64
- field_counter += 1
65
- }
66
- query_string += ';'
67
-
68
- query_string
69
-
70
- end #def
71
-
72
- def self.block_update(accessor,
73
- &block)
74
-
75
- query_string = 'UPDATE '+accessor.get_table_name
76
-
77
- if block_given? then
78
- yield_obj = Lore::Clause_Parser.new(accessor.table_name)
79
- clause = yield *yield_obj
80
- end
81
-
82
- query_string += clause.set_part
83
- query_string += clause.where_part
84
-
85
- Lore::Context.enter(accessor.get_context) unless accessor.get_context.nil?
86
-
87
- begin
88
- Lore::Connection.perform(query_string)
89
- ensure
90
- Lore::Context.leave unless accessor.get_context.nil?
91
- end
92
-
93
- end
94
-
95
- # :nodoc
96
- def self.update_query(table_name,
97
- is_a_hierarchy,
98
-
99
- attributes,
100
- primary_key_values,
101
- value_keys,
102
- explicit_fields,
103
-
104
- query_string='')
105
-
106
- is_a_hierarchy.each_pair { |table, base_tables|
107
-
108
- # pass base tables first, recursively, as IS_A-based creation has
109
- # to be done bottom-up:
110
- query_string += update_query(table,
111
- base_tables,
112
-
113
- attributes,
114
- primary_key_values,
115
- value_keys,
116
- explicit_fields
117
- ).to_s
118
- }
119
- # finally, add query string for this table:
120
- query_string += atomic_update_query(table_name,
121
- attributes[table_name],
122
- primary_key_values[table_name],
123
- value_keys[table_name],
124
- # value_keys[table_name],
125
- explicit_fields[table_name]
126
- ).to_s
127
-
128
- query_string
129
-
130
- end #def
131
-
132
- # :nodoc
133
- def self.perform_update(accessor, accessor_instance)
134
-
135
- query_string = update_query(accessor.get_table_name,
136
- accessor.get_is_a,
137
- accessor.get_attributes,
138
- accessor_instance.get_primary_key_values,
139
- accessor_instance.get_attribute_values,
140
- accessor.get_explicit)
141
-
142
- Context.enter(accessor.get_context) unless accessor.get_context.nil?
143
- begin
144
- Lore::Connection.perform("BEGIN;\n#{query_string}\nCOMMIT;")
145
- rescue ::Exception => excep
146
- Lore::Connection.perform("ROLLBACK;")
147
- ensure
148
- Context.leave unless accessor.get_context.nil?
149
- end
150
-
151
- accessor.flush_entity_cache()
152
-
153
- end #def
154
-
155
- end # module
156
-
157
- end # module
@@ -1,65 +0,0 @@
1
-
2
-
3
- module Lore
4
- module Validation
5
-
6
-
7
- def validates(attrib, constraints)
8
- # {{{
9
- if attrib.kind_of? Clause then
10
- attrib_split = attrib.to_s.split('.')
11
- table = attrib_split[0..-2]
12
- attrib = attrib_split[-1]
13
- else
14
- table = get_table_name
15
- end
16
- attrib = attrib.intern unless attrib.instance_of? Symbol
17
-
18
- @constraints = Hash.new if @constraints.nil?
19
- @constraints[table] = Hash.new if @constraints[table].nil?
20
- @constraints[table][attrib] = Hash.new
21
-
22
- if constraints[:mandatory] then
23
- add_explicit_attribute(table, attrib.to_s)
24
- end
25
- if constraints[:type] then
26
- # @attribute_types[table][attrib] = constraints[:type]
27
- @constraints[table][attrib][:type] = constraints[:type]
28
- end
29
- if constraints[:format] then
30
- @constraints[table][attrib][:format] = constraints[:format]
31
- end
32
- if constraints[:length] then
33
- if constraints[:length].kind_of? Range then
34
- @constraints[table][attrib][:minlength] = constraints[:length].first
35
- @constraints[table][attrib][:maxlength] = constraints[:length].last
36
- else
37
- @constraints[table][attrib][:minlength] = constraints[:length]
38
- @constraints[table][attrib][:maxlength] = constraints[:length]
39
- end
40
- end
41
- if constraints[:minlength] then
42
- @constraints[table][attrib][:minlength] = constraints[:minlength]
43
- end
44
- if constraints[:maxlength] then
45
- @constraints[table][attrib][:maxlength] = constraints[:maxlength]
46
- end
47
- end # }}}
48
-
49
-
50
- def get_constraints
51
- # {{{
52
-
53
- @constraints = Hash.new if @constraints.nil?
54
- if !@is_a_klasses.nil? then
55
- @is_a_klasses.each_pair { |foreign_key, klass|
56
- @constraints.update(klass.get_constraints)
57
- }
58
- end
59
- @constraints
60
-
61
- end # }}}
62
-
63
-
64
- end
65
- end