sequel 2.11.0 → 2.12.0

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 (162) hide show
  1. data/CHANGELOG +168 -0
  2. data/README.rdoc +77 -95
  3. data/Rakefile +100 -80
  4. data/bin/sequel +2 -1
  5. data/doc/advanced_associations.rdoc +23 -32
  6. data/doc/cheat_sheet.rdoc +23 -40
  7. data/doc/dataset_filtering.rdoc +6 -6
  8. data/doc/prepared_statements.rdoc +22 -22
  9. data/doc/release_notes/2.12.0.txt +534 -0
  10. data/doc/schema.rdoc +3 -1
  11. data/doc/sharding.rdoc +8 -8
  12. data/doc/virtual_rows.rdoc +65 -0
  13. data/lib/sequel.rb +1 -1
  14. data/lib/{sequel_core → sequel}/adapters/ado.rb +3 -3
  15. data/lib/{sequel_core → sequel}/adapters/db2.rb +0 -0
  16. data/lib/{sequel_core → sequel}/adapters/dbi.rb +1 -1
  17. data/lib/{sequel_core → sequel}/adapters/do.rb +9 -5
  18. data/lib/{sequel_core → sequel}/adapters/do/mysql.rb +1 -1
  19. data/lib/{sequel_core → sequel}/adapters/do/postgres.rb +1 -1
  20. data/lib/{sequel_core → sequel}/adapters/do/sqlite.rb +1 -1
  21. data/lib/{sequel_core → sequel}/adapters/firebird.rb +84 -80
  22. data/lib/{sequel_core → sequel}/adapters/informix.rb +1 -1
  23. data/lib/{sequel_core → sequel}/adapters/jdbc.rb +21 -14
  24. data/lib/{sequel_core → sequel}/adapters/jdbc/h2.rb +14 -13
  25. data/lib/{sequel_core → sequel}/adapters/jdbc/mysql.rb +1 -1
  26. data/lib/{sequel_core → sequel}/adapters/jdbc/oracle.rb +1 -1
  27. data/lib/{sequel_core → sequel}/adapters/jdbc/postgresql.rb +1 -1
  28. data/lib/{sequel_core → sequel}/adapters/jdbc/sqlite.rb +1 -1
  29. data/lib/{sequel_core → sequel}/adapters/mysql.rb +60 -39
  30. data/lib/{sequel_core → sequel}/adapters/odbc.rb +8 -4
  31. data/lib/{sequel_core → sequel}/adapters/openbase.rb +0 -0
  32. data/lib/{sequel_core → sequel}/adapters/oracle.rb +38 -7
  33. data/lib/{sequel_core → sequel}/adapters/postgres.rb +24 -24
  34. data/lib/{sequel_core → sequel}/adapters/shared/mssql.rb +5 -5
  35. data/lib/{sequel_core → sequel}/adapters/shared/mysql.rb +126 -71
  36. data/lib/{sequel_core → sequel}/adapters/shared/oracle.rb +7 -10
  37. data/lib/{sequel_core → sequel}/adapters/shared/postgres.rb +159 -125
  38. data/lib/{sequel_core → sequel}/adapters/shared/progress.rb +1 -2
  39. data/lib/{sequel_core → sequel}/adapters/shared/sqlite.rb +72 -67
  40. data/lib/{sequel_core → sequel}/adapters/sqlite.rb +11 -7
  41. data/lib/{sequel_core → sequel}/adapters/utils/date_format.rb +0 -0
  42. data/lib/{sequel_core → sequel}/adapters/utils/stored_procedures.rb +0 -0
  43. data/lib/{sequel_core → sequel}/adapters/utils/unsupported.rb +19 -0
  44. data/lib/{sequel_core → sequel}/connection_pool.rb +7 -5
  45. data/lib/sequel/core.rb +221 -0
  46. data/lib/{sequel_core → sequel}/core_sql.rb +91 -49
  47. data/lib/{sequel_core → sequel}/database.rb +264 -149
  48. data/lib/{sequel_core/schema/generator.rb → sequel/database/schema_generator.rb} +6 -2
  49. data/lib/{sequel_core/database/schema.rb → sequel/database/schema_methods.rb} +12 -12
  50. data/lib/sequel/database/schema_sql.rb +224 -0
  51. data/lib/{sequel_core → sequel}/dataset.rb +78 -236
  52. data/lib/{sequel_core → sequel}/dataset/convenience.rb +99 -61
  53. data/lib/{sequel_core/object_graph.rb → sequel/dataset/graph.rb} +16 -14
  54. data/lib/{sequel_core → sequel}/dataset/prepared_statements.rb +1 -1
  55. data/lib/{sequel_core → sequel}/dataset/sql.rb +150 -99
  56. data/lib/sequel/deprecated.rb +593 -0
  57. data/lib/sequel/deprecated_migration.rb +91 -0
  58. data/lib/sequel/exceptions.rb +48 -0
  59. data/lib/sequel/extensions/blank.rb +42 -0
  60. data/lib/{sequel_model → sequel/extensions}/inflector.rb +8 -1
  61. data/lib/{sequel_core → sequel/extensions}/migration.rb +1 -1
  62. data/lib/{sequel_core/dataset → sequel/extensions}/pagination.rb +0 -0
  63. data/lib/{sequel_core → sequel/extensions}/pretty_table.rb +7 -0
  64. data/lib/{sequel_core/dataset → sequel/extensions}/query.rb +7 -0
  65. data/lib/sequel/extensions/string_date_time.rb +47 -0
  66. data/lib/sequel/metaprogramming.rb +43 -0
  67. data/lib/sequel/model.rb +110 -0
  68. data/lib/sequel/model/associations.rb +1300 -0
  69. data/lib/sequel/model/base.rb +937 -0
  70. data/lib/sequel/model/deprecated.rb +204 -0
  71. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  72. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  73. data/lib/sequel/model/deprecated_validations.rb +388 -0
  74. data/lib/sequel/model/errors.rb +39 -0
  75. data/lib/{sequel_model → sequel/model}/exceptions.rb +4 -4
  76. data/lib/sequel/model/inflections.rb +208 -0
  77. data/lib/sequel/model/plugins.rb +76 -0
  78. data/lib/sequel/plugins/caching.rb +122 -0
  79. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  80. data/lib/sequel/plugins/schema.rb +53 -0
  81. data/lib/sequel/plugins/serialization.rb +117 -0
  82. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  83. data/lib/sequel/plugins/validation_class_methods.rb +384 -0
  84. data/lib/sequel/plugins/validation_helpers.rb +150 -0
  85. data/lib/{sequel_core → sequel}/sql.rb +125 -190
  86. data/lib/{sequel_core → sequel}/version.rb +2 -1
  87. data/lib/sequel_core.rb +1 -172
  88. data/lib/sequel_model.rb +1 -91
  89. data/spec/adapters/firebird_spec.rb +5 -5
  90. data/spec/adapters/informix_spec.rb +1 -1
  91. data/spec/adapters/mysql_spec.rb +128 -42
  92. data/spec/adapters/oracle_spec.rb +47 -19
  93. data/spec/adapters/postgres_spec.rb +64 -52
  94. data/spec/adapters/spec_helper.rb +1 -1
  95. data/spec/adapters/sqlite_spec.rb +12 -17
  96. data/spec/{sequel_core → core}/connection_pool_spec.rb +10 -10
  97. data/spec/{sequel_core → core}/core_ext_spec.rb +19 -19
  98. data/spec/{sequel_core → core}/core_sql_spec.rb +68 -71
  99. data/spec/{sequel_core → core}/database_spec.rb +135 -99
  100. data/spec/{sequel_core → core}/dataset_spec.rb +398 -242
  101. data/spec/{sequel_core → core}/expression_filters_spec.rb +13 -13
  102. data/spec/core/migration_spec.rb +263 -0
  103. data/spec/{sequel_core → core}/object_graph_spec.rb +10 -10
  104. data/spec/{sequel_core → core}/pretty_table_spec.rb +2 -2
  105. data/spec/{sequel_core → core}/schema_generator_spec.rb +0 -0
  106. data/spec/{sequel_core → core}/schema_spec.rb +8 -10
  107. data/spec/{sequel_core → core}/spec_helper.rb +29 -2
  108. data/spec/{sequel_core → core}/version_spec.rb +0 -0
  109. data/spec/extensions/blank_spec.rb +67 -0
  110. data/spec/extensions/caching_spec.rb +201 -0
  111. data/spec/{sequel_model/hooks_spec.rb → extensions/hook_class_methods_spec.rb} +8 -23
  112. data/spec/{sequel_model → extensions}/inflector_spec.rb +3 -0
  113. data/spec/{sequel_core → extensions}/migration_spec.rb +4 -4
  114. data/spec/extensions/pagination_spec.rb +99 -0
  115. data/spec/extensions/pretty_table_spec.rb +91 -0
  116. data/spec/extensions/query_spec.rb +85 -0
  117. data/spec/{sequel_model → extensions}/schema_spec.rb +22 -1
  118. data/spec/extensions/serialization_spec.rb +109 -0
  119. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  120. data/spec/{sequel_model → extensions}/spec_helper.rb +13 -4
  121. data/spec/extensions/string_date_time_spec.rb +93 -0
  122. data/spec/{sequel_model/validations_spec.rb → extensions/validation_class_methods_spec.rb} +15 -103
  123. data/spec/extensions/validation_helpers_spec.rb +291 -0
  124. data/spec/integration/dataset_test.rb +31 -0
  125. data/spec/integration/eager_loader_test.rb +17 -30
  126. data/spec/integration/schema_test.rb +8 -5
  127. data/spec/integration/spec_helper.rb +17 -0
  128. data/spec/integration/transaction_test.rb +68 -0
  129. data/spec/{sequel_model → model}/association_reflection_spec.rb +0 -0
  130. data/spec/{sequel_model → model}/associations_spec.rb +23 -10
  131. data/spec/{sequel_model → model}/base_spec.rb +29 -20
  132. data/spec/{sequel_model → model}/caching_spec.rb +16 -14
  133. data/spec/{sequel_model → model}/dataset_methods_spec.rb +0 -0
  134. data/spec/{sequel_model → model}/eager_loading_spec.rb +8 -8
  135. data/spec/model/hooks_spec.rb +472 -0
  136. data/spec/model/inflector_spec.rb +126 -0
  137. data/spec/{sequel_model → model}/model_spec.rb +25 -20
  138. data/spec/model/plugins_spec.rb +142 -0
  139. data/spec/{sequel_model → model}/record_spec.rb +121 -62
  140. data/spec/model/schema_spec.rb +92 -0
  141. data/spec/model/spec_helper.rb +124 -0
  142. data/spec/model/validations_spec.rb +1080 -0
  143. metadata +136 -107
  144. data/lib/sequel_core/core_ext.rb +0 -217
  145. data/lib/sequel_core/dataset/callback.rb +0 -13
  146. data/lib/sequel_core/dataset/schema.rb +0 -15
  147. data/lib/sequel_core/deprecated.rb +0 -26
  148. data/lib/sequel_core/exceptions.rb +0 -44
  149. data/lib/sequel_core/schema.rb +0 -2
  150. data/lib/sequel_core/schema/sql.rb +0 -325
  151. data/lib/sequel_model/association_reflection.rb +0 -267
  152. data/lib/sequel_model/associations.rb +0 -499
  153. data/lib/sequel_model/base.rb +0 -539
  154. data/lib/sequel_model/caching.rb +0 -82
  155. data/lib/sequel_model/dataset_methods.rb +0 -26
  156. data/lib/sequel_model/eager_loading.rb +0 -370
  157. data/lib/sequel_model/hooks.rb +0 -101
  158. data/lib/sequel_model/plugins.rb +0 -62
  159. data/lib/sequel_model/record.rb +0 -568
  160. data/lib/sequel_model/schema.rb +0 -49
  161. data/lib/sequel_model/validations.rb +0 -429
  162. data/spec/sequel_model/plugins_spec.rb +0 -80
