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,72 +0,0 @@
1
-
2
- module Lore
3
- module Behaviours
4
-
5
- # Move an entity within a given criteria range,
6
- # e.g. within nodes of a tree.
7
- #
8
- # Usage:
9
- #
10
- # class My_Model < Lore::Model
11
- # extend Lore::Behaviours::Movable
12
- # include Lore::Behaviours::Movable_Entity
13
- # # ...
14
- # ordered_by(:position)
15
- # end
16
- #
17
- # # Will move entity to position 12 within child entries
18
- # # of node with id 2:
19
- # my_model_entity.move_to(12, (My_Model.parent_id == 2))
20
- # # Same as
21
- # My_Model.move(my_model_entity, 12, (My_Model.parent_id == 2))
22
- #
23
- module Movable
24
-
25
- def ordered_by(attrib)
26
- @order_attr = attrib
27
- @order_attr_name = attrib.to_s.split('.')[-1].intern
28
- end
29
-
30
- def move(inst, sortpos, criteria)
31
- sortpos = sortpos.to_i
32
- return if sortpos < 1
33
-
34
- criteria ||= Lore::Clause.new()
35
- sortpos_old = inst.attr[@order_attr_name].to_i
36
-
37
- # move down:
38
- if sortpos.to_i > sortpos_old then
39
- self.update { |na|
40
- na.set({@order_attr_name => @order_attr-1}).where(
41
- (criteria) &
42
- (@order_attr <= sortpos) &
43
- (@order_attr > sortpos_old)
44
- )
45
- }
46
- # move up:
47
- elsif sortpos.to_i < sortpos_old then
48
- self.update { |na|
49
- na.set({@order_attr_name => @order_attr+1}).where(
50
- (criteria) &
51
- (@order_attr >= sortpos) &
52
- (@order_attr < sortpos_old)
53
- )
54
- }
55
- end
56
- # In case we actually had to move the entity:
57
- if sortpos != sortpos_old then
58
- inst.set_attribute_value(@order_attr_name, sortpos)
59
- inst.commit()
60
- end
61
- end # def
62
-
63
- end # module
64
-
65
- module Movable_Entity
66
- def move_to(position, criteria=nil)
67
- self.class.move(self, position, criteria)
68
- end
69
- end
70
-
71
- end # module
72
- end # module
@@ -1,31 +0,0 @@
1
-
2
- module Lore
3
- module Behaviours
4
-
5
-
6
- # Usage:
7
- #
8
- # class My_Model < Lore::Model
9
- # extend Lore::Behaviours::Paginated
10
- #
11
- # def self.search(search, page)
12
- # paginate(:per_page => 10,
13
- # :page => page,
14
- # :filter => all_with(search).order_by(:name, :desc))
15
- # end
16
- #
17
- # end
18
- #
19
- # first_page_entities => My_Model.search((My_Model.attribute == 'foo'), 1)
20
- #
21
- module Paginated
22
-
23
- def paginate(params)
24
- entities = params[:filter].limit(params[:per_page], params[:page]).entities
25
- end
26
-
27
- end
28
-
29
- end
30
- end
31
-
@@ -1,36 +0,0 @@
1
-
2
- module Lore
3
- module Behaviours
4
-
5
- # Usage:
6
- #
7
- # class My_Model < Lore::Model
8
- # extend Lore::Behaviours::Versioned
9
- # # ...
10
- # version_by :version_number
11
- # end
12
- #
13
- # my_model_entity.foo = 'bar'
14
- # my_model_entity.commit # Will create a new version
15
- #
16
- module Versioned
17
-
18
- # Defines attribute the version number is stored in.
19
- # Default is 'version'.
20
- def version_by(attrib=:version)
21
- @version_attr = attrib
22
- @version_attr_name = attrib.to_s.split('.')[-1].intern
23
- end
24
-
25
- # Overloads commit so it increments the version attribute
26
- # before saving instance to database and creates a new
27
- # entity with incremented version instead.
28
- def commit()
29
- set_attribute_value(@version_attr, self.attr[@version_attr].to_i + 1)
30
- create(self.attr)
31
- end
32
-
33
- end # module
34
-
35
- end # module
36
- end # module
@@ -1,152 +0,0 @@
1
-
2
- $:.push('/opt/local/lib/ruby/1.8/postgres')
3
-
4
- require('postgres')
5
- require('logger')
6
- require('lore')
7
- require('lore/result')
8
-
9
- module Lore
10
-
11
- class Connection_Error < ::Exception
12
-
13
- end
14
-
15
- class Context
16
-
17
- @@logger = Lore.logger
18
- @@context_stack = Array.new
19
-
20
- def self.get_connection()
21
- if @@context_stack.empty? then
22
- raise ::Exception.new('No context given. ')
23
- end
24
- return Connection_Pool.get_connection(@@context_stack.last)
25
- end
26
-
27
- def self.inspect
28
- @@context_stack.inspect
29
- end
30
-
31
- def self.enter(context_name)
32
- Lore.log { 'Entering context ' + context_name.to_s }
33
- @@context_stack.push(context_name)
34
- end
35
-
36
- def self.leave()
37
- context_name = @@context_stack.pop
38
- @@logger.debug('Leaving context ' << context_name.to_s)
39
- end
40
-
41
- def self.clear()
42
- @@context_stack = Array.new
43
- $cb__project = nil
44
- end
45
-
46
- def self.switch_to(project)
47
- clear()
48
- enter(project.context)
49
- $cb__project = project
50
- end
51
-
52
- end
53
-
54
- class Connection_Pool
55
-
56
- @@pool = Hash.new
57
-
58
- def self.get_connection(db_name)
59
-
60
- db_name = db_name.intern unless db_name.instance_of? Symbol
61
-
62
- # If requested connection is not in pool yet:
63
- if !@@pool.has_key? db_name then
64
- # Try to establish connection
65
- begin
66
- connection = PGconn.connect(Lore.pg_server, Lore.pg_port, '', '', db_name.to_s, Lore.user_for(db_name), Lore.pass_for(db_name.to_s))
67
- connection.exec(Lore.on_connect_commands)
68
- @@pool[db_name] = connection
69
- # Handle errors
70
- rescue PGError => pge
71
- raise Lore::Connection_Error.new("Could not establish connection to database '#{db_name.to_s}': " << pge.message)
72
- rescue ::Exception => excep
73
- raise Lore::Connection_Error.new("Could not establish connection to database '#{db_name.to_s}': " << excep.message)
74
- end
75
- end
76
-
77
- # Return requested connection
78
- return @@pool[db_name]
79
-
80
- end
81
-
82
- end
83
-
84
- class Connection # :nodoc
85
- #include Singleton
86
-
87
- @@logger = Lore.logger
88
- @@query_count = 0
89
- @@result_row_count = 0
90
-
91
- def initialize
92
- end
93
-
94
- def self.reset_query_count
95
- @@query_count = 0
96
- end
97
- def self.reset_result_row_count
98
- @@result_row_count = 0
99
- end
100
- def self.query_count
101
- @@query_count
102
- end
103
- def self.result_row_count
104
- @@result_row_count
105
- end
106
-
107
- def self.perform_cacheable(query)
108
-
109
- if Lore::Cache::Cached_Entities.include?(query) then
110
- result = Lore::Cache::Cached_Entities[query]
111
- else
112
- result = perform(query)
113
- Lore::Cache::Cached_Entities[query] = result
114
- end
115
- return result
116
- end
117
-
118
- def self.perform(query)
119
-
120
- begin
121
-
122
- connection = Context.get_connection
123
-
124
- @@query_count += 1
125
- result = connection.exec(query)
126
- @@result_row_count += result.num_tuples
127
-
128
- # Log database query on low level:
129
-
130
- if Lore.log_queries? then
131
- query.split("\n").each { |line|
132
- @@logger.debug { line }
133
- }
134
- end
135
-
136
- rescue ::Exception => pge
137
-
138
- pge.message << "\n" << query
139
- @@logger.error { pge.message }
140
- @@logger.error { 'Context: ' << Context.inspect }
141
- @@logger.error { 'Query: ' << "\n" << query }
142
- raise pge
143
-
144
- end
145
-
146
- return Result.new(query, result)
147
-
148
- end
149
-
150
- end # class Connection
151
-
152
- end # module Lore
@@ -1,63 +0,0 @@
1
-
2
- module Lore
3
- module Exception
4
-
5
- # Usage:
6
- #
7
- # raise Lore::Exception::Invalid_Klass_Parameters.new(The_Model, {
8
- # # Generic error. Example: :user_id => Lore.integer
9
- # :table_foo => Invalid_Parameters.new( :the_attribute => :error_type )
10
- # # Constraint error. Example: :email => :format
11
- # :table bar => Unmet_Constraints.new( :the_attribute => :error_type )
12
- # # Type error. Example: :user_id => Lore.integer or :user_id => :missing
13
- # :table_batz => Invalid_Types.new( :the_attribute => :error_type )
14
- # })
15
- #
16
- class Invalid_Klass_Parameters < ::Exception
17
-
18
- attr_reader :invalid_parameters
19
- attr_reader :invalid_klass
20
-
21
- def initialize(klass, invalid_params_hash)
22
-
23
- @logger = Lore.logger
24
- # Instances of Exception::Invalid_Parameters
25
- @invalid_parameters = invalid_params_hash
26
- @invalid_klass = klass
27
-
28
- end
29
-
30
- def log()
31
-
32
- @logger.error('Invalid parameters for klass '+@invalid_klass.to_s+': ')
33
- @logger.error('Invalid parameters: ')
34
- @logger.error(@invalid_parameters.inspect)
35
- @logger.error('Explicit attributes: ')
36
- @logger.error(@invalid_klass.get_explicit_attributes.inspect)
37
-
38
- end
39
-
40
- def serialize() # {{{
41
-
42
- serials = {}
43
- @invalid_parameters.each_pair { |table, invalid_param|
44
- serials[table] = invalid_param.serialize
45
- }
46
- return serials
47
-
48
- end # def }}}
49
-
50
- def inspect()
51
- 'Model('+@invalid_klass.to_s+') => '+
52
- @invalid_parameters.serialize +
53
- ' Explicit: '+
54
- @invalid_klass.get_explicit_attributes.inspect
55
- end
56
- alias explain serialize
57
-
58
- end
59
-
60
-
61
- end # module
62
- end # module
63
-
@@ -1,19 +0,0 @@
1
-
2
- module Lore
3
- module Exception
4
-
5
- class Unknown_Typecode < ::Exception
6
-
7
- attr_reader :code
8
-
9
- def initialize(_code)
10
-
11
- @code = _code
12
- @message = 'Unknown PGSQL type: ' + _code.to_s
13
-
14
- end
15
-
16
- end
17
-
18
- end # module
19
- end # module
@@ -1,119 +0,0 @@
1
-
2
- require('postgres')
3
- require('digest/md5')
4
-
5
- module Lore
6
-
7
- # :nodoc
8
- class Result
9
-
10
- attr_reader :query_hashval
11
-
12
- def initialize(query, result) # expects PGresult
13
-
14
- @result = result
15
- @field_types = nil
16
- @result_rows = Array.new
17
- # @query_hashval = Digest::MD5.hexdigest(query)
18
- @num_fields = @result.num_fields
19
- @field_counter = 0
20
-
21
- end # def initialize
22
-
23
- def get_field_value(row_index, field_name)
24
-
25
- field_index = @result.fieldnum(field_name)
26
- return @result.getvalue(row_index, field_index)
27
-
28
- end # def get_field_value
29
-
30
- def get_field_names()
31
- return @result.fields
32
- end
33
-
34
- def get_field_types()
35
-
36
- return @field_types unless @field_types.nil?
37
-
38
- @field_types = Hash.new
39
- for field_index in 0...get_field_num()
40
- @field_types[@result.fields[field_index]] = @result.type(field_index)
41
- end
42
-
43
- return @field_types
44
- end
45
-
46
- def get_field_num()
47
- return @result.num_fields
48
- end
49
-
50
- def get_tuple_num()
51
- return @result.num_tuples
52
- end
53
-
54
- def get_row(row_num=0)
55
-
56
- return @result_rows.at(row_num) if @result_rows.at(row_num)
57
- return if @result.num_tuples == 0
58
-
59
- # We cannot use a hash here, as there might be
60
- # duplicate attribute names due to joins:
61
- #
62
- # {
63
- # :fields => [ 'id', 'foo', 'foreign_id, 'id', 'bar' ]
64
- # :values => [ '1', 'wombat', '5', '5', 'cthulluh' ]
65
- # }
66
- row_result = Array.new
67
-
68
- @field_counter = 0
69
- for @field_counter in 0...@num_fields do
70
- row_result << @result.getvalue(row_num, @field_counter)
71
- end
72
- @result_rows[row_num] = row_result
73
- return row_result
74
-
75
- end
76
- def get_row_with_field_names(row_num=0)
77
-
78
- return @result_rows.at(row_num) if @result_rows.at(row_num)
79
- return if @result.num_tuples == 0
80
-
81
- row_result = Array.new
82
-
83
- @field_counter = 0
84
- for @field_counter in 0...@num_fields do
85
- row_result << @result.getvalue(row_num, @field_counter)
86
- end
87
- @result_rows[row_num] = row_result
88
- @fieldnames = []
89
- for @field_counter in 0...@num_fields do
90
- @fieldnames << @result.fieldname(@field_counter)
91
- end
92
- return { :values => row_result, :fields => @fieldnames }
93
-
94
- end
95
-
96
- def get_rows()
97
- if !@result_rows.first then
98
- for tuple_counter in 0...@result.num_tuples do
99
- get_row(tuple_counter)
100
- end
101
- @fieldnames = []
102
- for @field_counter in 0...@num_fields do
103
- @fieldnames << @result.fieldname(@field_counter)
104
- end
105
- end
106
-
107
- result = { :values => @result_rows, :fields => @fieldnames }
108
- return result
109
- end
110
-
111
- def fieldname(index)
112
-
113
- return @result.fieldname(index)
114
-
115
- end
116
-
117
- end # class Result
118
-
119
- end # module Lore