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
@@ -3,11 +3,12 @@ require('logger')
3
3
 
4
4
  module Lore
5
5
 
6
- VERSION='0.4.7'
6
+ VERSION='0.9.2'
7
7
 
8
8
  @logfile = STDERR
9
- @log_queries = false
10
- @logging_enabled = false
9
+ @query_logfile = STDERR
10
+ @log_queries = true
11
+ @logging_enabled = true
11
12
  @cache_entities = false
12
13
  @pg_server = 'localhost'
13
14
  @pg_port = 5432
@@ -17,13 +18,25 @@ module Lore
17
18
  def self.logfile
18
19
  @logfile
19
20
  end
21
+ def self.query_logfile
22
+ @query_logfile
23
+ end
20
24
  def self.logfile=(file)
21
- @logger = Logger.new(file)
25
+ @logger = Logger.new(file)
26
+ @query_logger = Logger.new(file)
27
+ end
28
+ def self.query_logfile=(file)
29
+ @query_logger = Logger.new(file)
22
30
  end
23
31
  def self.logger
24
32
  @logger
25
33
  end
34
+ def self.query_logger
35
+ @query_logger
36
+ end
37
+
26
38
  @logger = Logger.new(Lore.logfile)
39
+ @query_logger = Logger.new(Lore.query_logfile)
27
40
 
28
41
  def self.log(&log_block)
29
42
  return if Lore.logging_disabled?
@@ -36,9 +49,11 @@ module Lore
36
49
 
37
50
  def self.disable_logging
38
51
  @logging_enabled = false
52
+ Lore.logger.level = Logger::ERROR
39
53
  end
40
54
  def self.enable_logging
41
55
  @logging_enabled = true
56
+ Lore.logger.level = Logger::DEBUG
42
57
  end
43
58
  def self.enable_query_log
44
59
  @log_queries = true
@@ -82,7 +97,7 @@ module Lore
82
97
  end
83
98
  end
84
99
  def self.pass_for(dbname)
85
- @logins[dbname.to_s][1].to_s
100
+ @logins[dbname.to_s][1]
86
101
  end
87
102
 
88
103
  def self.disable_cache
@@ -103,7 +118,6 @@ module Lore
103
118
 
104
119
  end
105
120
 
121
+ require('lore/adapters/postgres')
106
122
  require('lore/validation/parameter_validator')