@@ -1,5 +1,4 @@
1
- require 'sequel_core/adapters/utils/date_format'
2
- require 'sequel_core/adapters/utils/unsupported'
1
+ Sequel.require %w'date_format unsupported', 'adapters/utils'
3
2
 
4
3
  module Sequel
5
4
  module Progress
@@ -1,13 +1,13 @@
1
- require 'sequel_core/adapters/utils/unsupported'
1
+ Sequel.require 'adapters/utils/unsupported'
2
2
 
3
3
  module Sequel
4
4
  module SQLite
5
5
  module DatabaseMethods
6
- AUTO_VACUUM = {'0' => :none, '1' => :full, '2' => :incremental}.freeze
7
- SYNCHRONOUS = {'0' => :off, '1' => :normal, '2' => :full}.freeze
6
+ AUTO_VACUUM = [:none, :full, :incremental].freeze
7
+ SYNCHRONOUS = [:off, :normal, :full].freeze
8
8
  TABLES_FILTER = "type = 'table' AND NOT name = 'sqlite_sequence'"
9
- TEMP_STORE = {'0' => :default, '1' => :file, '2' => :memory}.freeze
10
- TYPES = Sequel::Schema::SQL::TYPES.merge(Bignum=>'integer')
9
+ TEMP_STORE = [:default, :file, :memory].freeze
10
+ TYPES = Sequel::Database::TYPES.merge(Bignum=>'integer')
11
11
 
