sequel 4.45.0 → 4.46.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +108 -0
- data/doc/release_notes/4.46.0.txt +404 -0
- data/doc/security.rdoc +9 -0
- data/doc/sql.rdoc +2 -2
- data/doc/testing.rdoc +1 -1
- data/doc/validations.rdoc +1 -2
- data/lib/sequel/adapters/ado.rb +8 -3
- data/lib/sequel/adapters/ado/access.rb +8 -4
- data/lib/sequel/adapters/ado/mssql.rb +3 -1
- data/lib/sequel/adapters/amalgalite.rb +5 -0
- data/lib/sequel/adapters/cubrid.rb +16 -7
- data/lib/sequel/adapters/do.rb +7 -1
- data/lib/sequel/adapters/do/mysql.rb +8 -4
- data/lib/sequel/adapters/ibmdb.rb +10 -5
- data/lib/sequel/adapters/jdbc.rb +8 -2
- data/lib/sequel/adapters/jdbc/as400.rb +10 -3
- data/lib/sequel/adapters/jdbc/db2.rb +27 -16
- data/lib/sequel/adapters/jdbc/derby.rb +47 -20
- data/lib/sequel/adapters/jdbc/h2.rb +13 -7
- data/lib/sequel/adapters/jdbc/hsqldb.rb +18 -9
- data/lib/sequel/adapters/jdbc/mssql.rb +5 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +3 -2
- data/lib/sequel/adapters/jdbc/oracle.rb +3 -2
- data/lib/sequel/adapters/jdbc/postgresql.rb +4 -3
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +2 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +10 -3
- data/lib/sequel/adapters/jdbc/sqlserver.rb +23 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +16 -10
- data/lib/sequel/adapters/mock.rb +5 -0
- data/lib/sequel/adapters/mysql.rb +8 -1
- data/lib/sequel/adapters/mysql2.rb +6 -1
- data/lib/sequel/adapters/odbc.rb +20 -8
- data/lib/sequel/adapters/odbc/mssql.rb +6 -3
- data/lib/sequel/adapters/oracle.rb +12 -6
- data/lib/sequel/adapters/postgres.rb +20 -8
- data/lib/sequel/adapters/shared/access.rb +76 -47
- data/lib/sequel/adapters/shared/cubrid.rb +16 -11
- data/lib/sequel/adapters/shared/db2.rb +46 -19
- data/lib/sequel/adapters/shared/firebird.rb +20 -8
- data/lib/sequel/adapters/shared/informix.rb +6 -3
- data/lib/sequel/adapters/shared/mssql.rb +132 -72
- data/lib/sequel/adapters/shared/mysql.rb +112 -65
- data/lib/sequel/adapters/shared/oracle.rb +36 -21
- data/lib/sequel/adapters/shared/postgres.rb +91 -56
- data/lib/sequel/adapters/shared/sqlanywhere.rb +65 -37
- data/lib/sequel/adapters/shared/sqlite.rb +67 -32
- data/lib/sequel/adapters/sqlanywhere.rb +9 -1
- data/lib/sequel/adapters/sqlite.rb +8 -1
- data/lib/sequel/adapters/swift.rb +5 -0
- data/lib/sequel/adapters/swift/mysql.rb +4 -2
- data/lib/sequel/adapters/swift/sqlite.rb +1 -1
- data/lib/sequel/adapters/tinytds.rb +10 -3
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +1 -1
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +1 -0
- data/lib/sequel/adapters/utils/pg_types.rb +14 -6
- data/lib/sequel/adapters/utils/replace.rb +4 -2
- data/lib/sequel/connection_pool/single.rb +2 -2
- data/lib/sequel/core.rb +24 -11
- data/lib/sequel/database/connecting.rb +9 -3
- data/lib/sequel/database/dataset_defaults.rb +7 -1
- data/lib/sequel/database/logging.rb +1 -0
- data/lib/sequel/database/misc.rb +5 -2
- data/lib/sequel/database/query.rb +7 -5
- data/lib/sequel/database/schema_generator.rb +1 -0
- data/lib/sequel/database/schema_methods.rb +50 -27
- data/lib/sequel/database/transactions.rb +19 -9
- data/lib/sequel/dataset/actions.rb +15 -6
- data/lib/sequel/dataset/graph.rb +15 -5
- data/lib/sequel/dataset/misc.rb +12 -4
- data/lib/sequel/dataset/mutation.rb +17 -8
- data/lib/sequel/dataset/prepared_statements.rb +3 -2
- data/lib/sequel/dataset/query.rb +84 -38
- data/lib/sequel/dataset/sql.rb +302 -191
- data/lib/sequel/deprecated.rb +26 -17
- data/lib/sequel/extensions/_deprecated_identifier_mangling.rb +2 -2
- data/lib/sequel/extensions/auto_literal_strings.rb +74 -0
- data/lib/sequel/extensions/from_block.rb +1 -0
- data/lib/sequel/extensions/graph_each.rb +1 -1
- data/lib/sequel/extensions/identifier_mangling.rb +2 -2
- data/lib/sequel/extensions/migration.rb +28 -4
- data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -0
- data/lib/sequel/extensions/schema_dumper.rb +4 -4
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +5 -3
- data/lib/sequel/extensions/set_overrides.rb +2 -0
- data/lib/sequel/extensions/split_array_nil.rb +2 -2
- data/lib/sequel/extensions/virtual_row_method_block.rb +44 -0
- data/lib/sequel/model.rb +11 -7
- data/lib/sequel/model/associations.rb +5 -7
- data/lib/sequel/model/base.rb +47 -45
- data/lib/sequel/model/dataset_module.rb +9 -14
- data/lib/sequel/model/plugins.rb +3 -0
- data/lib/sequel/no_core_ext.rb +1 -0
- data/lib/sequel/plugins/blacklist_security.rb +1 -1
- data/lib/sequel/plugins/boolean_subsets.rb +7 -5
- data/lib/sequel/plugins/class_table_inheritance.rb +47 -10
- data/lib/sequel/plugins/dataset_associations.rb +1 -1
- data/lib/sequel/plugins/def_dataset_method.rb +90 -0
- data/lib/sequel/plugins/finder.rb +240 -0
- data/lib/sequel/plugins/inverted_subsets.rb +19 -12
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/nested_attributes.rb +1 -1
- data/lib/sequel/plugins/schema.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +7 -1
- data/lib/sequel/plugins/subset_conditions.rb +11 -3
- data/lib/sequel/plugins/whitelist_security.rb +118 -0
- data/lib/sequel/sql.rb +80 -36
- data/lib/sequel/timezones.rb +2 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +20 -0
- data/spec/adapters/mysql_spec.rb +1 -1
- data/spec/adapters/oracle_spec.rb +12 -8
- data/spec/adapters/postgres_spec.rb +1 -1
- data/spec/adapters/spec_helper.rb +1 -1
- data/spec/adapters/sqlite_spec.rb +36 -34
- data/spec/core/connection_pool_spec.rb +2 -1
- data/spec/core/database_spec.rb +87 -9
- data/spec/core/dataset_spec.rb +501 -129
- data/spec/core/deprecated_spec.rb +1 -1
- data/spec/core/expression_filters_spec.rb +146 -60
- data/spec/core/mock_adapter_spec.rb +1 -1
- data/spec/core/object_graph_spec.rb +61 -9
- data/spec/core/placeholder_literalizer_spec.rb +20 -2
- data/spec/core/schema_generator_spec.rb +6 -6
- data/spec/core/schema_spec.rb +54 -5
- data/spec/core_extensions_spec.rb +122 -18
- data/spec/deprecation_helper.rb +27 -2
- data/spec/extensions/_deprecated_identifier_mangling_spec.rb +6 -6
- data/spec/extensions/association_proxies_spec.rb +2 -2
- data/spec/extensions/auto_literal_strings_spec.rb +212 -0
- data/spec/extensions/blacklist_security_spec.rb +1 -0
- data/spec/extensions/class_table_inheritance_spec.rb +1037 -39
- data/spec/extensions/column_select_spec.rb +20 -8
- data/spec/extensions/columns_introspection_spec.rb +3 -3
- data/spec/extensions/core_refinements_spec.rb +29 -12
- data/spec/extensions/dataset_associations_spec.rb +12 -12
- data/spec/extensions/def_dataset_method_spec.rb +100 -0
- data/spec/extensions/error_sql_spec.rb +1 -1
- data/spec/extensions/finder_spec.rb +260 -0
- data/spec/extensions/graph_each_spec.rb +2 -2
- data/spec/extensions/identifier_mangling_spec.rb +14 -8
- data/spec/extensions/inverted_subsets_spec.rb +4 -4
- data/spec/extensions/lazy_attributes_spec.rb +7 -0
- data/spec/extensions/many_through_many_spec.rb +38 -14
- data/spec/extensions/nested_attributes_spec.rb +18 -6
- data/spec/extensions/no_auto_literal_strings_spec.rb +1 -1
- data/spec/extensions/pg_enum_spec.rb +16 -1
- data/spec/extensions/pg_interval_spec.rb +11 -2
- data/spec/extensions/pg_loose_count_spec.rb +5 -0
- data/spec/extensions/pg_row_spec.rb +25 -0
- data/spec/extensions/prepared_statements_spec.rb +10 -1
- data/spec/extensions/query_spec.rb +2 -2
- data/spec/extensions/schema_dumper_spec.rb +2 -2
- data/spec/extensions/schema_spec.rb +2 -2
- data/spec/extensions/set_overrides_spec.rb +7 -3
- data/spec/extensions/sql_expr_spec.rb +0 -1
- data/spec/extensions/subset_conditions_spec.rb +6 -6
- data/spec/extensions/table_select_spec.rb +24 -12
- data/spec/extensions/to_dot_spec.rb +4 -4
- data/spec/extensions/whitelist_security_spec.rb +131 -0
- data/spec/integration/dataset_test.rb +9 -5
- data/spec/integration/model_test.rb +2 -0
- data/spec/integration/plugin_test.rb +2 -2
- data/spec/integration/spec_helper.rb +1 -1
- data/spec/model/associations_spec.rb +39 -11
- data/spec/model/base_spec.rb +44 -24
- data/spec/model/class_dataset_methods_spec.rb +18 -16
- data/spec/model/dataset_methods_spec.rb +4 -4
- data/spec/model/eager_loading_spec.rb +84 -24
- data/spec/model/model_spec.rb +97 -63
- data/spec/model/record_spec.rb +21 -13
- metadata +13 -2
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 = 46
|
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/mssql_spec.rb
CHANGED
@@ -68,6 +68,26 @@ describe "MSSQL" do
|
|
68
68
|
it "should should support OUTER APPLY" do
|
69
69
|
@db[:test3].outer_apply(@db[:test4].where(Sequel[:test3][:v3]=>Sequel[:test4][:v4])).select_order_map([:v3, :v4]).must_equal [[1,1], [2, nil]]
|
70
70
|
end
|
71
|
+
|
72
|
+
cspecify "should handle time values with fractional seconds", [:ado] do
|
73
|
+
# ado: Returns nil values
|
74
|
+
t = Sequel::SQLTime.create(10, 20, 30, 999900)
|
75
|
+
v = @db.get(Sequel.cast(t, 'time'))
|
76
|
+
v = Sequel.string_to_time(v) if v.is_a?(String)
|
77
|
+
pr = lambda{|x| [:hour, :min, :sec, :usec].map{|m| x.send(m)}}
|
78
|
+
pr[v].must_equal(pr[t])
|
79
|
+
end
|
80
|
+
|
81
|
+
cspecify "should get datetimeoffset values as Time with fractional seconds", [:odbc], [:ado], [:tinytds, proc{|db| TinyTds::VERSION < '0.9'}] do
|
82
|
+
# odbc: Returns string rounded to nearest second
|
83
|
+
# ado: Returns nil values
|
84
|
+
# tiny_tds < 0.9: Returns wrong value for hour
|
85
|
+
t = Time.local(2010, 11, 12, 10, 20, 30, 999000)
|
86
|
+
v = @db.get(Sequel.cast(t, 'datetimeoffset'))
|
87
|
+
v = Sequel.string_to_datetime(v) if v.is_a?(String)
|
88
|
+
pr = lambda{|x| [:year, :month, :day, :hour, :min, :sec, :usec].map{|m| x.send(m)}}
|
89
|
+
pr[v].must_equal(pr[t])
|
90
|
+
end
|
71
91
|
end
|
72
92
|
|
73
93
|
# This spec is currently disabled as the SQL Server 2008 R2 Express doesn't support
|
data/spec/adapters/mysql_spec.rb
CHANGED
@@ -354,7 +354,7 @@ describe "A MySQL database" do
|
|
354
354
|
|
355
355
|
it "should handle qualified tables in #indexes" do
|
356
356
|
DB.create_table!(:test_innodb){primary_key :id; String :name; index :name, :unique=>true, :name=>:test_innodb_name_idx}
|
357
|
-
DB.indexes(Sequel.qualify(DB.get{database
|
357
|
+
DB.indexes(Sequel.qualify(DB.get{database.function}, :test_innodb)).must_equal(:test_innodb_name_idx=>{:unique=>true, :columns=>[:name]})
|
358
358
|
end
|
359
359
|
end
|
360
360
|
|
@@ -63,15 +63,19 @@ describe "An Oracle database" do
|
|
63
63
|
DB.view_exists?(:cats).must_equal false
|
64
64
|
DB.create_view(:cats, DB[:categories])
|
65
65
|
DB.view_exists?(:cats).must_equal true
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
66
|
+
if IDENTIFIER_MANGLING && !DB.frozen?
|
67
|
+
om = DB.identifier_output_method
|
68
|
+
im = DB.identifier_input_method
|
69
|
+
DB.identifier_output_method = :reverse
|
70
|
+
DB.identifier_input_method = :reverse
|
71
|
+
DB.view_exists?(:STAC).must_equal true
|
72
|
+
DB.view_exists?(:cats).must_equal false
|
73
|
+
end
|
72
74
|
ensure
|
73
|
-
DB.
|
74
|
-
|
75
|
+
if IDENTIFIER_MANGLING && !DB.frozen?
|
76
|
+
DB.identifier_output_method = om
|
77
|
+
DB.identifier_input_method = im
|
78
|
+
end
|
75
79
|
DB.drop_view(:cats)
|
76
80
|
end
|
77
81
|
end
|
@@ -463,7 +463,7 @@ describe "A PostgreSQL dataset" do
|
|
463
463
|
end if DB.server_version >= 90300
|
464
464
|
|
465
465
|
it "should support ordered-set and hypothetical-set aggregate functions" do
|
466
|
-
@d.from{generate_series(1,3,1).as(:a)}.select{(a.sql_number % 2).as(:a)}.from_self.get{mode
|
466
|
+
@d.from{generate_series(1,3,1).as(:a)}.select{(a.sql_number % 2).as(:a)}.from_self.get{mode.function.within_group(:a)}.must_equal 1
|
467
467
|
end if DB.server_version >= 90400
|
468
468
|
|
469
469
|
it "should support filtered aggregate functions" do
|
@@ -40,7 +40,7 @@ class Minitest::HooksSpec
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
IDENTIFIER_MANGLING =
|
43
|
+
IDENTIFIER_MANGLING = !!ENV['SEQUEL_IDENTIFIER_MANGLING'] unless defined?(IDENTIFIER_MANGLING)
|
44
44
|
|
45
45
|
unless defined?(DB)
|
46
46
|
env_var = "SEQUEL_#{SEQUEL_ADAPTER_TEST.to_s.upcase}_URL"
|
@@ -5,19 +5,23 @@ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
|
|
5
5
|
describe "An SQLite database" do
|
6
6
|
before do
|
7
7
|
@db = DB
|
8
|
+
deprecated do
|
8
9
|
@fk = @db.foreign_keys
|
10
|
+
end
|
9
11
|
end
|
10
12
|
after do
|
11
13
|
@db.drop_table?(:fk)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
deprecated do
|
15
|
+
@db.auto_vacuum = :none
|
16
|
+
@db.run 'VACUUM'
|
17
|
+
@db.foreign_keys = @fk
|
18
|
+
@db.case_sensitive_like = true
|
19
|
+
end
|
16
20
|
@db.use_timestamp_timezones = false
|
17
21
|
Sequel.datetime_class = Time
|
18
22
|
end
|
19
23
|
|
20
|
-
|
24
|
+
deprecated "should support getting setting pragma values" do
|
21
25
|
@db.pragma_set(:auto_vacuum, '0')
|
22
26
|
@db.run 'VACUUM'
|
23
27
|
@db.pragma_get(:auto_vacuum).to_s.must_equal '0'
|
@@ -29,7 +33,7 @@ describe "An SQLite database" do
|
|
29
33
|
@db.pragma_get(:auto_vacuum).to_s.must_equal '2'
|
30
34
|
end
|
31
35
|
|
32
|
-
|
36
|
+
deprecated "should support getting and setting the auto_vacuum pragma" do
|
33
37
|
@db.auto_vacuum = :full
|
34
38
|
@db.run 'VACUUM'
|
35
39
|
@db.auto_vacuum.must_equal :full
|
@@ -40,12 +44,12 @@ describe "An SQLite database" do
|
|
40
44
|
proc {@db.auto_vacuum = :invalid}.must_raise(Sequel::Error)
|
41
45
|
end
|
42
46
|
|
43
|
-
|
47
|
+
deprecated "should respect case sensitive like false" do
|
44
48
|
@db.case_sensitive_like = false
|
45
49
|
@db.get(Sequel.like('a', 'A')).to_s.must_equal '1'
|
46
50
|
end
|
47
51
|
|
48
|
-
|
52
|
+
deprecated "should respect case sensitive like true" do
|
49
53
|
@db.case_sensitive_like = true
|
50
54
|
@db.get(Sequel.like('a', 'A')).to_s.must_equal '0'
|
51
55
|
end
|
@@ -63,13 +67,13 @@ describe "An SQLite database" do
|
|
63
67
|
@db.sqlite_version.must_be_kind_of(Integer)
|
64
68
|
end
|
65
69
|
|
66
|
-
|
70
|
+
deprecated "should support setting and getting the foreign_keys pragma" do
|
67
71
|
(@db.sqlite_version >= 30619 ? [true, false] : [nil]).must_include(@db.foreign_keys)
|
68
72
|
@db.foreign_keys = true
|
69
73
|
@db.foreign_keys = false
|
70
74
|
end
|
71
75
|
|
72
|
-
|
76
|
+
deprecated "should enforce foreign key integrity if foreign_keys pragma is set" do
|
73
77
|
@db.foreign_keys = true
|
74
78
|
@db.create_table!(:fk){primary_key :id; foreign_key :parent_id, :fk}
|
75
79
|
@db[:fk].insert(1, nil)
|
@@ -78,7 +82,7 @@ describe "An SQLite database" do
|
|
78
82
|
proc{@db[:fk].insert(4, 5)}.must_raise(Sequel::ForeignKeyConstraintViolation, Sequel::ConstraintViolation, Sequel::DatabaseError)
|
79
83
|
end if DB.sqlite_version >= 30619
|
80
84
|
|
81
|
-
|
85
|
+
deprecated "should not enforce foreign key integrity if foreign_keys pragma is unset" do
|
82
86
|
@db.foreign_keys = false
|
83
87
|
@db.create_table!(:fk){primary_key :id; foreign_key :parent_id, :fk}
|
84
88
|
@db[:fk].insert(1, 2)
|
@@ -104,7 +108,7 @@ describe "An SQLite database" do
|
|
104
108
|
@db.tables.must_include(:fk)
|
105
109
|
end
|
106
110
|
|
107
|
-
|
111
|
+
deprecated "should support getting and setting the synchronous pragma" do
|
108
112
|
@db.synchronous = :off
|
109
113
|
@db.synchronous.must_equal :off
|
110
114
|
@db.synchronous = :normal
|
@@ -115,7 +119,7 @@ describe "An SQLite database" do
|
|
115
119
|
proc {@db.synchronous = :invalid}.must_raise(Sequel::Error)
|
116
120
|
end
|
117
121
|
|
118
|
-
|
122
|
+
deprecated "should support getting and setting the temp_store pragma" do
|
119
123
|
@db.temp_store = :default
|
120
124
|
@db.temp_store.must_equal :default
|
121
125
|
@db.temp_store = :file
|
@@ -527,30 +531,28 @@ describe "A SQLite database" do
|
|
527
531
|
@db[:test3].select(:id).all.must_equal [{:id => 1}, {:id => 3}]
|
528
532
|
end
|
529
533
|
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
541
|
-
end
|
534
|
+
it "should keep foreign keys when dropping a column" do
|
535
|
+
@db.create_table! :test do
|
536
|
+
primary_key :id
|
537
|
+
String :name
|
538
|
+
Integer :value
|
539
|
+
end
|
540
|
+
@db.create_table! :test3 do
|
541
|
+
String :name
|
542
|
+
Integer :value
|
543
|
+
foreign_key :test_id, :test, :on_delete => :set_null, :on_update => :cascade
|
544
|
+
end
|
542
545
|
|
543
|
-
|
544
|
-
|
546
|
+
@db[:test3].insert(:name => "abc", :test_id => @db[:test].insert(:name => "foo", :value => 3))
|
547
|
+
@db[:test3].insert(:name => "def", :test_id => @db[:test].insert(:name => "bar", :value => 4))
|
545
548
|
|
546
|
-
|
549
|
+
@db.drop_column :test3, :value
|
547
550
|
|
548
|
-
|
549
|
-
|
551
|
+
@db[:test].filter(:name => 'bar').delete
|
552
|
+
@db[:test3][:name => 'def'][:test_id].must_be_nil
|
550
553
|
|
551
|
-
|
552
|
-
|
553
|
-
end
|
554
|
+
@db[:test].filter(:name => 'foo').update(:id=>100)
|
555
|
+
@db[:test3][:name => 'abc'][:test_id].must_equal 100
|
554
556
|
end
|
555
557
|
|
556
558
|
it "should support rename_column operations" do
|
@@ -690,7 +692,7 @@ describe "A SQLite database" do
|
|
690
692
|
sqls.last.must_equal "BEGIN DEFERRED TRANSACTION"
|
691
693
|
end
|
692
694
|
@db.transaction do
|
693
|
-
sqls.last.must_equal
|
695
|
+
sqls.last.must_equal 'BEGIN'
|
694
696
|
end
|
695
697
|
|
696
698
|
@db.transaction_mode.must_be_nil
|
@@ -761,11 +761,12 @@ describe "SingleConnectionPool" do
|
|
761
761
|
it "should provide a #disconnect method" do
|
762
762
|
conn = nil
|
763
763
|
x = nil
|
764
|
-
pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| conn = c}){1234}, ST_CONNECTION_POOL_DEFAULTS)
|
764
|
+
pool = Sequel::ConnectionPool.get_pool(mock_db.call(proc{|c| conn = c; c.must_be_kind_of(Integer)}){1234}, ST_CONNECTION_POOL_DEFAULTS)
|
765
765
|
pool.hold{|c| x = c}
|
766
766
|
x.must_equal 1234
|
767
767
|
pool.disconnect
|
768
768
|
conn.must_equal 1234
|
769
|
+
pool.disconnect
|
769
770
|
end
|
770
771
|
end
|
771
772
|
|
data/spec/core/database_spec.rb
CHANGED
@@ -38,6 +38,7 @@ describe "A new Database" do
|
|
38
38
|
it "should support :preconnect option to preconnect to database" do
|
39
39
|
@db.pool.size.must_equal 0
|
40
40
|
c = Class.new(Sequel::Database) do
|
41
|
+
def dataset_class_default; Sequel::Dataset end
|
41
42
|
def connect(_)
|
42
43
|
:connect
|
43
44
|
end
|
@@ -191,17 +192,17 @@ describe "Database#log_yield" do
|
|
191
192
|
@db = Sequel::Database.new(:logger=>@o)
|
192
193
|
end
|
193
194
|
|
194
|
-
|
195
|
+
deprecated "should yield to the passed block" do
|
195
196
|
a = nil
|
196
197
|
@db.log_yield('blah'){a = 1}
|
197
198
|
a.must_equal 1
|
198
199
|
end
|
199
200
|
|
200
|
-
|
201
|
+
deprecated "should raise an exception if a block is not passed" do
|
201
202
|
proc{@db.log_yield('blah')}.must_raise LocalJumpError
|
202
203
|
end
|
203
204
|
|
204
|
-
|
205
|
+
deprecated "should log message with duration at info level to all loggers" do
|
205
206
|
@db.log_yield('blah'){}
|
206
207
|
@o.logs.length.must_equal 1
|
207
208
|
@o.logs.first.length.must_equal 2
|
@@ -209,7 +210,7 @@ describe "Database#log_yield" do
|
|
209
210
|
@o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
|
210
211
|
end
|
211
212
|
|
212
|
-
|
213
|
+
deprecated "should respect sql_log_level setting" do
|
213
214
|
@db.sql_log_level = :debug
|
214
215
|
@db.log_yield('blah'){}
|
215
216
|
@o.logs.length.must_equal 1
|
@@ -218,7 +219,7 @@ describe "Database#log_yield" do
|
|
218
219
|
@o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
|
219
220
|
end
|
220
221
|
|
221
|
-
|
222
|
+
deprecated "should log message with duration at warn level if duration greater than log_warn_duration" do
|
222
223
|
@db.log_warn_duration = 0
|
223
224
|
@db.log_yield('blah'){}
|
224
225
|
@o.logs.length.must_equal 1
|
@@ -227,7 +228,7 @@ describe "Database#log_yield" do
|
|
227
228
|
@o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
|
228
229
|
end
|
229
230
|
|
230
|
-
|
231
|
+
deprecated "should log message with duration at info level if duration less than log_warn_duration" do
|
231
232
|
@db.log_warn_duration = 1000
|
232
233
|
@db.log_yield('blah'){}
|
233
234
|
@o.logs.length.must_equal 1
|
@@ -236,7 +237,7 @@ describe "Database#log_yield" do
|
|
236
237
|
@o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
|
237
238
|
end
|
238
239
|
|
239
|
-
|
240
|
+
deprecated "should log message at error level if block raises an error" do
|
240
241
|
@db.log_warn_duration = 0
|
241
242
|
proc{@db.log_yield('blah'){raise Sequel::Error, 'adsf'}}.must_raise Sequel::Error
|
242
243
|
@o.logs.length.must_equal 1
|
@@ -245,7 +246,7 @@ describe "Database#log_yield" do
|
|
245
246
|
@o.logs.first.last.must_match(/\ASequel::Error: adsf: blah\z/)
|
246
247
|
end
|
247
248
|
|
248
|
-
|
249
|
+
deprecated "should include args with message if args passed" do
|
249
250
|
@db.log_yield('blah', [1, 2]){}
|
250
251
|
@o.logs.length.must_equal 1
|
251
252
|
@o.logs.first.length.must_equal 2
|
@@ -259,6 +260,7 @@ describe "Database#log_connection_yield" do
|
|
259
260
|
@o = Object.new
|
260
261
|
def @o.logs; @logs || []; end
|
261
262
|
def @o.to_ary; [self]; end
|
263
|
+
def @o.warn(*args); (@logs ||= []) << [:warn] + args; end
|
262
264
|
def @o.method_missing(*args); (@logs ||= []) << args; end
|
263
265
|
@conn = Object.new
|
264
266
|
@db = Sequel::Database.new(:logger=>@o)
|
@@ -281,11 +283,74 @@ describe "Database#log_connection_yield" do
|
|
281
283
|
@o.logs.first.first.must_equal :info
|
282
284
|
@o.logs.first.last.must_match(/\(conn: -?\d+\) some SQL\z/)
|
283
285
|
end
|
286
|
+
|
287
|
+
it "should yield to the passed block" do
|
288
|
+
a = nil
|
289
|
+
@db.log_connection_yield('blah', @conn){a = 1}
|
290
|
+
a.must_equal 1
|
291
|
+
end
|
292
|
+
|
293
|
+
it "should raise an exception if a block is not passed" do
|
294
|
+
proc{@db.log_connection_yield('blah', @conn)}.must_raise LocalJumpError
|
295
|
+
end
|
296
|
+
|
297
|
+
it "should log message with duration at info level to all loggers" do
|
298
|
+
@db.log_connection_yield('blah', @conn){}
|
299
|
+
@o.logs.length.must_equal 1
|
300
|
+
@o.logs.first.length.must_equal 2
|
301
|
+
@o.logs.first.first.must_equal :info
|
302
|
+
@o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should respect sql_log_level setting" do
|
306
|
+
@db.sql_log_level = :debug
|
307
|
+
@db.log_connection_yield('blah', @conn){}
|
308
|
+
@o.logs.length.must_equal 1
|
309
|
+
@o.logs.first.length.must_equal 2
|
310
|
+
@o.logs.first.first.must_equal :debug
|
311
|
+
@o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
|
312
|
+
end
|
313
|
+
|
314
|
+
it "should log message with duration at warn level if duration greater than log_warn_duration" do
|
315
|
+
@db.log_warn_duration = 0
|
316
|
+
@db.log_connection_yield('blah', @conn){}
|
317
|
+
@o.logs.length.must_equal 1
|
318
|
+
@o.logs.first.length.must_equal 2
|
319
|
+
@o.logs.first.first.must_equal :warn
|
320
|
+
@o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
|
321
|
+
end
|
322
|
+
|
323
|
+
it "should log message with duration at info level if duration less than log_warn_duration" do
|
324
|
+
@db.log_warn_duration = 1000
|
325
|
+
@db.log_connection_yield('blah', @conn){}
|
326
|
+
@o.logs.length.must_equal 1
|
327
|
+
@o.logs.first.length.must_equal 2
|
328
|
+
@o.logs.first.first.must_equal :info
|
329
|
+
@o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah\z/)
|
330
|
+
end
|
331
|
+
|
332
|
+
it "should log message at error level if block raises an error" do
|
333
|
+
@db.log_warn_duration = 0
|
334
|
+
proc{@db.log_connection_yield('blah', @conn){raise Sequel::Error, 'adsf'}}.must_raise Sequel::Error
|
335
|
+
@o.logs.length.must_equal 1
|
336
|
+
@o.logs.first.length.must_equal 2
|
337
|
+
@o.logs.first.first.must_equal :error
|
338
|
+
@o.logs.first.last.must_match(/\ASequel::Error: adsf: blah\z/)
|
339
|
+
end
|
340
|
+
|
341
|
+
it "should include args with message if args passed" do
|
342
|
+
@db.log_connection_yield('blah', @conn, [1, 2]){}
|
343
|
+
@o.logs.length.must_equal 1
|
344
|
+
@o.logs.first.length.must_equal 2
|
345
|
+
@o.logs.first.first.must_equal :info
|
346
|
+
@o.logs.first.last.must_match(/\A\(\d\.\d{6}s\) blah; \[1, 2\]\z/)
|
347
|
+
end
|
284
348
|
end
|
285
349
|
|
286
350
|
describe "Database#uri" do
|
287
351
|
before do
|
288
352
|
@c = Class.new(Sequel::Database) do
|
353
|
+
def dataset_class_default; Sequel::Dataset end
|
289
354
|
set_adapter_scheme :mau
|
290
355
|
end
|
291
356
|
|
@@ -310,6 +375,7 @@ describe "Database.adapter_scheme and #adapter_scheme" do
|
|
310
375
|
Sequel::Database.adapter_scheme.must_be_nil
|
311
376
|
|
312
377
|
@c = Class.new(Sequel::Database) do
|
378
|
+
def dataset_class_default; Sequel::Dataset end
|
313
379
|
set_adapter_scheme :mau
|
314
380
|
end
|
315
381
|
|
@@ -723,6 +789,18 @@ DatabaseTransactionSpecs = shared_description do
|
|
723
789
|
@db.sqls.must_equal ['BEGIN']
|
724
790
|
end
|
725
791
|
|
792
|
+
it "should raise original exception if there is an exception raised when rolling back when using :rollback=>:always" do
|
793
|
+
ec = Class.new(StandardError)
|
794
|
+
meta_def(@db, :database_error_classes){[ec]}
|
795
|
+
meta_def(@db, :log_connection_execute){|c, sql| sql =~ /ROLLBACK/ ? raise(ec, 'bad') : super(c, sql)}
|
796
|
+
begin
|
797
|
+
@db.transaction(:rollback=>:always){}
|
798
|
+
rescue => e
|
799
|
+
end
|
800
|
+
e.must_be_kind_of(ec)
|
801
|
+
@db.sqls.must_equal ['BEGIN']
|
802
|
+
end
|
803
|
+
|
726
804
|
it "should issue ROLLBACK if Sequel::Rollback is called in the transaction" do
|
727
805
|
@db.transaction do
|
728
806
|
@db.drop_table(:a)
|
@@ -834,7 +912,7 @@ DatabaseTransactionSpecs = shared_description do
|
|
834
912
|
tr.must_be :empty?
|
835
913
|
end
|
836
914
|
|
837
|
-
it "should correctly handle nested
|
915
|
+
it "should correctly handle nested transaction use with separate shards" do
|
838
916
|
@db.transaction do |c1|
|
839
917
|
@db.transaction(:server=>:test) do |c2|
|
840
918
|
c1.wont_equal c2
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -310,10 +310,13 @@ describe "Dataset#unused_table_alias" do
|
|
310
310
|
@ds.from(:test, :test_0).cross_join(:test_1).unused_table_alias(:test).must_equal :test_2
|
311
311
|
end
|
312
312
|
|
313
|
-
|
314
|
-
@ds.unused_table_alias('test').must_equal :test_0
|
313
|
+
with_symbol_splitting "should return an appropriate symbol if given splittable symbol" do
|
315
314
|
@ds.unused_table_alias(:b__t___test).must_equal :test_0
|
316
315
|
@ds.unused_table_alias(:b__test).must_equal :test_0
|
316
|
+
end
|
317
|
+
|
318
|
+
it "should return an appropriate symbol if given other forms of identifiers" do
|
319
|
+
@ds.unused_table_alias('test').must_equal :test_0
|
317
320
|
@ds.unused_table_alias(Sequel.qualify(:b, :test)).must_equal :test_0
|
318
321
|
@ds.unused_table_alias(Sequel.expr(:b).as(:test)).must_equal :test_0
|
319
322
|
@ds.unused_table_alias(Sequel.expr(:b).as(Sequel.identifier(:test))).must_equal :test_0
|
@@ -346,65 +349,116 @@ describe "Dataset#where" do
|
|
346
349
|
before do
|
347
350
|
@dataset = Sequel.mock[:test]
|
348
351
|
@d1 = @dataset.where(:region => 'Asia')
|
349
|
-
@d2 = @dataset.where('region = ?', 'Asia')
|
350
|
-
@d3 = @dataset.where("a = 1")
|
351
352
|
end
|
352
353
|
|
353
|
-
|
354
|
+
if false # SEQUEL5: remove if
|
355
|
+
it "should just clone if given no arguments or block" do
|
356
|
+
proc{@dataset.where}.must_raise Sequel::Error
|
357
|
+
end
|
358
|
+
|
359
|
+
it "should handle nil argument if block is given" do
|
360
|
+
@d1.where(nil){a}.sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND NULL AND a)"
|
361
|
+
end
|
362
|
+
|
363
|
+
it "should handle nil argument if block has no existing filter" do
|
364
|
+
@dataset.where(nil).sql.must_equal "SELECT * FROM test WHERE NULL"
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
it "should just clone if given an empty array or hash argument" do
|
354
369
|
@dataset.where({}).sql.must_equal @dataset.sql
|
355
370
|
@dataset.where([]).sql.must_equal @dataset.sql
|
356
|
-
@dataset.where('').sql.must_equal @dataset.sql
|
357
371
|
|
358
372
|
@dataset.filter({}).sql.must_equal @dataset.sql
|
359
373
|
@dataset.filter([]).sql.must_equal @dataset.sql
|
374
|
+
end
|
375
|
+
|
376
|
+
deprecated "should just clone if given an empty string argument" do
|
377
|
+
@dataset.where('').sql.must_equal @dataset.sql
|
360
378
|
@dataset.filter('').sql.must_equal @dataset.sql
|
361
379
|
end
|
362
380
|
|
381
|
+
deprecated "should just clone if given no arguments or block" do
|
382
|
+
@dataset.where.sql.must_equal @dataset.sql
|
383
|
+
@dataset.filter.sql.must_equal @dataset.sql
|
384
|
+
end
|
385
|
+
|
386
|
+
deprecated "should ignore nil argument if block is given" do
|
387
|
+
@d1.where(nil){a}.sql.must_equal @d1.where(:a).sql
|
388
|
+
end
|
389
|
+
|
390
|
+
deprecated "should ignore nil argument if block has no existing filter" do
|
391
|
+
@dataset.where(nil).sql.must_equal @dataset.sql
|
392
|
+
end
|
393
|
+
|
363
394
|
it "should work with hashes" do
|
364
395
|
@dataset.where(:name => 'xyz', :price => 342).select_sql.
|
365
396
|
must_match(/WHERE \(\(name = 'xyz'\) AND \(price = 342\)\)|WHERE \(\(price = 342\) AND \(name = 'xyz'\)\)/)
|
366
397
|
end
|
367
398
|
|
368
|
-
|
399
|
+
deprecated "should handle literal strings in arrays in filter methods" do
|
400
|
+
@dataset.where([Sequel.lit("a")]).sql.must_equal 'SELECT * FROM test WHERE (a)'
|
401
|
+
end
|
402
|
+
|
403
|
+
deprecated "should work with a string with placeholders and arguments for those placeholders" do
|
369
404
|
@dataset.where('price < ? AND id in ?', 100, [1, 2, 3]).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
|
370
405
|
end
|
371
406
|
|
372
|
-
it "should
|
407
|
+
it "should work with a placeholder literal string" do
|
408
|
+
@dataset.where(Sequel.lit('price < ? AND id in ?', 100, [1, 2, 3])).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
|
409
|
+
end
|
410
|
+
|
411
|
+
deprecated "should not modify passed array with placeholders" do
|
373
412
|
a = ['price < ? AND id in ?', 100, 1, 2, 3]
|
374
413
|
b = a.dup
|
375
414
|
@dataset.where(a)
|
376
415
|
b.must_equal a
|
377
416
|
end
|
378
417
|
|
379
|
-
|
380
|
-
@dataset.where('(a = 1 AND b = 2)').select_sql.
|
381
|
-
|
418
|
+
deprecated "should work with strings (custom SQL expressions)" do
|
419
|
+
@dataset.where('(a = 1 AND b = 2)').select_sql.must_equal "SELECT * FROM test WHERE ((a = 1 AND b = 2))"
|
420
|
+
end
|
421
|
+
|
422
|
+
it "should work with literal strings" do
|
423
|
+
@dataset.where(Sequel.lit('(a = 1 AND b = 2)')).select_sql.must_equal "SELECT * FROM test WHERE ((a = 1 AND b = 2))"
|
424
|
+
end
|
425
|
+
|
426
|
+
deprecated "should work with a string with named placeholders and a hash of placeholder value arguments" do
|
427
|
+
@dataset.where('price < :price AND id in :ids', :price=>100, :ids=>[1, 2, 3]).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
|
382
428
|
end
|
383
429
|
|
384
|
-
it "should work with
|
385
|
-
@dataset.where('price < :price AND id in :ids', :price=>100, :ids=>[1, 2, 3]).select_sql.
|
386
|
-
must_equal "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
|
430
|
+
it "should work with named placeholder strings" do
|
431
|
+
@dataset.where(Sequel.lit('price < :price AND id in :ids', :price=>100, :ids=>[1, 2, 3])).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
|
387
432
|
end
|
388
433
|
|
389
|
-
|
434
|
+
deprecated "should not modify passed array with named placeholders" do
|
390
435
|
a = ['price < :price AND id in :ids', {:price=>100}]
|
391
436
|
b = a.dup
|
392
437
|
@dataset.where(a)
|
393
438
|
b.must_equal a
|
394
439
|
end
|
395
440
|
|
396
|
-
|
441
|
+
deprecated "should not replace named placeholders that don't exist in the hash" do
|
397
442
|
@dataset.where('price < :price AND id in :ids', :price=>100).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in :ids)"
|
398
443
|
end
|
399
444
|
|
400
|
-
it "should
|
445
|
+
it "should not replace named placeholders that don't exist in the hash when using placeholder strings" do
|
446
|
+
@dataset.where(Sequel.lit('price < :price AND id in :ids', :price=>100)).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in :ids)"
|
447
|
+
end
|
448
|
+
|
449
|
+
deprecated "should raise an error for a mismatched number of placeholders" do
|
401
450
|
proc{@dataset.where('price < ? AND id in ?', 100).select_sql}.must_raise(Sequel::Error)
|
402
451
|
proc{@dataset.where('price < ? AND id in ?', 100, [1, 2, 3], 4).select_sql}.must_raise(Sequel::Error)
|
403
452
|
end
|
404
453
|
|
454
|
+
it "should raise an error for a mismatched number of placeholders in placeholder literal strings" do
|
455
|
+
proc{@dataset.where(Sequel.lit('price < ? AND id in ?', 100)).select_sql}.must_raise(Sequel::Error)
|
456
|
+
proc{@dataset.where(Sequel.lit('price < ? AND id in ?', 100, [1, 2, 3], 4)).select_sql}.must_raise(Sequel::Error)
|
457
|
+
end
|
458
|
+
|
405
459
|
it "should handle placeholders when using an array" do
|
406
|
-
@dataset.where(Sequel.lit(['price < ', ' AND id in '], 100, [1, 2, 3])).select_sql.must_equal "SELECT * FROM test WHERE price < 100 AND id in (1, 2, 3)"
|
407
|
-
@dataset.where(Sequel.lit(['price < ', ' AND id in '], 100)).select_sql.must_equal "SELECT * FROM test WHERE price < 100 AND id in "
|
460
|
+
@dataset.where(Sequel.lit(['price < ', ' AND id in '], 100, [1, 2, 3])).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in (1, 2, 3))"
|
461
|
+
@dataset.where(Sequel.lit(['price < ', ' AND id in '], 100)).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id in )"
|
408
462
|
end
|
409
463
|
|
410
464
|
it "should handle a mismatched number of placeholders when using an array" do
|
@@ -412,24 +466,49 @@ describe "Dataset#where" do
|
|
412
466
|
proc{@dataset.where(Sequel.lit(['price < ', ' AND id in '], 100, [1, 2, 3], 4)).select_sql}.must_raise(Sequel::Error)
|
413
467
|
end
|
414
468
|
|
415
|
-
|
469
|
+
deprecated "should handle partial names" do
|
416
470
|
@dataset.where('price < :price AND id = :p', :p=>2, :price=>100).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id = 2)"
|
417
471
|
end
|
418
472
|
|
419
|
-
it "should handle
|
473
|
+
it "should handle partial names when using placeholder literal strings" do
|
474
|
+
@dataset.where(Sequel.lit('price < :price AND id = :p', :p=>2, :price=>100)).select_sql.must_equal "SELECT * FROM test WHERE (price < 100 AND id = 2)"
|
475
|
+
end
|
476
|
+
|
477
|
+
deprecated "should handle ::cast syntax when no parameters are supplied" do
|
420
478
|
@dataset.where('price::float = 10', {}).select_sql.must_equal "SELECT * FROM test WHERE (price::float = 10)"
|
421
479
|
@dataset.where('price::float ? 10', {}).select_sql.must_equal "SELECT * FROM test WHERE (price::float ? 10)"
|
422
480
|
end
|
423
481
|
|
482
|
+
it "should handle ::cast syntax when no parameters are supplied when using placeholder strings" do
|
483
|
+
@dataset.where(Sequel.lit('price::float = 10', {})).select_sql.must_equal "SELECT * FROM test WHERE (price::float = 10)"
|
484
|
+
@dataset.where(Sequel.lit('price::float ? 10', {})).select_sql.must_equal "SELECT * FROM test WHERE (price::float ? 10)"
|
485
|
+
end
|
486
|
+
|
424
487
|
it "should affect select, delete and update statements" do
|
425
488
|
@d1.select_sql.must_equal "SELECT * FROM test WHERE (region = 'Asia')"
|
426
489
|
@d1.delete_sql.must_equal "DELETE FROM test WHERE (region = 'Asia')"
|
427
490
|
@d1.update_sql(:GDP => 0).must_equal "UPDATE test SET GDP = 0 WHERE (region = 'Asia')"
|
491
|
+
end
|
428
492
|
|
493
|
+
deprecated "should affect select, delete and update statements when using strings" do
|
494
|
+
@d2 = @dataset.where('region = ?', 'Asia')
|
495
|
+
@d2.select_sql.must_equal "SELECT * FROM test WHERE (region = 'Asia')"
|
496
|
+
@d2.delete_sql.must_equal "DELETE FROM test WHERE (region = 'Asia')"
|
497
|
+
@d2.update_sql(:GDP => 0).must_equal "UPDATE test SET GDP = 0 WHERE (region = 'Asia')"
|
498
|
+
|
499
|
+
@d3 = @dataset.where("a = 1")
|
500
|
+
@d3.select_sql.must_equal "SELECT * FROM test WHERE (a = 1)"
|
501
|
+
@d3.delete_sql.must_equal "DELETE FROM test WHERE (a = 1)"
|
502
|
+
@d3.update_sql(:GDP => 0).must_equal "UPDATE test SET GDP = 0 WHERE (a = 1)"
|
503
|
+
end
|
504
|
+
|
505
|
+
it "should affect select, delete and update statements when using literal strings" do
|
506
|
+
@d2 = @dataset.where(Sequel.lit('region = ?', 'Asia'))
|
429
507
|
@d2.select_sql.must_equal "SELECT * FROM test WHERE (region = 'Asia')"
|
430
508
|
@d2.delete_sql.must_equal "DELETE FROM test WHERE (region = 'Asia')"
|
431
509
|
@d2.update_sql(:GDP => 0).must_equal "UPDATE test SET GDP = 0 WHERE (region = 'Asia')"
|
432
510
|
|
511
|
+
@d3 = @dataset.where(Sequel.lit("a = 1"))
|
433
512
|
@d3.select_sql.must_equal "SELECT * FROM test WHERE (a = 1)"
|
434
513
|
@d3.delete_sql.must_equal "DELETE FROM test WHERE (a = 1)"
|
435
514
|
@d3.update_sql(:GDP => 0).must_equal "UPDATE test SET GDP = 0 WHERE (a = 1)"
|
@@ -437,27 +516,48 @@ describe "Dataset#where" do
|
|
437
516
|
|
438
517
|
it "should be composable using AND operator (for scoping)" do
|
439
518
|
@d1.where(:size => 'big').select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (size = 'big'))"
|
440
|
-
@d1.where
|
441
|
-
@d1.where(
|
442
|
-
@d1.where(
|
519
|
+
@d1.where{population > 1000}.select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (population > 1000))"
|
520
|
+
@d1.where{(a > 1) | (b < 2)}.select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND ((a > 1) OR (b < 2)))"
|
521
|
+
@d1.where{GDP() > 1000}.select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
|
522
|
+
end
|
523
|
+
|
524
|
+
deprecated "should be composable using AND operator (for scoping) when using strings" do
|
525
|
+
@d2 = @dataset.where('region = ?', 'Asia')
|
443
526
|
@d2.where('GDP > ?', 1000).select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
|
444
527
|
@d2.where(:name => ['Japan', 'China']).select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (name IN ('Japan', 'China')))"
|
445
528
|
@d2.where('GDP > ?').select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > ?))"
|
529
|
+
|
530
|
+
@d3 = @dataset.where("a = 1")
|
446
531
|
@d3.where('b = 2').select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (b = 2))"
|
447
532
|
@d3.where(:c => 3).select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (c = 3))"
|
448
533
|
@d3.where('d = ?', 4).select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (d = 4))"
|
449
534
|
end
|
450
535
|
|
451
|
-
it "should be composable using AND operator (for scoping)
|
452
|
-
@
|
536
|
+
it "should be composable using AND operator (for scoping) when using literal strings" do
|
537
|
+
@d2 = @dataset.where(Sequel.lit('region = ?', 'Asia'))
|
538
|
+
@d2.where(Sequel.lit('GDP > ?', 1000)).select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > 1000))"
|
539
|
+
@d2.where(:name => ['Japan', 'China']).select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (name IN ('Japan', 'China')))"
|
540
|
+
@d2.where(Sequel.lit('GDP > ?')).select_sql.must_equal "SELECT * FROM test WHERE ((region = 'Asia') AND (GDP > ?))"
|
541
|
+
|
542
|
+
@d3 = @dataset.where(Sequel.lit("a = 1"))
|
543
|
+
@d3.where(Sequel.lit('b = 2')).select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (b = 2))"
|
544
|
+
@d3.where(:c => 3).select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (c = 3))"
|
545
|
+
@d3.where(Sequel.lit('d = ?', 4)).select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (d = 4))"
|
546
|
+
end
|
547
|
+
|
548
|
+
deprecated "should be composable using AND operator (for scoping) with block and string" do
|
549
|
+
@dataset.where("a = 1").where{e < 5}.select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (e < 5))"
|
550
|
+
end
|
551
|
+
|
552
|
+
it "should be composable using AND operator (for scoping) with block and literal string" do
|
553
|
+
@dataset.where(Sequel.lit("a = 1")).where{e < 5}.select_sql.must_equal "SELECT * FROM test WHERE ((a = 1) AND (e < 5))"
|
453
554
|
end
|
454
555
|
|
455
556
|
it "should accept ranges" do
|
456
557
|
@dataset.filter(:id => 4..7).sql.must_equal 'SELECT * FROM test WHERE ((id >= 4) AND (id <= 7))'
|
457
558
|
@dataset.filter(:id => 4...7).sql.must_equal 'SELECT * FROM test WHERE ((id >= 4) AND (id < 7))'
|
458
|
-
|
459
|
-
@dataset.filter(:
|
460
|
-
@dataset.filter(:table__id => 4...7).sql.must_equal 'SELECT * FROM test WHERE ((table.id >= 4) AND (table.id < 7))'
|
559
|
+
@dataset.filter(:id => 4..7).sql.must_equal 'SELECT * FROM test WHERE ((id >= 4) AND (id <= 7))'
|
560
|
+
@dataset.filter(:id => 4...7).sql.must_equal 'SELECT * FROM test WHERE ((id >= 4) AND (id < 7))'
|
461
561
|
end
|
462
562
|
|
463
563
|
it "should accept nil" do
|
@@ -465,7 +565,7 @@ describe "Dataset#where" do
|
|
465
565
|
end
|
466
566
|
|
467
567
|
it "should accept a subquery" do
|
468
|
-
@dataset.filter
|
568
|
+
@dataset.filter{|o| o.gdp > @d1.select(Sequel.function(:avg, :gdp))}.sql.must_equal "SELECT * FROM test WHERE (gdp > (SELECT avg(gdp) FROM test WHERE (region = 'Asia')))"
|
469
569
|
end
|
470
570
|
|
471
571
|
it "should handle all types of IN/NOT IN queries with empty arrays" do
|
@@ -578,16 +678,16 @@ describe "Dataset#where" do
|
|
578
678
|
x = nil
|
579
679
|
@dataset.filter{|r| x = r; false}
|
580
680
|
x.must_be_kind_of(Sequel::SQL::VirtualRow)
|
581
|
-
@dataset.filter{|r| ((r.name < 'b') & {r.
|
582
|
-
must_equal "SELECT * FROM test WHERE (((name < 'b') AND (
|
681
|
+
@dataset.filter{|r| ((r.name < 'b') & {r.table_id => 1}) | r.is_active(r.blah, r.xx, r.x_y_z)}.sql.
|
682
|
+
must_equal "SELECT * FROM test WHERE (((name < 'b') AND (table_id = 1)) OR is_active(blah, xx, x_y_z))"
|
583
683
|
end
|
584
684
|
|
585
685
|
it "should instance_eval the block in the context of a VirtualRow if the block doesn't request an argument" do
|
586
686
|
x = nil
|
587
687
|
@dataset.filter{x = self; false}
|
588
688
|
x.must_be_kind_of(Sequel::SQL::VirtualRow)
|
589
|
-
@dataset.filter{((name < 'b') & {
|
590
|
-
must_equal "SELECT * FROM test WHERE (((name < 'b') AND (
|
689
|
+
@dataset.filter{((name < 'b') & {table_id => 1}) | is_active(blah, xx, x_y_z)}.sql.
|
690
|
+
must_equal "SELECT * FROM test WHERE (((name < 'b') AND (table_id = 1)) OR is_active(blah, xx, x_y_z))"
|
591
691
|
end
|
592
692
|
|
593
693
|
it "should handle arbitrary objects" do
|
@@ -620,9 +720,12 @@ describe "Dataset#or" do
|
|
620
720
|
@dataset.or(:a => 1).sql.must_equal 'SELECT * FROM test'
|
621
721
|
end
|
622
722
|
|
623
|
-
it "should just clone if given an empty argument" do
|
723
|
+
it "should just clone if given an empty array or hash argument" do
|
624
724
|
@d1.or({}).sql.must_equal @d1.sql
|
625
725
|
@d1.or([]).sql.must_equal @d1.sql
|
726
|
+
end
|
727
|
+
|
728
|
+
deprecated "should just clone if given an empty string argument" do
|
626
729
|
@d1.or('').sql.must_equal @d1.sql
|
627
730
|
end
|
628
731
|
|
@@ -630,8 +733,15 @@ describe "Dataset#or" do
|
|
630
733
|
@d1.or(:y => 2).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) OR (y = 2))'
|
631
734
|
end
|
632
735
|
|
633
|
-
|
736
|
+
deprecated "should accept string filters" do
|
634
737
|
@d1.or('y > ?', 2).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) OR (y > 2))'
|
738
|
+
end
|
739
|
+
|
740
|
+
it "should accept literal string filters" do
|
741
|
+
@d1.or(Sequel.lit('y > ?', 2)).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) OR (y > 2))'
|
742
|
+
end
|
743
|
+
|
744
|
+
it "should accept expression filters" do
|
635
745
|
@d1.or(Sequel.expr(:yy) > 3).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) OR (yy > 3))'
|
636
746
|
end
|
637
747
|
|
@@ -663,8 +773,15 @@ describe "Dataset#and" do
|
|
663
773
|
@d1.and(:y => 2).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) AND (y = 2))'
|
664
774
|
end
|
665
775
|
|
666
|
-
|
776
|
+
deprecated "should accept string filters with placeholders" do
|
667
777
|
@d1.and('y > ?', 2).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
|
778
|
+
end
|
779
|
+
|
780
|
+
it "should accept placeholder literal string filters" do
|
781
|
+
@d1.and(Sequel.lit('y > ?', 2)).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) AND (y > 2))'
|
782
|
+
end
|
783
|
+
|
784
|
+
it "should accept expression filters" do
|
668
785
|
@d1.and(Sequel.expr(:yy) > 3).sql.must_equal 'SELECT * FROM test WHERE ((x = 1) AND (yy > 3))'
|
669
786
|
end
|
670
787
|
|
@@ -693,14 +810,22 @@ describe "Dataset#exclude" do
|
|
693
810
|
/WHERE \(\(name != 'Japan'\) OR \(region != 'Asia'\)\)/))
|
694
811
|
end
|
695
812
|
|
696
|
-
|
813
|
+
deprecated "should parenthesize a single string condition correctly" do
|
697
814
|
@dataset.exclude("region = 'Asia' AND name = 'Japan'").select_sql.must_equal "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
698
815
|
end
|
699
816
|
|
700
|
-
|
817
|
+
deprecated "should parenthesize an array condition correctly" do
|
701
818
|
@dataset.exclude('region = ? AND name = ?', 'Asia', 'Japan').select_sql.must_equal "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
702
819
|
end
|
703
820
|
|
821
|
+
it "should parenthesize a single literal string condition correctly" do
|
822
|
+
@dataset.exclude(Sequel.lit("region = 'Asia' AND name = 'Japan'")).select_sql.must_equal "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
823
|
+
end
|
824
|
+
|
825
|
+
it "should parenthesize a placeholder literal string condition correctly" do
|
826
|
+
@dataset.exclude(Sequel.lit('region = ? AND name = ?', 'Asia', 'Japan')).select_sql.must_equal "SELECT * FROM test WHERE NOT (region = 'Asia' AND name = 'Japan')"
|
827
|
+
end
|
828
|
+
|
704
829
|
it "should correctly parenthesize when it is used twice" do
|
705
830
|
@dataset.exclude(:region => 'Asia').exclude(:name => 'Japan').select_sql.must_equal "SELECT * FROM test WHERE ((region != 'Asia') AND (name != 'Japan'))"
|
706
831
|
end
|
@@ -763,16 +888,23 @@ describe "Dataset#having" do
|
|
763
888
|
@grouped = @dataset.group(:region).select(:region, Sequel.function(:sum, :population), Sequel.function(:avg, :gdp))
|
764
889
|
end
|
765
890
|
|
766
|
-
it "should just clone if given an empty argument" do
|
891
|
+
it "should just clone if given an empty array or hash argument" do
|
767
892
|
@dataset.having({}).sql.must_equal @dataset.sql
|
768
893
|
@dataset.having([]).sql.must_equal @dataset.sql
|
894
|
+
end
|
895
|
+
|
896
|
+
deprecated "should just clone if given an empty string argument" do
|
769
897
|
@dataset.having('').sql.must_equal @dataset.sql
|
770
898
|
end
|
771
899
|
|
772
|
-
|
900
|
+
deprecated "should handle string arguments" do
|
773
901
|
@grouped.having('sum(population) > 10').select_sql.must_equal "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
|
774
902
|
end
|
775
903
|
|
904
|
+
it "should handle literal string arguments" do
|
905
|
+
@grouped.having(Sequel.lit('sum(population) > 10')).select_sql.must_equal "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
|
906
|
+
end
|
907
|
+
|
776
908
|
it "should support proc expressions" do
|
777
909
|
@grouped.having{Sequel.function(:sum, :population) > 10}.sql.must_equal "SELECT region, sum(population), avg(gdp) FROM test GROUP BY region HAVING (sum(population) > 10)"
|
778
910
|
end
|
@@ -908,21 +1040,57 @@ describe "Dataset#as" do
|
|
908
1040
|
end
|
909
1041
|
end
|
910
1042
|
|
911
|
-
describe "Dataset#literal" do
|
1043
|
+
describe "Dataset#literal with expressions" do
|
1044
|
+
before do
|
1045
|
+
@ds = Sequel.mock.dataset
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
it "should convert qualified identifiers into dot notation" do
|
1049
|
+
@ds.literal(Sequel[:abc][:def]).must_equal 'abc.def'
|
1050
|
+
end
|
1051
|
+
|
1052
|
+
it "should convert aliased expressions into SQL AS notation" do
|
1053
|
+
@ds.literal(Sequel[:xyz].as(:x)).must_equal 'xyz AS x'
|
1054
|
+
@ds.literal(Sequel[:abc][:def].as(:x)).must_equal 'abc.def AS x'
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
it "should support names with digits" do
|
1058
|
+
@ds.literal(:abc2).must_equal 'abc2'
|
1059
|
+
@ds.literal(Sequel[:xx][:yy3]).must_equal 'xx.yy3'
|
1060
|
+
@ds.literal(Sequel[:ab34][:temp3_4ax]).must_equal 'ab34.temp3_4ax'
|
1061
|
+
@ds.literal(Sequel[:x1].as(:y2)).must_equal 'x1 AS y2'
|
1062
|
+
@ds.literal(Sequel[:abc2][:def3].as(:ggg4)).must_equal 'abc2.def3 AS ggg4'
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
it "should support upper case and lower case" do
|
1066
|
+
@ds.literal(:ABC).must_equal 'ABC'
|
1067
|
+
@ds.literal(Sequel[:Zvashtoy][:aBcD]).must_equal 'Zvashtoy.aBcD'
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
it "should support spaces inside column names" do
|
1071
|
+
@ds = @ds.with_quote_identifiers(true)
|
1072
|
+
@ds.literal(:"AB C").must_equal '"AB C"'
|
1073
|
+
@ds.literal(Sequel[:"Zvas htoy"][:"aB cD"]).must_equal '"Zvas htoy"."aB cD"'
|
1074
|
+
@ds.literal(Sequel[:"aB cD"].as(:"XX XX")).must_equal '"aB cD" AS "XX XX"'
|
1075
|
+
@ds.literal(Sequel[:"Zva shtoy"][:"aB cD"].as("XX XX")).must_equal '"Zva shtoy"."aB cD" AS "XX XX"'
|
1076
|
+
end
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
describe "Dataset#literal with splittable symbols" do
|
912
1080
|
before do
|
913
1081
|
@ds = Sequel.mock.dataset
|
914
1082
|
end
|
915
1083
|
|
916
|
-
|
1084
|
+
with_symbol_splitting "should convert qualified symbol notation into dot notation" do
|
917
1085
|
@ds.literal(:abc__def).must_equal 'abc.def'
|
918
1086
|
end
|
919
1087
|
|
920
|
-
|
1088
|
+
with_symbol_splitting "should convert AS symbol notation into SQL AS notation" do
|
921
1089
|
@ds.literal(:xyz___x).must_equal 'xyz AS x'
|
922
1090
|
@ds.literal(:abc__def___x).must_equal 'abc.def AS x'
|
923
1091
|
end
|
924
1092
|
|
925
|
-
|
1093
|
+
with_symbol_splitting "should support names with digits" do
|
926
1094
|
@ds.literal(:abc2).must_equal 'abc2'
|
927
1095
|
@ds.literal(:xx__yy3).must_equal 'xx.yy3'
|
928
1096
|
@ds.literal(:ab34__temp3_4ax).must_equal 'ab34.temp3_4ax'
|
@@ -930,12 +1098,12 @@ describe "Dataset#literal" do
|
|
930
1098
|
@ds.literal(:abc2__def3___ggg4).must_equal 'abc2.def3 AS ggg4'
|
931
1099
|
end
|
932
1100
|
|
933
|
-
|
1101
|
+
with_symbol_splitting "should support upper case and lower case" do
|
934
1102
|
@ds.literal(:ABC).must_equal 'ABC'
|
935
1103
|
@ds.literal(:Zvashtoy__aBcD).must_equal 'Zvashtoy.aBcD'
|
936
1104
|
end
|
937
1105
|
|
938
|
-
|
1106
|
+
with_symbol_splitting "should support spaces inside column names" do
|
939
1107
|
@ds = @ds.with_quote_identifiers(true)
|
940
1108
|
@ds.literal(:"AB C").must_equal '"AB C"'
|
941
1109
|
@ds.literal(:"Zvas htoy__aB cD").must_equal '"Zvas htoy"."aB cD"'
|
@@ -980,6 +1148,9 @@ describe "Dataset#literal" do
|
|
980
1148
|
|
981
1149
|
it "should literalize symbols as column references" do
|
982
1150
|
@dataset.literal(:name).must_equal "name"
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
with_symbol_splitting "should literalize symbols with embedded qualifiers as column references" do
|
983
1154
|
@dataset.literal(:items__name).must_equal "items.name"
|
984
1155
|
@dataset.literal(:"items__na#m$e").must_equal "items.na#m$e"
|
985
1156
|
end
|
@@ -1023,6 +1194,13 @@ describe "Dataset#literal" do
|
|
1023
1194
|
@dataset.literal(DateTime.new(2010, 1, 2, 3, 4, Rational(55, 10))).must_equal "'2010-01-02 03:04:05.500'"
|
1024
1195
|
end
|
1025
1196
|
|
1197
|
+
it "should literalize times properly for databases with different time and timestamp precision" do
|
1198
|
+
@dataset = @dataset.with_extend{def timestamp_precision; 3 end; def sqltime_precision; 6 end}
|
1199
|
+
@dataset.literal(Sequel::SQLTime.create(1, 2, 3, 500000)).must_equal "'01:02:03.500000'"
|
1200
|
+
@dataset.literal(Time.local(2010, 1, 2, 3, 4, 5, 500000)).must_equal "'2010-01-02 03:04:05.500'"
|
1201
|
+
@dataset.literal(DateTime.new(2010, 1, 2, 3, 4, Rational(55, 10))).must_equal "'2010-01-02 03:04:05.500'"
|
1202
|
+
end
|
1203
|
+
|
1026
1204
|
it "should literalize Date properly" do
|
1027
1205
|
d = Date.today
|
1028
1206
|
s = d.strftime("'%Y-%m-%d'")
|
@@ -1143,7 +1321,7 @@ describe "Dataset#from" do
|
|
1143
1321
|
@dataset.select_sql.must_equal "SELECT * FROM DEFFROM"
|
1144
1322
|
end
|
1145
1323
|
|
1146
|
-
|
1324
|
+
with_symbol_splitting "should accept :schema__table___alias symbol format" do
|
1147
1325
|
@dataset.from(:abc__def).select_sql.must_equal "SELECT * FROM abc.def"
|
1148
1326
|
@dataset.from(:a_b__c).select_sql.must_equal "SELECT * FROM a_b.c"
|
1149
1327
|
@dataset.from(:'#__#').select_sql.must_equal 'SELECT * FROM #.#'
|
@@ -1155,7 +1333,7 @@ describe "Dataset#from" do
|
|
1155
1333
|
@dataset.from(:'#___#').select_sql.must_equal 'SELECT * FROM # AS #'
|
1156
1334
|
end
|
1157
1335
|
|
1158
|
-
|
1336
|
+
with_symbol_splitting "should not handle multi level qualification in embedded symbols specially" do
|
1159
1337
|
@dataset.from(:foo__schema__table___alias).select_sql.must_equal "SELECT * FROM foo.schema__table AS alias"
|
1160
1338
|
end
|
1161
1339
|
|
@@ -1176,15 +1354,20 @@ describe "Dataset#select" do
|
|
1176
1354
|
|
1177
1355
|
it "should accept variable arity" do
|
1178
1356
|
@d.select(:name).sql.must_equal 'SELECT name FROM test'
|
1179
|
-
@d.select(:a, :b, :
|
1357
|
+
@d.select(:a, :b, Sequel[:test][:c]).sql.must_equal 'SELECT a, b, test.c FROM test'
|
1358
|
+
end
|
1359
|
+
|
1360
|
+
with_symbol_splitting "should accept symbols with embedded qualification and aliasing" do
|
1361
|
+
@d.select(:test__cc).sql.must_equal 'SELECT test.cc FROM test'
|
1362
|
+
@d.select(:test___cc).sql.must_equal 'SELECT test AS cc FROM test'
|
1363
|
+
@d.select(:test__name___n).sql.must_equal 'SELECT test.name AS n FROM test'
|
1180
1364
|
end
|
1181
1365
|
|
1182
1366
|
it "should accept symbols and literal strings" do
|
1183
1367
|
@d.select(Sequel.lit('aaa')).sql.must_equal 'SELECT aaa FROM test'
|
1184
1368
|
@d.select(:a, Sequel.lit('b')).sql.must_equal 'SELECT a, b FROM test'
|
1185
|
-
@d.select(:
|
1186
|
-
@d.select(Sequel.lit('test.d AS e'), :
|
1187
|
-
@d.select(:test__name___n).sql.must_equal 'SELECT test.name AS n FROM test'
|
1369
|
+
@d.select(:test, Sequel.lit('test.d AS e')).sql.must_equal 'SELECT test, test.d AS e FROM test'
|
1370
|
+
@d.select(Sequel.lit('test.d AS e'), :test).sql.must_equal 'SELECT test.d AS e, test FROM test'
|
1188
1371
|
end
|
1189
1372
|
|
1190
1373
|
it "should accept ColumnAlls" do
|
@@ -1192,6 +1375,10 @@ describe "Dataset#select" do
|
|
1192
1375
|
end
|
1193
1376
|
|
1194
1377
|
it "should accept QualifiedIdentifiers" do
|
1378
|
+
@d.select(Sequel.expr(Sequel[:test][:name]).as(:n)).sql.must_equal 'SELECT test.name AS n FROM test'
|
1379
|
+
end
|
1380
|
+
|
1381
|
+
with_symbol_splitting "should accept qualified identifiers in symbols in expressions" do
|
1195
1382
|
@d.select(Sequel.expr(:test__name).as(:n)).sql.must_equal 'SELECT test.name AS n FROM test'
|
1196
1383
|
end
|
1197
1384
|
|
@@ -1214,7 +1401,7 @@ describe "Dataset#select" do
|
|
1214
1401
|
|
1215
1402
|
it "should accept arbitrary objects and literalize them correctly" do
|
1216
1403
|
@d.select(1, :a, 't').sql.must_equal "SELECT 1, a, 't' FROM test"
|
1217
|
-
@d.select(nil, Sequel.function(:sum, :t), :
|
1404
|
+
@d.select(nil, Sequel.function(:sum, :t), Sequel[:x].as(:y)).sql.must_equal "SELECT NULL, sum(t), x AS y FROM test"
|
1218
1405
|
@d.select(nil, 1, Sequel.as(:x, :y)).sql.must_equal "SELECT NULL, 1, x AS y FROM test"
|
1219
1406
|
end
|
1220
1407
|
|
@@ -1240,6 +1427,10 @@ describe "Dataset#select_group" do
|
|
1240
1427
|
|
1241
1428
|
it "should set both SELECT and GROUP" do
|
1242
1429
|
@d.select_group(:name).sql.must_equal 'SELECT name FROM test GROUP BY name'
|
1430
|
+
@d.select_group(:a, Sequel[:b][:c], Sequel[:d].as(:e)).sql.must_equal 'SELECT a, b.c, d AS e FROM test GROUP BY a, b.c, d'
|
1431
|
+
end
|
1432
|
+
|
1433
|
+
with_symbol_splitting "should set both SELECT and GROUP when using splittable symbols" do
|
1243
1434
|
@d.select_group(:a, :b__c, :d___e).sql.must_equal 'SELECT a, b.c, d AS e FROM test GROUP BY a, b.c, d'
|
1244
1435
|
end
|
1245
1436
|
|
@@ -1275,11 +1466,11 @@ describe "Dataset#select_all" do
|
|
1275
1466
|
@d.select_all(:test, :foo).sql.must_equal 'SELECT test.*, foo.* FROM test'
|
1276
1467
|
end
|
1277
1468
|
|
1278
|
-
|
1469
|
+
with_symbol_splitting "should work correctly with qualified symbols" do
|
1279
1470
|
@d.select_all(:sch__test).sql.must_equal 'SELECT sch.test.* FROM test'
|
1280
1471
|
end
|
1281
1472
|
|
1282
|
-
|
1473
|
+
with_symbol_splitting "should work correctly with aliased symbols" do
|
1283
1474
|
@d.select_all(:test___al).sql.must_equal 'SELECT al.* FROM test'
|
1284
1475
|
@d.select_all(:sch__test___al).sql.must_equal 'SELECT al.* FROM test'
|
1285
1476
|
end
|
@@ -1296,10 +1487,15 @@ describe "Dataset#select_all" do
|
|
1296
1487
|
@d.select_all(Sequel.expr(:test).as(:al)).sql.must_equal 'SELECT al.* FROM test'
|
1297
1488
|
end
|
1298
1489
|
|
1299
|
-
|
1490
|
+
with_symbol_splitting "should work correctly with SQL::JoinClauses with splittable symbols" do
|
1300
1491
|
d = @d.cross_join(:foo).cross_join(:test___al)
|
1301
1492
|
@d.select_all(*d.opts[:join]).sql.must_equal 'SELECT foo.*, al.* FROM test'
|
1302
1493
|
end
|
1494
|
+
|
1495
|
+
it "should work correctly with SQL::JoinClauses" do
|
1496
|
+
d = @d.cross_join(:foo).cross_join(Sequel[:test].as(:al))
|
1497
|
+
@d.select_all(*d.opts[:join]).sql.must_equal 'SELECT foo.*, al.* FROM test'
|
1498
|
+
end
|
1303
1499
|
end
|
1304
1500
|
|
1305
1501
|
describe "Dataset#select_more" do
|
@@ -1734,10 +1930,14 @@ describe "Dataset#qualified_column_name" do
|
|
1734
1930
|
@dataset.literal(@dataset.send(:qualified_column_name, :b1, :items)).must_equal 'items.b1'
|
1735
1931
|
end
|
1736
1932
|
|
1737
|
-
|
1933
|
+
with_symbol_splitting "should not changed the qualifed column's table if given a qualified symbol" do
|
1738
1934
|
@dataset.literal(@dataset.send(:qualified_column_name, :ccc__b, :items)).must_equal 'ccc.b'
|
1739
1935
|
end
|
1740
1936
|
|
1937
|
+
it "should not changed the qualifed column's table if given a qualified identifier" do
|
1938
|
+
@dataset.literal(@dataset.send(:qualified_column_name, Sequel[:ccc][:b], :items)).must_equal 'ccc.b'
|
1939
|
+
end
|
1940
|
+
|
1741
1941
|
it "should handle an aliased identifier" do
|
1742
1942
|
@dataset.literal(@dataset.send(:qualified_column_name, :ccc, Sequel.expr(:items).as(:i))).must_equal 'i.ccc'
|
1743
1943
|
end
|
@@ -2018,6 +2218,11 @@ describe "Dataset#group_and_count" do
|
|
2018
2218
|
end
|
2019
2219
|
|
2020
2220
|
it "should format column aliases in the select clause but not in the group clause" do
|
2221
|
+
@ds.group_and_count(Sequel[:name].as(:n)).sql.must_equal "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
2222
|
+
@ds.group_and_count(Sequel[:name][:n]).sql.must_equal "SELECT name.n, count(*) AS count FROM test GROUP BY name.n"
|
2223
|
+
end
|
2224
|
+
|
2225
|
+
with_symbol_splitting "should format column aliases in the select clause but not in the group clause when using splittable symbols" do
|
2021
2226
|
@ds.group_and_count(:name___n).sql.must_equal "SELECT name AS n, count(*) AS count FROM test GROUP BY name"
|
2022
2227
|
@ds.group_and_count(:name__n).sql.must_equal "SELECT name.n, count(*) AS count FROM test GROUP BY name.n"
|
2023
2228
|
end
|
@@ -2066,23 +2271,35 @@ describe "Dataset#first_source_alias" do
|
|
2066
2271
|
@ds = Sequel.mock.dataset
|
2067
2272
|
end
|
2068
2273
|
|
2274
|
+
it "should be the entire first source if not aliased" do
|
2275
|
+
deprecated do
|
2276
|
+
# SEQUEL5: Remove deprecation block, but keep code
|
2277
|
+
@ds.from(:s__t).first_source_alias.must_equal :s__t
|
2278
|
+
end
|
2279
|
+
end
|
2280
|
+
|
2281
|
+
with_symbol_splitting "should be the alias if aliased when using symbol splitting" do
|
2282
|
+
@ds.from(:t___a).first_source_alias.must_equal :a
|
2283
|
+
@ds.from(:s__t___a).first_source_alias.must_equal :a
|
2284
|
+
end
|
2285
|
+
|
2286
|
+
with_symbol_splitting "should be aliased as first_source when using symbol splitting" do
|
2287
|
+
@ds.from(:s__t___a).first_source.must_equal :a
|
2288
|
+
end
|
2289
|
+
|
2069
2290
|
it "should be the entire first source if not aliased" do
|
2070
2291
|
@ds.from(:t).first_source_alias.must_equal :t
|
2071
2292
|
@ds.from(Sequel.identifier(:t__a)).first_source_alias.must_equal Sequel.identifier(:t__a)
|
2072
|
-
@ds.from(:s__t).first_source_alias.must_equal :s__t
|
2073
2293
|
@ds.from(Sequel.qualify(:s, :t)).first_source_alias.must_equal Sequel.qualify(:s, :t)
|
2074
2294
|
end
|
2075
2295
|
|
2076
2296
|
it "should be the alias if aliased" do
|
2077
|
-
@ds.from(:t___a).first_source_alias.must_equal :a
|
2078
|
-
@ds.from(:s__t___a).first_source_alias.must_equal :a
|
2079
2297
|
@ds.from(Sequel.expr(:t).as(:a)).first_source_alias.must_equal :a
|
2080
2298
|
end
|
2081
2299
|
|
2082
2300
|
it "should be aliased as first_source" do
|
2083
2301
|
@ds.from(:t).first_source.must_equal :t
|
2084
2302
|
@ds.from(Sequel.identifier(:t__a)).first_source.must_equal Sequel.identifier(:t__a)
|
2085
|
-
@ds.from(:s__t___a).first_source.must_equal :a
|
2086
2303
|
@ds.from(Sequel.expr(:t).as(:a)).first_source.must_equal :a
|
2087
2304
|
end
|
2088
2305
|
|
@@ -2098,14 +2315,23 @@ describe "Dataset#first_source_table" do
|
|
2098
2315
|
|
2099
2316
|
it "should be the entire first source if not aliased" do
|
2100
2317
|
@ds.from(:t).first_source_table.must_equal :t
|
2318
|
+
deprecated do
|
2319
|
+
# SEQUEL5: Remove deprecation block, but keep code
|
2320
|
+
@ds.from(:s__t).first_source_table.must_equal :s__t
|
2321
|
+
end
|
2322
|
+
end
|
2323
|
+
|
2324
|
+
it "should be the entire first source if not aliased" do
|
2101
2325
|
@ds.from(Sequel.identifier(:t__a)).first_source_table.must_equal Sequel.identifier(:t__a)
|
2102
|
-
@ds.from(:s__t).first_source_table.must_equal :s__t
|
2103
2326
|
@ds.from(Sequel.qualify(:s, :t)).first_source_table.must_equal Sequel.qualify(:s, :t)
|
2104
2327
|
end
|
2105
2328
|
|
2106
|
-
|
2329
|
+
with_symbol_splitting "should be the unaliased part if aliased symbols with embedded aliasing" do
|
2107
2330
|
@ds.literal(@ds.from(:t___a).first_source_table).must_equal "t"
|
2108
2331
|
@ds.literal(@ds.from(:s__t___a).first_source_table).must_equal "s.t"
|
2332
|
+
end
|
2333
|
+
|
2334
|
+
it "should be the unaliased part if aliased" do
|
2109
2335
|
@ds.literal(@ds.from(Sequel.expr(:t).as(:a)).first_source_table).must_equal "t"
|
2110
2336
|
end
|
2111
2337
|
|
@@ -2184,6 +2410,10 @@ describe "Dataset#join_table" do
|
|
2184
2410
|
end
|
2185
2411
|
|
2186
2412
|
it "should support multiple joins" do
|
2413
|
+
@d.join_table(:inner, :b, :items_id=>:id).join_table(:left_outer, :c, :b_id => Sequel[:b][:id]).sql.must_equal 'SELECT * FROM "items" INNER JOIN "b" ON ("b"."items_id" = "items"."id") LEFT OUTER JOIN "c" ON ("c"."b_id" = "b"."id")'
|
2414
|
+
end
|
2415
|
+
|
2416
|
+
with_symbol_splitting "should support multiple joins with splittable symbols" do
|
2187
2417
|
@d.join_table(:inner, :b, :items_id=>:id).join_table(:left_outer, :c, :b_id => :b__id).sql.must_equal 'SELECT * FROM "items" INNER JOIN "b" ON ("b"."items_id" = "items"."id") LEFT OUTER JOIN "c" ON ("c"."b_id" = "b"."id")'
|
2188
2418
|
end
|
2189
2419
|
|
@@ -2260,11 +2490,11 @@ describe "Dataset#join_table" do
|
|
2260
2490
|
@d.from(Sequel.as(:foo, :f)).join_table(:inner, :bar, :id => :bar_id).sql.must_equal 'SELECT * FROM "foo" AS "f" INNER JOIN "bar" ON ("bar"."id" = "f"."bar_id")'
|
2261
2491
|
end
|
2262
2492
|
|
2263
|
-
|
2493
|
+
with_symbol_splitting "should support implicit schemas in from table symbols" do
|
2264
2494
|
@d.from(:s__t).join(:u__v, {:id => :player_id}).sql.must_equal 'SELECT * FROM "s"."t" INNER JOIN "u"."v" ON ("u"."v"."id" = "s"."t"."player_id")'
|
2265
2495
|
end
|
2266
2496
|
|
2267
|
-
|
2497
|
+
with_symbol_splitting "should support implicit aliases in from table symbols" do
|
2268
2498
|
@d.from(:t___z).join(:v___y, {:id => :player_id}).sql.must_equal 'SELECT * FROM "t" AS "z" INNER JOIN "v" AS "y" ON ("y"."id" = "z"."player_id")'
|
2269
2499
|
@d.from(:s__t___z).join(:u__v___y, {:id => :player_id}).sql.must_equal 'SELECT * FROM "s"."t" AS "z" INNER JOIN "u"."v" AS "y" ON ("y"."id" = "z"."player_id")'
|
2270
2500
|
end
|
@@ -2318,6 +2548,11 @@ describe "Dataset#join_table" do
|
|
2318
2548
|
end
|
2319
2549
|
|
2320
2550
|
it "should support joining datasets and aliasing the join" do
|
2551
|
+
ds = Sequel.mock.dataset.from(:categories)
|
2552
|
+
@d.join_table(:left_outer, ds, {Sequel[:ds][:item_id] => :id}, :table_alias=>:ds).sql.must_equal 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "ds" ON ("ds"."item_id" = "items"."id")'
|
2553
|
+
end
|
2554
|
+
|
2555
|
+
with_symbol_splitting "should support joining datasets and aliasing the join when using symbols with embedded qualification" do
|
2321
2556
|
ds = Sequel.mock.dataset.from(:categories)
|
2322
2557
|
@d.join_table(:left_outer, ds, {:ds__item_id => :id}, :table_alias=>:ds).sql.must_equal 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "ds" ON ("ds"."item_id" = "items"."id")'
|
2323
2558
|
end
|
@@ -2325,7 +2560,7 @@ describe "Dataset#join_table" do
|
|
2325
2560
|
it "should support joining multiple datasets" do
|
2326
2561
|
ds = Sequel.mock.dataset.from(:categories)
|
2327
2562
|
ds2 = Sequel.mock.dataset.from(:nodes).select(:name)
|
2328
|
-
ds3 = Sequel.mock.dataset.from(:attributes).
|
2563
|
+
ds3 = Sequel.mock.dataset.from(:attributes).where(Sequel.lit("name = 'blah'"))
|
2329
2564
|
|
2330
2565
|
@d.join_table(:left_outer, ds, :item_id => :id).join_table(:inner, ds2, :node_id=>:id).join_table(:right_outer, ds3, :attribute_id=>:id).sql.
|
2331
2566
|
must_equal 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "t1" ON ("t1"."item_id" = "items"."id") ' \
|
@@ -2333,10 +2568,14 @@ describe "Dataset#join_table" do
|
|
2333
2568
|
'RIGHT OUTER JOIN (SELECT * FROM attributes WHERE (name = \'blah\')) AS "t3" ON ("t3"."attribute_id" = "t2"."id")'
|
2334
2569
|
end
|
2335
2570
|
|
2336
|
-
|
2571
|
+
deprecated "should support using a string as the join condition" do
|
2337
2572
|
@d.join(:categories, "c.item_id = items.id", :table_alias=>:c).sql.must_equal 'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
|
2338
2573
|
end
|
2339
2574
|
|
2575
|
+
it "should support using a literal string as the join condition" do
|
2576
|
+
@d.join(:categories, Sequel.lit("c.item_id = items.id"), :table_alias=>:c).sql.must_equal 'SELECT * FROM "items" INNER JOIN "categories" AS "c" ON (c.item_id = items.id)'
|
2577
|
+
end
|
2578
|
+
|
2340
2579
|
it "should support using a boolean column as the join condition" do
|
2341
2580
|
@d.join(:categories, :active).sql.must_equal 'SELECT * FROM "items" INNER JOIN "categories" ON "active"'
|
2342
2581
|
end
|
@@ -2374,6 +2613,14 @@ describe "Dataset#join_table" do
|
|
2374
2613
|
proc{@d.join(:categories, [:id]){|j,lj,js|}}.must_raise(Sequel::Error)
|
2375
2614
|
end
|
2376
2615
|
|
2616
|
+
with_symbol_splitting "should support using a block that receieves the join table/alias, last join table/alias, and array of previous joins when using splittable symbols" do
|
2617
|
+
@d.from(:items___i).join(:categories, nil, :table_alias=>:c) do |join_alias, last_join_alias, joins|
|
2618
|
+
join_alias.must_equal :c
|
2619
|
+
last_join_alias.must_equal :i
|
2620
|
+
joins.must_equal []
|
2621
|
+
end
|
2622
|
+
end
|
2623
|
+
|
2377
2624
|
it "should support using a block that receieves the join table/alias, last join table/alias, and array of previous joins" do
|
2378
2625
|
@d.join(:categories) do |join_alias, last_join_alias, joins|
|
2379
2626
|
join_alias.must_equal :categories
|
@@ -2387,12 +2634,6 @@ describe "Dataset#join_table" do
|
|
2387
2634
|
joins.must_equal []
|
2388
2635
|
end
|
2389
2636
|
|
2390
|
-
@d.from(:items___i).join(:categories, nil, :table_alias=>:c) do |join_alias, last_join_alias, joins|
|
2391
|
-
join_alias.must_equal :c
|
2392
|
-
last_join_alias.must_equal :i
|
2393
|
-
joins.must_equal []
|
2394
|
-
end
|
2395
|
-
|
2396
2637
|
@d.join(:blah).join(:categories, nil, :table_alias=>:c) do |join_alias, last_join_alias, joins|
|
2397
2638
|
join_alias.must_equal :c
|
2398
2639
|
last_join_alias.must_equal :blah
|
@@ -2434,6 +2675,12 @@ describe "Dataset#join_table" do
|
|
2434
2675
|
end
|
2435
2676
|
|
2436
2677
|
it "should prefer explicit aliases over implicit" do
|
2678
|
+
@d.from(Sequel[:items].as(:i)).join(Sequel[:categories].as(:c), {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.must_equal 'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
|
2679
|
+
@d.from(Sequel.expr(:items).as(:i)).join(Sequel.expr(:categories).as(:c), {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.
|
2680
|
+
must_equal 'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
|
2681
|
+
end
|
2682
|
+
|
2683
|
+
with_symbol_splitting "should prefer explicit aliases over implicit when using splittable symbols" do
|
2437
2684
|
@d.from(:items___i).join(:categories___c, {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.must_equal 'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
|
2438
2685
|
@d.from(Sequel.expr(:items).as(:i)).join(Sequel.expr(:categories).as(:c), {:category_id => :id}, {:table_alias=>:c2, :implicit_qualifier=>:i2}).sql.
|
2439
2686
|
must_equal 'SELECT * FROM "items" AS "i" INNER JOIN "categories" AS "c2" ON ("c2"."category_id" = "i2"."id")'
|
@@ -2478,7 +2725,7 @@ describe "Dataset aggregate methods" do
|
|
2478
2725
|
|
2479
2726
|
it "should accept qualified columns" do
|
2480
2727
|
5.times do
|
2481
|
-
@d.avg(:
|
2728
|
+
@d.avg(Sequel[:test][:bc]).must_equal 'SELECT avg(test.bc) AS avg FROM test LIMIT 1'
|
2482
2729
|
end
|
2483
2730
|
end
|
2484
2731
|
|
@@ -2586,9 +2833,9 @@ describe "Dataset #first and #last" do
|
|
2586
2833
|
ds = @d.order(:a).freeze
|
2587
2834
|
5.times do
|
2588
2835
|
ds.first(:z => 26).must_equal(:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1')
|
2589
|
-
ds.first(
|
2836
|
+
ds.first([[:z, 15]]).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1')
|
2590
2837
|
ds.last(:z => 26).must_equal(:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1')
|
2591
|
-
ds.last(
|
2838
|
+
ds.last([[:z, 15]]).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1')
|
2592
2839
|
end
|
2593
2840
|
end
|
2594
2841
|
|
@@ -2613,10 +2860,30 @@ describe "Dataset #first and #last" do
|
|
2613
2860
|
ds = @d.order(:name).freeze
|
2614
2861
|
5.times do
|
2615
2862
|
@d.first(:y=>25){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 25) AND (z > 26)) LIMIT 1')
|
2616
|
-
ds.last(
|
2863
|
+
ds.last(:y=>16){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 16) AND (z > 26)) ORDER BY name DESC LIMIT 1')
|
2617
2864
|
end
|
2618
2865
|
end
|
2619
2866
|
|
2867
|
+
it "should combine block and standard argument filters if argument is a literal string" do
|
2868
|
+
ds = @d.order(:name).freeze
|
2869
|
+
5.times do
|
2870
|
+
@d.first(Sequel.lit('y = 25')){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 25) AND (z > 26)) LIMIT 1')
|
2871
|
+
ds.last(Sequel.lit('y = 16')){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 16) AND (z > 26)) ORDER BY name DESC LIMIT 1')
|
2872
|
+
@d.first(Sequel.lit('y = ?', 25)){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 25) AND (z > 26)) LIMIT 1')
|
2873
|
+
ds.last(Sequel.lit('y = ?', 16)){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 16) AND (z > 26)) ORDER BY name DESC LIMIT 1')
|
2874
|
+
end
|
2875
|
+
end
|
2876
|
+
|
2877
|
+
deprecated "should combine block and standard argument filters if argument is a string" do
|
2878
|
+
ds = @d.order(:name).freeze
|
2879
|
+
5.times do
|
2880
|
+
@d.first('y = 25'){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 25) AND (z > 26)) LIMIT 1')
|
2881
|
+
ds.last('y = 16'){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 16) AND (z > 26)) ORDER BY name DESC LIMIT 1')
|
2882
|
+
@d.first('y = ?', 25){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 25) AND (z > 26)) LIMIT 1')
|
2883
|
+
ds.last('y = ?', 16){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 16) AND (z > 26)) ORDER BY name DESC LIMIT 1')
|
2884
|
+
end
|
2885
|
+
end
|
2886
|
+
|
2620
2887
|
it "should filter and return an array of records if an Integer argument is provided and a block is given" do
|
2621
2888
|
ds = @d.order(:a).freeze
|
2622
2889
|
5.times do
|
@@ -2657,7 +2924,7 @@ describe "Dataset #first!" do
|
|
2657
2924
|
|
2658
2925
|
it "should return the first! matching record if argument is not an Integer" do
|
2659
2926
|
@d.order(:a).first!(:z => 26).must_equal(:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1')
|
2660
|
-
@d.order(:a).first!('z = ?', 15).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1')
|
2927
|
+
@d.order(:a).first!(Sequel.lit('z = ?', 15)).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1')
|
2661
2928
|
end
|
2662
2929
|
|
2663
2930
|
it "should set the limit and return an array of records if the given number is > 1" do
|
@@ -2902,7 +3169,7 @@ describe "Dataset#get" do
|
|
2902
3169
|
it "should work with aliased fields" do
|
2903
3170
|
@d.freeze
|
2904
3171
|
5.times do
|
2905
|
-
@d.get(Sequel.expr(:
|
3172
|
+
@d.get(Sequel.expr(Sequel[:x][:b]).as(:name)).must_equal "SELECT x.b AS name FROM test LIMIT 1"
|
2906
3173
|
end
|
2907
3174
|
end
|
2908
3175
|
|
@@ -2914,7 +3181,7 @@ describe "Dataset#get" do
|
|
2914
3181
|
end
|
2915
3182
|
|
2916
3183
|
it "should accept a block that yields a virtual row" do
|
2917
|
-
@d.get{|o| o.
|
3184
|
+
@d.get{|o| o.x_b.as(:name)}.must_equal "SELECT x_b AS name FROM test LIMIT 1"
|
2918
3185
|
@d.get{x(1).as(:name)}.must_equal "SELECT x(1) AS name FROM test LIMIT 1"
|
2919
3186
|
end
|
2920
3187
|
|
@@ -2937,26 +3204,32 @@ describe "Dataset#get" do
|
|
2937
3204
|
@d.get([:name]).must_equal ['SELECT name FROM test LIMIT 1']
|
2938
3205
|
end
|
2939
3206
|
|
2940
|
-
it "should handle an array with
|
3207
|
+
it "should handle an array with aliased expressions" do
|
2941
3208
|
@d = @d.with_fetch(:name=>1, :abc=>2)
|
2942
|
-
@d.get([:
|
3209
|
+
@d.get([Sequel[:n].as(:name), Sequel.as(:a, :abc)]).must_equal [1, 2]
|
2943
3210
|
@d.db.sqls.must_equal ['SELECT n AS name, a AS abc FROM test LIMIT 1']
|
2944
3211
|
end
|
2945
3212
|
|
3213
|
+
with_symbol_splitting "should handle an array with symbols with embedded aliases" do
|
3214
|
+
@d = @d.with_fetch(:name=>1, :abc=>2)
|
3215
|
+
@d.get([:n___name, :a__b___abc]).must_equal [1, 2]
|
3216
|
+
@d.db.sqls.must_equal ['SELECT n AS name, a.b AS abc FROM test LIMIT 1']
|
3217
|
+
end
|
3218
|
+
|
2946
3219
|
it "should raise an Error if an alias cannot be determined" do
|
2947
3220
|
proc{@d.with_fetch(:name=>1, :abc=>2).get([Sequel.+(:a, 1), :a])}.must_raise(Sequel::Error)
|
2948
3221
|
end
|
2949
3222
|
|
2950
3223
|
it "should support an array of expressions in a virtual row" do
|
2951
3224
|
@d = @d.with_fetch(:name=>1, :abc=>2)
|
2952
|
-
@d.get{[name,
|
3225
|
+
@d.get{[name, n[abc]]}.must_equal [1, 2]
|
2953
3226
|
@d.db.sqls.must_equal ['SELECT name, n.abc FROM test LIMIT 1']
|
2954
3227
|
end
|
2955
3228
|
|
2956
3229
|
it "should work with static SQL" do
|
2957
3230
|
@d.with_sql('SELECT foo').get(:name).must_equal "SELECT foo"
|
2958
3231
|
@d = @d.with_fetch(:name=>1, :abc=>2)
|
2959
|
-
@d.with_sql('SELECT foo').get{[name,
|
3232
|
+
@d.with_sql('SELECT foo').get{[name, n[abc]]}.must_equal [1, 2]
|
2960
3233
|
@d.db.sqls.must_equal ['SELECT foo'] * 2
|
2961
3234
|
end
|
2962
3235
|
|
@@ -3023,7 +3296,7 @@ describe "Dataset#columns" do
|
|
3023
3296
|
@dataset.db.sqls.must_equal ['SELECT * FROM items LIMIT 1']
|
3024
3297
|
@dataset.columns.must_equal [:a]
|
3025
3298
|
@dataset.db.sqls.must_equal []
|
3026
|
-
ds = @dataset.select{foo
|
3299
|
+
ds = @dataset.select{foo.function}
|
3027
3300
|
ds.columns.must_equal [:b]
|
3028
3301
|
@dataset.db.sqls.must_equal ['SELECT foo() FROM items LIMIT 1']
|
3029
3302
|
end
|
@@ -3251,7 +3524,7 @@ describe "Dataset#multi_insert" do
|
|
3251
3524
|
'COMMIT']
|
3252
3525
|
end
|
3253
3526
|
|
3254
|
-
|
3527
|
+
with_symbol_splitting "should handle splittable symbols for tables" do
|
3255
3528
|
@ds = @ds.from(:sch__tab)
|
3256
3529
|
@ds.multi_insert(@list)
|
3257
3530
|
@db.sqls.must_equal ['BEGIN',
|
@@ -3259,7 +3532,9 @@ describe "Dataset#multi_insert" do
|
|
3259
3532
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
3260
3533
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
3261
3534
|
'COMMIT']
|
3535
|
+
end
|
3262
3536
|
|
3537
|
+
it "should handle SQL::QualifiedIdentifier for tables" do
|
3263
3538
|
@ds = @ds.from(Sequel.qualify(:sch, :tab))
|
3264
3539
|
@ds.multi_insert(@list)
|
3265
3540
|
@db.sqls.must_equal ['BEGIN',
|
@@ -3267,7 +3542,9 @@ describe "Dataset#multi_insert" do
|
|
3267
3542
|
"INSERT INTO sch.tab (name) VALUES ('def')",
|
3268
3543
|
"INSERT INTO sch.tab (name) VALUES ('ghi')",
|
3269
3544
|
'COMMIT']
|
3545
|
+
end
|
3270
3546
|
|
3547
|
+
it "should handle SQL::Identifier for tables" do
|
3271
3548
|
@ds = @ds.from(Sequel.identifier(:sch__tab))
|
3272
3549
|
@ds.multi_insert(@list)
|
3273
3550
|
@db.sqls.must_equal ['BEGIN',
|
@@ -3320,11 +3597,19 @@ describe "Dataset#update_sql" do
|
|
3320
3597
|
@ds = Sequel.mock.dataset.from(:items)
|
3321
3598
|
end
|
3322
3599
|
|
3323
|
-
|
3600
|
+
deprecated "should accept strings" do
|
3324
3601
|
@ds.update_sql("a = b").must_equal "UPDATE items SET a = b"
|
3325
3602
|
end
|
3326
3603
|
|
3327
|
-
it "should
|
3604
|
+
it "should accept literal strings" do
|
3605
|
+
@ds.update_sql(Sequel.lit("a = b")).must_equal "UPDATE items SET a = b"
|
3606
|
+
end
|
3607
|
+
|
3608
|
+
it "should handle qualified identifiers" do
|
3609
|
+
@ds.update_sql(Sequel[:items][:a]=>:b).must_equal "UPDATE items SET items.a = b"
|
3610
|
+
end
|
3611
|
+
|
3612
|
+
with_symbol_splitting "should handle implicitly qualified symbols" do
|
3328
3613
|
@ds.update_sql(:items__a=>:b).must_equal "UPDATE items SET items.a = b"
|
3329
3614
|
end
|
3330
3615
|
|
@@ -3400,8 +3685,11 @@ describe "Dataset#insert_sql" do
|
|
3400
3685
|
@ds.insert_sql([:a, :b, :c], Sequel.lit('VALUES (1, 2, 3)')).must_equal "INSERT INTO items (a, b, c) VALUES (1, 2, 3)"
|
3401
3686
|
end
|
3402
3687
|
|
3403
|
-
|
3688
|
+
with_symbol_splitting "should use unaliased table name when using splittable symbol" do
|
3404
3689
|
@ds.from(:items___i).insert_sql(1).must_equal "INSERT INTO items VALUES (1)"
|
3690
|
+
end
|
3691
|
+
|
3692
|
+
it "should use unaliased table name" do
|
3405
3693
|
@ds.from(Sequel.as(:items, :i)).insert_sql(1).must_equal "INSERT INTO items VALUES (1)"
|
3406
3694
|
end
|
3407
3695
|
end
|
@@ -3724,11 +4012,16 @@ describe "Dataset prepared statements and bound variables " do
|
|
3724
4012
|
'<Sequel::Mock::Dataset/PreparedStatement "SELECT * FROM items WHERE (num = $n)">'
|
3725
4013
|
end
|
3726
4014
|
|
3727
|
-
|
4015
|
+
deprecated "should handle literal strings" do
|
3728
4016
|
@ds.filter("num = ?", :$n).call(:select, :n=>1)
|
3729
4017
|
@db.sqls.must_equal ['SELECT * FROM items WHERE (num = 1)']
|
3730
4018
|
end
|
3731
4019
|
|
4020
|
+
it "should handle literal strings" do
|
4021
|
+
@ds.filter(Sequel.lit("num = ?", :$n)).call(:select, :n=>1)
|
4022
|
+
@db.sqls.must_equal ['SELECT * FROM items WHERE (num = 1)']
|
4023
|
+
end
|
4024
|
+
|
3732
4025
|
it "should handle columns on prepared statements correctly" do
|
3733
4026
|
@db.columns = [:num]
|
3734
4027
|
@ds = @ds.with_extend{def select_where_sql(sql) super(sql); sql << " OR #{columns.first} = 1" if opts[:where] end}
|
@@ -3751,11 +4044,16 @@ describe "Dataset prepared statements and bound variables " do
|
|
3751
4044
|
@db.sqls.must_equal ['SELECT * FROM items WHERE (0 AND (num IN (SELECT num FROM items WHERE (num IN (SELECT num FROM items WHERE (num = 1))))))']
|
3752
4045
|
end
|
3753
4046
|
|
3754
|
-
|
4047
|
+
deprecated "should handle subselects with strings" do
|
3755
4048
|
@ds.filter(:$b).filter(:num=>@ds.select(:num).filter("num = ?", :$n)).call(:select, :n=>1, :b=>0)
|
3756
4049
|
@db.sqls.must_equal ['SELECT * FROM items WHERE (0 AND (num IN (SELECT num FROM items WHERE (num = 1))))']
|
3757
4050
|
end
|
3758
4051
|
|
4052
|
+
it "should handle subselects with literal strings" do
|
4053
|
+
@ds.filter(:$b).filter(:num=>@ds.select(:num).filter(Sequel.lit("num = ?", :$n))).call(:select, :n=>1, :b=>0)
|
4054
|
+
@db.sqls.must_equal ['SELECT * FROM items WHERE (0 AND (num IN (SELECT num FROM items WHERE (num = 1))))']
|
4055
|
+
end
|
4056
|
+
|
3759
4057
|
it "should handle subselects with static sql and placeholders" do
|
3760
4058
|
@ds.filter(:$b).filter(:num=>@db["SELECT num FROM items WHERE (num = ?)", :$n]).call(:select, :n=>1, :b=>0)
|
3761
4059
|
@db.sqls.must_equal ['SELECT * FROM items WHERE (0 AND (num IN (SELECT num FROM items WHERE (num = 1))))']
|
@@ -3873,6 +4171,10 @@ describe "Sequel::Dataset#qualify" do
|
|
3873
4171
|
end
|
3874
4172
|
|
3875
4173
|
it "should handle symbols" do
|
4174
|
+
@ds.select(:a).qualify.sql.must_equal 'SELECT t.a FROM t'
|
4175
|
+
end
|
4176
|
+
|
4177
|
+
with_symbol_splitting "should handle splittable symbols" do
|
3876
4178
|
@ds.select(:a, :b__c, :d___e, :f__g___h).qualify.sql.must_equal 'SELECT t.a, b.c, t.d AS e, f.g AS h FROM t'
|
3877
4179
|
end
|
3878
4180
|
|
@@ -3922,11 +4224,11 @@ describe "Sequel::Dataset#qualify" do
|
|
3922
4224
|
end
|
3923
4225
|
|
3924
4226
|
it "should handle SQL::PlaceholderLiteralStrings" do
|
3925
|
-
@ds.filter('? > ?', :a, 1).qualify.sql.must_equal 'SELECT t.* FROM t WHERE (t.a > 1)'
|
4227
|
+
@ds.filter(Sequel.lit('? > ?', :a, 1)).qualify.sql.must_equal 'SELECT t.* FROM t WHERE (t.a > 1)'
|
3926
4228
|
end
|
3927
4229
|
|
3928
4230
|
it "should handle SQL::PlaceholderLiteralStrings with named placeholders" do
|
3929
|
-
@ds.filter(':a > :b', :a=>:c, :b=>1).qualify.sql.must_equal 'SELECT t.* FROM t WHERE (t.c > 1)'
|
4231
|
+
@ds.filter(Sequel.lit(':a > :b', :a=>:c, :b=>1)).qualify.sql.must_equal 'SELECT t.* FROM t WHERE (t.c > 1)'
|
3930
4232
|
end
|
3931
4233
|
|
3932
4234
|
it "should handle SQL::Wrappers" do
|
@@ -3960,7 +4262,7 @@ describe "Sequel::Dataset#qualify" do
|
|
3960
4262
|
end
|
3961
4263
|
|
3962
4264
|
it "should handle all other objects by returning them unchanged" do
|
3963
|
-
@ds.select("a").filter{a(3)}.filter('blah').order(Sequel.lit('true')).group(Sequel.lit('a > ?', 1)).having(false).qualify.sql.must_equal "SELECT 'a' FROM t WHERE (a(3) AND (blah)) GROUP BY a > 1 HAVING 'f' ORDER BY true"
|
4265
|
+
@ds.select("a").filter{a(3)}.filter(Sequel.lit('blah')).order(Sequel.lit('true')).group(Sequel.lit('a > ?', 1)).having(false).qualify.sql.must_equal "SELECT 'a' FROM t WHERE (a(3) AND (blah)) GROUP BY a > 1 HAVING 'f' ORDER BY true"
|
3964
4266
|
end
|
3965
4267
|
end
|
3966
4268
|
|
@@ -4313,7 +4615,12 @@ describe "Sequel::Dataset#select_map" do
|
|
4313
4615
|
@ds.db.sqls.must_equal ['SELECT a FROM t']
|
4314
4616
|
end
|
4315
4617
|
|
4316
|
-
it "should handle
|
4618
|
+
it "should handle qualified identifiers in arguments" do
|
4619
|
+
@ds.select_map(Sequel[:a][:b]).must_equal [1, 2]
|
4620
|
+
@ds.db.sqls.must_equal ['SELECT a.b FROM t']
|
4621
|
+
end
|
4622
|
+
|
4623
|
+
with_symbol_splitting "should handle implicit qualifiers in arguments" do
|
4317
4624
|
@ds.select_map(:a__b).must_equal [1, 2]
|
4318
4625
|
@ds.db.sqls.must_equal ['SELECT a.b FROM t']
|
4319
4626
|
end
|
@@ -4321,14 +4628,19 @@ describe "Sequel::Dataset#select_map" do
|
|
4321
4628
|
it "should raise if multiple arguments and can't determine alias" do
|
4322
4629
|
proc{@ds.select_map([Sequel.function(:a), :b])}.must_raise(Sequel::Error)
|
4323
4630
|
proc{@ds.select_map(Sequel.function(:a)){b}}.must_raise(Sequel::Error)
|
4324
|
-
proc{@ds.select_map{[a
|
4631
|
+
proc{@ds.select_map{[a.function, b]}}.must_raise(Sequel::Error)
|
4325
4632
|
end
|
4326
4633
|
|
4327
|
-
|
4634
|
+
with_symbol_splitting "should handle implicit aliases in arguments" do
|
4328
4635
|
@ds.select_map(:a___b).must_equal [1, 2]
|
4329
4636
|
@ds.db.sqls.must_equal ['SELECT a AS b FROM t']
|
4330
4637
|
end
|
4331
4638
|
|
4639
|
+
it "should handle aliased expressions in arguments" do
|
4640
|
+
@ds.select_map(Sequel[:a].as(:b)).must_equal [1, 2]
|
4641
|
+
@ds.db.sqls.must_equal ['SELECT a AS b FROM t']
|
4642
|
+
end
|
4643
|
+
|
4332
4644
|
it "should handle other objects" do
|
4333
4645
|
@ds.select_map(Sequel.lit("a").as(:b)).must_equal [1, 2]
|
4334
4646
|
@ds.db.sqls.must_equal ['SELECT a AS b FROM t']
|
@@ -4345,35 +4657,40 @@ describe "Sequel::Dataset#select_map" do
|
|
4345
4657
|
end
|
4346
4658
|
|
4347
4659
|
it "should handle an expression without a determinable alias" do
|
4348
|
-
@ds.select_map{a(
|
4660
|
+
@ds.select_map{a(t[c])}.must_equal [1, 2]
|
4349
4661
|
@ds.db.sqls.must_equal ['SELECT a(t.c) AS v FROM t']
|
4350
4662
|
end
|
4351
4663
|
|
4352
4664
|
it "should accept a block" do
|
4353
|
-
@ds.select_map{a(
|
4665
|
+
@ds.select_map{a(t[c]).as(b)}.must_equal [1, 2]
|
4354
4666
|
@ds.db.sqls.must_equal ['SELECT a(t.c) AS b FROM t']
|
4355
4667
|
end
|
4356
4668
|
|
4357
4669
|
it "should accept a block with an array of columns" do
|
4358
|
-
@ds.select_map{[a(
|
4670
|
+
@ds.select_map{[a(t[c]).as(c), a(t[c]).as(c)]}.must_equal [[1, 1], [2, 2]]
|
4359
4671
|
@ds.db.sqls.must_equal ['SELECT a(t.c) AS c, a(t.c) AS c FROM t']
|
4360
4672
|
end
|
4361
4673
|
|
4362
4674
|
it "should accept a block with a column" do
|
4363
|
-
@ds.select_map(:c){a(
|
4675
|
+
@ds.select_map(:c){a(t[c]).as(c)}.must_equal [[1, 1], [2, 2]]
|
4364
4676
|
@ds.db.sqls.must_equal ['SELECT c, a(t.c) AS c FROM t']
|
4365
4677
|
end
|
4366
4678
|
|
4367
4679
|
it "should accept a block and array of arguments" do
|
4368
|
-
@ds.select_map([:c, :c]){[a(
|
4680
|
+
@ds.select_map([:c, :c]){[a(t[c]).as(c), a(t[c]).as(c)]}.must_equal [[1, 1, 1, 1], [2, 2, 2, 2]]
|
4369
4681
|
@ds.db.sqls.must_equal ['SELECT c, c, a(t.c) AS c, a(t.c) AS c FROM t']
|
4370
4682
|
end
|
4371
4683
|
|
4372
4684
|
it "should handle an array of columns" do
|
4373
4685
|
@ds.select_map([:c, :c]).must_equal [[1, 1], [2, 2]]
|
4374
4686
|
@ds.db.sqls.must_equal ['SELECT c, c FROM t']
|
4375
|
-
@ds.select_map([Sequel.expr(:d).as(:c), Sequel.qualify(:b, :c), Sequel.identifier(:c), Sequel.identifier(:c).qualify(:b)
|
4376
|
-
@ds.db.sqls.must_equal ['SELECT d AS c, b.c, c, b.c
|
4687
|
+
@ds.select_map([Sequel.expr(:d).as(:c), Sequel.qualify(:b, :c), Sequel.identifier(:c), Sequel.identifier(:c).qualify(:b)]).must_equal [[1, 1, 1, 1], [2, 2, 2, 2]]
|
4688
|
+
@ds.db.sqls.must_equal ['SELECT d AS c, b.c, c, b.c FROM t']
|
4689
|
+
end
|
4690
|
+
|
4691
|
+
with_symbol_splitting "should handle an array of columns with splittable symbols" do
|
4692
|
+
@ds.select_map([:a__c, :a__d___c]).must_equal [[1, 1], [2, 2]]
|
4693
|
+
@ds.db.sqls.must_equal ['SELECT a.c, a.d AS c FROM t']
|
4377
4694
|
end
|
4378
4695
|
|
4379
4696
|
it "should handle an array with a single element" do
|
@@ -4392,7 +4709,12 @@ describe "Sequel::Dataset#select_order_map" do
|
|
4392
4709
|
@ds.db.sqls.must_equal ['SELECT a FROM t ORDER BY a']
|
4393
4710
|
end
|
4394
4711
|
|
4395
|
-
it "should handle
|
4712
|
+
it "should handle qualified identifiers in arguments" do
|
4713
|
+
@ds.select_order_map(Sequel[:a][:b]).must_equal [1, 2]
|
4714
|
+
@ds.db.sqls.must_equal ['SELECT a.b FROM t ORDER BY a.b']
|
4715
|
+
end
|
4716
|
+
|
4717
|
+
with_symbol_splitting "should handle implicit qualifiers in arguments" do
|
4396
4718
|
@ds.select_order_map(:a__b).must_equal [1, 2]
|
4397
4719
|
@ds.db.sqls.must_equal ['SELECT a.b FROM t ORDER BY a.b']
|
4398
4720
|
end
|
@@ -4400,15 +4722,15 @@ describe "Sequel::Dataset#select_order_map" do
|
|
4400
4722
|
it "should raise if multiple arguments and can't determine alias" do
|
4401
4723
|
proc{@ds.select_order_map([Sequel.function(:a), :b])}.must_raise(Sequel::Error)
|
4402
4724
|
proc{@ds.select_order_map(Sequel.function(:a)){b}}.must_raise(Sequel::Error)
|
4403
|
-
proc{@ds.select_order_map{[a
|
4725
|
+
proc{@ds.select_order_map{[a.function, b]}}.must_raise(Sequel::Error)
|
4404
4726
|
end
|
4405
4727
|
|
4406
|
-
|
4728
|
+
with_symbol_splitting "should handle implicit aliases in arguments" do
|
4407
4729
|
@ds.select_order_map(:a___b).must_equal [1, 2]
|
4408
4730
|
@ds.db.sqls.must_equal ['SELECT a AS b FROM t ORDER BY a']
|
4409
4731
|
end
|
4410
4732
|
|
4411
|
-
|
4733
|
+
with_symbol_splitting "should handle implicit qualifiers and aliases in arguments" do
|
4412
4734
|
@ds.select_order_map(:t__a___b).must_equal [1, 2]
|
4413
4735
|
@ds.db.sqls.must_equal ['SELECT t.a AS b FROM t ORDER BY t.a']
|
4414
4736
|
end
|
@@ -4416,6 +4738,10 @@ describe "Sequel::Dataset#select_order_map" do
|
|
4416
4738
|
it "should handle AliasedExpressions" do
|
4417
4739
|
@ds.select_order_map(Sequel.lit("a").as(:b)).must_equal [1, 2]
|
4418
4740
|
@ds.db.sqls.must_equal ['SELECT a AS b FROM t ORDER BY a']
|
4741
|
+
@ds.select_order_map(Sequel[:a].as(:b)).must_equal [1, 2]
|
4742
|
+
@ds.db.sqls.must_equal ['SELECT a AS b FROM t ORDER BY a']
|
4743
|
+
@ds.select_order_map(Sequel[:t][:a].as(:b)).must_equal [1, 2]
|
4744
|
+
@ds.db.sqls.must_equal ['SELECT t.a AS b FROM t ORDER BY t.a']
|
4419
4745
|
end
|
4420
4746
|
|
4421
4747
|
it "should handle OrderedExpressions" do
|
@@ -4424,35 +4750,43 @@ describe "Sequel::Dataset#select_order_map" do
|
|
4424
4750
|
end
|
4425
4751
|
|
4426
4752
|
it "should handle an expression without a determinable alias" do
|
4427
|
-
@ds.select_order_map{a(
|
4753
|
+
@ds.select_order_map{a(t[c])}.must_equal [1, 2]
|
4428
4754
|
@ds.db.sqls.must_equal ['SELECT a(t.c) AS v FROM t ORDER BY a(t.c)']
|
4429
4755
|
end
|
4430
4756
|
|
4431
4757
|
it "should accept a block" do
|
4432
|
-
@ds.select_order_map{a(
|
4758
|
+
@ds.select_order_map{a(t[c]).as(b)}.must_equal [1, 2]
|
4433
4759
|
@ds.db.sqls.must_equal ['SELECT a(t.c) AS b FROM t ORDER BY a(t.c)']
|
4434
4760
|
end
|
4435
4761
|
|
4436
4762
|
it "should accept a block with an array of columns" do
|
4437
|
-
@ds.select_order_map{[c.desc, a(
|
4763
|
+
@ds.select_order_map{[c.desc, a(t[c]).as(c)]}.must_equal [[1, 1], [2, 2]]
|
4438
4764
|
@ds.db.sqls.must_equal ['SELECT c, a(t.c) AS c FROM t ORDER BY c DESC, a(t.c)']
|
4439
4765
|
end
|
4440
4766
|
|
4441
4767
|
it "should accept a block with a column" do
|
4442
|
-
@ds.select_order_map(:c){a(
|
4768
|
+
@ds.select_order_map(:c){a(t[c]).as(c)}.must_equal [[1, 1], [2, 2]]
|
4443
4769
|
@ds.db.sqls.must_equal ['SELECT c, a(t.c) AS c FROM t ORDER BY c, a(t.c)']
|
4444
4770
|
end
|
4445
4771
|
|
4446
4772
|
it "should accept a block and array of arguments" do
|
4447
|
-
@ds.select_order_map([:c, :c]){[a(
|
4773
|
+
@ds.select_order_map([:c, :c]){[a(t[c]).as(c), c.desc]}.must_equal [[1, 1, 1, 1], [2, 2, 2, 2]]
|
4448
4774
|
@ds.db.sqls.must_equal ['SELECT c, c, a(t.c) AS c, c FROM t ORDER BY c, c, a(t.c), c DESC']
|
4449
4775
|
end
|
4450
4776
|
|
4451
4777
|
it "should handle an array of columns" do
|
4452
4778
|
@ds.select_order_map([:c, :c]).must_equal [[1, 1], [2, 2]]
|
4453
4779
|
@ds.db.sqls.must_equal ['SELECT c, c FROM t ORDER BY c, c']
|
4454
|
-
|
4455
|
-
|
4780
|
+
end
|
4781
|
+
|
4782
|
+
it "should handle an array of columns" do
|
4783
|
+
@ds.select_order_map([Sequel.expr(:d).as(:c), Sequel.qualify(:b, :c), Sequel.identifier(:c), Sequel.identifier(:c).qualify(:b), Sequel.identifier(:c).qualify(:b).desc]).must_equal [[1, 1, 1, 1, 1], [2, 2, 2, 2, 2]]
|
4784
|
+
@ds.db.sqls.must_equal ['SELECT d AS c, b.c, c, b.c, b.c FROM t ORDER BY d, b.c, c, b.c, b.c DESC']
|
4785
|
+
end
|
4786
|
+
|
4787
|
+
with_symbol_splitting "should handle an array of columns with splittable symbols" do
|
4788
|
+
@ds.select_order_map([:a__c, Sequel.desc(:a__d___c), Sequel.desc(Sequel.expr(:a__d___c))]).must_equal [[1, 1, 1], [2, 2, 2]]
|
4789
|
+
@ds.db.sqls.must_equal ['SELECT a.c, a.d AS c, a.d AS c FROM t ORDER BY a.c, a.d DESC, a.d DESC']
|
4456
4790
|
end
|
4457
4791
|
|
4458
4792
|
it "should handle an array with a single element" do
|
@@ -4472,17 +4806,32 @@ describe "Sequel::Dataset#select_hash" do
|
|
4472
4806
|
@ds.db.sqls.must_equal ['SELECT a, b FROM t']
|
4473
4807
|
end
|
4474
4808
|
|
4475
|
-
it "should handle
|
4809
|
+
it "should handle qualified identifiers in arguments" do
|
4810
|
+
@ds.select_hash(Sequel[:t][:a], Sequel[:t][:b]).must_equal(1=>2, 3=>4)
|
4811
|
+
@ds.db.sqls.must_equal ['SELECT t.a, t.b FROM t']
|
4812
|
+
end
|
4813
|
+
|
4814
|
+
with_symbol_splitting "should handle implicit qualifiers in arguments" do
|
4476
4815
|
@ds.select_hash(:t__a, :t__b).must_equal(1=>2, 3=>4)
|
4477
4816
|
@ds.db.sqls.must_equal ['SELECT t.a, t.b FROM t']
|
4478
4817
|
end
|
4479
4818
|
|
4480
|
-
it "should handle
|
4819
|
+
it "should handle aliased expresssions in arguments" do
|
4820
|
+
@ds.select_hash(Sequel[:c].as(:a), Sequel[:d].as(:b)).must_equal(1=>2, 3=>4)
|
4821
|
+
@ds.db.sqls.must_equal ['SELECT c AS a, d AS b FROM t']
|
4822
|
+
end
|
4823
|
+
|
4824
|
+
with_symbol_splitting "should handle implicit aliases in arguments" do
|
4481
4825
|
@ds.select_hash(:c___a, :d___b).must_equal(1=>2, 3=>4)
|
4482
4826
|
@ds.db.sqls.must_equal ['SELECT c AS a, d AS b FROM t']
|
4483
4827
|
end
|
4484
4828
|
|
4485
|
-
it "should handle
|
4829
|
+
it "should handle qualified identifiers and aliased expressions in arguments" do
|
4830
|
+
@ds.select_hash(Sequel[:t][:c].as(:a), Sequel[:t][:d].as(:b)).must_equal(1=>2, 3=>4)
|
4831
|
+
@ds.db.sqls.must_equal ['SELECT t.c AS a, t.d AS b FROM t']
|
4832
|
+
end
|
4833
|
+
|
4834
|
+
with_symbol_splitting "should handle implicit qualifiers and aliases in arguments" do
|
4486
4835
|
@ds.select_hash(:t__c___a, :t__d___b).must_equal(1=>2, 3=>4)
|
4487
4836
|
@ds.db.sqls.must_equal ['SELECT t.c AS a, t.d AS b FROM t']
|
4488
4837
|
end
|
@@ -4528,17 +4877,17 @@ describe "Sequel::Dataset#select_hash_groups" do
|
|
4528
4877
|
@ds.db.sqls.must_equal ['SELECT a, b FROM t']
|
4529
4878
|
end
|
4530
4879
|
|
4531
|
-
|
4880
|
+
with_symbol_splitting "should handle implicit qualifiers in arguments" do
|
4532
4881
|
@ds.select_hash_groups(:t__a, :t__b).must_equal(1=>[2], 3=>[4])
|
4533
4882
|
@ds.db.sqls.must_equal ['SELECT t.a, t.b FROM t']
|
4534
4883
|
end
|
4535
4884
|
|
4536
|
-
|
4885
|
+
with_symbol_splitting "should handle implicit aliases in arguments" do
|
4537
4886
|
@ds.select_hash_groups(:c___a, :d___b).must_equal(1=>[2], 3=>[4])
|
4538
4887
|
@ds.db.sqls.must_equal ['SELECT c AS a, d AS b FROM t']
|
4539
4888
|
end
|
4540
4889
|
|
4541
|
-
|
4890
|
+
with_symbol_splitting "should handle implicit qualifiers and aliases in arguments" do
|
4542
4891
|
@ds.select_hash_groups(:t__c___a, :t__d___b).must_equal(1=>[2], 3=>[4])
|
4543
4892
|
@ds.db.sqls.must_equal ['SELECT t.c AS a, t.d AS b FROM t']
|
4544
4893
|
end
|
@@ -4558,6 +4907,11 @@ describe "Sequel::Dataset#select_hash_groups" do
|
|
4558
4907
|
@ds.db.sqls.must_equal ['SELECT c AS a, t AS b FROM t']
|
4559
4908
|
end
|
4560
4909
|
|
4910
|
+
it "should handle SQL::QualifiedIdentifiers and SQL::AliasedExpressions in arguments" do
|
4911
|
+
@ds.select_hash_groups(Sequel[:t][:c].as(:a), Sequel[:t][:d].as(:b)).must_equal(1=>[2], 3=>[4])
|
4912
|
+
@ds.db.sqls.must_equal ['SELECT t.c AS a, t.d AS b FROM t']
|
4913
|
+
end
|
4914
|
+
|
4561
4915
|
it "should work with arrays of columns" do
|
4562
4916
|
@db.fetch = [{:a=>1, :b=>2, :c=>3}, {:a=>4, :b=>5, :c=>6}]
|
4563
4917
|
@ds.select_hash_groups([:a, :c], :b).must_equal([1, 3]=>[2], [4, 6]=>[5])
|
@@ -4631,15 +4985,24 @@ describe "Dataset#skip_locked" do
|
|
4631
4985
|
end
|
4632
4986
|
|
4633
4987
|
describe "Custom ASTTransformer" do
|
4634
|
-
|
4635
|
-
c = Class.new(Sequel::ASTTransformer) do
|
4988
|
+
before do
|
4989
|
+
@c = Class.new(Sequel::ASTTransformer) do
|
4636
4990
|
def v(s)
|
4637
4991
|
(s.is_a?(Symbol) || s.is_a?(String)) ? :"#{s}#{s}" : super
|
4638
4992
|
end
|
4639
4993
|
end.new
|
4994
|
+
end
|
4995
|
+
|
4996
|
+
it "should transform given objects" do
|
4997
|
+
ds = Sequel.mock.dataset.from(:t).cross_join(Sequel[:a].as(:g)).join(Sequel[:b].as(:h), [:c]).join(Sequel[:d].as(:i), :e=>:f)
|
4998
|
+
ds.sql.must_equal 'SELECT * FROM t CROSS JOIN a AS g INNER JOIN b AS h USING (c) INNER JOIN d AS i ON (i.e = h.f)'
|
4999
|
+
ds.clone(:from=>@c.transform(ds.opts[:from]), :join=>@c.transform(ds.opts[:join])).sql.must_equal 'SELECT * FROM tt CROSS JOIN aa AS g INNER JOIN bb AS h USING (cc) INNER JOIN dd AS i ON (ii.ee = hh.ff)'
|
5000
|
+
end
|
5001
|
+
|
5002
|
+
with_symbol_splitting "should transform given objects with splittable symbols" do
|
4640
5003
|
ds = Sequel.mock.dataset.from(:t).cross_join(:a___g).join(:b___h, [:c]).join(:d___i, :e=>:f)
|
4641
5004
|
ds.sql.must_equal 'SELECT * FROM t CROSS JOIN a AS g INNER JOIN b AS h USING (c) INNER JOIN d AS i ON (i.e = h.f)'
|
4642
|
-
ds.clone(:from
|
5005
|
+
ds.clone(:from=>@c.transform(ds.opts[:from]), :join=>@c.transform(ds.opts[:join])).sql.must_equal 'SELECT * FROM tt CROSS JOIN aa AS g INNER JOIN bb AS h USING (cc) INNER JOIN dd AS i ON (ii.ee = hh.ff)'
|
4643
5006
|
end
|
4644
5007
|
end
|
4645
5008
|
|
@@ -4795,7 +5158,7 @@ describe "Dataset#schema_and_table" do
|
|
4795
5158
|
@ds = Sequel.mock[:test]
|
4796
5159
|
end
|
4797
5160
|
|
4798
|
-
|
5161
|
+
with_symbol_splitting "should correctly handle symbols" do
|
4799
5162
|
@ds.schema_and_table(:s).must_equal [nil, 's']
|
4800
5163
|
@ds.schema_and_table(:s___a).must_equal [nil, 's']
|
4801
5164
|
@ds.schema_and_table(:t__s).must_equal ['t', 's']
|
@@ -4827,6 +5190,9 @@ describe "Dataset#split_qualifiers" do
|
|
4827
5190
|
|
4828
5191
|
it "should correctly handle symbols" do
|
4829
5192
|
@ds.split_qualifiers(:s).must_equal ['s']
|
5193
|
+
end
|
5194
|
+
|
5195
|
+
with_symbol_splitting "should correctly handle splittable symbols" do
|
4830
5196
|
@ds.split_qualifiers(:s___a).must_equal ['s']
|
4831
5197
|
@ds.split_qualifiers(:t__s).must_equal ['t', 's']
|
4832
5198
|
@ds.split_qualifiers(:t__s___a).must_equal ['t', 's']
|
@@ -4844,12 +5210,15 @@ describe "Dataset#split_qualifiers" do
|
|
4844
5210
|
@ds.split_qualifiers(Sequel.qualify(:t, :s)).must_equal ['t', 's']
|
4845
5211
|
end
|
4846
5212
|
|
4847
|
-
|
5213
|
+
with_symbol_splitting "should correctly handle complex qualified identifiers with splittable symbols" do
|
4848
5214
|
@ds.split_qualifiers(Sequel.qualify(:d__t, :s)).must_equal ['d', 't', 's']
|
4849
|
-
@ds.split_qualifiers(Sequel.qualify(Sequel.qualify(:d, :t), :s)).must_equal ['d', 't', 's']
|
4850
5215
|
@ds.split_qualifiers(Sequel.qualify(:d, :t__s)).must_equal ['d', 't', 's']
|
4851
|
-
@ds.split_qualifiers(Sequel.qualify(:d, Sequel.qualify(:t, :s))).must_equal ['d', 't', 's']
|
4852
5216
|
@ds.split_qualifiers(Sequel.qualify(:d__t, :s__s2)).must_equal ['d', 't', 's', 's2']
|
5217
|
+
end
|
5218
|
+
|
5219
|
+
it "should correctly handle complex qualified identifiers" do
|
5220
|
+
@ds.split_qualifiers(Sequel.qualify(Sequel.qualify(:d, :t), :s)).must_equal ['d', 't', 's']
|
5221
|
+
@ds.split_qualifiers(Sequel.qualify(:d, Sequel.qualify(:t, :s))).must_equal ['d', 't', 's']
|
4853
5222
|
@ds.split_qualifiers(Sequel.qualify(Sequel.qualify(:d, :t), Sequel.qualify(:s, :s2))).must_equal ['d', 't', 's', 's2']
|
4854
5223
|
end
|
4855
5224
|
end
|
@@ -5115,6 +5484,9 @@ describe "#unqualified_column_for" do
|
|
5115
5484
|
|
5116
5485
|
it "should handle Symbols" do
|
5117
5486
|
@ds.unqualified_column_for(:a).must_equal Sequel.identifier('a')
|
5487
|
+
end
|
5488
|
+
|
5489
|
+
with_symbol_splitting "should handle splittable symbols" do
|
5118
5490
|
@ds.unqualified_column_for(:b__a).must_equal Sequel.identifier('a')
|
5119
5491
|
@ds.unqualified_column_for(:a___c).must_equal Sequel.identifier('a').as('c')
|
5120
5492
|
@ds.unqualified_column_for(:b__a___c).must_equal Sequel.identifier('a').as('c')
|