sequel 4.34.0 → 4.35.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 +30 -0
- data/Rakefile +14 -17
- data/doc/object_model.rdoc +4 -4
- data/doc/release_notes/4.35.0.txt +130 -0
- data/doc/schema_modification.rdoc +8 -3
- data/doc/security.rdoc +3 -3
- data/lib/sequel/adapters/ado.rb +2 -2
- data/lib/sequel/adapters/ado/access.rb +6 -6
- data/lib/sequel/adapters/ado/mssql.rb +2 -2
- data/lib/sequel/adapters/amalgalite.rb +6 -6
- data/lib/sequel/adapters/cubrid.rb +4 -4
- data/lib/sequel/adapters/do.rb +2 -2
- data/lib/sequel/adapters/do/mysql.rb +1 -1
- data/lib/sequel/adapters/do/postgres.rb +1 -1
- data/lib/sequel/adapters/do/sqlite3.rb +1 -1
- data/lib/sequel/adapters/ibmdb.rb +6 -6
- data/lib/sequel/adapters/jdbc.rb +15 -15
- data/lib/sequel/adapters/jdbc/db2.rb +1 -1
- data/lib/sequel/adapters/jdbc/derby.rb +3 -3
- data/lib/sequel/adapters/jdbc/h2.rb +3 -3
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -2
- data/lib/sequel/adapters/jdbc/mssql.rb +1 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +1 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +2 -2
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
- data/lib/sequel/adapters/jdbc/transactions.rb +10 -10
- data/lib/sequel/adapters/mock.rb +1 -1
- data/lib/sequel/adapters/mysql.rb +2 -2
- data/lib/sequel/adapters/mysql2.rb +2 -2
- data/lib/sequel/adapters/odbc.rb +2 -2
- data/lib/sequel/adapters/odbc/mssql.rb +2 -2
- data/lib/sequel/adapters/oracle.rb +9 -9
- data/lib/sequel/adapters/postgres.rb +3 -3
- data/lib/sequel/adapters/shared/mssql.rb +36 -8
- data/lib/sequel/adapters/shared/oracle.rb +15 -0
- data/lib/sequel/adapters/shared/postgres.rb +22 -1
- data/lib/sequel/adapters/sqlanywhere.rb +1 -1
- data/lib/sequel/adapters/sqlite.rb +7 -7
- data/lib/sequel/adapters/swift.rb +3 -3
- data/lib/sequel/adapters/swift/mysql.rb +1 -1
- data/lib/sequel/adapters/swift/postgres.rb +1 -1
- data/lib/sequel/adapters/swift/sqlite.rb +1 -1
- data/lib/sequel/adapters/tinytds.rb +5 -7
- data/lib/sequel/database/logging.rb +18 -3
- data/lib/sequel/database/misc.rb +19 -8
- data/lib/sequel/database/schema_generator.rb +7 -2
- data/lib/sequel/database/schema_methods.rb +9 -2
- data/lib/sequel/database/transactions.rb +52 -18
- data/lib/sequel/dataset/actions.rb +24 -19
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/query.rb +6 -0
- data/lib/sequel/extensions/_pretty_table.rb +1 -1
- data/lib/sequel/extensions/error_sql.rb +3 -3
- data/lib/sequel/extensions/pg_range.rb +10 -1
- data/lib/sequel/extensions/schema_dumper.rb +8 -5
- data/lib/sequel/extensions/server_logging.rb +61 -0
- data/lib/sequel/extensions/sql_comments.rb +91 -0
- data/lib/sequel/model/associations.rb +40 -8
- data/lib/sequel/model/base.rb +19 -5
- data/lib/sequel/plugins/class_table_inheritance.rb +12 -0
- data/lib/sequel/plugins/delay_add_association.rb +1 -0
- data/lib/sequel/plugins/json_serializer.rb +10 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapter_spec.rb +4 -0
- data/spec/adapters/mysql_spec.rb +1 -1
- data/spec/adapters/postgres_spec.rb +3 -2
- data/spec/core/connection_pool_spec.rb +2 -0
- data/spec/core/database_spec.rb +49 -0
- data/spec/core/dataset_spec.rb +25 -1
- data/spec/core/mock_adapter_spec.rb +3 -1
- data/spec/core/schema_generator_spec.rb +1 -1
- data/spec/core_model_spec.rb +2 -0
- data/spec/core_spec.rb +1 -0
- data/spec/extensions/delay_add_association_spec.rb +22 -0
- data/spec/extensions/json_serializer_spec.rb +6 -0
- data/spec/extensions/pg_range_spec.rb +30 -2
- data/spec/extensions/schema_dumper_spec.rb +3 -2
- data/spec/extensions/server_logging_spec.rb +45 -0
- data/spec/extensions/sql_comments_spec.rb +27 -0
- data/spec/files/reversible_migrations/006_reversible.rb +10 -0
- data/spec/files/reversible_migrations/007_reversible.rb +10 -0
- data/spec/integration/dataset_test.rb +28 -2
- data/spec/integration/migrator_test.rb +23 -1
- data/spec/integration/schema_test.rb +12 -32
- data/spec/integration/transaction_test.rb +10 -0
- data/spec/integration/type_test.rb +1 -1
- data/spec/model/eager_loading_spec.rb +16 -0
- data/spec/model/record_spec.rb +9 -0
- data/spec/model_no_assoc_spec.rb +1 -0
- data/spec/model_spec.rb +1 -0
- data/spec/plugin_spec.rb +1 -0
- metadata +16 -2
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
#
|
3
|
+
# The server_logging extension makes the logger include the server/shard
|
4
|
+
# the query was issued on. This makes it easier to use the logs when
|
5
|
+
# using sharding.
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
#
|
9
|
+
# DB.opts[:server]
|
10
|
+
# # {:read_only=>{}, :b=>{}}
|
11
|
+
# DB.extension :server_logging
|
12
|
+
# DB[:a].all
|
13
|
+
# # (0.000005s) (conn: 1014942550, server: read_only) SELECT * FROM a
|
14
|
+
# DB[:a].server(:b).all
|
15
|
+
# # (0.000004s) (conn: 997304100, server: b) SELECT * FROM a
|
16
|
+
# DB[:a].insert
|
17
|
+
# # (0.000004s) (conn: 1014374750, server: default) INSERT INTO a DEFAULT VALUES
|
18
|
+
#
|
19
|
+
# In order for the server/shard to be correct for all connections, you need to
|
20
|
+
# use this before connections to the database are made, or you need to call
|
21
|
+
# <tt>Database#disconnect</tt> after loading this extension.
|
22
|
+
#
|
23
|
+
# Related module: Sequel::ServerLogging
|
24
|
+
|
25
|
+
#
|
26
|
+
module Sequel
|
27
|
+
module ServerLogging
|
28
|
+
# Initialize the hash mapping connections to shards, and turn on logging
|
29
|
+
# of connection info unless it has specifically been turned off.
|
30
|
+
def self.extended(db)
|
31
|
+
db.instance_exec do
|
32
|
+
@server_connection_map ||= {}
|
33
|
+
self.log_connection_info = true if log_connection_info.nil?
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# When setting up a new connection, associate the connection with the
|
38
|
+
# shard.
|
39
|
+
def connect(server)
|
40
|
+
conn = super
|
41
|
+
Sequel.synchronize{@server_connection_map[conn] = server}
|
42
|
+
conn
|
43
|
+
end
|
44
|
+
|
45
|
+
# When disconnecting a connection, remove the related connection from the mapping.
|
46
|
+
def disconnect_connection(conn)
|
47
|
+
super
|
48
|
+
ensure
|
49
|
+
Sequel.synchronize{@server_connection_map.delete(conn)}
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# Include the server with the connection's id.
|
55
|
+
def connection_info(conn)
|
56
|
+
"(conn: #{conn.__id__}, server: #{Sequel.synchronize{@server_connection_map[conn]}}) "
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Database.register_extension(:server_logging, ServerLogging)
|
61
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
#
|
3
|
+
# The sql_comments extension adds Dataset#comment to the datasets,
|
4
|
+
# allowing you to set SQL comments in the resulting query. These
|
5
|
+
# comments are appended to the end of the SQL query:
|
6
|
+
#
|
7
|
+
# ds = DB[:table].comment("Some Comment").all
|
8
|
+
# # SELECT * FROM table -- Some Comment
|
9
|
+
# #
|
10
|
+
#
|
11
|
+
# As you can see, this uses single line SQL comments (--) suffixed
|
12
|
+
# by a newline. This # plugin transforms all consecutive
|
13
|
+
# whitespace in the comment to # a single string:
|
14
|
+
#
|
15
|
+
# ds = DB[:table].comment("Some\r\nComment Here").all
|
16
|
+
# # SELECT * FROM table -- Some Comment Here
|
17
|
+
# #
|
18
|
+
#
|
19
|
+
# The reason for the prefixing and suffixing by newlines is to
|
20
|
+
# work correctly when used in subqueries:
|
21
|
+
#
|
22
|
+
# ds = DB[:table].comment("Some\r\nComment Here")
|
23
|
+
# ds.where(:id=>ds).all
|
24
|
+
# # SELECT * FROM table WHERE (id IN (SELECT * FROM table -- Some Comment Here
|
25
|
+
# # )) -- Some Comment Here
|
26
|
+
# #
|
27
|
+
#
|
28
|
+
# In addition to working on SELECT queries, it also works when
|
29
|
+
# inserting, updating, and deleting.
|
30
|
+
#
|
31
|
+
# Due to the use of single line SQL comments and converting all
|
32
|
+
# whitespace to spaces, this should correctly handle even
|
33
|
+
# malicious input. However, it would be unwise to rely on that,
|
34
|
+
# you should probably attempt to ensure that the argument given
|
35
|
+
# to Dataset#comment is not derived from user input.
|
36
|
+
#
|
37
|
+
# You can load this extension into specific datasets:
|
38
|
+
#
|
39
|
+
# ds = DB[:table]
|
40
|
+
# ds = ds.extension(:sql_comments)
|
41
|
+
#
|
42
|
+
# Or you can load it into all of a database's datasets, which
|
43
|
+
# is probably the desired behavior if you are using this extension:
|
44
|
+
#
|
45
|
+
# DB.extension(:sql_comments)
|
46
|
+
#
|
47
|
+
# Note that Microsoft Access does not support inline comments,
|
48
|
+
# and attempting to use comments on it will result in SQL syntax
|
49
|
+
# errors.
|
50
|
+
#
|
51
|
+
# Related module: Sequel::SQLComments
|
52
|
+
|
53
|
+
#
|
54
|
+
module Sequel
|
55
|
+
module SQLComments
|
56
|
+
# Return a modified copy of the dataset that will use the given comment.
|
57
|
+
# To uncomment a commented dataset, pass nil as the argument.
|
58
|
+
def comment(comment)
|
59
|
+
clone(:comment=>(format_sql_comment(comment) if comment))
|
60
|
+
end
|
61
|
+
|
62
|
+
%w'select insert update delete'.each do |type|
|
63
|
+
define_method(:"#{type}_sql") do |*a|
|
64
|
+
sql = super(*a)
|
65
|
+
if comment = @opts[:comment]
|
66
|
+
# This assumes that the comment stored in the dataset has
|
67
|
+
# already been formatted. If not, this could result in SQL
|
68
|
+
# injection.
|
69
|
+
#
|
70
|
+
# Additionally, due to the use of an SQL comment, if any
|
71
|
+
# SQL is appened to the query after the comment is added,
|
72
|
+
# it will become part of the comment unless it is preceded
|
73
|
+
# by a newline.
|
74
|
+
sql << comment
|
75
|
+
end
|
76
|
+
sql
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
# Format the comment. For maximum compatibility, this uses a
|
83
|
+
# single line SQL comment, and converts all consecutive whitespace
|
84
|
+
# in the comment to a single space.
|
85
|
+
def format_sql_comment(comment)
|
86
|
+
" -- #{comment.to_s.gsub(/\s+/, ' ')}\n"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
Dataset.register_extension(:sql_comments, SQLComments)
|
91
|
+
end
|
@@ -2194,14 +2194,7 @@ module Sequel
|
|
2194
2194
|
|
2195
2195
|
# Add the given associated object to the given association
|
2196
2196
|
def add_associated_object(opts, o, *args)
|
2197
|
-
|
2198
|
-
if o.is_a?(Hash)
|
2199
|
-
o = klass.new(o)
|
2200
|
-
elsif o.is_a?(Integer) || o.is_a?(String) || o.is_a?(Array)
|
2201
|
-
o = klass.with_pk!(o)
|
2202
|
-
elsif !o.is_a?(klass)
|
2203
|
-
raise(Sequel::Error, "associated object #{o.inspect} not of correct type #{klass}")
|
2204
|
-
end
|
2197
|
+
o = make_add_associated_object(opts, o)
|
2205
2198
|
raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk
|
2206
2199
|
ensure_associated_primary_key(opts, o, *args)
|
2207
2200
|
return if run_association_callbacks(opts, :before_add, o) == false
|
@@ -2317,6 +2310,25 @@ module Sequel
|
|
2317
2310
|
opts.send(:cached_fetch, :many_to_one_pk_lookup){opts.primary_key == opts.associated_class.primary_key}
|
2318
2311
|
end
|
2319
2312
|
|
2313
|
+
# Convert the input of the add_* association method into an associated object. For
|
2314
|
+
# hashes, this creates a new object using the hash. For integers, strings, and arrays,
|
2315
|
+
# assume the value specifies a primary key, and lookup an existing object with that primary key.
|
2316
|
+
# Otherwise, if the object is not already an instance of the class, raise an exception.
|
2317
|
+
def make_add_associated_object(opts, o)
|
2318
|
+
klass = opts.associated_class
|
2319
|
+
|
2320
|
+
case o
|
2321
|
+
when Hash
|
2322
|
+
klass.new(o)
|
2323
|
+
when Integer, String, Array
|
2324
|
+
klass.with_pk!(o)
|
2325
|
+
when klass
|
2326
|
+
o
|
2327
|
+
else
|
2328
|
+
raise(Sequel::Error, "associated object #{o.inspect} not of correct type #{klass}")
|
2329
|
+
end
|
2330
|
+
end
|
2331
|
+
|
2320
2332
|
# Remove all associated objects from the given association
|
2321
2333
|
def remove_all_associated_objects(opts, *args)
|
2322
2334
|
raise(Sequel::Error, "model object #{inspect} does not have a primary key") if opts.dataset_need_primary_key? && !pk
|
@@ -2650,6 +2662,26 @@ END
|
|
2650
2662
|
end
|
2651
2663
|
end
|
2652
2664
|
|
2665
|
+
# If the dataset is being eagerly loaded, default to calling all
|
2666
|
+
# instead of each.
|
2667
|
+
def to_hash(key_column=nil, value_column=nil, opts=OPTS)
|
2668
|
+
if (@opts[:eager_graph] || @opts[:eager]) && !opts.has_key?(:all)
|
2669
|
+
opts = Hash[opts]
|
2670
|
+
opts[:all] = true
|
2671
|
+
end
|
2672
|
+
super
|
2673
|
+
end
|
2674
|
+
|
2675
|
+
# If the dataset is being eagerly loaded, default to calling all
|
2676
|
+
# instead of each.
|
2677
|
+
def to_hash_groups(key_column, value_column=nil, opts=OPTS)
|
2678
|
+
if (@opts[:eager_graph] || @opts[:eager]) && !opts.has_key?(:all)
|
2679
|
+
opts = Hash[opts]
|
2680
|
+
opts[:all] = true
|
2681
|
+
end
|
2682
|
+
super
|
2683
|
+
end
|
2684
|
+
|
2653
2685
|
# Do not attempt to split the result set into associations,
|
2654
2686
|
# just return results as simple objects. This is useful if you
|
2655
2687
|
# want to use eager_graph as a shortcut to have all of the joins
|
data/lib/sequel/model/base.rb
CHANGED
@@ -1402,17 +1402,31 @@ module Sequel
|
|
1402
1402
|
@values.keys
|
1403
1403
|
end
|
1404
1404
|
|
1405
|
-
# Refresh this record using +for_update+
|
1406
|
-
# This can be used to make sure no other
|
1407
|
-
# same time.
|
1405
|
+
# Refresh this record using +for_update+ (by default, or the specified style when given)
|
1406
|
+
# unless this is a new record. Returns self. This can be used to make sure no other
|
1407
|
+
# process is updating the record at the same time.
|
1408
|
+
#
|
1409
|
+
# If style is a string, it will be used directly. You should never pass a string
|
1410
|
+
# to this method that is derived from user input, as that can lead to
|
1411
|
+
# SQL injection.
|
1412
|
+
#
|
1413
|
+
# A symbol may be used for database independent locking behavior, but
|
1414
|
+
# all supported symbols have separate methods (e.g. for_update).
|
1415
|
+
#
|
1408
1416
|
#
|
1409
1417
|
# a = Artist[1]
|
1410
1418
|
# Artist.db.transaction do
|
1411
1419
|
# a.lock!
|
1412
1420
|
# a.update(:name=>'A')
|
1413
1421
|
# end
|
1414
|
-
|
1415
|
-
|
1422
|
+
#
|
1423
|
+
# a = Artist[2]
|
1424
|
+
# Artist.db.transaction do
|
1425
|
+
# a.lock!('FOR NO KEY UPDATE')
|
1426
|
+
# a.update(:name=>'B')
|
1427
|
+
# end
|
1428
|
+
def lock!(style=:update)
|
1429
|
+
_refresh(this.lock_style(style)) unless new?
|
1416
1430
|
self
|
1417
1431
|
end
|
1418
1432
|
|
@@ -84,6 +84,18 @@ module Sequel
|
|
84
84
|
# a.values # {:id=>1, name=>'S', :kind=>'CEO'}
|
85
85
|
# a.refresh.values # {:id=>1, name=>'S', :kind=>'Executive', :num_staff=>4, :num_managers=>2}
|
86
86
|
#
|
87
|
+
# You can also load directly from a subclass:
|
88
|
+
#
|
89
|
+
# a = Executive.first
|
90
|
+
# a.values # {:id=>1, name=>'S', :kind=>'Executive', :num_staff=>4, :num_managers=>2}
|
91
|
+
#
|
92
|
+
# Note that when loading from a subclass, because the subclass dataset uses a JOIN,
|
93
|
+
# if you are referencing the primary key column, you need to disambiguate the reference
|
94
|
+
# by explicitly qualifying it:
|
95
|
+
#
|
96
|
+
# a = Executive.where(:id=>1).first # database error
|
97
|
+
# a = Executive.where(:executives__id=>1).first # no error
|
98
|
+
#
|
87
99
|
# = Usage
|
88
100
|
#
|
89
101
|
# # Use the default of storing the class name in the sti_key
|
@@ -38,6 +38,7 @@ module Sequel
|
|
38
38
|
# current object.
|
39
39
|
def add_associated_object(opts, o, *args)
|
40
40
|
if opts.dataset_need_primary_key? && new?
|
41
|
+
o = make_add_associated_object(opts, o)
|
41
42
|
delay_validate_associated_object(opts, o)
|
42
43
|
send(opts[:name]) << o
|
43
44
|
after_create_hook{super(opts, o, *args)}
|
@@ -300,8 +300,16 @@ module Sequel
|
|
300
300
|
if inc.is_a?(Hash)
|
301
301
|
inc.each do |k, v|
|
302
302
|
v = v.empty? ? [] : [v]
|
303
|
-
|
304
|
-
|
303
|
+
|
304
|
+
objs = send(k)
|
305
|
+
|
306
|
+
is_array = if r = model.association_reflection(k)
|
307
|
+
r.returns_array?
|
308
|
+
else
|
309
|
+
objs.is_a?(Array)
|
310
|
+
end
|
311
|
+
|
312
|
+
h[k.to_s] = if is_array
|
305
313
|
objs.map{|obj| Literal.new(Sequel.object_to_json(obj, *v))}
|
306
314
|
else
|
307
315
|
Literal.new(Sequel.object_to_json(objs, *v))
|
data/lib/sequel/version.rb
CHANGED
@@ -5,7 +5,7 @@ module Sequel
|
|
5
5
|
MAJOR = 4
|
6
6
|
# The minor version of Sequel. Bumped for every non-patch level
|
7
7
|
# release, generally around once a month.
|
8
|
-
MINOR =
|
8
|
+
MINOR = 35
|
9
9
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
10
10
|
# releases that fix regressions from previous versions.
|
11
11
|
TINY = 0
|
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -528,7 +528,7 @@ describe "A MySQL database" do
|
|
528
528
|
|
529
529
|
it "should have set_column_type support keep existing options" do
|
530
530
|
@db.create_table(:items){Integer :id, :null=>false, :default=>5}
|
531
|
-
@db.alter_table(:items){set_column_type :id, Bignum}
|
531
|
+
@db.alter_table(:items){set_column_type :id, :Bignum}
|
532
532
|
check_sqls do
|
533
533
|
@db.sqls.must_equal ["CREATE TABLE `items` (`id` integer NOT NULL DEFAULT 5)", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `id` bigint NOT NULL DEFAULT 5"]
|
534
534
|
end
|
@@ -945,7 +945,7 @@ describe "A PostgreSQL database" do
|
|
945
945
|
@db.create_table!(:posts){primary_key :a, :type=>Fixnum}
|
946
946
|
@db[:posts].insert.must_equal 1
|
947
947
|
@db[:posts].insert.must_equal 2
|
948
|
-
@db.create_table!(:posts){primary_key :a, :type
|
948
|
+
@db.create_table!(:posts){primary_key :a, :type=>:Bignum}
|
949
949
|
@db[:posts].insert.must_equal 1
|
950
950
|
@db[:posts].insert.must_equal 2
|
951
951
|
end
|
@@ -973,6 +973,7 @@ describe "A PostgreSQL database" do
|
|
973
973
|
@db[:posts].insert(:title=>'ruby scooby', :body=>'x')
|
974
974
|
|
975
975
|
@db[:posts].full_text_search(:title, 'rails').all.must_equal [{:title=>'ruby rails', :body=>'yowsa'}]
|
976
|
+
@db[:posts].full_text_search(:title, 'rails', :headline=>true).all.must_equal [{:title=>'ruby rails', :body=>'yowsa', :headline=>'ruby <b>rails</b>'}]
|
976
977
|
@db[:posts].full_text_search([:title, :body], ['yowsa', 'rails']).all.must_equal [:title=>'ruby rails', :body=>'yowsa']
|
977
978
|
@db[:posts].full_text_search(:title, 'scooby', :language => 'french').all.must_equal [{:title=>'ruby scooby', :body=>'x'}]
|
978
979
|
|
@@ -997,7 +998,7 @@ describe "A PostgreSQL database" do
|
|
997
998
|
@db[:posts].insert(:title=>t1)
|
998
999
|
@db[:posts].insert(:title=>t2)
|
999
1000
|
@db[:posts].full_text_search(:title, 'ruby & sequel', :rank=>true).select_map(:title).must_equal [t2, t1]
|
1000
|
-
end
|
1001
|
+
end if DB.server_version >= 80300
|
1001
1002
|
|
1002
1003
|
it "should support spatial indexes" do
|
1003
1004
|
@db.create_table(:posts){box :geom; spatial_index [:geom]}
|
@@ -8,6 +8,8 @@ mock_db = lambda do |*a, &b|
|
|
8
8
|
if b2 = a.shift
|
9
9
|
(class << db; self end).send(:define_method, :disconnect_connection){|c| b2.arity == 1 ? b2.call(c) : b2.call}
|
10
10
|
end
|
11
|
+
# Work around JRuby Issue #3854
|
12
|
+
(class << db; self end).send(:public, :connect, :disconnect_connection)
|
11
13
|
db
|
12
14
|
end
|
13
15
|
|
data/spec/core/database_spec.rb
CHANGED
@@ -341,6 +341,35 @@ describe "Database#log_yield" do
|
|
341
341
|
end
|
342
342
|
end
|
343
343
|
|
344
|
+
describe "Database#log_connection_yield" do
|
345
|
+
before do
|
346
|
+
@o = Object.new
|
347
|
+
def @o.logs; @logs || []; end
|
348
|
+
def @o.to_ary; [self]; end
|
349
|
+
def @o.method_missing(*args); (@logs ||= []) << args; end
|
350
|
+
@conn = Object.new
|
351
|
+
@db = Sequel::Database.new(:logger=>@o)
|
352
|
+
end
|
353
|
+
|
354
|
+
it "should log SQL to the loggers" do
|
355
|
+
@db.log_connection_yield("some SQL", @conn){}
|
356
|
+
@o.logs.length.must_equal 1
|
357
|
+
@o.logs.first.length.must_equal 2
|
358
|
+
@o.logs.first.first.must_equal :info
|
359
|
+
@o.logs.first.last.must_match(/some SQL\z/)
|
360
|
+
@o.logs.first.last.wont_match(/\(conn: -?\d+\) some SQL\z/)
|
361
|
+
end
|
362
|
+
|
363
|
+
it "should include connection information when logging" do
|
364
|
+
@db.log_connection_info = true
|
365
|
+
@db.log_connection_yield("some SQL", @conn){}
|
366
|
+
@o.logs.length.must_equal 1
|
367
|
+
@o.logs.first.length.must_equal 2
|
368
|
+
@o.logs.first.first.must_equal :info
|
369
|
+
@o.logs.first.last.must_match(/\(conn: -?\d+\) some SQL\z/)
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
344
373
|
describe "Database#uri" do
|
345
374
|
before do
|
346
375
|
@c = Class.new(Sequel::Database) do
|
@@ -993,6 +1022,15 @@ describe "Database#transaction with savepoint support" do
|
|
993
1022
|
a.must_equal [1, 1]
|
994
1023
|
end
|
995
1024
|
|
1025
|
+
it "should automatically use a savepoint if :rollback=>:always given inside a transaction" do
|
1026
|
+
@db.transaction do
|
1027
|
+
@db.transaction(:rollback=>:always) do
|
1028
|
+
@db.get(1)
|
1029
|
+
end
|
1030
|
+
end
|
1031
|
+
@db.sqls.must_equal ["BEGIN", "SAVEPOINT autopoint_1", "SELECT 1 AS v LIMIT 1", "ROLLBACK TO SAVEPOINT autopoint_1", "COMMIT"]
|
1032
|
+
end
|
1033
|
+
|
996
1034
|
it "should support :retry_on option for automatically retrying transactions inside an :auto_savepoint transaction" do
|
997
1035
|
a = []
|
998
1036
|
@db.transaction(:auto_savepoint=>true) do
|
@@ -1058,6 +1096,17 @@ describe "Database#transaction without savepoint support" do
|
|
1058
1096
|
@db.sqls.must_equal ['BEGIN', 'COMMIT']
|
1059
1097
|
end
|
1060
1098
|
|
1099
|
+
it "should automatically use a savepoint if :rollback=>:always given inside a transaction" do
|
1100
|
+
proc do
|
1101
|
+
@db.transaction do
|
1102
|
+
@db.transaction(:rollback=>:always) do
|
1103
|
+
@db.get(1)
|
1104
|
+
end
|
1105
|
+
end
|
1106
|
+
end.must_raise Sequel::Error
|
1107
|
+
@db.sqls.must_equal ["BEGIN", "ROLLBACK"]
|
1108
|
+
end
|
1109
|
+
|
1061
1110
|
include DatabaseTransactionSpecs
|
1062
1111
|
end
|
1063
1112
|
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -1822,10 +1822,17 @@ describe "Dataset#to_hash_groups" do
|
|
1822
1822
|
@d.to_hash_groups([:a, :b]).must_equal([1, 2] => [{:a => 1, :b => 2}], [3, 4] => [{:a => 3, :b => 4}], [1, 6] => [{:a => 1, :b => 6}], [7, 4] => [{:a => 7, :b => 4}])
|
1823
1823
|
end
|
1824
1824
|
|
1825
|
-
it "should accept
|
1825
|
+
it "should accept a :hash option into which entries can be merged" do
|
1826
1826
|
@d.to_hash_groups(:a, :b, :hash => (tmp = {})).must_be_same_as(tmp)
|
1827
1827
|
end
|
1828
1828
|
|
1829
|
+
it "should accept an :all option to use all into which entries can be merged" do
|
1830
|
+
called = false
|
1831
|
+
meta_def(@d, :post_load){|_| called = true}
|
1832
|
+
@d.to_hash_groups(:a, :b, :all=>true)
|
1833
|
+
called.must_equal true
|
1834
|
+
end
|
1835
|
+
|
1829
1836
|
it "should not call the row_proc if two arguments are given" do
|
1830
1837
|
@d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
|
1831
1838
|
@d.to_hash_groups(:a, :b).must_equal(1 => [2, 6], 3 => [4], 7 => [4])
|
@@ -4534,6 +4541,23 @@ describe "Dataset#lock_style and for_update" do
|
|
4534
4541
|
end
|
4535
4542
|
end
|
4536
4543
|
|
4544
|
+
describe "Dataset#skip_locked" do
|
4545
|
+
before do
|
4546
|
+
@ds = Sequel.mock.dataset.from(:t).for_update
|
4547
|
+
end
|
4548
|
+
|
4549
|
+
it "should raise an error if not supported" do
|
4550
|
+
proc{@ds.skip_locked}.must_raise Sequel::Error
|
4551
|
+
end
|
4552
|
+
|
4553
|
+
it "should skipped locked rows if supported" do
|
4554
|
+
def @ds.supports_skip_locked?; true end
|
4555
|
+
def @ds.select_lock_sql(sql) super; sql << " SKIP LOCKED" if @opts[:skip_locked] end
|
4556
|
+
@ds.sql.must_equal "SELECT * FROM t FOR UPDATE"
|
4557
|
+
@ds.skip_locked.sql.must_equal "SELECT * FROM t FOR UPDATE SKIP LOCKED"
|
4558
|
+
end
|
4559
|
+
end
|
4560
|
+
|
4537
4561
|
describe "Custom ASTTransformer" do
|
4538
4562
|
it "should transform given objects" do
|
4539
4563
|
c = Class.new(Sequel::ASTTransformer) do
|