12
12
  # Run all alter_table commands in a transaction. This is technically only
13
13
  # needed for drop column.
@@ -15,6 +15,64 @@ module Sequel
15
15
  transaction{super}
16
16
  end
17
17
 
18
+ # A symbol signifying the value of the auto_vacuum PRAGMA.
19
+ def auto_vacuum
20
+ AUTO_VACUUM[pragma_get(:auto_vacuum).to_i]
21
+ end
22
+
23
+ # Set the auto_vacuum PRAGMA using the given symbol (:none, :full, or
24
+ # :incremental).
25
+ def auto_vacuum=(value)
26
+ value = AUTO_VACUUM.index(value) || (raise Error, "Invalid value for auto_vacuum option. Please specify one of :none, :full, :incremental.")
27
+ pragma_set(:auto_vacuum, value)
28
+ end
29
+
30
+ # Get the value of the given PRAGMA.
31
+ def pragma_get(name)
32
+ self["PRAGMA #{name}"].single_value
33
+ end
34
+
35
+ # Set the value of the given PRAGMA to value.
36
+ def pragma_set(name, value)
37
+ execute_ddl("PRAGMA #{name} = #{value}")
38
+ end
39
+
40
+ # A symbol signifying the value of the synchronous PRAGMA.
41
+ def synchronous
42
+ SYNCHRONOUS[pragma_get(:synchronous).to_i]
43
+ end
44
+
45
+ # Set the synchronous PRAGMA using the given symbol (:off, :normal, or :full).
46
+ def synchronous=(value)
47
+ value = SYNCHRONOUS.index(value) || (raise Error, "Invalid value for synchronous option. Please specify one of :off, :normal, :full.")
48
+ pragma_set(:synchronous, value)
49
+ end
50
+
51
+ # Array of symbols specifying the table names in the current database.
52
+ #
53
+ # Options:
54
+ # * :server - Set the server to use.
55
+ def tables(opts={})
56
+ ds = self[:sqlite_master].server(opts[:server]).filter(TABLES_FILTER)
57
+ ds.identifier_output_method = nil
58
+ ds.identifier_input_method = nil
59
+ ds2 = dataset
60
+ ds.map{|r| ds2.send(:output_identifier, r[:name])}
61
+ end
62
+
63
+ # A symbol signifying the value of the temp_store PRAGMA.
64
+ def temp_store
65
+ TEMP_STORE[pragma_get(:temp_store).to_i]
66
+ end
67
+
68
+ # Set the temp_store PRAGMA using the given symbol (:default, :file, or :memory).
69
+ def temp_store=(value)
70
+ value = TEMP_STORE.index(value) || (raise Error, "Invalid value for temp_store option. Please specify one of :default, :file, :memory.")
71
+ pragma_set(:temp_store, value)
72
+ end
73
+
74
+ private
75
+
18
76
  # SQLite supports limited table modification. You can add a column