107
- require('lore/exception/invalid_parameter')
108
- require('lore/exception/invalid_klass_parameters')
109
- require('lore/connection')
123
+
@@ -0,0 +1,64 @@
1
+
2
+ require('lore')
3
+
4
+ module Lore
5
+
6
+ class Connection_Error < ::Exception
7
+
8
+ end
9
+
10
+ class Context
11
+
12
+ @@context_stack = Array.new
13
+
14
+ def self.get_connection()
15
+ if @@context_stack.empty? then
16
+ raise ::Exception.new('No context given. ')
17
+ end
18
+ return Connection_Pool.get_connection(@@context_stack.last)
19
+ end
20
+
21
+ def self.get_context
22
+ @@context_stack.last
23
+ end
24
+
25
+ def self.inspect
26
+ @@context_stack.inspect
27
+ end
28
+
29
+ def self.enter(context_name)
30
+ Lore.logger.debug { "Entering context #{context_name}" }
31
+ @@context_stack.push(context_name.to_sym)
32
+ end
33
+
34
+ def self.leave()
35
+ Lore.logger.debug { "Leaving context #{context_name}" }
36
+ context_name = @@context_stack.pop
37
+ end
38
+
39
+ end
40
+
41
+ class Connection_Pool
42
+
43
+ @@pool = Hash.new
44
+
45
+ def self.get_connection(db_name)
46
+
47
+ db_name = db_name.to_sym
48
+
49
+ # If requested connection is not in pool yet:
50
+ if !@@pool.has_key? db_name then
51
+ # Try to establish connection
52
+ connection = Lore::Connection.establish(db_name)
53
+ connection.exec(Lore.on_connect_commands)
54
+ @@pool[db_name] = connection
55
+ end
56
+
57
+ # Return requested connection
58
+ return @@pool[db_name]
59
+
60
+ end
61
+
62
+ end
63
+
64
+ end # module Lore
@@ -0,0 +1,6 @@
1
+
2
+ require('rubygems')
3
+ require('lore/adapters/postgres-pr/connection')
4
+ require('lore/adapters/postgres-pr/result')
5
+ require('lore/adapters/postgres-pr/types')
6
+
@@ -0,0 +1,93 @@
1
+
2
+ $:.push('/opt/local/lib/ruby/1.8/postgres')
3
+
4
+ require('postgres-pr/connection')
5
+ require('lore')
6
+ require('lore/exceptions/database_exception')
7
+ require('lore/adapters/context')
8
+ require('lore/adapters/postgres-pr/result')
9
+ require('lore/adapters/postgres-pr/types')
10
+
11
+ module PostgresPR
12
+ class Connection
13
+ alias exec query
14
+ alias exec_async query
15
+ end
16
+ end
17
+
18
+ module Lore
19
+
20
+ class Connection
21
+
22
+ @@query_count = 0
23
+ @@result_row_count = 0
24
+
25
+ def initialize
26
+ end
27
+
28
+ def self.reset_query_count
29
+ @@query_count = 0
30
+ end
31
+ def self.reset_result_row_count
32
+ @@result_row_count = 0
33
+ end
34
+ def self.query_count
35
+ @@query_count
36
+ end
37
+ def self.result_row_count
38
+ @@result_row_count
39
+ end
40
+
41
+ def self.perform_cacheable(query)
42
+ if Lore::Cache::Cached_Entities.include?(query) then
43
+ result = Lore::Cache::Cached_Entities[query]
44
+ else
45
+ result = perform(query)
46
+ Lore::Cache::Cached_Entities[query] = result
47
+ end
48
+ return result
49
+ end
50
+
51
+ def self.perform(query)
52
+ begin
53
+ @@query_count += 1
54
+ # result = Context.get_connection.exec(query)
55
+ result = Context.get_connection.query(query)
56
+ @@result_row_count += result.rows.length
57
+
58
+ if Lore.log_queries? then
59
+ query.split("\n").each { |line|
60
+ Lore.query_logger.debug { " sql|#{Context.get_context}| #{line}" }
61
+ }
62
+ end
63
+ rescue ::Exception => pge
64
+ Lore.logger.error { pge.message }
65
+ Lore.logger.error { 'Context: ' << Context.inspect }
66
+ Lore.logger.error { 'Query: ' << "\n" << query }
67
+ raise pge
68
+ raise Lore::Exceptions::Database_Exception.new(pge.message << "\n" << query.to_s)
69
+ end
70
+
71
+ return Result.new(query, result)
72
+ end
73
+
74
+ def self.establish(db_name)
75
+ Lore.logger.info { "Establishing connection to #{db_name}" }
76
+ Lore.logger.info { "User: #{Lore.user_for(db_name.to_sym).inspect}"}
77
+ Lore.logger.info { "Pass: #{Lore.pass_for(db_name.to_sym).inspect}"}
78
+ Lore.logger.info { "Server: #{Lore.pg_server}" }
79
+ begin
80
+ PostgresPR::Connection.new(db_name.to_s,
81
+ Lore.user_for(db_name.to_sym),
82
+ Lore.pass_for(db_name.to_sym),
83
+ # including port, example:
84
+ # 'unix:/var/run/postgresql/.s.PGSQL.5432'
85
+ Lore.pg_server)
86
+ rescue ::Exception => e
87
+ raise Lore::Exceptions::Database_Exception.new(e.message)
88
+ end
89
+ end
90
+
91
+ end # class Connection
92
+
93
+ end # module Lore
@@ -0,0 +1,63 @@
1
+
2
+ require('postgres-pr/connection')
3
+
4
+ module Lore
5
+
6
+ class Result
7
+
8
+ attr_reader :query_hashval, :field_names, :field_types
9
+
10
+ # expects PostgresPR::Result
11
+ def initialize(query, result)
12
+ @result = result
13
+ @field_types = {}
14
+ @result.fields.each { |f|
15
+ @field_types[f.name] = f.type_oid
16
+ }
17
+ @num_fields = @result.fields.length
18
+ @num_tuples = @result.rows.length
19
+ @field_names = @result.fields.map { |f| f.name }
20
+ end
21
+
22
+ def get_field_value(row_index, field_name)
23
+ # TODO: Optimize this!
24
+ field_index = 0
25
+ @result.fields.each { |f|
26
+ break if f.name == field_name
27
+ field_index += 1
28
+ }
29
+ return @result.rows[row_index][field_index]
30
+ end
31
+
32
+ def get_field_types()
33
+ return @field_types
34
+ end
35
+ alias field_types get_field_types
36
+ alias get_field_names field_names
37
+
38
+ def get_field_num()
39
+ @num_fields
40
+ end
41
+
42
+ def get_tuple_num()
43
+ @num_tuples
44
+ end
45
+
46
+ def get_row(row_num=0)
47
+ @result.rows[row_num]
48
+ end
49
+ def get_row_with_field_names(row_num=0)
50
+ return { :values => @result.rows, :fields => @result.fields }
51
+ end
52
+
53
+ def get_rows()
54
+ return @result.rows
55
+ end
56
+
57
+ def fieldname(index)
58
+ return @fields_names[index]
59
+ end
60
+
61
+ end # class Result
62
+
63
+ end # module Lore
@@ -7,6 +7,7 @@ module Lore
7
7
  PG_CHAR = 18
