sequel 4.16.0 → 4.17.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.
- checksums.yaml +4 -4
- data/CHANGELOG +22 -0
- data/README.rdoc +6 -1
- data/doc/active_record.rdoc +1 -1
- data/doc/model_hooks.rdoc +1 -1
- data/doc/querying.rdoc +1 -1
- data/doc/release_notes/4.16.0.txt +1 -1
- data/doc/release_notes/4.17.0.txt +38 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +13 -0
- data/lib/sequel/adapters/postgres.rb +1 -1
- data/lib/sequel/adapters/shared/postgres.rb +1 -1
- data/lib/sequel/connection_pool.rb +5 -0
- data/lib/sequel/connection_pool/sharded_single.rb +10 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +6 -1
- data/lib/sequel/connection_pool/single.rb +19 -7
- data/lib/sequel/connection_pool/threaded.rb +15 -8
- data/lib/sequel/database/misc.rb +16 -7
- data/lib/sequel/dataset/query.rb +12 -1
- data/lib/sequel/model/base.rb +3 -2
- data/lib/sequel/plugins/sharding.rb +2 -2
- data/lib/sequel/plugins/update_or_create.rb +5 -3
- data/lib/sequel/version.rb +1 -1
- data/spec/core/connection_pool_spec.rb +33 -0
- data/spec/core/database_spec.rb +11 -0
- data/spec/core/dataset_spec.rb +1 -1
- data/spec/core/expression_filters_spec.rb +2 -2
- data/spec/extensions/dataset_associations_spec.rb +1 -1
- data/spec/extensions/rcte_tree_spec.rb +2 -2
- data/spec/extensions/update_or_create_spec.rb +6 -0
- data/spec/integration/prepared_statement_test.rb +7 -0
- data/spec/model/record_spec.rb +6 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d6fa8ec8783c8834b984323d9e1c73bef006df5
|
4
|
+
data.tar.gz: 40e551bc46ec90be6a411ca2eec0e4114394b03d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/doc/active_record.rdoc
CHANGED
@@ -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
|
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
|
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 =
|
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#
|
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
|
@@ -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
|
-
|
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
|
-
|
148
|
-
|
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)
|
data/lib/sequel/database/misc.rb
CHANGED
@@ -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
|
-
# :
|
108
|
-
# :
|
109
|
-
# :
|
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
|
data/lib/sequel/dataset/query.rb
CHANGED
@@ -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
|
-
|
1133
|
+
server?(:default)
|
1123
1134
|
end
|
1124
1135
|
|
1125
1136
|
# Treat the +block+ as a virtual_row block if not +nil+ and
|
data/lib/sequel/model/base.rb
CHANGED
@@ -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
|
-
|
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.
|
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)
|
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)
|
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)
|
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
|
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?
|
data/lib/sequel/version.rb
CHANGED
@@ -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 =
|
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}, {})
|
data/spec/core/database_spec.rb
CHANGED
@@ -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)
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -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{|
|
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{|
|
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{|
|
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=>:
|
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, :
|
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, :
|
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)
|
data/spec/model/record_spec.rb
CHANGED
@@ -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.
|
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
|
+
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.
|
739
|
+
rubygems_version: 2.4.4
|
738
740
|
signing_key:
|
739
741
|
specification_version: 4
|
740
742
|
summary: The Database Toolkit for Ruby
|