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,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