19
77
  # or an index. Dropping columns is supported by copying the table into
20
78
  # a temporary table, dropping the table, and creating a new table without
@@ -68,64 +126,6 @@ module Sequel
68
126
  end
69
127
  end
70
128
 
71
- # A symbol signifying the value of the auto_vacuum PRAGMA.
72
- def auto_vacuum
73
- AUTO_VACUUM[pragma_get(:auto_vacuum).to_s]
74
- end
75
-
76
- # Set the auto_vacuum PRAGMA using the given symbol (:none, :full, or
77
- # :incremental).
78
- def auto_vacuum=(value)
79
- value = AUTO_VACUUM.key(value) || (raise Error, "Invalid value for auto_vacuum option. Please specify one of :none, :full, :incremental.")
80
- pragma_set(:auto_vacuum, value)
81
- end
82
-
83
- # Get the value of the given PRAGMA.
84
- def pragma_get(name)
85
- self["PRAGMA #{name}"].single_value
86
- end
87
-
88
- # Set the value of the given PRAGMA to value.
89
- def pragma_set(name, value)
90
- execute_ddl("PRAGMA #{name} = #{value}")
91
- end
92
-
93
- # A symbol signifying the value of the synchronous PRAGMA.
94
- def synchronous
95
- SYNCHRONOUS[pragma_get(:synchronous).to_s]
96
- end
97
-
98
- # Set the synchronous PRAGMA using the given symbol (:off, :normal, or :full).
99
- def synchronous=(value)
100
- value = SYNCHRONOUS.key(value) || (raise Error, "Invalid value for synchronous option. Please specify one of :off, :normal, :full.")
101
- pragma_set(:synchronous, value)
102
- end
103
-
104
- # Array of symbols specifying the table names in the current database.
105
- #
106
- # Options:
107
- # * :server - Set the server to use.
108
- def tables(opts={})
109
- ds = self[:sqlite_master].server(opts[:server]).filter(TABLES_FILTER)
110
- ds.identifier_output_method = nil
111
- ds.identifier_input_method = nil
112
- ds2 = dataset
113
- ds.map{|r| ds2.send(:output_identifier, r[:name])}
114
- end
115
-
116
- # A symbol signifying the value of the temp_store PRAGMA.
117
- def temp_store
118
- TEMP_STORE[pragma_get(:temp_store).to_s]
119
- end
120
-
121
- # Set the temp_store PRAGMA using the given symbol (:default, :file, or :memory).
122
- def temp_store=(value)
123
- value = TEMP_STORE.key(value) || (raise Error, "Invalid value for temp_store option. Please specify one of :default, :file, :memory.")
124
- pragma_set(:temp_store, value)
125
- end
126
-
127
- private
128
-
129
129
  # The array of column symbols in the table, except for ones given in opts[:except]
