sequel 2.11.0 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.
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