8
8
  PG_INT = 23
9
9
  PG_TEXT = 25
10
+ PG_FLOAT = 701
10
11
  PG_CHARACTER = 1042
11
12
  PG_VARCHAR = 1043
12
13
  PG_TIME = 1083
@@ -23,6 +24,7 @@ module Lore
23
24
  PG_CHAR => 'char',
24
25
  PG_INT => 'integer',
25
26
  PG_TEXT => 'text',
27
+ PG_FLOAT => 'float',
26
28
  PG_CHARACTER => 'character',
27
29
  PG_VARCHAR => 'character varying(1000)',
28
30
  PG_TIME => 'time',
@@ -52,4 +54,38 @@ module Lore
52
54
 
53
55
  end
54
56
 
57
+ class Type_Filters
58
+
59
+ @@input_filters = {
60
+ PG_VCHAR_LIST => lambda { |v| "{#{v.join(',')}}" },
61
+ PG_BOOL => lambda { |v| if (v && v != 'f' || v == 't') then 'f' elsif (v.instance_of?(FalseClass) || v == 'f') then 'f' else nil end },
62
+ PG_DATE => lambda { |v| v.to_s },
63
+ PG_TIME => lambda { |v| v.to_s },
64
+ PG_TIMESTAMP_TIMEZONE => lambda { |v| v.to_s },
65
+ PG_TIMESTAMP => lambda { |v| v.to_s },
66
+ }
67
+ @@output_filters = {
68
+ PG_VCHAR_LIST => lambda { |v| v[1..-2].split(',') },
69
+ PG_INT => lambda { |v| if v then v.to_i else nil end },
70
+ PG_SMALLINT => lambda { |v| if v then v.to_i else nil end },
71
+ PG_FLOAT => lambda { |v| if v && v.length > 0 then v.to_f else nil end },
72
+ PG_DECIMAL => lambda { |v| if v && v.length > 0 then v.to_f else nil end },
73
+ PG_BOOL => lambda { |v| if v == 't' then true elsif v == 'f' then false else nil end }
74
+ # SLOW!
75
+ # PG_DATE => lambda { |v| Date.parse(v) if v },
76
+ # PG_TIME => lambda { |v| Time.parse(v) if v },
77
+ # PG_TIMESTAMP_TIMEZONE => lambda { |v| DateTime.parse(v) if v },
78
+ # PG_TIMESTAMP => lambda { |v| DateTime.parse(v) if v }
79
+ }
80
+
81
+ def self.in
82
+ @@input_filters
83
+ end
84
+
85
+ def self.out
86
+ @@output_filters
87
+ end
88
+
89
+ end
90
+
55
91
  end # module