130
130
  def backup_table_name(table, opts={})
131
131
  (opts[:times]||1000).times do |i|
@@ -172,7 +172,7 @@ module Sequel
172
172
  row[:allow_null] = row.delete(:notnull).to_i == 0
173
173
  row[:default] = row.delete(:dflt_value)
174
174
  row[:primary_key] = row.delete(:pk).to_i == 1
175
- row[:default] = nil if row[:default].blank?
175
+ row[:default] = nil if blank_object?(row[:default])
176
176
  row[:db_type] = row.delete(:type)
177
177
  row[:type] = schema_column_type(row[:db_type])
178
178
  row
@@ -197,6 +197,7 @@ module Sequel
197
197
  # Instance methods for datasets that connect to an SQLite database
198
198
  module DatasetMethods
199
199
  include Dataset::UnsupportedIntersectExceptAll
200
+ include Dataset::UnsupportedIsTrue
200
201
 
201
202
  # SQLite does not support pattern matching via regular expressions.
202
203
  # SQLite is case insensitive (depending on pragma), so use LIKE for
@@ -216,10 +217,14 @@ module Sequel
216
217
  # SQLite performs a TRUNCATE style DELETE if no filter is specified.
217
218
  # Since we want to always return the count of records, add a condition
218
219
  # that is always true and then delete.
219
- def delete(opts = {})
220
+ def delete(opts = (defarg=true;{}))
220
221
  # check if no filter is specified
221
- opts = @opts.merge(opts)
222
- super(opts[:where] ? opts : opts.merge(:where=>{1=>1}))
222
+ if defarg
223
+ @opts[:where] ? super() : filter(1=>1).delete
224
+ else
225
+ opts = @opts.merge(opts)
226
+ super(opts[:where] ? opts : opts.merge(:where=>{1=>1}))
227
+ end
223
228
  end
224
229
 
225
230
  # Insert the values into the database.
@@ -1,5 +1,5 @@
1
1
  require 'sqlite3'
2
- require 'sequel_core/adapters/shared/sqlite'
2
+ Sequel.require 'adapters/shared/sqlite'
3
3
 
4
4
  module Sequel
5
5
  # Top level module for holding all SQLite-related modules and classes
@@ -27,7 +27,7 @@ module Sequel
27
27
  # be available if it is locked, given in milliseconds (default is 5000).
28
28
  def connect(server)
29
29
  opts = server_opts(server)
30
- opts[:database] = ':memory:' if opts[:database].blank?
30
+ opts[:database] = ':memory:' if blank_object?(opts[:database])
31
31
  db = ::SQLite3::Database.new(opts[:database])
32
32
  db.busy_timeout(opts.fetch(:timeout, 5000))
33
33
  db.type_translation = true
@@ -35,7 +35,7 @@ module Sequel
35
35
  # Handle datetime's with Sequel.datetime_class
36
36
  prok = proc do |t,v|
37
37
  v = Time.at(v.to_i).iso8601 if UNIX_EPOCH_TIME_FORMAT.match(v)
38
- v.to_sequel_time
38
+ Sequel.string_to_datetime(v)
39
39
  end
40
40
  db.translator.add_translator("timestamp", &prok)
41
41
  db.translator.add_translator("datetime", &prok)
@@ -86,8 +86,12 @@ module Sequel
86
86
  # Use the native driver transaction method if there isn't already a transaction
87
87
  # in progress on the connection, always yielding a connection inside a transaction
88
88
  # transaction.
89
- def transaction(server=nil, &block)
90
- synchronize(server) do |conn|
89
+ def transaction(opts={})
90
+ unless opts.is_a?(Hash)
91
+ Deprecation.deprecate('Passing an argument other than a Hash to Database#transaction', "Use DB.transaction(:server=>#{opts.inspect})")
92
+ opts = {:server=>opts}
93
+ end
94
+ synchronize(opts[:server]) do |conn|
91
95
  return yield(conn) if conn.transaction_active?
92
96
  begin
93
97
  result = nil
@@ -106,7 +110,7 @@ module Sequel
106
110
  private
107
111
 
108
112
  # Log the SQL and the arguments, and yield an available connection. Rescue
109
- # any SQLite3::Exceptions and turn the into Error::InvalidStatements.
113
+ # any SQLite3::Exceptions and turn the into DatabaseErrors.
110
114
  def _execute(sql, opts)
