sequel 3.44.0 → 3.45.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.
- data/CHANGELOG +44 -0
- data/Rakefile +12 -4
- data/doc/reflection.rdoc +3 -3
- data/doc/release_notes/3.45.0.txt +179 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/transactions.rdoc +23 -0
- data/lib/sequel/adapters/db2.rb +1 -0
- data/lib/sequel/adapters/ibmdb.rb +19 -3
- data/lib/sequel/adapters/jdbc.rb +15 -0
- data/lib/sequel/adapters/jdbc/derby.rb +1 -5
- data/lib/sequel/adapters/jdbc/h2.rb +1 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -1
- data/lib/sequel/adapters/jdbc/jtds.rb +5 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +5 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +7 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +1 -1
- data/lib/sequel/adapters/jdbc/transactions.rb +28 -1
- data/lib/sequel/adapters/mysql.rb +4 -0
- data/lib/sequel/adapters/mysql2.rb +5 -1
- data/lib/sequel/adapters/oracle.rb +18 -0
- data/lib/sequel/adapters/postgres.rb +11 -1
- data/lib/sequel/adapters/shared/access.rb +14 -2
- data/lib/sequel/adapters/shared/cubrid.rb +1 -11
- data/lib/sequel/adapters/shared/db2.rb +11 -6
- data/lib/sequel/adapters/shared/mssql.rb +10 -10
- data/lib/sequel/adapters/shared/mysql.rb +11 -1
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +17 -1
- data/lib/sequel/adapters/shared/oracle.rb +16 -15
- data/lib/sequel/adapters/shared/postgres.rb +91 -59
- data/lib/sequel/adapters/shared/sqlite.rb +1 -4
- data/lib/sequel/adapters/tinytds.rb +15 -0
- data/lib/sequel/connection_pool/threaded.rb +1 -1
- data/lib/sequel/core.rb +10 -0
- data/lib/sequel/database/connecting.rb +2 -0
- data/lib/sequel/database/misc.rb +46 -4
- data/lib/sequel/database/query.rb +33 -14
- data/lib/sequel/database/schema_methods.rb +0 -5
- data/lib/sequel/dataset/misc.rb +9 -0
- data/lib/sequel/dataset/mutation.rb +9 -7
- data/lib/sequel/dataset/sql.rb +13 -0
- data/lib/sequel/exceptions.rb +3 -0
- data/lib/sequel/extensions/connection_validator.rb +1 -1
- data/lib/sequel/extensions/date_arithmetic.rb +0 -8
- data/lib/sequel/extensions/eval_inspect.rb +2 -0
- data/lib/sequel/extensions/named_timezones.rb +18 -2
- data/lib/sequel/extensions/pg_array.rb +5 -1
- data/lib/sequel/extensions/pg_array_ops.rb +2 -0
- data/lib/sequel/extensions/pg_hstore.rb +2 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -0
- data/lib/sequel/extensions/pg_json.rb +3 -1
- data/lib/sequel/extensions/pg_range.rb +2 -0
- data/lib/sequel/extensions/pg_range_ops.rb +2 -0
- data/lib/sequel/extensions/pg_row.rb +2 -0
- data/lib/sequel/extensions/pg_row_ops.rb +2 -0
- data/lib/sequel/extensions/query.rb +18 -22
- data/lib/sequel/model/associations.rb +3 -4
- data/lib/sequel/model/base.rb +2 -0
- data/lib/sequel/plugins/force_encoding.rb +2 -0
- data/lib/sequel/plugins/json_serializer.rb +155 -39
- data/lib/sequel/plugins/serialization.rb +14 -2
- data/lib/sequel/plugins/unlimited_update.rb +31 -0
- data/lib/sequel/plugins/validation_class_methods.rb +6 -4
- data/lib/sequel/plugins/xml_serializer.rb +133 -30
- data/lib/sequel/sql.rb +2 -0
- data/lib/sequel/timezones.rb +4 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mysql_spec.rb +0 -11
- data/spec/adapters/postgres_spec.rb +86 -54
- data/spec/adapters/spec_helper.rb +6 -0
- data/spec/core/connection_pool_spec.rb +16 -0
- data/spec/core/database_spec.rb +77 -1
- data/spec/core/dataset_spec.rb +30 -15
- data/spec/core/expression_filters_spec.rb +55 -13
- data/spec/core/mock_adapter_spec.rb +4 -0
- data/spec/core/schema_spec.rb +0 -2
- data/spec/core/spec_helper.rb +5 -0
- data/spec/core_extensions_spec.rb +33 -28
- data/spec/extensions/constraint_validations_spec.rb +2 -2
- data/spec/extensions/core_refinements_spec.rb +12 -12
- data/spec/extensions/json_serializer_spec.rb +137 -31
- data/spec/extensions/named_timezones_spec.rb +10 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +5 -0
- data/spec/extensions/pg_json_spec.rb +14 -0
- data/spec/extensions/pg_row_spec.rb +11 -0
- data/spec/extensions/pretty_table_spec.rb +2 -2
- data/spec/extensions/query_spec.rb +11 -8
- data/spec/extensions/serialization_spec.rb +20 -0
- data/spec/extensions/spec_helper.rb +8 -2
- data/spec/extensions/sql_expr_spec.rb +1 -1
- data/spec/extensions/unlimited_update_spec.rb +20 -0
- data/spec/extensions/xml_serializer_spec.rb +68 -16
- data/spec/integration/dataset_test.rb +28 -0
- data/spec/integration/spec_helper.rb +6 -0
- data/spec/integration/transaction_test.rb +39 -0
- data/spec/model/model_spec.rb +1 -1
- data/spec/sequel_coverage.rb +15 -0
- metadata +8 -3
@@ -1,5 +1,11 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'logger'
|
3
|
+
|
4
|
+
if ENV['COVERAGE']
|
5
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "../sequel_coverage")
|
6
|
+
SimpleCov.sequel_coverage(:group=>%r{lib/sequel/adapters})
|
7
|
+
end
|
8
|
+
|
3
9
|
unless Object.const_defined?('Sequel')
|
4
10
|
$:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
|
5
11
|
require 'sequel/no_core_ext'
|
@@ -256,6 +256,22 @@ shared_examples_for "A threaded connection pool" do
|
|
256
256
|
t.join
|
257
257
|
end
|
258
258
|
|
259
|
+
specify "should wait until a connection is available if all are checked out" do
|
260
|
+
pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:max_connections=>1, :pool_timeout=>0.1, :pool_sleep_time=>0))
|
261
|
+
q, q1 = Queue.new, Queue.new
|
262
|
+
t = Thread.new do
|
263
|
+
pool.hold do |c|
|
264
|
+
q1.push nil
|
265
|
+
3.times{Thread.pass}
|
266
|
+
q.pop
|
267
|
+
end
|
268
|
+
end
|
269
|
+
q1.pop
|
270
|
+
proc{pool.hold{}}.should raise_error(Sequel::PoolTimeout)
|
271
|
+
q.push nil
|
272
|
+
t.join
|
273
|
+
end
|
274
|
+
|
259
275
|
specify "should not have all_connections yield all available connections" do
|
260
276
|
pool = Sequel::ConnectionPool.get_pool(mock_db.call(&@icpp), @cp_opts.merge(:max_connections=>2, :pool_timeout=>0))
|
261
277
|
q, q1 = Queue.new, Queue.new
|
data/spec/core/database_spec.rb
CHANGED
@@ -656,9 +656,58 @@ shared_examples_for "Database#transaction" do
|
|
656
656
|
a.should == [1, 1]
|
657
657
|
end
|
658
658
|
|
659
|
-
specify "should
|
659
|
+
specify "should support :retry_on option for automatically retrying transactions" do
|
660
|
+
a = []
|
661
|
+
@db.transaction(:retry_on=>Sequel::DatabaseDisconnectError){a << 1; raise Sequel::DatabaseDisconnectError if a.length < 2}
|
662
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK', 'BEGIN', 'COMMIT']
|
663
|
+
a.should == [1, 1]
|
664
|
+
|
665
|
+
a = []
|
666
|
+
@db.transaction(:retry_on=>[Sequel::ConstraintViolation, Sequel::SerializationFailure]) do
|
667
|
+
a << 1
|
668
|
+
raise Sequel::SerializationFailure if a.length == 1
|
669
|
+
raise Sequel::ConstraintViolation if a.length == 2
|
670
|
+
end
|
671
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK', 'BEGIN', 'ROLLBACK', 'BEGIN', 'COMMIT']
|
672
|
+
a.should == [1, 1, 1]
|
673
|
+
end
|
674
|
+
|
675
|
+
specify "should support :num_retries option for limiting the number of retry times" do
|
676
|
+
a = []
|
677
|
+
lambda do
|
678
|
+
@db.transaction(:num_retries=>1, :retry_on=>[Sequel::ConstraintViolation, Sequel::SerializationFailure]) do
|
679
|
+
a << 1
|
680
|
+
raise Sequel::SerializationFailure if a.length == 1
|
681
|
+
raise Sequel::ConstraintViolation if a.length == 2
|
682
|
+
end
|
683
|
+
end.should raise_error(Sequel::ConstraintViolation)
|
684
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK', 'BEGIN', 'ROLLBACK']
|
685
|
+
a.should == [1, 1]
|
686
|
+
end
|
687
|
+
|
688
|
+
specify "should support :num_retries=>nil option to retry indefinitely" do
|
689
|
+
a = []
|
690
|
+
lambda do
|
691
|
+
@db.transaction(:num_retries=>nil, :retry_on=>[Sequel::ConstraintViolation]) do
|
692
|
+
a << 1
|
693
|
+
raise Sequel::SerializationFailure if a.length >= 100
|
694
|
+
raise Sequel::ConstraintViolation
|
695
|
+
end
|
696
|
+
end.should raise_error(Sequel::SerializationFailure)
|
697
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK'] * 100
|
698
|
+
a.should == [1] * 100
|
699
|
+
end
|
700
|
+
|
701
|
+
specify "should raise an error if using :disconnect=>:retry and :retry_on together" do
|
702
|
+
proc{@db.transaction(:disconnect=>:retry, :retry_on=>Sequel::ConstraintViolation){}}.should raise_error(Sequel::Error)
|
703
|
+
@db.sqls.should == []
|
704
|
+
end
|
705
|
+
|
706
|
+
specify "should raise an error if attempting to use :disconnect=>:retry or :retry_on inside another transaction" do
|
660
707
|
proc{@db.transaction{@db.transaction(:disconnect=>:retry){}}}.should raise_error(Sequel::Error)
|
661
708
|
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
709
|
+
proc{@db.transaction{@db.transaction(:retry_on=>Sequel::ConstraintViolation){}}}.should raise_error(Sequel::Error)
|
710
|
+
@db.sqls.should == ['BEGIN', 'ROLLBACK']
|
662
711
|
end
|
663
712
|
|
664
713
|
specify "should handle returning inside of the block by committing" do
|
@@ -2259,3 +2308,30 @@ describe "Database extensions" do
|
|
2259
2308
|
proc{@db.extension(:foo2)}.should raise_error(Sequel::Error)
|
2260
2309
|
end
|
2261
2310
|
end
|
2311
|
+
|
2312
|
+
describe "Database specific exception classes" do
|
2313
|
+
before do
|
2314
|
+
@db = Sequel.mock
|
2315
|
+
class << @db
|
2316
|
+
attr_accessor :sql_state
|
2317
|
+
|
2318
|
+
def database_exception_sqlstate(exception, opts={})
|
2319
|
+
@sql_state
|
2320
|
+
end
|
2321
|
+
end
|
2322
|
+
end
|
2323
|
+
|
2324
|
+
specify "should use appropriate exception classes for given SQL states" do
|
2325
|
+
@db.fetch = ArgumentError
|
2326
|
+
@db.sql_state = '23502'
|
2327
|
+
proc{@db.get(1)}.should raise_error(Sequel::NotNullConstraintViolation)
|
2328
|
+
@db.sql_state = '23503'
|
2329
|
+
proc{@db.get(1)}.should raise_error(Sequel::ForeignKeyConstraintViolation)
|
2330
|
+
@db.sql_state = '23505'
|
2331
|
+
proc{@db.get(1)}.should raise_error(Sequel::UniqueConstraintViolation)
|
2332
|
+
@db.sql_state = '23513'
|
2333
|
+
proc{@db.get(1)}.should raise_error(Sequel::CheckConstraintViolation)
|
2334
|
+
@db.sql_state = '40001'
|
2335
|
+
proc{@db.get(1)}.should raise_error(Sequel::SerializationFailure)
|
2336
|
+
end
|
2337
|
+
end
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -575,8 +575,8 @@ describe "Dataset#where" do
|
|
575
575
|
@dataset.filter{gdp > d}.sql.should == "SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
|
576
576
|
@dataset.filter{a < 1}.sql.should == 'SELECT * FROM test WHERE (a < 1)'
|
577
577
|
@dataset.filter{(a >= 1) & (b <= 2)}.sql.should == 'SELECT * FROM test WHERE ((a >= 1) AND (b <= 2))'
|
578
|
-
@dataset.filter{c.like 'ABC%'}.sql.should == "SELECT * FROM test WHERE (c LIKE 'ABC%')"
|
579
|
-
@dataset.filter{c.like 'ABC%', '%XYZ'}.sql.should == "SELECT * FROM test WHERE ((c LIKE 'ABC%') OR (c LIKE '%XYZ'))"
|
578
|
+
@dataset.filter{c.like 'ABC%'}.sql.should == "SELECT * FROM test WHERE (c LIKE 'ABC%' ESCAPE '\\')"
|
579
|
+
@dataset.filter{c.like 'ABC%', '%XYZ'}.sql.should == "SELECT * FROM test WHERE ((c LIKE 'ABC%' ESCAPE '\\') OR (c LIKE '%XYZ' ESCAPE '\\'))"
|
580
580
|
end
|
581
581
|
|
582
582
|
specify "should work for grouped datasets" do
|
@@ -2047,6 +2047,11 @@ describe "Dataset#from_self" do
|
|
2047
2047
|
ds.from(:a).with(:a, ds.from(:b)).from_self.sql.should == 'WITH a AS (SELECT * FROM b) SELECT * FROM (SELECT * FROM a) AS t1'
|
2048
2048
|
ds.from(:a, :c).with(:a, ds.from(:b)).with(:c, ds.from(:d)).from_self.sql.should == 'WITH a AS (SELECT * FROM b), c AS (SELECT * FROM d) SELECT * FROM (SELECT * FROM a, c) AS t1'
|
2049
2049
|
end
|
2050
|
+
|
2051
|
+
specify "should have working mutation method" do
|
2052
|
+
@ds.from_self!
|
2053
|
+
@ds.sql.should == 'SELECT * FROM (SELECT name FROM test LIMIT 1) AS t1'
|
2054
|
+
end
|
2050
2055
|
end
|
2051
2056
|
|
2052
2057
|
describe "Dataset#join_table" do
|
@@ -3194,47 +3199,47 @@ describe "Dataset#grep" do
|
|
3194
3199
|
end
|
3195
3200
|
|
3196
3201
|
specify "should format a SQL filter correctly" do
|
3197
|
-
@ds.grep(:title, 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby'))"
|
3202
|
+
@ds.grep(:title, 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby' ESCAPE '\\'))"
|
3198
3203
|
end
|
3199
3204
|
|
3200
3205
|
specify "should support multiple columns" do
|
3201
|
-
@ds.grep([:title, :body], 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby') OR (body LIKE 'ruby'))"
|
3206
|
+
@ds.grep([:title, :body], 'ruby').sql.should == "SELECT * FROM posts WHERE ((title LIKE 'ruby' ESCAPE '\\') OR (body LIKE 'ruby' ESCAPE '\\'))"
|
3202
3207
|
end
|
3203
3208
|
|
3204
3209
|
specify "should support multiple search terms" do
|
3205
|
-
@ds.grep(:title, ['abc', 'def']).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def'))"
|
3210
|
+
@ds.grep(:title, ['abc', 'def']).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc' ESCAPE '\\') OR (title LIKE 'def' ESCAPE '\\'))"
|
3206
3211
|
end
|
3207
3212
|
|
3208
3213
|
specify "should support multiple columns and search terms" do
|
3209
|
-
@ds.grep([:title, :body], ['abc', 'def']).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') OR (title LIKE 'def') OR (body LIKE 'abc') OR (body LIKE 'def'))"
|
3214
|
+
@ds.grep([:title, :body], ['abc', 'def']).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc' ESCAPE '\\') OR (title LIKE 'def' ESCAPE '\\') OR (body LIKE 'abc' ESCAPE '\\') OR (body LIKE 'def' ESCAPE '\\'))"
|
3210
3215
|
end
|
3211
3216
|
|
3212
3217
|
specify "should support the :all_patterns option" do
|
3213
|
-
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true).sql.should == "SELECT * FROM posts WHERE (((title LIKE 'abc') OR (body LIKE 'abc')) AND ((title LIKE 'def') OR (body LIKE 'def')))"
|
3218
|
+
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true).sql.should == "SELECT * FROM posts WHERE (((title LIKE 'abc' ESCAPE '\\') OR (body LIKE 'abc' ESCAPE '\\')) AND ((title LIKE 'def' ESCAPE '\\') OR (body LIKE 'def' ESCAPE '\\')))"
|
3214
3219
|
end
|
3215
3220
|
|
3216
3221
|
specify "should support the :all_columns option" do
|
3217
|
-
@ds.grep([:title, :body], ['abc', 'def'], :all_columns=>true).sql.should == "SELECT * FROM posts WHERE (((title LIKE 'abc') OR (title LIKE 'def')) AND ((body LIKE 'abc') OR (body LIKE 'def')))"
|
3222
|
+
@ds.grep([:title, :body], ['abc', 'def'], :all_columns=>true).sql.should == "SELECT * FROM posts WHERE (((title LIKE 'abc' ESCAPE '\\') OR (title LIKE 'def' ESCAPE '\\')) AND ((body LIKE 'abc' ESCAPE '\\') OR (body LIKE 'def' ESCAPE '\\')))"
|
3218
3223
|
end
|
3219
3224
|
|
3220
3225
|
specify "should support the :case_insensitive option" do
|
3221
|
-
@ds.grep([:title, :body], ['abc', 'def'], :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE ((title
|
3226
|
+
@ds.grep([:title, :body], ['abc', 'def'], :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE ((UPPER(title) LIKE UPPER('abc') ESCAPE '\\') OR (UPPER(title) LIKE UPPER('def') ESCAPE '\\') OR (UPPER(body) LIKE UPPER('abc') ESCAPE '\\') OR (UPPER(body) LIKE UPPER('def') ESCAPE '\\'))"
|
3222
3227
|
end
|
3223
3228
|
|
3224
3229
|
specify "should support the :all_patterns and :all_columns options together" do
|
3225
|
-
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :all_columns=>true).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc') AND (body LIKE 'abc') AND (title LIKE 'def') AND (body LIKE 'def'))"
|
3230
|
+
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :all_columns=>true).sql.should == "SELECT * FROM posts WHERE ((title LIKE 'abc' ESCAPE '\\') AND (body LIKE 'abc' ESCAPE '\\') AND (title LIKE 'def' ESCAPE '\\') AND (body LIKE 'def' ESCAPE '\\'))"
|
3226
3231
|
end
|
3227
3232
|
|
3228
3233
|
specify "should support the :all_patterns and :case_insensitive options together" do
|
3229
|
-
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE (((title
|
3234
|
+
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE (((UPPER(title) LIKE UPPER('abc') ESCAPE '\\') OR (UPPER(body) LIKE UPPER('abc') ESCAPE '\\')) AND ((UPPER(title) LIKE UPPER('def') ESCAPE '\\') OR (UPPER(body) LIKE UPPER('def') ESCAPE '\\')))"
|
3230
3235
|
end
|
3231
3236
|
|
3232
3237
|
specify "should support the :all_columns and :case_insensitive options together" do
|
3233
|
-
@ds.grep([:title, :body], ['abc', 'def'], :all_columns=>true, :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE (((title
|
3238
|
+
@ds.grep([:title, :body], ['abc', 'def'], :all_columns=>true, :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE (((UPPER(title) LIKE UPPER('abc') ESCAPE '\\') OR (UPPER(title) LIKE UPPER('def') ESCAPE '\\')) AND ((UPPER(body) LIKE UPPER('abc') ESCAPE '\\') OR (UPPER(body) LIKE UPPER('def') ESCAPE '\\')))"
|
3234
3239
|
end
|
3235
3240
|
|
3236
3241
|
specify "should support the :all_patterns, :all_columns, and :case_insensitive options together" do
|
3237
|
-
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :all_columns=>true, :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE ((title
|
3242
|
+
@ds.grep([:title, :body], ['abc', 'def'], :all_patterns=>true, :all_columns=>true, :case_insensitive=>true).sql.should == "SELECT * FROM posts WHERE ((UPPER(title) LIKE UPPER('abc') ESCAPE '\\') AND (UPPER(body) LIKE UPPER('abc') ESCAPE '\\') AND (UPPER(title) LIKE UPPER('def') ESCAPE '\\') AND (UPPER(body) LIKE UPPER('def') ESCAPE '\\'))"
|
3238
3243
|
end
|
3239
3244
|
|
3240
3245
|
specify "should not support regexps if the database doesn't supports it" do
|
@@ -3245,11 +3250,11 @@ describe "Dataset#grep" do
|
|
3245
3250
|
specify "should support regexps if the database supports it" do
|
3246
3251
|
def @ds.supports_regexp?; true end
|
3247
3252
|
@ds.grep(:title, /ruby/).sql.should == "SELECT * FROM posts WHERE ((title ~ 'ruby'))"
|
3248
|
-
@ds.grep(:title, [/^ruby/, 'ruby']).sql.should == "SELECT * FROM posts WHERE ((title ~ '^ruby') OR (title LIKE 'ruby'))"
|
3253
|
+
@ds.grep(:title, [/^ruby/, 'ruby']).sql.should == "SELECT * FROM posts WHERE ((title ~ '^ruby') OR (title LIKE 'ruby' ESCAPE '\\'))"
|
3249
3254
|
end
|
3250
3255
|
|
3251
3256
|
specify "should support searching against other columns" do
|
3252
|
-
@ds.grep(:title, :body).sql.should == "SELECT * FROM posts WHERE ((title LIKE body))"
|
3257
|
+
@ds.grep(:title, :body).sql.should == "SELECT * FROM posts WHERE ((title LIKE body ESCAPE '\\'))"
|
3253
3258
|
end
|
3254
3259
|
end
|
3255
3260
|
|
@@ -4608,3 +4613,13 @@ describe "Dataset#paged_each" do
|
|
4608
4613
|
end
|
4609
4614
|
end
|
4610
4615
|
|
4616
|
+
describe "Dataset#escape_like" do
|
4617
|
+
before do
|
4618
|
+
@ds = Sequel.mock[:test]
|
4619
|
+
end
|
4620
|
+
|
4621
|
+
it "should escape % and _ and \\ characters" do
|
4622
|
+
@ds.escape_like("foo\\%_bar").should == "foo\\\\\\%\\_bar"
|
4623
|
+
end
|
4624
|
+
end
|
4625
|
+
|
@@ -96,9 +96,9 @@ describe "Blockless Ruby Filters" do
|
|
96
96
|
@d.lit(Sequel.expr(:x) - ~Sequel.expr(:y)).should == '(x - NOT y)'
|
97
97
|
@d.lit(Sequel.expr(:x) / (Sequel.expr(:y) & :z)).should == '(x / (y AND z))'
|
98
98
|
@d.lit(Sequel.expr(:x) * (Sequel.expr(:y) | :z)).should == '(x * (y OR z))'
|
99
|
-
@d.lit(Sequel.expr(:x) + Sequel.expr(:y).like('a')).should == "(x + (y LIKE 'a'))"
|
100
|
-
@d.lit(Sequel.expr(:x) - ~Sequel.expr(:y).like('a')).should == "(x - (y NOT LIKE 'a'))"
|
101
|
-
@d.lit(Sequel.join([:x, ~Sequel.expr(:y).like('a')])).should == "(x || (y NOT LIKE 'a'))"
|
99
|
+
@d.lit(Sequel.expr(:x) + Sequel.expr(:y).like('a')).should == "(x + (y LIKE 'a' ESCAPE '\\'))"
|
100
|
+
@d.lit(Sequel.expr(:x) - ~Sequel.expr(:y).like('a')).should == "(x - (y NOT LIKE 'a' ESCAPE '\\'))"
|
101
|
+
@d.lit(Sequel.join([:x, ~Sequel.expr(:y).like('a')])).should == "(x || (y NOT LIKE 'a' ESCAPE '\\'))"
|
102
102
|
end
|
103
103
|
|
104
104
|
it "should support AND conditions via &" do
|
@@ -143,7 +143,7 @@ describe "Blockless Ruby Filters" do
|
|
143
143
|
@d.l(Sequel.expr(Sequel.lit('y') => Sequel.lit('z')) & Sequel.lit('x')).should == '((y = z) AND x)'
|
144
144
|
@d.l((Sequel.lit('x') > 200) & (Sequel.lit('y') < 200)).should == '((x > 200) AND (y < 200))'
|
145
145
|
@d.l(~(Sequel.lit('x') + 1 > 100)).should == '((x + 1) <= 100)'
|
146
|
-
@d.l(Sequel.lit('x').like('a')).should == '(x LIKE \'a\')'
|
146
|
+
@d.l(Sequel.lit('x').like('a')).should == '(x LIKE \'a\' ESCAPE \'\\\')'
|
147
147
|
@d.l(Sequel.lit('x') + 1 > 100).should == '((x + 1) > 100)'
|
148
148
|
@d.l((Sequel.lit('x') * :y) < 100.01).should == '((x * y) < 100.01)'
|
149
149
|
@d.l((Sequel.lit('x') - Sequel.expr(:y)/2) >= 100000000000000000000000000000000000).should == '((x - (y / 2)) >= 100000000000000000000000000000000000)'
|
@@ -380,8 +380,8 @@ describe "Blockless Ruby Filters" do
|
|
380
380
|
@d.lit(d.asc).should == '(SELECT a FROM items) ASC'
|
381
381
|
@d.lit(d.desc).should == '(SELECT a FROM items) DESC'
|
382
382
|
|
383
|
-
@d.lit(d.like(:b)).should == '((SELECT a FROM items) LIKE b)'
|
384
|
-
@d.lit(d.ilike(:b)).should == '((SELECT a FROM items)
|
383
|
+
@d.lit(d.like(:b)).should == '((SELECT a FROM items) LIKE b ESCAPE \'\\\')'
|
384
|
+
@d.lit(d.ilike(:b)).should == '(UPPER((SELECT a FROM items)) LIKE UPPER(b) ESCAPE \'\\\')'
|
385
385
|
end
|
386
386
|
|
387
387
|
it "should handled emulated char_length function" do
|
@@ -781,17 +781,17 @@ describe "Sequel core extension replacements" do
|
|
781
781
|
end
|
782
782
|
|
783
783
|
it "Sequel.like should use a LIKE expression" do
|
784
|
-
l(Sequel.like('a', 'b'), "('a' LIKE 'b')")
|
785
|
-
l(Sequel.like(:a, :b), "(a LIKE b)")
|
784
|
+
l(Sequel.like('a', 'b'), "('a' LIKE 'b' ESCAPE '\\')")
|
785
|
+
l(Sequel.like(:a, :b), "(a LIKE b ESCAPE '\\')")
|
786
786
|
l(Sequel.like(:a, /b/), "(a ~ 'b')")
|
787
|
-
l(Sequel.like(:a, 'c', /b/), "((a LIKE 'c') OR (a ~ 'b'))")
|
787
|
+
l(Sequel.like(:a, 'c', /b/), "((a LIKE 'c' ESCAPE '\\') OR (a ~ 'b'))")
|
788
788
|
end
|
789
789
|
|
790
790
|
it "Sequel.ilike should use an ILIKE expression" do
|
791
|
-
l(Sequel.ilike('a', 'b'), "('a'
|
792
|
-
l(Sequel.ilike(:a, :b), "(a
|
791
|
+
l(Sequel.ilike('a', 'b'), "(UPPER('a') LIKE UPPER('b') ESCAPE '\\')")
|
792
|
+
l(Sequel.ilike(:a, :b), "(UPPER(a) LIKE UPPER(b) ESCAPE '\\')")
|
793
793
|
l(Sequel.ilike(:a, /b/), "(a ~* 'b')")
|
794
|
-
l(Sequel.ilike(:a, 'c', /b/), "((a
|
794
|
+
l(Sequel.ilike(:a, 'c', /b/), "((UPPER(a) LIKE UPPER('c') ESCAPE '\\') OR (a ~* 'b'))")
|
795
795
|
end
|
796
796
|
|
797
797
|
it "Sequel.subscript should use an SQL subscript" do
|
@@ -913,7 +913,7 @@ describe "Sequel::SQL::Wrapper" do
|
|
913
913
|
@ds.literal(s & true).should == "(foo AND 't')"
|
914
914
|
@ds.literal(s < 1).should == "(foo < 1)"
|
915
915
|
@ds.literal(s.sql_subscript(1)).should == "foo[1]"
|
916
|
-
@ds.literal(s.like('a')).should == "(foo LIKE 'a')"
|
916
|
+
@ds.literal(s.like('a')).should == "(foo LIKE 'a' ESCAPE '\\')"
|
917
917
|
@ds.literal(s.as(:a)).should == "foo AS a"
|
918
918
|
@ds.literal(s.cast(Integer)).should == "CAST(foo AS integer)"
|
919
919
|
@ds.literal(s.desc).should == "foo DESC"
|
@@ -1009,3 +1009,45 @@ describe "Sequel.delay" do
|
|
1009
1009
|
proc{Sequel.delay}.should raise_error(Sequel::Error)
|
1010
1010
|
end
|
1011
1011
|
end
|
1012
|
+
|
1013
|
+
describe "Sequel.parse_json" do
|
1014
|
+
before do
|
1015
|
+
Sequel::JSON = Object.new
|
1016
|
+
def (Sequel::JSON).parse(json, opts={})
|
1017
|
+
[json, opts]
|
1018
|
+
end
|
1019
|
+
end
|
1020
|
+
after do
|
1021
|
+
Sequel.send(:remove_const, :JSON)
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
specify "should parse json correctly" do
|
1025
|
+
Sequel.parse_json('[]').should == ['[]', {:create_additions=>false}]
|
1026
|
+
end
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
describe "Sequel::LiteralString" do
|
1030
|
+
before do
|
1031
|
+
@s = Sequel::LiteralString.new("? = ?")
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
specify "should have lit return self if no arguments" do
|
1035
|
+
@s.lit.should equal(@s)
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
specify "should have lit return self if return a placeholder literal string if arguments" do
|
1039
|
+
@s.lit(1, 2).should be_a_kind_of(Sequel::SQL::PlaceholderLiteralString)
|
1040
|
+
Sequel.mock.literal(@s.lit(1, :a)).should == '1 = a'
|
1041
|
+
end
|
1042
|
+
|
1043
|
+
specify "should have to_sequel_blob convert to blob" do
|
1044
|
+
@s.to_sequel_blob.should == @s
|
1045
|
+
@s.to_sequel_blob.should be_a_kind_of(Sequel::SQL::Blob)
|
1046
|
+
end
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
describe "Sequel core extensions" do
|
1050
|
+
specify "should have Sequel.core_extensions? be false by default" do
|
1051
|
+
Sequel.core_extensions?.should be_false
|
1052
|
+
end
|
1053
|
+
end
|
@@ -448,6 +448,10 @@ describe "Sequel Mock Adapter" do
|
|
448
448
|
Sequel.mock(:host=>'postgres').primary_key(:t).should == :id
|
449
449
|
end
|
450
450
|
|
451
|
+
specify "should stub out the bound_variable_arg method for postgres" do
|
452
|
+
Sequel.mock(:host=>'postgres').bound_variable_arg(:t, nil).should == :t
|
453
|
+
end
|
454
|
+
|
451
455
|
specify "should handle creating tables on oracle" do
|
452
456
|
proc{Sequel.mock(:host=>'oracle').create_table(:a){String :b}}.should_not raise_error
|
453
457
|
end
|
data/spec/core/schema_spec.rb
CHANGED
@@ -1393,7 +1393,6 @@ describe "Schema Parser" do
|
|
1393
1393
|
@db.schema(:"number(10,0)").first.last[:type].should == :integer
|
1394
1394
|
@db.schema(:"numeric(10, 10)").first.last[:type].should == :decimal
|
1395
1395
|
@db.schema(:"decimal(10,1)").first.last[:type].should == :decimal
|
1396
|
-
@db.schema(:money).first.last[:type].should == :decimal
|
1397
1396
|
@db.schema(:bytea).first.last[:type].should == :blob
|
1398
1397
|
@db.schema(:blob).first.last[:type].should == :blob
|
1399
1398
|
@db.schema(:image).first.last[:type].should == :blob
|
@@ -1401,7 +1400,6 @@ describe "Schema Parser" do
|
|
1401
1400
|
@db.schema(:nvarchar).first.last[:type].should == :string
|
1402
1401
|
@db.schema(:ntext).first.last[:type].should == :string
|
1403
1402
|
@db.schema(:smalldatetime).first.last[:type].should == :datetime
|
1404
|
-
@db.schema(:smallmoney).first.last[:type].should == :decimal
|
1405
1403
|
@db.schema(:binary).first.last[:type].should == :blob
|
1406
1404
|
@db.schema(:varbinary).first.last[:type].should == :blob
|
1407
1405
|
@db.schema(:enum).first.last[:type].should == :enum
|
data/spec/core/spec_helper.rb
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
|
3
|
+
if ENV['COVERAGE']
|
4
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "../sequel_coverage")
|
5
|
+
SimpleCov.sequel_coverage(:filter=>%r{lib/sequel/(\w+\.rb|(dataset|database|model|connection_pool)/\w+\.rb|adapters/mock\.rb)\z})
|
6
|
+
end
|
7
|
+
|
3
8
|
unless Object.const_defined?('Sequel')
|
4
9
|
$:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
|
5
10
|
SEQUEL_NO_CORE_EXTENSIONS = true
|
@@ -1,5 +1,10 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
|
3
|
+
if ENV['COVERAGE']
|
4
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "sequel_coverage")
|
5
|
+
SimpleCov.sequel_coverage(:filter=>%r{lib/sequel/extensions/core_extensions\.rb\z})
|
6
|
+
end
|
7
|
+
|
3
8
|
unless Object.const_defined?('Sequel') && Sequel.const_defined?('Model')
|
4
9
|
$:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
|
5
10
|
require 'sequel/no_core_ext'
|
@@ -85,16 +90,16 @@ describe "Core extensions" do
|
|
85
90
|
end
|
86
91
|
|
87
92
|
it "should support LIKE via Symbol#like" do
|
88
|
-
@d.l(:x.like('a')).should == '(x LIKE \'a\')'
|
93
|
+
@d.l(:x.like('a')).should == '(x LIKE \'a\' ESCAPE \'\\\')'
|
89
94
|
@d.l(:x.like(/a/)).should == '(x ~ \'a\')'
|
90
|
-
@d.l(:x.like('a', 'b')).should == '((x LIKE \'a\') OR (x LIKE \'b\'))'
|
95
|
+
@d.l(:x.like('a', 'b')).should == '((x LIKE \'a\' ESCAPE \'\\\') OR (x LIKE \'b\' ESCAPE \'\\\'))'
|
91
96
|
@d.l(:x.like(/a/, /b/i)).should == '((x ~ \'a\') OR (x ~* \'b\'))'
|
92
|
-
@d.l(:x.like('a', /b/)).should == '((x LIKE \'a\') OR (x ~ \'b\'))'
|
97
|
+
@d.l(:x.like('a', /b/)).should == '((x LIKE \'a\' ESCAPE \'\\\') OR (x ~ \'b\'))'
|
93
98
|
|
94
|
-
@d.l('a'.like(:x)).should == "('a' LIKE x)"
|
95
|
-
@d.l('a'.like(:x, 'b')).should == "(('a' LIKE x) OR ('a' LIKE 'b'))"
|
96
|
-
@d.l('a'.like(:x, /b/)).should == "(('a' LIKE x) OR ('a' ~ 'b'))"
|
97
|
-
@d.l('a'.like(:x, /b/i)).should == "(('a' LIKE x) OR ('a' ~* 'b'))"
|
99
|
+
@d.l('a'.like(:x)).should == "('a' LIKE x ESCAPE '\\')"
|
100
|
+
@d.l('a'.like(:x, 'b')).should == "(('a' LIKE x ESCAPE '\\') OR ('a' LIKE 'b' ESCAPE '\\'))"
|
101
|
+
@d.l('a'.like(:x, /b/)).should == "(('a' LIKE x ESCAPE '\\') OR ('a' ~ 'b'))"
|
102
|
+
@d.l('a'.like(:x, /b/i)).should == "(('a' LIKE x ESCAPE '\\') OR ('a' ~* 'b'))"
|
98
103
|
|
99
104
|
@d.l(/a/.like(:x)).should == "('a' ~ x)"
|
100
105
|
@d.l(/a/.like(:x, 'b')).should == "(('a' ~ x) OR ('a' ~ 'b'))"
|
@@ -108,16 +113,16 @@ describe "Core extensions" do
|
|
108
113
|
end
|
109
114
|
|
110
115
|
it "should support NOT LIKE via Symbol#like and Symbol#~" do
|
111
|
-
@d.l(~:x.like('a')).should == '(x NOT LIKE \'a\')'
|
116
|
+
@d.l(~:x.like('a')).should == '(x NOT LIKE \'a\' ESCAPE \'\\\')'
|
112
117
|
@d.l(~:x.like(/a/)).should == '(x !~ \'a\')'
|
113
|
-
@d.l(~:x.like('a', 'b')).should == '((x NOT LIKE \'a\') AND (x NOT LIKE \'b\'))'
|
118
|
+
@d.l(~:x.like('a', 'b')).should == '((x NOT LIKE \'a\' ESCAPE \'\\\') AND (x NOT LIKE \'b\' ESCAPE \'\\\'))'
|
114
119
|
@d.l(~:x.like(/a/, /b/i)).should == '((x !~ \'a\') AND (x !~* \'b\'))'
|
115
|
-
@d.l(~:x.like('a', /b/)).should == '((x NOT LIKE \'a\') AND (x !~ \'b\'))'
|
120
|
+
@d.l(~:x.like('a', /b/)).should == '((x NOT LIKE \'a\' ESCAPE \'\\\') AND (x !~ \'b\'))'
|
116
121
|
|
117
|
-
@d.l(~'a'.like(:x)).should == "('a' NOT LIKE x)"
|
118
|
-
@d.l(~'a'.like(:x, 'b')).should == "(('a' NOT LIKE x) AND ('a' NOT LIKE 'b'))"
|
119
|
-
@d.l(~'a'.like(:x, /b/)).should == "(('a' NOT LIKE x) AND ('a' !~ 'b'))"
|
120
|
-
@d.l(~'a'.like(:x, /b/i)).should == "(('a' NOT LIKE x) AND ('a' !~* 'b'))"
|
122
|
+
@d.l(~'a'.like(:x)).should == "('a' NOT LIKE x ESCAPE '\\')"
|
123
|
+
@d.l(~'a'.like(:x, 'b')).should == "(('a' NOT LIKE x ESCAPE '\\') AND ('a' NOT LIKE 'b' ESCAPE '\\'))"
|
124
|
+
@d.l(~'a'.like(:x, /b/)).should == "(('a' NOT LIKE x ESCAPE '\\') AND ('a' !~ 'b'))"
|
125
|
+
@d.l(~'a'.like(:x, /b/i)).should == "(('a' NOT LIKE x ESCAPE '\\') AND ('a' !~* 'b'))"
|
121
126
|
|
122
127
|
@d.l(~/a/.like(:x)).should == "('a' !~ x)"
|
123
128
|
@d.l(~/a/.like(:x, 'b')).should == "(('a' !~ x) AND ('a' !~ 'b'))"
|
@@ -131,16 +136,16 @@ describe "Core extensions" do
|
|
131
136
|
end
|
132
137
|
|
133
138
|
it "should support ILIKE via Symbol#ilike" do
|
134
|
-
@d.l(:x.ilike('a')).should == '(x
|
139
|
+
@d.l(:x.ilike('a')).should == '(UPPER(x) LIKE UPPER(\'a\') ESCAPE \'\\\')'
|
135
140
|
@d.l(:x.ilike(/a/)).should == '(x ~* \'a\')'
|
136
|
-
@d.l(:x.ilike('a', 'b')).should == '((x
|
141
|
+
@d.l(:x.ilike('a', 'b')).should == '((UPPER(x) LIKE UPPER(\'a\') ESCAPE \'\\\') OR (UPPER(x) LIKE UPPER(\'b\') ESCAPE \'\\\'))'
|
137
142
|
@d.l(:x.ilike(/a/, /b/i)).should == '((x ~* \'a\') OR (x ~* \'b\'))'
|
138
|
-
@d.l(:x.ilike('a', /b/)).should == '((x
|
143
|
+
@d.l(:x.ilike('a', /b/)).should == '((UPPER(x) LIKE UPPER(\'a\') ESCAPE \'\\\') OR (x ~* \'b\'))'
|
139
144
|
|
140
|
-
@d.l('a'.ilike(:x)).should == "('a'
|
141
|
-
@d.l('a'.ilike(:x, 'b')).should == "(('a'
|
142
|
-
@d.l('a'.ilike(:x, /b/)).should == "(('a'
|
143
|
-
@d.l('a'.ilike(:x, /b/i)).should == "(('a'
|
145
|
+
@d.l('a'.ilike(:x)).should == "(UPPER('a') LIKE UPPER(x) ESCAPE '\\')"
|
146
|
+
@d.l('a'.ilike(:x, 'b')).should == "((UPPER('a') LIKE UPPER(x) ESCAPE '\\') OR (UPPER('a') LIKE UPPER('b') ESCAPE '\\'))"
|
147
|
+
@d.l('a'.ilike(:x, /b/)).should == "((UPPER('a') LIKE UPPER(x) ESCAPE '\\') OR ('a' ~* 'b'))"
|
148
|
+
@d.l('a'.ilike(:x, /b/i)).should == "((UPPER('a') LIKE UPPER(x) ESCAPE '\\') OR ('a' ~* 'b'))"
|
144
149
|
|
145
150
|
@d.l(/a/.ilike(:x)).should == "('a' ~* x)"
|
146
151
|
@d.l(/a/.ilike(:x, 'b')).should == "(('a' ~* x) OR ('a' ~* 'b'))"
|
@@ -154,16 +159,16 @@ describe "Core extensions" do
|
|
154
159
|
end
|
155
160
|
|
156
161
|
it "should support NOT ILIKE via Symbol#ilike and Symbol#~" do
|
157
|
-
@d.l(~:x.ilike('a')).should == '(x NOT
|
162
|
+
@d.l(~:x.ilike('a')).should == '(UPPER(x) NOT LIKE UPPER(\'a\') ESCAPE \'\\\')'
|
158
163
|
@d.l(~:x.ilike(/a/)).should == '(x !~* \'a\')'
|
159
|
-
@d.l(~:x.ilike('a', 'b')).should == '((x NOT
|
164
|
+
@d.l(~:x.ilike('a', 'b')).should == '((UPPER(x) NOT LIKE UPPER(\'a\') ESCAPE \'\\\') AND (UPPER(x) NOT LIKE UPPER(\'b\') ESCAPE \'\\\'))'
|
160
165
|
@d.l(~:x.ilike(/a/, /b/i)).should == '((x !~* \'a\') AND (x !~* \'b\'))'
|
161
|
-
@d.l(~:x.ilike('a', /b/)).should == '((x NOT
|
166
|
+
@d.l(~:x.ilike('a', /b/)).should == '((UPPER(x) NOT LIKE UPPER(\'a\') ESCAPE \'\\\') AND (x !~* \'b\'))'
|
162
167
|
|
163
|
-
@d.l(~'a'.ilike(:x)).should == "('a' NOT
|
164
|
-
@d.l(~'a'.ilike(:x, 'b')).should == "(('a' NOT
|
165
|
-
@d.l(~'a'.ilike(:x, /b/)).should == "(('a' NOT
|
166
|
-
@d.l(~'a'.ilike(:x, /b/i)).should == "(('a' NOT
|
168
|
+
@d.l(~'a'.ilike(:x)).should == "(UPPER('a') NOT LIKE UPPER(x) ESCAPE '\\')"
|
169
|
+
@d.l(~'a'.ilike(:x, 'b')).should == "((UPPER('a') NOT LIKE UPPER(x) ESCAPE '\\') AND (UPPER('a') NOT LIKE UPPER('b') ESCAPE '\\'))"
|
170
|
+
@d.l(~'a'.ilike(:x, /b/)).should == "((UPPER('a') NOT LIKE UPPER(x) ESCAPE '\\') AND ('a' !~* 'b'))"
|
171
|
+
@d.l(~'a'.ilike(:x, /b/i)).should == "((UPPER('a') NOT LIKE UPPER(x) ESCAPE '\\') AND ('a' !~* 'b'))"
|
167
172
|
|
168
173
|
@d.l(~/a/.ilike(:x)).should == "('a' !~* x)"
|
169
174
|
@d.l(~/a/.ilike(:x, 'b')).should == "(('a' !~* x) AND ('a' !~* 'b'))"
|