sequel 4.45.0 → 4.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +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')
|