111
115
  begin
112
116
  log_info(sql, opts[:arguments])
@@ -123,7 +127,7 @@ module Sequel
123
127
  o = super.merge(:pool_convert_exceptions=>false)
124
128
  # Default to only a single connection if a memory database is used,
125
129
  # because otherwise each connection will get a separate database
126
- o[:max_connections] = 1 if @opts[:database] == ':memory:' || @opts[:database].blank?
130
+ o[:max_connections] = 1 if @opts[:database] == ':memory:' || blank_object?(@opts[:database])
127
131
  o
128
132
  end
129
133
 
@@ -40,4 +40,23 @@ class Sequel::Dataset
40
40
  super(ds)
41
41
  end
42
42
  end
43
+
44
+ # This module should be included in the dataset class for all databases that
45
+ # don't support IS [NOT] (TRUE|FALSE)
46
+ module UnsupportedIsTrue
47
+ # Use an = construct instead of IS and an != OR IS NULL construct instead of IS NOT.
48
+ def complex_expression_sql(op, args)
49
+ case op
50
+ when :IS, :'IS NOT'
51
+ isnot = op != :IS
52
+ return super if (v1 = args.at(1)).nil?
53
+ v0 = literal(args.at(0))
54
+ s = "(#{v0} #{'!' if isnot}= #{literal(v1)})"
55
+ s = "(#{s} OR (#{v0} IS NULL))" if isnot
56
+ s
57
+ else
58
+ super(op, args)
59
+ end
60
+ end
61
+ end
43
62
  end
@@ -28,6 +28,7 @@ class Sequel::ConnectionPool
28
28
  #
29
29
  # The connection pool takes the following options:
30
30
  #
31
+ # * :disconnection_proc - The proc called when removing connections from the pool.
31
32
  # * :max_connections - The maximum number of connections the connection pool
32
33
  # will open (default 4)
33
34
  # * :pool_convert_exceptions - Whether to convert non-StandardError based exceptions
@@ -90,7 +91,7 @@ class Sequel::ConnectionPool
90
91
  # If no connection is immediately available and the pool is already using the maximum
91
92
  # number of connections, Pool#hold will block until a connection
92
93
  # is available or the timeout expires. If the timeout expires before a
93
- # connection can be acquired, a Sequel::Error::PoolTimeoutError is
94
+ # connection can be acquired, a Sequel::PoolTimeout is
94
95
  # raised.
95
96
  def hold(server=:default)
96
97
  begin
@@ -102,7 +103,7 @@ class Sequel::ConnectionPool
102
103
  return yield(conn)
103
104
  end
104
105
  until conn = acquire(t, server)
105
- raise(::Sequel::Error::PoolTimeoutError) if Time.new > timeout
106
+ raise(::Sequel::PoolTimeout) if Time.new > timeout
106
107
  sleep sleep_time
107
108
  end
108
109
  begin
@@ -203,9 +204,6 @@ end
203
204
  # A SingleThreadedPool acts as a replacement for a ConnectionPool for use
204
205
  # in single-threaded applications. ConnectionPool imposes a substantial
205
206
  # performance penalty, so SingleThreadedPool is used to gain some speed.
206
- #
207
- # Note that using a single threaded pool with some adapters can cause
208
- # errors in certain cases, see Sequel.single_threaded=.
209
207
  class Sequel::SingleThreadedPool
210
208
  # The proc used to create a new database connection
211
209
  attr_writer :connection_proc
@@ -217,8 +215,12 @@ class Sequel::SingleThreadedPool
217
215
  #
218
216
  # The single threaded pool takes the following options:
219
217
  #
218
+ # * :disconnection_proc - The proc called when removing connections from the pool.
220
219
  # * :pool_convert_exceptions - Whether to convert non-StandardError based exceptions
221
220
  # to RuntimeError exceptions (default true)
221
+ # * :servers - A hash of servers to use. Keys should be symbols. If not
222
+ # present, will use a single :default server. The server name symbol will
223
+ # be passed to the connection_proc.
222
224
  def initialize(opts={}, &block)
223
225
  @connection_proc = block
224
226
  @disconnection_proc = opts[:disconnection_proc]
