sequel 4.16.0 → 4.17.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 505bc666a3de9a394dd0bb31e07afff6feca86da
4
- data.tar.gz: 2082ac9b3731827b5c4e0c39859e8471e706a99d
3
+ metadata.gz: 1d6fa8ec8783c8834b984323d9e1c73bef006df5
4
+ data.tar.gz: 40e551bc46ec90be6a411ca2eec0e4114394b03d
5
5
  SHA512:
6
- metadata.gz: f728df92423ad2e207a2db67d89cc7c79819351973c348845978d7ba93826f33caf21b4251dec609c5fcc48c0c13b55460ac2800f7cd36b328d87463c804cc3a
7
- data.tar.gz: 836ab1fb7bc23c595070f15dff4cf300b80d4b4eaf3e024c305d073a84a3a84c19782bef11359e9e96c0cb739206995ac8a4828ece1a5057c66a8c50fee0f87b
6
+ metadata.gz: 06d6af6daccc3ae11f55e17d6b39472509c3ddd90af821e0e6e353dfab49b6b30ea4c213b4596f46f048a6ff3807bcfc9257a13d08d8ccdc9a52d18478e59e6a
7
+ data.tar.gz: 6c31bed38421bb9acf75235b01229fe777baeb311fef31554c4b6070454147d37b4a249650e4c6c788602d5550c0db373546af9066a398aa9d01b2882568b810
data/CHANGELOG CHANGED
@@ -1,3 +1,25 @@
1
+ === 4.17.0 (2014-12-01)
2
+
3
+ * Fix handling of Sequel::SQL::Blob instances in bound variables in the postgres adapter (jeremyevans) (#917)
4
+
5
+ * Add :preconnect Database option for immediately creating the maximum number of connections (jeremyevans)
6
+
7
+ * Support DB.pool.max_size for the single connection pools (jeremyevans)
8
+
9
+ * Work around regression in jdbc-sqlite3 3.8.7 where empty blobs are returned as nil (jeremyevans)
10
+
11
+ * Work around regression in jdbc-sqlite3 3.8.7 when using JDBC getDate method for date parsing (jeremyevans)
12
+
13
+ * Make Model#update_or_create return object if existing object exists but updates are not necessary (contentfree) (#916)
14
+
15
+ * Add Dataset#server? for conditionally setting a default server to use if no default is present (jeremyevans)
16
+
17
+ * Add Database#sharded? for determining if database uses sharding (jeremyevans)
18
+
19
+ * Fix server used by Dataset#insert_select on PostgreSQL (jeremyevans)
20
+
21
+ * Fix server used for deleting model instances when using sharding (jeremyevans)
22
+
1
23
  === 4.16.0 (2014-11-01)
2
24
 
3
25
  * Make Database#create_table? and #create_join_table? not use IF NOT EXISTS if indexes are being added (jeremyevans) (#904)
data/README.rdoc CHANGED
@@ -20,10 +20,15 @@ toolkit for Ruby.
20
20
 
21
21
  * {Website}[http://sequel.jeremyevans.net]
22
22
  * {Source code}[http://github.com/jeremyevans/sequel]
23
- * {Bug tracking}[http://github.com/jeremyevans/sequel/issues]
24
23
  * {Google group}[http://groups.google.com/group/sequel-talk]
24
+ * {IRC}[irc://irc.freenode.net/sequel]
25
+ * {Bug tracking}[http://github.com/jeremyevans/sequel/issues]
25
26
  * {RDoc}[http://sequel.jeremyevans.net/rdoc]
26
27
 
28
+ If you have questions about how to use Sequel, please ask on the
29
+ Google Group or IRC. Only use the the bug tracker to report
30
+ bugs in Sequel, not to ask for help on using Sequel.
31
+
27
32
  To check out the source code:
28
33
 
29
34
  git clone git://github.com/jeremyevans/sequel.git
@@ -756,7 +756,7 @@ ActiveRecord Method :: Notes, Workarounds
756
756
  +silence+ :: No equivalent. Because the logger is handled at the <tt>Sequel::Database</tt> level, there is no thread-safe way to turn it off for specific blocks.
757
757
  +scopes+ :: No equivalent
758
758
  +sti_name+ :: No equivalent.
759
- +update_counters+ :: <tt>Album.where(:id=>:id).update(:counter_name=>:counter_name + 1, :other_counter=>:other_counter - 1)</tt>
759
+ +update_counters+ :: <tt>Album.where(:id=>:id).update(:counter_name=>Sequel.+(:counter_name, 1), :other_counter=>Sequel.-(:other_counter, 1))</tt>
760
760
  +uncached+ :: No equivalent
761
761
 
762
762
  === Instance Methods with Significantly Different Behavior
data/doc/model_hooks.rdoc CHANGED
@@ -96,7 +96,7 @@ Sequel does not provide a simple way to turn off the running of save/create/upda
96
96
 
97
97
  However, you should note that there are plenty of ways to modify the database without saving a model object. One example is by using plain datasets, or one of the model's dataset methods:
98
98
 
99
- Album.where(:name=>'RF').update(:copies_sold=>:copies_sold + 1)
99
+ Album.where(:name=>'RF').update(:copies_sold=>Sequel.+(:copies_sold, 1))
100
100
  # UPDATE albums SET copies_sold = copies_sold + 1 WHERE name = 'RF'
101
101
 
102
102
  In this case, the +update+ method is called on the dataset returned by <tt>Album.where</tt>. Even if there is only a single object with the name RF, this will not call any hooks. If you want model hooks to be called, you need to make sure to operate on a model object:
data/doc/querying.rdoc CHANGED
@@ -292,7 +292,7 @@ in another place. This is what is meant by a functional style API.
292
292
  Let's say we only want to select the id and name columns, and that
293
293
  we want to order by name:
294
294
 
295
- ds3 = ds.order(:name).select(:id, :name)
295
+ ds3 = ds2.order(:name).select(:id, :name)
296
296
  # SELECT id, name FROM artists WHERE name LIKE 'A%' ESCAPE '\' ORDER BY name
297
297
 
298
298
  Note how you don't need to assign the returned value of order to a variable,
@@ -5,7 +5,7 @@
5
5
 
6
6
  * Dataset#distinct now accepts a virtual row block.
7
7
 
8
- * Database#drop_view with :foreign=>true option now drops foreign
8
+ * Database#drop_table with :foreign=>true option now drops foreign
9
9
  tables on PostgreSQL. Database#create_table with :foreign option
10
10
  is now reversible on PostgreSQL.
11
11
 
@@ -0,0 +1,38 @@
1
+ = New Features
2
+
3
+ * A :preconnect Database option has been added, for automatically
4
+ creating the maximum number of connections to the database on
5
+ instantiation. This is useful when there is high latency for
6
+ initial connection setup, where Sequel's usual approach of
7
+ connecting as needed can cause pauses at runtime.
8
+
9
+ * Database#sharded? has been added for checking whether the Database
10
+ object uses multiple servers.
11
+
12
+ * Dataset#server? has been added, for returning a cloned dataset
13
+ associated with the given server/shard if the dataset does not
14
+ already have a server set. This returns the receiver if the
15
+ server has already been set or the Database is not sharded.
16
+
17
+ = Other Improvements
18
+
19
+ * Sequel now uses the correct shard when deleting model instances.
20
+ Previously, the correct shard was only used in the unoptimized
21
+ case, not in the optimized case.
22
+
23
+ * Sequel now uses the correct shard when using Dataset#insert_select
24
+ on PostgreSQL. This was first broken in the 4.13.0 release.
25
+
26
+ * Sequel now correctly handles Sequel::SQL::Blob instances used in
27
+ bound variables in the postgres adapter. Previously this resulted
28
+ in duplicate apostrophes being used.
29
+
30
+ * When using the jdbc/sqlite3 adapter with jdbc-sqlite3 3.8.7, Sequel
31
+ now handles date objects and empty blobs correctly, working around
32
+ bugs in the driver.
33
+
34
+ = Backwards Compatibility
35
+
36
+ * In the update_or_create plugin, Model.update_or_create now always
37
+ returns the object. Previously it would not return the object if
38
+ the object already existed but no updates were necessary.
@@ -71,10 +71,23 @@ module Sequel
71
71
  end
72
72
 
73
73
  # Use getLong instead of getInt for converting integers on SQLite, since SQLite does not enforce a limit of 2**32.
74
+ # Work around regressions in jdbc-sqlite 3.8.7 for date and blob types.
74
75
  def setup_type_convertor_map
75
76
  super
76
77
  @type_convertor_map[Java::JavaSQL::Types::INTEGER] = @type_convertor_map[Java::JavaSQL::Types::BIGINT]
77
78
  @basic_type_convertor_map[Java::JavaSQL::Types::INTEGER] = @basic_type_convertor_map[Java::JavaSQL::Types::BIGINT]
79
+ @type_convertor_map[Java::JavaSQL::Types::DATE] = lambda do |r, i|
80
+ if v = r.getString(i)
81
+ Sequel.string_to_date(v)
82
+ end
83
+ end
84
+ @type_convertor_map[Java::JavaSQL::Types::BLOB] = lambda do |r, i|
85
+ if v = r.getBytes(i)
86
+ Sequel::SQL::Blob.new(String.from_java_bytes(v))
87
+ elsif !r.wasNull
88
+ Sequel::SQL::Blob.new('')
89
+ end
90
+ end
78
91
  end
79
92
  end
80
93
  end
@@ -192,7 +192,7 @@ module Sequel
192
192
  def bound_variable_arg(arg, conn)
193
193
  case arg
194
194
  when Sequel::SQL::Blob
195
- conn.escape_bytea(arg)
195
+ {:value=>arg, :type=>17, :format=>1}
196
196
  when Sequel::SQLTime
197
197
  literal(arg)
198
198
  when DateTime, Time
@@ -1329,7 +1329,7 @@ module Sequel
1329
1329
  # inserting a query if disable_insert_returning is used.
1330
1330
  def insert_select(*values)
1331
1331
  return unless supports_insert_select?
1332
- with_sql_first(insert_select_sql(*values))
1332
+ server?(:default).with_sql_first(insert_select_sql(*values))
1333
1333
  end
1334
1334
 
1335
1335
  # The SQL to use for an insert_select, adds a RETURNING clause to the insert
@@ -13,6 +13,8 @@
13
13
  # connection pool recognizes.
14
14
  # size :: an integer representing the total number of connections in the pool,
15
15
  # or for the given shard/server if sharding is supported.
16
+ # max_size :: an integer representing the maximum size of the connection pool,
17
+ # or the maximum size per shard/server if sharding is supported.
16
18
  #
17
19
  # For sharded connection pools, the sharded API adds the following methods:
18
20
  #
@@ -72,6 +74,9 @@ class Sequel::ConnectionPool
72
74
  # :after_connect :: A callable object called after each new connection is made, with the
73
75
  # connection object (and server argument if the callable accepts 2 arguments),
74
76
  # useful for customizations that you want to apply to all connections.
77
+ # :preconnect :: Automatically create the maximum number of connections, so that they don't
78
+ # need to be created as needed. This is useful when connecting takes a long time
79
+ # and you want to avoid possible latency during runtime.
75
80
  def initialize(db, opts=OPTS)
76
81
  @db = db
77
82
  @after_connect = opts[:after_connect]
@@ -54,6 +54,11 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
54
54
  end
55
55
  end
56
56
 
57
+ # The ShardedSingleConnectionPool always has a maximum size of 1.
58
+ def max_size
59
+ 1
60
+ end
61
+
57
62
  # Remove servers from the connection pool. Primarily used in conjunction with master/slave
58
63
  # or shard configurations. Similar to disconnecting from all given servers,
59
64
  # except that after it is used, future requests for the server will use the
@@ -94,5 +99,10 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
94
99
  @servers[server]
95
100
  end
96
101
 
102
+ # Make sure there is a valid connection for each server.
103
+ def preconnect
104
+ servers.each{|s| hold(s){}}
105
+ end
106
+
97
107
  CONNECTION_POOL_MAP[[true, true]] = self
98
108
  end
@@ -1,4 +1,4 @@
1
- Sequel.require 'connection_pool/threaded'
1
+ require 'sequel/connection_pool/threaded'
2
2
 
3
3
  # The slowest and most advanced connection, dealing with both multi-threaded
4
4
  # access and configurations with multiple shards/servers.
@@ -235,6 +235,11 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
235
235
  sync{@servers[server]}
236
236
  end
237
237
 
238
+ # Create the maximum number of connections to each server immediately.
239
+ def preconnect
240
+ servers.each{|s| (max_size - size(s)).times{checkin_connection(s, make_new(s))}}
241
+ end
242
+
238
243
  # Releases the connection assigned to the supplied thread and server. If the
239
244
  # server or connection given is scheduled for disconnection, remove the
240
245
  # connection instead of releasing it back to the pool.
@@ -2,17 +2,11 @@
2
2
  # It is just a wrapper around a single connection that uses the connection pool
3
3
  # API.
4
4
  class Sequel::SingleConnectionPool < Sequel::ConnectionPool
5
- # The SingleConnectionPool always has a size of 1 if connected
6
- # and 0 if not.
7
- def size
8
- @conn ? 1 : 0
9
- end
10
-
11
5
  # Yield the connection if one has been made.
12
6
  def all_connections
13
7
  yield @conn if @conn
14
8
  end
15
-
9
+
16
10
  # Disconnect the connection from the database.
17
11
  def disconnect(opts=nil)
18
12
  return unless @conn
@@ -30,9 +24,27 @@ class Sequel::SingleConnectionPool < Sequel::ConnectionPool
30
24
  end
31
25
  end
32
26
 
27
+ # The SingleConnectionPool always has a maximum size of 1.
28
+ def max_size
29
+ 1
30
+ end
31
+
33
32
  def pool_type
34
33
  :single
35
34
  end
36
35
 
36
+ # The SingleConnectionPool always has a size of 1 if connected
37
+ # and 0 if not.
38
+ def size
39
+ @conn ? 1 : 0
40
+ end
41
+
42
+ private
43
+
44
+ # Make sure there is a valid connection.
45
+ def preconnect
46
+ hold{}
47
+ end
48
+
37
49
  CONNECTION_POOL_MAP[[true, false]] = self
38
50
  end
@@ -34,12 +34,6 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
34
34
  @sleep_time = Float(opts[:pool_sleep_time] || 0.001)
35
35
  end
36
36
 
37
- # The total number of connections opened, either available or allocated.
38
- # This may not be completely accurate as it isn't protected by the mutex.
39
- def size
40
- @allocated.length + @available_connections.length
41
- end
42
-
43
37
  # Yield all of the available connections, and the one currently allocated to
44
38
  # this thread. This will not yield connections currently allocated to other
45
39
  # threads, as it is not safe to operate on them. This holds the mutex while
@@ -117,6 +111,12 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
117
111
  :threaded
118
112
  end
119
113
 
114
+ # The total number of connections opened, either available or allocated.
115
+ # This may not be completely accurate as it isn't protected by the mutex.
116
+ def size
117
+ @allocated.length + @available_connections.length
118
+ end
119
+
120
120
  private
121
121
 
122
122
  # Assigns a connection to the supplied thread, if one
@@ -144,8 +144,10 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
144
144
  conn
145
145
  end
146
146
 
147
- # Alias the default make_new method, so subclasses can call it directly.
148
- alias default_make_new make_new
147
+ unless method_defined?(:default_make_new)
148
+ # Alias the default make_new method, so subclasses can call it directly.
149
+ alias default_make_new make_new
150
+ end
149
151
 
150
152
  # Creates a new connection to the given server if the size of the pool for
151
153
  # the server is less than the maximum size of the pool. The calling code
@@ -176,6 +178,11 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
176
178
  sync{@allocated[thread]}
177
179
  end
178
180
 
181
+ # Create the maximum number of connections immediately.
182
+ def preconnect
183
+ (max_size - size).times{checkin_connection(make_new(nil))}
184
+ end
185
+
179
186
  # Releases the connection assigned to the supplied thread back to the pool.
180
187
  # The calling code should already have the mutex before calling this.
181
188
  def release(thread)
@@ -100,13 +100,14 @@ module Sequel
100
100
  #
101
101
  # Accepts the following options:
102
102
  # :default_string_column_size :: The default size of string columns, 255 by default.
103
- # :identifier_input_method :: A string method symbol to call on identifiers going into the database
104
- # :identifier_output_method :: A string method symbol to call on identifiers coming from the database
105
- # :logger :: A specific logger to use
106
- # :loggers :: An array of loggers to use
107
- # :quote_identifiers :: Whether to quote identifiers
108
- # :servers :: A hash specifying a server/shard specific options, keyed by shard symbol
109
- # :single_threaded :: Whether to use a single-threaded connection pool
103
+ # :identifier_input_method :: A string method symbol to call on identifiers going into the database.
104
+ # :identifier_output_method :: A string method symbol to call on identifiers coming from the database.
105
+ # :logger :: A specific logger to use.
106
+ # :loggers :: An array of loggers to use.
107
+ # :preconnect :: Whether to automatically connect to the maximum number of servers.
108
+ # :quote_identifiers :: Whether to quote identifiers.
109
+ # :servers :: A hash specifying a server/shard specific options, keyed by shard symbol .
110
+ # :single_threaded :: Whether to use a single-threaded connection pool.
110
111
  # :sql_log_level :: Method to use to log SQL to a logger, :info by default.
111
112
  #
112
113
  # All options given are also passed to the connection pool.
@@ -117,6 +118,7 @@ module Sequel
117
118
  self.log_warn_duration = @opts[:log_warn_duration]
118
119
  block ||= proc{|server| connect(server)}
119
120
  @opts[:servers] = {} if @opts[:servers].is_a?(String)
121
+ @sharded = !!@opts[:servers]
120
122
  @opts[:adapter_class] = self.class
121
123
 
122
124
  @opts[:single_threaded] = @single_threaded = typecast_value_boolean(@opts.fetch(:single_threaded, Database.single_threaded))
@@ -143,6 +145,7 @@ module Sequel
143
145
  Sequel.synchronize{::Sequel::DATABASES.push(self)}
144
146
  end
145
147
  Sequel::Database.run_after_initialize(self)
148
+ @pool.send(:preconnect) if typecast_value_boolean(@opts[:preconnect]) && @pool.respond_to?(:preconnect, true)
146
149
  end
147
150
 
148
151
  # If a transaction is not currently in process, yield to the block immediately.
@@ -276,6 +279,12 @@ module Sequel
276
279
  Sequel.synchronize{prepared_statements[name] = ps}
277
280
  end
278
281
 
282
+ # Whether this database instance uses multiple servers, either for sharding
283
+ # or for master/slave.
284
+ def sharded?
285
+ @sharded
286
+ end
287
+
279
288
  # The timezone to use for this database, defaulting to <tt>Sequel.database_timezone</tt>.
280
289
  def timezone
281
290
  @timezone || Sequel.database_timezone
@@ -794,6 +794,17 @@ module Sequel
794
794
  clone(:server=>servr)
795
795
  end
796
796
 
797
+ # If the database uses sharding and the current dataset has not had a
798
+ # server set, return a cloned dataset that uses the given server.
799
+ # Otherwise, return the receiver directly instead of returning a clone.
800
+ def server?(server)
801
+ if db.sharded? && !opts[:server]
802
+ server(server)
803
+ else
804
+ self
805
+ end
806
+ end
807
+
797
808
  # Unbind bound variables from this dataset's filter and return an array of two
798
809
  # objects. The first object is a modified dataset where the filter has been
799
810
  # replaced with one that uses bound variable placeholders. The second object
@@ -1119,7 +1130,7 @@ module Sequel
1119
1130
  # Return self if the dataset already has a server, or a cloned dataset with the
1120
1131
  # default server otherwise.
1121
1132
  def default_server
1122
- @opts[:server] ? self : clone(:server=>:default)
1133
+ server?(:default)
1123
1134
  end
1124
1135
 
1125
1136
  # Treat the +block+ as a virtual_row block if not +nil+ and
@@ -1752,7 +1752,8 @@ module Sequel
1752
1752
  def _delete_without_checking
1753
1753
  if sql = (m = model).fast_instance_delete_sql
1754
1754
  sql = sql.dup
1755
- (ds = m.dataset).literal_append(sql, pk)
1755
+ ds = use_server(m.dataset)
1756
+ ds.literal_append(sql, pk)
1756
1757
  ds.with_sql_delete(sql)
1757
1758
  else
1758
1759
  _delete_dataset.delete
@@ -1903,7 +1904,7 @@ module Sequel
1903
1904
  # default values of all columns. Separated from _save so it
1904
1905
  # can be overridden to avoid the refresh.
1905
1906
  def _save_refresh
1906
- _save_set_values(_refresh_get(this.opts[:server] ? this : this.server(:default)) || raise(Error, "Record not found"))
1907
+ _save_set_values(_refresh_get(this.server?(:default)) || raise(Error, "Record not found"))
1907
1908
  changed_columns.clear
1908
1909
  end
1909
1910
 
@@ -30,7 +30,7 @@ module Sequel
30
30
  eb = eo[:eager_block]
31
31
  set_server = proc do |ds|
32
32
  ds = eb.call(ds) if eb
33
- ds = ds.server(server) unless ds.opts[:server]
33
+ ds = ds.server?(server)
34
34
  ds
35
35
  end
36
36
  eo = eo.merge(:eager_block=>set_server)
@@ -53,7 +53,7 @@ module Sequel
53
53
  def eager_graph_dataset(opts, eager_options)
54
54
  ds = super
55
55
  if s = eager_options[:self].opts[:server]
56
- ds = ds.server(s) unless ds.opts[:server]
56
+ ds = ds.server?(s)
57
57
  end
58
58
  ds
59
59
  end
@@ -41,14 +41,16 @@ module Sequel
41
41
  # create a new record with the columns specified by both +attrs+ and
42
42
  # +set_attrs+, with the ones in +set_attrs+ taking priority. If
43
43
  # a block is given, the object is yielded to the block before the
44
- # object is saved.
44
+ # object is saved. Returns the new or updated object.
45
45
  def update_or_create(attrs, set_attrs=nil, &block)
46
- find_or_new(attrs, set_attrs, &block).save_changes
46
+ obj = find_or_new(attrs, set_attrs, &block)
47
+ obj.save_changes
48
+ obj
47
49
  end
48
50
 
49
51
  # Operates the same as +update_or_create+, but returns the objects
50
52
  # without persisting changes (no UPDATE/INSERT queries).
51
- def find_or_new(attrs, set_attrs=nil, &block)
53
+ def find_or_new(attrs, set_attrs=nil)
52
54
  obj = find(attrs) || new(attrs)
53
55
  obj.set(set_attrs) if set_attrs
54
56
  yield obj if block_given?
@@ -3,7 +3,7 @@ module Sequel
3
3
  MAJOR = 4
4
4
  # The minor version of Sequel. Bumped for every non-patch level
5
5
  # release, generally around once a month.
6
- MINOR = 16
6
+ MINOR = 17
7
7
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
8
8
  # releases that fix regressions from previous versions.
9
9
  TINY = 0
@@ -488,6 +488,13 @@ describe "A connection pool with multiple servers" do
488
488
  @pool = Sequel::ConnectionPool.get_pool(mock_db.call{|server| "#{server}#{ic[server] += 1}"}, CONNECTION_POOL_DEFAULTS.merge(:servers=>{:read_only=>{}}))
489
489
  end
490
490
 
491
+ specify "should support preconnect method that immediately creates the maximum number of connections" do
492
+ @pool.send(:preconnect)
493
+ i = 0
494
+ @pool.all_connections{|c1| i+=1}
495
+ i.should == @pool.max_size * 2
496
+ end
497
+
491
498
  specify "#all_connections should return connections for all servers" do
492
499
  @pool.hold{}
493
500
  @pool.all_connections{|c1| c1.should == "default1"}
@@ -755,6 +762,13 @@ describe "A single threaded pool with multiple servers" do
755
762
  @pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| msp.call}){|c| c}, ST_CONNECTION_POOL_DEFAULTS.merge(:servers=>{:read_only=>{}}))
756
763
  end
757
764
 
765
+ specify "should support preconnect method that immediately creates the maximum number of connections" do
766
+ @pool.send(:preconnect)
767
+ i = 0
768
+ @pool.all_connections{|c1| i+=1}
769
+ i.should == 2
770
+ end
771
+
758
772
  specify "#all_connections should return connections for all servers" do
759
773
  @pool.hold{}
760
774
  @pool.all_connections{|c1| c1.should == :default}
@@ -879,6 +893,25 @@ shared_examples_for "All connection pools classes" do
879
893
  p.hold{|c| p.all_connections{|c1| c.should == c1}}
880
894
  end
881
895
 
896
+ specify "should have a size method that gives the current size of the pool" do
897
+ p = @class.new(mock_db.call{123}, {})
898
+ p.size.should == 0
899
+ p.hold{}
900
+ p.size.should == 1
901
+ end
902
+
903
+ specify "should have a max_size method that gives the maximum size of the pool" do
904
+ @class.new(mock_db.call{123}, {}).max_size.should >= 1
905
+ end
906
+
907
+ specify "should support preconnect method that immediately creates the maximum number of connections" do
908
+ p = @class.new(mock_db.call{123}, {})
909
+ p.send(:preconnect)
910
+ i = 0
911
+ p.all_connections{|c1| i+=1}
912
+ i.should == p.max_size
913
+ end
914
+
882
915
  specify "should be able to modify after_connect proc after the pool is created" do
883
916
  a = []
884
917
  p = @class.new(mock_db.call{123}, {})
@@ -23,6 +23,17 @@ describe "A new Database" do
23
23
  Sequel::Database.new(1 => 2, :logger => [4], :loggers => [3]).loggers.should == [4,3]
24
24
  end
25
25
 
26
+ specify "should support :preconnect option to preconnect to database" do
27
+ @db.pool.size.should == 0
28
+ c = Class.new(Sequel::Database) do
29
+ def connect(_)
30
+ :connect
31
+ end
32
+ end
33
+ db = c.new(1 => 2, :logger => 3, :preconnect=>true)
34
+ db.pool.size.should == db.pool.max_size
35
+ end
36
+
26
37
  specify "should handle the default string column size" do
27
38
  @db.default_string_column_size.should == 255
28
39
  db = Sequel::Database.new(:default_string_column_size=>50)
@@ -3723,7 +3723,7 @@ describe "Sequel::Dataset#qualify" do
3723
3723
  end
3724
3724
 
3725
3725
  specify "should handle SQL::DelayedEvaluations that take dataset arguments" do
3726
- ds = @ds.filter(Sequel.delay{|ds| ds.first_source}).qualify
3726
+ ds = @ds.filter(Sequel.delay{|x| x.first_source}).qualify
3727
3727
  ds.sql.should == 'SELECT t.* FROM t WHERE t.t'
3728
3728
  end
3729
3729
 
@@ -1117,7 +1117,7 @@ describe "Sequel.delay" do
1117
1117
  end
1118
1118
 
1119
1119
  specify "should call the block with the current dataset if it accepts one argument" do
1120
- ds = Sequel.mock[:b].where(Sequel.delay{|ds| ds.first_source})
1120
+ ds = Sequel.mock[:b].where(Sequel.delay{|x| x.first_source})
1121
1121
  ds.sql.should == "SELECT * FROM b WHERE b"
1122
1122
  ds.from(:c).sql.should == "SELECT * FROM c WHERE c"
1123
1123
  end
@@ -1132,7 +1132,7 @@ describe "Sequel.delay" do
1132
1132
  end
1133
1133
 
1134
1134
  specify "should have the condition specifier handling call block with the current dataset if it accepts one argument" do
1135
- ds = Sequel.mock[:b].where(:a=>Sequel.delay{|ds| ds.first_source})
1135
+ ds = Sequel.mock[:b].where(:a=>Sequel.delay{|x| x.first_source})
1136
1136
  ds.sql.should == "SELECT * FROM b WHERE (a = b)"
1137
1137
  ds.from(:c).sql.should == "SELECT * FROM c WHERE (a = c)"
1138
1138
  end
@@ -196,7 +196,7 @@ describe "Sequel::Plugins::DatasetAssociations" do
196
196
  end
197
197
 
198
198
  it "should deal correctly with :order option for one_through_many associations" do
199
- @Artist.one_through_many :otag, :clone=>:otag, :order=>:id, :order=>:tags__name
199
+ @Artist.one_through_many :otag, :clone=>:otag, :order=>:tags__name
200
200
  @Artist.otags.sql.should == 'SELECT tags.* FROM tags WHERE (tags.id IN (SELECT albums_tags.tag_id FROM artists INNER JOIN albums ON (albums.artist_id = artists.id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) INNER JOIN tags ON (tags.id = albums_tags.tag_id) WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND ((albums.artist_id, tags.id) IN (SELECT DISTINCT ON (albums.artist_id) albums.artist_id, tags.id FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) ORDER BY albums.artist_id, tags.name))))) ORDER BY tags.name'
201
201
  end
202
202
 
@@ -367,7 +367,7 @@ describe Sequel::Model, "rcte_tree with composite keys" do
367
367
 
368
368
  it "should eagerly load descendants to a given level" do
369
369
  @c.plugin :rcte_tree, :key=>[:parent_id, :parent_id2]
370
- @ds._fetch = [[{:id=>2, :id2=>3, :parent_id=>1, :parent_id=>2, :name=>'AA'}, {:id=>6, :id2=>7, :parent_id=>2, :parent_id2=>3, :name=>'C'}, {:id=>7, :id2=>8, :parent_id=>1, :parent_id2=>2, :name=>'D'}],
370
+ @ds._fetch = [[{:id=>2, :id2=>3, :parent_id=>1, :parent_id2=>2, :name=>'AA'}, {:id=>6, :id2=>7, :parent_id=>2, :parent_id2=>3, :name=>'C'}, {:id=>7, :id2=>8, :parent_id=>1, :parent_id2=>2, :name=>'D'}],
371
371
  [{:id=>6, :id2=>7, :parent_id=>2, :parent_id2=>3, :name=>'C', :x_root_x_0=>2, :x_root_x_1=>3, :x_level_x=>0}, {:id=>9, :id2=>10, :parent_id=>2, :parent_id2=>3, :name=>'E', :x_root_x_0=>2, :x_root_x_1=>3, :x_level_x=>0},
372
372
  {:id=>3, :id2=>4, :name=>'00', :parent_id=>6, :parent_id2=>7, :x_root_x_0=>6, :x_root_x_1=>7, :x_level_x=>0}, {:id=>3, :id2=>4, :name=>'00', :parent_id=>6, :parent_id2=>7, :x_root_x_0=>2, :x_root_x_1=>3, :x_level_x=>1},
373
373
  {:id=>4, :id2=>5, :name=>'?', :parent_id=>7, :parent_id2=>8, :x_root_x_0=>7, :x_root_x_1=>8, :x_level_x=>0}, {:id=>5, :id2=>6, :name=>'?', :parent_id=>4, :parent_id2=>5, :x_root_x_0=>7, :x_root_x_1=>8, :x_level_x=>1}]]
@@ -375,7 +375,7 @@ describe Sequel::Model, "rcte_tree with composite keys" do
375
375
  sqls = @db.sqls
376
376
  sqls.first.should == "SELECT * FROM nodes"
377
377
  sqls.last.should =~ /WITH t AS \(SELECT parent_id AS x_root_x_0, parent_id2 AS x_root_x_1, nodes\.\*, CAST\(0 AS integer\) AS x_level_x FROM nodes WHERE \(\(parent_id, parent_id2\) IN \(\([267], [378]\), \([267], [378]\), \([267], [378]\)\)\) UNION ALL SELECT t\.x_root_x_0, t\.x_root_x_1, nodes\.\*, \(t\.x_level_x \+ 1\) AS x_level_x FROM nodes INNER JOIN t ON \(\(t\.id = nodes\.parent_id\) AND \(t\.id2 = nodes\.parent_id2\)\) WHERE \(t\.x_level_x < 1\)\) SELECT \* FROM t AS nodes/
378
- os.should == [@c.load(:id=>2, :id2=>3, :parent_id=>1, :parent_id=>2, :name=>'AA'), @c.load(:id=>6, :id2=>7, :parent_id=>2, :parent_id2=>3, :name=>'C'), @c.load(:id=>7, :id2=>8, :parent_id=>1, :parent_id2=>2, :name=>'D')]
378
+ os.should == [@c.load(:id=>2, :id2=>3, :parent_id=>1, :parent_id2=>2, :name=>'AA'), @c.load(:id=>6, :id2=>7, :parent_id=>2, :parent_id2=>3, :name=>'C'), @c.load(:id=>7, :id2=>8, :parent_id=>1, :parent_id2=>2, :name=>'D')]
379
379
  os.map{|o| o.descendants}.should == [[@c.load(:id=>6, :id2=>7, :parent_id=>2, :parent_id2=>3, :name=>'C'), @c.load(:id=>9, :id2=>10, :parent_id=>2, :parent_id2=>3, :name=>'E'), @c.load(:id=>3, :id2=>4, :name=>'00', :parent_id=>6, :parent_id2=>7)],
380
380
  [@c.load(:id=>3, :id2=>4, :name=>'00', :parent_id=>6, :parent_id2=>7)],
381
381
  [@c.load(:id=>4, :id2=>5, :name=>'?', :parent_id=>7, :parent_id2=>8), @c.load(:id=>5, :id2=>6, :name=>'?', :parent_id=>4, :parent_id2=>5)]]
@@ -48,6 +48,12 @@ describe "Sequel::Plugins::UpdateOrCreate" do
48
48
  sqls.shift.should == "SELECT * FROM test WHERE (id = 1) LIMIT 1"
49
49
  end
50
50
 
51
+ it ".update_or_create should return an existing record even if no changes necessary" do
52
+ @db.fetch = [[{:id=>1, :a=>2, :b=>3}]]
53
+ @c.update_or_create(:a=>2){|t| t.b = 3}.should == @c.load(:id=>1, :a=>2, :b=>3)
54
+ @db.sqls.should == ["SELECT * FROM test WHERE (a = 2) LIMIT 1"]
55
+ end
56
+
51
57
  it ".find_or_new should return an existing record" do
52
58
  @db.fetch = [[{:id=>1, :a=>2, :b=>3}]]
53
59
  @c.find_or_new(:a=>2){|t| t.b = 4}.should == @c.load(:id=>1, :a=>2, :b=>4)
@@ -327,6 +327,13 @@ describe "Bound Argument Types" do
327
327
  @ds.get(:file).should == @vs[:file]
328
328
  end
329
329
 
330
+ cspecify "should handle blob type with special characters", [:odbc], [:oracle] do
331
+ @ds.delete
332
+ blob = Sequel.blob("\"'[]`a0 ")
333
+ @ds.prepare(:insert, :ps_blob, {:file=>:$x}).call(:x=>blob)
334
+ @ds.get(:file).should == blob
335
+ end
336
+
330
337
  cspecify "should handle blob type with nil values", [:oracle], [:tinytds], [:jdbc, proc{|db| defined?(Sequel::JDBC::SQLServer::DatabaseMethods) && db.is_a?(Sequel::JDBC::SQLServer::DatabaseMethods)}] do
331
338
  @ds.delete
332
339
  @ds.prepare(:insert, :ps_blob, {:file=>:$x}).call(:x=>nil)
@@ -346,6 +346,12 @@ describe "Model#set_server" do
346
346
  @db.sqls.should == ["DELETE FROM items WHERE (id = 13) -- s1"]
347
347
  end
348
348
 
349
+ it "should set the server to use when deleting when using optimized delete" do
350
+ @c.set_primary_key :id
351
+ @c.load(:id=>13).set_server(:s1).delete
352
+ @db.sqls.should == ["DELETE FROM items WHERE id = 13 -- s1"]
353
+ end
354
+
349
355
  it "should set the server to use for transactions when destroying" do
350
356
  o = @c.load(:id=>13).set_server(:s1)
351
357
  o.use_transactions = true
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.16.0
4
+ version: 4.17.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-01 00:00:00.000000000 Z
11
+ date: 2014-12-01 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: The Database Toolkit for Ruby
14
14
  email: code@jeremyevans.net
@@ -133,6 +133,7 @@ extra_rdoc_files:
133
133
  - doc/release_notes/4.14.0.txt
134
134
  - doc/release_notes/4.15.0.txt
135
135
  - doc/release_notes/4.16.0.txt
136
+ - doc/release_notes/4.17.0.txt
136
137
  files:
137
138
  - CHANGELOG
138
139
  - MIT-LICENSE
@@ -236,6 +237,7 @@ files:
236
237
  - doc/release_notes/4.14.0.txt
237
238
  - doc/release_notes/4.15.0.txt
238
239
  - doc/release_notes/4.16.0.txt
240
+ - doc/release_notes/4.17.0.txt
239
241
  - doc/release_notes/4.2.0.txt
240
242
  - doc/release_notes/4.3.0.txt
241
243
  - doc/release_notes/4.4.0.txt
@@ -734,7 +736,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
734
736
  version: '0'
735
737
  requirements: []
736
738
  rubyforge_project:
737
- rubygems_version: 2.2.2
739
+ rubygems_version: 2.4.4
738
740
  signing_key:
739
741
  specification_version: 4
740
742
  summary: The Database Toolkit for Ruby