@@ -0,0 +1,24 @@
1
+
2
+ require('rubygems')
3
+ begin
4
+ require('postgres')
5
+ require('lore/adapters/postgres/connection')
6
+ require('lore/adapters/postgres/result')
7
+ require('lore/adapters/postgres/types')
8
+ rescue LoadError
9
+ begin
10
+ Lore.pg_server = 'unix:/var/run/postgresql/.s.PGSQL.5432'
11
+ Lore.logger.info { "Defaulted PG server to #{Lore.pg_server}" }
12
+ Lore.logger.info { "Use Lore.pg_server = 'server uri' to set a different one" }
13
+ # Bridges PostgresPR::Connection to PGConn
14
+ # require 'postgres-pr/postgres-compat'
15
+ require('postgres-pr/connection')
16
+ require('lore/adapters/postgres-pr/connection')
17
+ require('lore/adapters/postgres-pr/result')
18
+ require('lore/adapters/postgres-pr/types')
19
+ rescue LoadError
20
+ Lore.logger.error { "No binding for postgres found" }
21
+ Lore.logger.error { "Please install 'postgres' or 'postgres-pr'" }
22
+ end
23
+ end
24
+
@@ -0,0 +1,81 @@
1
+
2
+ $:.push('/opt/local/lib/ruby/1.8/postgres')
3
+
4
+ require('postgres')
5
+ require('lore')
6
+ require('lore/exceptions/database_exception')
7
+ require('lore/adapters/context')
8
+ require('lore/adapters/postgres/result')
9
+
10
+ module Lore
11
+
12
+ class Connection
13
+
14
+ @@query_count = 0
15
+ @@result_row_count = 0
16
+
17
+ def initialize
18
+ end
19
+
20
+ def self.reset_query_count
21
+ @@query_count = 0
22
+ end
23
+ def self.reset_result_row_count
24
+ @@result_row_count = 0
25
+ end
26
+ def self.query_count
27
+ @@query_count
28
+ end
29
+ def self.result_row_count
30
+ @@result_row_count
31
+ end
32
+
33
+ def self.perform_cacheable(query)
34
+ if Lore::Cache::Cached_Entities.include?(query) then
35
+ result = Lore::Cache::Cached_Entities[query]
36
+ else
37
+ result = perform(query)
38
+ Lore::Cache::Cached_Entities[query] = result
39
+ end
40
+ return result
41
+ end
42
+
43
+ def self.perform(query)
44
+ begin
45
+ @@query_count += 1
46
+ # result = Context.get_connection.exec(query)
47
+ result = Context.get_connection.async_exec(query)
48
+ @@result_row_count += result.num_tuples
49
+
50
+ if Lore.log_queries? then
51
+ query.split("\n").each { |line|
52
+ Lore.query_logger.debug { " sql|#{Context.get_context}| #{line}" }
53
+ }
54
+ end
55
+ rescue ::Exception => pge
56
+ pge.message << "\n" << query.inspect
57
+ Lore.logger.error { pge.message }
58
+ Lore.logger.error { 'Context: ' << Context.inspect }
59
+ Lore.logger.error { 'Query: ' << "\n" << query }
60
+ raise Lore::Exceptions::Database_Exception.new(pge.message << "\n" << query.to_s)
61
+ end
62
+
63
+ return Result.new(query, result)
64
+ end
65
+
66
+ def self.establish(db_name)
67
+ begin
68
+ PGconn.connect(Lore.pg_server,
69
+ Lore.pg_port,
70
+ '', '',
71
+ db_name.to_s,
72
+ Lore.user_for(db_name.to_sym),
73
+ Lore.pass_for(db_name.to_sym))
74
+ rescue ::Exception => e
75
+ raise Lore::Exceptions::Database_Exception.new(e.message)
76
+ end
77
+ end
78
+
79
+ end # class Connection
80
+
81
+ end # module Lore