@@ -0,0 +1,221 @@
1
+ %w'bigdecimal date thread time uri'.each{|f| require f}
2
+
3
+ # Top level module for Sequel
4
+ #
5
+ # There are some class methods that are added via metaprogramming, one for
6
+ # each supported adapter. For example:
7
+ #
8
+ # DB = Sequel.sqlite # Memory database
9
+ # DB = Sequel.sqlite('blog.db')
10
+ # DB = Sequel.postgres('database_name', :user=>'user',
11
+ # :password=>'password', :host=>'host', :port=>5432,
12
+ # :max_connections=>10)
13
+ #
14
+ # If a block is given to these methods, it is passed the opened Database
15
+ # object, which is closed (disconnected) when the block exits, just
16
+ # like a block passed to connect. For example:
17
+ #
18
+ # Sequel.sqlite('blog.db'){|db| puts db[:users].count}
19
+ #
20
+ # Sequel converts the column type tinyint to a boolean by default,
21
+ # you can override the conversion to use tinyint as an integer:
22
+ #
23
+ # Sequel.convert_tinyint_to_bool = false
24
+ #
25
+ # Sequel converts two digit years in Dates and DateTimes by default,
26
+ # so 01/02/03 is interpreted at January 2nd, 2003, and 12/13/99 is interpreted
27
+ # as December 13, 1999. You can override this to treat those dates as
28
+ # January 2nd, 0003 and December 13, 0099, respectively, by setting:
29
+ #
30
+ # Sequel.convert_two_digit_years = false
31
+ #
32
+ # Sequel can use either Time or DateTime for times returned from the
33
+ # database. It defaults to Time. To change it to DateTime, use:
34
+ #
35
+ # Sequel.datetime_class = DateTime
36
+ #
37
+ # Sequel currently does not use instance_eval for virtual row blocks by default
38
+ # (e.g. the block passed to Dataset#filter, #select, #order and other similar
39
+ # methods). If you want to use instance_eval for these blocks, don't have any
40
+ # block arguments, and set:
41
+ #
42
+ # Sequel.virtual_row_instance_eval = true
43
+ #
44
+ # When this is set, you can do:
45
+ #
46
+ # dataset.filter{|o| o.column > 0} # no instance_eval
47
+ # dataset.filter{column > 0} # instance eval
48
+ #
49
+ # When the virtual_row_instance_eval is false, using a virtual row block without a block
50
+ # argument will generate a deprecation message.
51
+ #
52
+ # The option to not use instance_eval for a block with no arguments will be removed in Sequel 3.0.
53
+ # If you have any virtual row blocks that you don't want to use instance_eval for,
54
+ # make sure the blocks have block arguments.
55
+ #
56
+ # You can set the SEQUEL_NO_CORE_EXTENSIONS constant or environment variable to have
57
+ # Sequel not extend the core classes.
58
+ module Sequel
59
+ @convert_tinyint_to_bool = true
60
+ @convert_two_digit_years = true
61
+ @datetime_class = Time
62
+ @virtual_row_instance_eval = false
63
+
64
+ class << self
65
+ attr_accessor :convert_tinyint_to_bool, :convert_two_digit_years, :datetime_class, :virtual_row_instance_eval
66
+ end
67
+
68
+ # Returns true if the passed object could be a specifier of conditions, false otherwise.
69
+ # Currently, Sequel considers hashes and arrays of all two pairs as
70
+ # condition specifiers.
71
+ def self.condition_specifier?(obj)
72
+ case obj
73
+ when Hash
74
+ true
75
+ when Array
76
+ !obj.empty? && obj.all?{|i| (Array === i) && (i.length == 2)}
77
+ else
78
+ false
79
+ end
80
+ end
81
+
82
+ # Creates a new database object based on the supplied connection string
83
+ # and optional arguments. The specified scheme determines the database
84
+ # class used, and the rest of the string specifies the connection options.
85
+ # For example:
86
+ #
87
+ # DB = Sequel.connect('sqlite:/') # Memory database
88
+ # DB = Sequel.connect('sqlite://blog.db') # ./blog.db
89
+ # DB = Sequel.connect('sqlite:///blog.db') # /blog.db
90
+ # DB = Sequel.connect('postgres://user:password@host:port/database_name')
91
+ # DB = Sequel.connect('sqlite:///blog.db', :max_connections=>10)
92
+ #
93
+ # If a block is given, it is passed the opened Database object, which is
94
+ # closed when the block exits. For example:
95
+ #
96
+ # Sequel.connect('sqlite://blog.db'){|db| puts db[:users].count}
97
+ def self.connect(*args, &block)
98
+ Database.connect(*args, &block)
99
+ end
100
+
101
+ # Set the method to call on identifiers going into the database. This affects
102
+ # the literalization of identifiers by calling this method on them before they are input.
103
+ # Sequel upcases identifiers in all SQL strings for most databases, so to turn that off:
104
+ #
105
+ # Sequel.identifier_input_method = nil
106
+ #
107
+ # to downcase instead:
108
+ #
109
+ # Sequel.identifier_input_method = :downcase
110
+ #
111
+ # Other String instance methods work as well.
112
+ def self.identifier_input_method=(value)
113
+ Database.identifier_input_method = value
114
+ end
115
+
116
+ # Set the method to call on identifiers coming out of the database. This affects
117
+ # the literalization of identifiers by calling this method on them when they are
118
+ # retrieved from the database. Sequel downcases identifiers retrieved for most
119
+ # databases, so to turn that off:
120
+ #
121
+ # Sequel.identifier_output_method = nil
122
+ #
123
+ # to upcase instead:
124
+ #
125
+ # Sequel.identifier_output_method = :upcase
126
+ #
127
+ # Other String instance methods work as well.
128
+ def self.identifier_output_method=(value)
129
+ Database.identifier_output_method = value
130
+ end
131
+
132
+ # Set whether to quote identifiers for all databases by default. By default,
133
+ # Sequel quotes identifiers in all SQL strings, so to turn that off:
134
+ #
135
+ # Sequel.quote_identifiers = false
136
+ def self.quote_identifiers=(value)
137
+ Database.quote_identifiers = value
138
+ end
139
+
140
+ # Require all given files which should be in the same or a subdirectory of
141
+ # this file. If a subdir is given, assume all files are in that subdir.
142
+ def self.require(files, subdir=nil)
143
+ Array(files).each{|f| super("#{File.dirname(__FILE__)}/#{"#{subdir}/" if subdir}#{f}")}
144
+ end
145
+
146
+ # Set whether to set the single threaded mode for all databases by default. By default,
147
+ # Sequel uses a threadsafe connection pool, which isn't as fast as the
148
+ # single threaded connection pool. If your program will only have one thread,
149
+ # and speed is a priority, you may want to set this to true:
150
+ #
151
+ # Sequel.single_threaded = true
152
+ def self.single_threaded=(value)
153
+ Database.single_threaded = value
154
+ end
155
+
156
+ # Converts the given string into a Date object.
157
+ def self.string_to_date(s)
158
+ begin
159
+ Date.parse(s, Sequel.convert_two_digit_years)
160
+ rescue => e
161
+ raise InvalidValue, "Invalid Date value '#{self}' (#{e.message})"
162
+ end
163
+ end
164
+
165
+ # Converts the given string into a Time or DateTime object, depending on the
166
+ # value of Sequel.datetime_class.
167
+ def self.string_to_datetime(s)
168
+ begin
169
+ if datetime_class == DateTime
170
+ DateTime.parse(s, convert_two_digit_years)
171
+ else
172
+ datetime_class.parse(s)
173
+ end
174
+ rescue => e
175
+ raise InvalidValue, "Invalid #{datetime_class} value '#{self}' (#{e.message})"
176
+ end
177
+ end
178
+
179
+ # Converts the given string into a Time object.
180
+ def self.string_to_time(s)
181
+ begin
182
+ Time.parse(s)
183
+ rescue => e
184
+ raise InvalidValue, "Invalid Time value '#{self}' (#{e.message})"
185
+ end
186
+ end
187
+
188
+ ### Private Class Methods ###
189
+
190
+ # Helper method that the database adapter class methods that are added to Sequel via
191
+ # metaprogramming use to parse arguments.
192
+ def self.adapter_method(adapter, *args, &block) # :nodoc:
193
+ raise(::Sequel::Error, "Wrong number of arguments, 0-2 arguments valid") if args.length > 2
194
+ opts = {:adapter=>adapter.to_sym}
195
+ opts[:database] = args.shift if args.length >= 1 && !(args[0].is_a?(Hash))
196
+ if Hash === (arg = args[0])
197
+ opts.merge!(arg)
198
+ elsif !arg.nil?
199
+ raise ::Sequel::Error, "Wrong format of arguments, either use (), (String), (Hash), or (String, Hash)"
200
+ end
201
+ connect(opts, &block)
202
+ end
203
+
204
+ # Method that adds a database adapter class method to Sequel that calls
205
+ # Sequel.adapter_method.
206
+ def self.def_adapter_method(*adapters) # :nodoc:
207
+ adapters.each do |adapter|
208
+ instance_eval("def #{adapter}(*args, &block); adapter_method('#{adapter}', *args, &block) end")
209
+ end
210
+ end
211
+
212
+ private_class_method :adapter_method, :def_adapter_method
213
+
214
+ require(%w"metaprogramming sql connection_pool exceptions dataset database version deprecated")
215
+ require(%w"schema_generator schema_methods schema_sql", 'database')
216
+ require(%w"convenience graph prepared_statements sql", 'dataset')
217
+ require('core_sql') if !defined?(::SEQUEL_NO_CORE_EXTENSIONS) && !ENV.has_key?('SEQUEL_NO_CORE_EXTENSIONS')
218
+
219
+ # Add the database adapter class methods to Sequel via metaprogramming
220
+ def_adapter_method(*Database::ADAPTERS)
221
+ end