sequel 3.42.0 → 3.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +40 -0
- data/MIT-LICENSE +1 -1
- data/Rakefile +1 -1
- data/doc/opening_databases.rdoc +2 -2
- data/doc/prepared_statements.rdoc +7 -0
- data/doc/release_notes/3.43.0.txt +105 -0
- data/doc/schema_modification.rdoc +19 -0
- data/lib/sequel/adapters/do/mysql.rb +1 -1
- data/lib/sequel/adapters/jdbc.rb +13 -8
- data/lib/sequel/adapters/jdbc/hsqldb.rb +5 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +6 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +9 -3
- data/lib/sequel/adapters/mysql.rb +1 -1
- data/lib/sequel/adapters/mysql2.rb +1 -1
- data/lib/sequel/adapters/oracle.rb +1 -1
- data/lib/sequel/adapters/postgres.rb +4 -2
- data/lib/sequel/adapters/shared/db2.rb +12 -0
- data/lib/sequel/adapters/shared/mssql.rb +9 -5
- data/lib/sequel/adapters/shared/postgres.rb +2 -0
- data/lib/sequel/adapters/swift/mysql.rb +1 -1
- data/lib/sequel/core.rb +2 -2
- data/lib/sequel/database.rb +0 -2
- data/lib/sequel/database/query.rb +20 -5
- data/lib/sequel/database/schema_generator.rb +5 -0
- data/lib/sequel/database/schema_methods.rb +5 -0
- data/lib/sequel/dataset.rb +0 -2
- data/lib/sequel/dataset/actions.rb +25 -2
- data/lib/sequel/dataset/misc.rb +1 -1
- data/lib/sequel/dataset/sql.rb +28 -6
- data/lib/sequel/extensions/core_refinements.rb +221 -0
- data/lib/sequel/extensions/date_arithmetic.rb +194 -0
- data/lib/sequel/extensions/meta_def.rb +30 -0
- data/lib/sequel/extensions/migration.rb +5 -0
- data/lib/sequel/extensions/null_dataset.rb +2 -0
- data/lib/sequel/extensions/pagination.rb +2 -0
- data/lib/sequel/extensions/pg_array.rb +12 -1
- data/lib/sequel/extensions/pg_array_ops.rb +10 -1
- data/lib/sequel/extensions/pg_hstore.rb +12 -1
- data/lib/sequel/extensions/pg_hstore_ops.rb +10 -1
- data/lib/sequel/extensions/pg_json.rb +18 -1
- data/lib/sequel/extensions/pg_range.rb +12 -1
- data/lib/sequel/extensions/pg_range_ops.rb +10 -1
- data/lib/sequel/extensions/pg_row.rb +18 -2
- data/lib/sequel/extensions/pg_row_ops.rb +10 -1
- data/lib/sequel/extensions/query.rb +2 -0
- data/lib/sequel/model/associations.rb +5 -13
- data/lib/sequel/model/base.rb +4 -6
- data/lib/sequel/plugins/boolean_readers.rb +4 -2
- data/lib/sequel/plugins/many_through_many.rb +23 -0
- data/lib/sequel/plugins/string_stripper.rb +53 -3
- data/lib/sequel/plugins/validation_class_methods.rb +5 -0
- data/lib/sequel/sql.rb +3 -3
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +19 -8
- data/spec/adapters/mssql_spec.rb +1 -2
- data/spec/adapters/mysql_spec.rb +2 -2
- data/spec/adapters/postgres_spec.rb +29 -3
- data/spec/core/dataset_spec.rb +107 -0
- data/spec/core/expression_filters_spec.rb +5 -0
- data/spec/core/schema_spec.rb +14 -3
- data/spec/core/spec_helper.rb +2 -0
- data/spec/extensions/core_refinements_spec.rb +551 -0
- data/spec/extensions/date_arithmetic_spec.rb +150 -0
- data/spec/extensions/force_encoding_spec.rb +1 -1
- data/spec/extensions/meta_def_spec.rb +21 -0
- data/spec/extensions/spec_helper.rb +5 -0
- data/spec/extensions/string_stripper_spec.rb +44 -2
- data/spec/integration/associations_test.rb +2 -2
- data/spec/integration/plugin_test.rb +90 -0
- data/spec/integration/schema_test.rb +1 -1
- data/spec/model/association_reflection_spec.rb +4 -4
- data/spec/model/associations_spec.rb +2 -2
- data/spec/model/base_spec.rb +2 -2
- data/spec/model/eager_loading_spec.rb +5 -5
- data/spec/model/hooks_spec.rb +4 -4
- data/spec/model/model_spec.rb +9 -9
- data/spec/model/record_spec.rb +15 -18
- metadata +12 -5
- data/lib/sequel/metaprogramming.rb +0 -13
@@ -594,6 +594,11 @@ describe "Sequel core extension replacements" do
|
|
594
594
|
l(Sequel.expr(proc{|v| @o}) + 1, "(foo + 1)")
|
595
595
|
end
|
596
596
|
|
597
|
+
it "Sequel.expr should handle lambda proc virtual rows" do
|
598
|
+
l(Sequel.expr(&lambda{1}), "1")
|
599
|
+
l(Sequel.expr(&lambda{|| 1}), "1")
|
600
|
+
end
|
601
|
+
|
597
602
|
it "Sequel.expr should raise an error if given an argument and a block" do
|
598
603
|
proc{Sequel.expr(nil){}}.should raise_error(Sequel::Error)
|
599
604
|
end
|
data/spec/core/schema_spec.rb
CHANGED
@@ -1327,16 +1327,27 @@ describe "Schema Parser" do
|
|
1327
1327
|
|
1328
1328
|
specify "should convert various types of table name arguments" do
|
1329
1329
|
@db.meta_def(:schema_parse_table) do |t, opts|
|
1330
|
-
[[t,
|
1330
|
+
[[t, opts]]
|
1331
1331
|
end
|
1332
1332
|
s1 = @db.schema(:x)
|
1333
|
-
s1.should == [['x', {:
|
1333
|
+
s1.should == [['x', {:ruby_default=>nil}]]
|
1334
1334
|
@db.schema(:x).object_id.should == s1.object_id
|
1335
1335
|
@db.schema(Sequel.identifier(:x)).object_id.should == s1.object_id
|
1336
|
+
|
1336
1337
|
s2 = @db.schema(:x__y)
|
1337
|
-
s2.should == [['y', {:
|
1338
|
+
s2.should == [['y', {:schema=>'x', :ruby_default=>nil}]]
|
1338
1339
|
@db.schema(:x__y).object_id.should == s2.object_id
|
1339
1340
|
@db.schema(Sequel.qualify(:x, :y)).object_id.should == s2.object_id
|
1341
|
+
|
1342
|
+
s2 = @db.schema(Sequel.qualify(:v, :x__y))
|
1343
|
+
s2.should == [['y', {:schema=>'x', :ruby_default=>nil, :information_schema_schema=>Sequel.identifier('v')}]]
|
1344
|
+
@db.schema(Sequel.qualify(:v, :x__y)).object_id.should == s2.object_id
|
1345
|
+
@db.schema(Sequel.qualify(:v__x, :y)).object_id.should == s2.object_id
|
1346
|
+
|
1347
|
+
s2 = @db.schema(Sequel.qualify(:u__v, :x__y))
|
1348
|
+
s2.should == [['y', {:schema=>'x', :ruby_default=>nil, :information_schema_schema=>Sequel.qualify('u', 'v')}]]
|
1349
|
+
@db.schema(Sequel.qualify(:u__v, :x__y)).object_id.should == s2.object_id
|
1350
|
+
@db.schema(Sequel.qualify(Sequel.qualify(:u, :v), Sequel.qualify(:x, :y))).object_id.should == s2.object_id
|
1340
1351
|
end
|
1341
1352
|
|
1342
1353
|
specify "should correctly parse all supported data types" do
|
data/spec/core/spec_helper.rb
CHANGED
@@ -0,0 +1,551 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
if RUBY_VERSION >= '2.0.0'
|
4
|
+
using Sequel::CoreRefinements
|
5
|
+
|
6
|
+
describe "Core refinements" do
|
7
|
+
before do
|
8
|
+
db = Sequel::Database.new
|
9
|
+
@d = db[:items]
|
10
|
+
def @d.supports_regexp?; true end
|
11
|
+
def @d.l(*args, &block)
|
12
|
+
literal(filter_expr(*args, &block))
|
13
|
+
end
|
14
|
+
def @d.lit(*args)
|
15
|
+
literal(*args)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
if RUBY_VERSION < '1.9.0'
|
20
|
+
it "should not allow inequality operations on true, false, or nil" do
|
21
|
+
@d.lit(:x > 1).should == "(x > 1)"
|
22
|
+
@d.lit(:x < true).should == "(x < 't')"
|
23
|
+
@d.lit(:x >= false).should == "(x >= 'f')"
|
24
|
+
@d.lit(:x <= nil).should == "(x <= NULL)"
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should not allow inequality operations on boolean complex expressions" do
|
28
|
+
@d.lit(:x > (:y > 5)).should == "(x > (y > 5))"
|
29
|
+
@d.lit(:x < (:y < 5)).should == "(x < (y < 5))"
|
30
|
+
@d.lit(:x >= (:y >= 5)).should == "(x >= (y >= 5))"
|
31
|
+
@d.lit(:x <= (:y <= 5)).should == "(x <= (y <= 5))"
|
32
|
+
@d.lit(:x > {:y => nil}).should == "(x > (y IS NULL))"
|
33
|
+
@d.lit(:x < ~{:y => nil}).should == "(x < (y IS NOT NULL))"
|
34
|
+
@d.lit(:x >= {:y => 5}).should == "(x >= (y = 5))"
|
35
|
+
@d.lit(:x <= ~{:y => 5}).should == "(x <= (y != 5))"
|
36
|
+
@d.lit(:x >= {:y => [1,2,3]}).should == "(x >= (y IN (1, 2, 3)))"
|
37
|
+
@d.lit(:x <= ~{:y => [1,2,3]}).should == "(x <= (y NOT IN (1, 2, 3)))"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should support >, <, >=, and <= via Symbol#>,<,>=,<=" do
|
41
|
+
@d.l(:x > 100).should == '(x > 100)'
|
42
|
+
@d.l(:x < 100.01).should == '(x < 100.01)'
|
43
|
+
@d.l(:x >= 100000000000000000000000000000000000).should == '(x >= 100000000000000000000000000000000000)'
|
44
|
+
@d.l(:x <= 100).should == '(x <= 100)'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should support negation of >, <, >=, and <= via Symbol#~" do
|
48
|
+
@d.l(~(:x > 100)).should == '(x <= 100)'
|
49
|
+
@d.l(~(:x < 100.01)).should == '(x >= 100.01)'
|
50
|
+
@d.l(~(:x >= 100000000000000000000000000000000000)).should == '(x < 100000000000000000000000000000000000)'
|
51
|
+
@d.l(~(:x <= 100)).should == '(x > 100)'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should support double negation via ~" do
|
55
|
+
@d.l(~~(:x > 100)).should == '(x > 100)'
|
56
|
+
end
|
57
|
+
end
|
58
|
+
it "should support NOT via Symbol#~" do
|
59
|
+
@d.l(~:x).should == 'NOT x'
|
60
|
+
@d.l(~:x__y).should == 'NOT x.y'
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should support + - * / via Symbol#+,-,*,/" do
|
64
|
+
@d.l(:x + 1 > 100).should == '((x + 1) > 100)'
|
65
|
+
@d.l((:x * :y) < 100.01).should == '((x * y) < 100.01)'
|
66
|
+
@d.l((:x - :y/2) >= 100000000000000000000000000000000000).should == '((x - (y / 2)) >= 100000000000000000000000000000000000)'
|
67
|
+
@d.l((((:x - :y)/(:x + :y))*:z) <= 100).should == '((((x - y) / (x + y)) * z) <= 100)'
|
68
|
+
@d.l(~((((:x - :y)/(:x + :y))*:z) <= 100)).should == '((((x - y) / (x + y)) * z) > 100)'
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should support LIKE via Symbol#like" do
|
72
|
+
@d.l(:x.like('a')).should == '(x LIKE \'a\')'
|
73
|
+
@d.l(:x.like(/a/)).should == '(x ~ \'a\')'
|
74
|
+
@d.l(:x.like('a', 'b')).should == '((x LIKE \'a\') OR (x LIKE \'b\'))'
|
75
|
+
@d.l(:x.like(/a/, /b/i)).should == '((x ~ \'a\') OR (x ~* \'b\'))'
|
76
|
+
@d.l(:x.like('a', /b/)).should == '((x LIKE \'a\') OR (x ~ \'b\'))'
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should support NOT LIKE via Symbol#like and Symbol#~" do
|
80
|
+
@d.l(~:x.like('a')).should == '(x NOT LIKE \'a\')'
|
81
|
+
@d.l(~:x.like(/a/)).should == '(x !~ \'a\')'
|
82
|
+
@d.l(~:x.like('a', 'b')).should == '((x NOT LIKE \'a\') AND (x NOT LIKE \'b\'))'
|
83
|
+
@d.l(~:x.like(/a/, /b/i)).should == '((x !~ \'a\') AND (x !~* \'b\'))'
|
84
|
+
@d.l(~:x.like('a', /b/)).should == '((x NOT LIKE \'a\') AND (x !~ \'b\'))'
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should support ILIKE via Symbol#ilike" do
|
88
|
+
@d.l(:x.ilike('a')).should == '(x ILIKE \'a\')'
|
89
|
+
@d.l(:x.ilike(/a/)).should == '(x ~* \'a\')'
|
90
|
+
@d.l(:x.ilike('a', 'b')).should == '((x ILIKE \'a\') OR (x ILIKE \'b\'))'
|
91
|
+
@d.l(:x.ilike(/a/, /b/i)).should == '((x ~* \'a\') OR (x ~* \'b\'))'
|
92
|
+
@d.l(:x.ilike('a', /b/)).should == '((x ILIKE \'a\') OR (x ~* \'b\'))'
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should support NOT ILIKE via Symbol#ilike and Symbol#~" do
|
96
|
+
@d.l(~:x.ilike('a')).should == '(x NOT ILIKE \'a\')'
|
97
|
+
@d.l(~:x.ilike(/a/)).should == '(x !~* \'a\')'
|
98
|
+
@d.l(~:x.ilike('a', 'b')).should == '((x NOT ILIKE \'a\') AND (x NOT ILIKE \'b\'))'
|
99
|
+
@d.l(~:x.ilike(/a/, /b/i)).should == '((x !~* \'a\') AND (x !~* \'b\'))'
|
100
|
+
@d.l(~:x.ilike('a', /b/)).should == '((x NOT ILIKE \'a\') AND (x !~* \'b\'))'
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should support sql_expr on arrays with all two pairs" do
|
104
|
+
@d.l([[:x, 100],[:y, 'a']].sql_expr).should == '((x = 100) AND (y = \'a\'))'
|
105
|
+
@d.l([[:x, true], [:y, false]].sql_expr).should == '((x IS TRUE) AND (y IS FALSE))'
|
106
|
+
@d.l([[:x, nil], [:y, [1,2,3]]].sql_expr).should == '((x IS NULL) AND (y IN (1, 2, 3)))'
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should support sql_negate on arrays with all two pairs" do
|
110
|
+
@d.l([[:x, 100],[:y, 'a']].sql_negate).should == '((x != 100) AND (y != \'a\'))'
|
111
|
+
@d.l([[:x, true], [:y, false]].sql_negate).should == '((x IS NOT TRUE) AND (y IS NOT FALSE))'
|
112
|
+
@d.l([[:x, nil], [:y, [1,2,3]]].sql_negate).should == '((x IS NOT NULL) AND (y NOT IN (1, 2, 3)))'
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should support ~ on arrays with all two pairs" do
|
116
|
+
@d.l(~[[:x, 100],[:y, 'a']]).should == '((x != 100) OR (y != \'a\'))'
|
117
|
+
@d.l(~[[:x, true], [:y, false]]).should == '((x IS NOT TRUE) OR (y IS NOT FALSE))'
|
118
|
+
@d.l(~[[:x, nil], [:y, [1,2,3]]]).should == '((x IS NOT NULL) OR (y NOT IN (1, 2, 3)))'
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should support sql_or on arrays with all two pairs" do
|
122
|
+
@d.l([[:x, 100],[:y, 'a']].sql_or).should == '((x = 100) OR (y = \'a\'))'
|
123
|
+
@d.l([[:x, true], [:y, false]].sql_or).should == '((x IS TRUE) OR (y IS FALSE))'
|
124
|
+
@d.l([[:x, nil], [:y, [1,2,3]]].sql_or).should == '((x IS NULL) OR (y IN (1, 2, 3)))'
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should support Array#sql_string_join for concatenation of SQL strings" do
|
128
|
+
@d.lit([:x].sql_string_join).should == '(x)'
|
129
|
+
@d.lit([:x].sql_string_join(', ')).should == '(x)'
|
130
|
+
@d.lit([:x, :y].sql_string_join).should == '(x || y)'
|
131
|
+
@d.lit([:x, :y].sql_string_join(', ')).should == "(x || ', ' || y)"
|
132
|
+
@d.lit([:x.sql_function(1), :y.sql_subscript(1)].sql_string_join).should == '(x(1) || y[1])'
|
133
|
+
@d.lit([:x.sql_function(1), 'y.z'.lit].sql_string_join(', ')).should == "(x(1) || ', ' || y.z)"
|
134
|
+
@d.lit([:x, 1, :y].sql_string_join).should == "(x || '1' || y)"
|
135
|
+
@d.lit([:x, 1, :y].sql_string_join(', ')).should == "(x || ', ' || '1' || ', ' || y)"
|
136
|
+
@d.lit([:x, 1, :y].sql_string_join(:y__z)).should == "(x || y.z || '1' || y.z || y)"
|
137
|
+
@d.lit([:x, 1, :y].sql_string_join(1)).should == "(x || '1' || '1' || '1' || y)"
|
138
|
+
@d.lit([:x, :y].sql_string_join('y.x || x.y'.lit)).should == "(x || y.x || x.y || y)"
|
139
|
+
@d.lit([[:x, :y].sql_string_join, [:a, :b].sql_string_join].sql_string_join).should == "(x || y || a || b)"
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should support sql_expr on hashes" do
|
143
|
+
@d.l({:x => 100, :y => 'a'}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x = 100)', '(y = \'a\')']
|
144
|
+
@d.l({:x => true, :y => false}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x IS TRUE)', '(y IS FALSE)']
|
145
|
+
@d.l({:x => nil, :y => [1,2,3]}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
|
146
|
+
end
|
147
|
+
|
148
|
+
it "should support sql_negate on hashes" do
|
149
|
+
@d.l({:x => 100, :y => 'a'}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x != 100)', '(y != \'a\')']
|
150
|
+
@d.l({:x => true, :y => false}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x IS NOT TRUE)', '(y IS NOT FALSE)']
|
151
|
+
@d.l({:x => nil, :y => [1,2,3]}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should support ~ on hashes" do
|
155
|
+
@d.l(~{:x => 100, :y => 'a'})[1...-1].split(' OR ').sort.should == ['(x != 100)', '(y != \'a\')']
|
156
|
+
@d.l(~{:x => true, :y => false})[1...-1].split(' OR ').sort.should == ['(x IS NOT TRUE)', '(y IS NOT FALSE)']
|
157
|
+
@d.l(~{:x => nil, :y => [1,2,3]})[1...-1].split(' OR ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should support sql_or on hashes" do
|
161
|
+
@d.l({:x => 100, :y => 'a'}.sql_or)[1...-1].split(' OR ').sort.should == ['(x = 100)', '(y = \'a\')']
|
162
|
+
@d.l({:x => true, :y => false}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS TRUE)', '(y IS FALSE)']
|
163
|
+
@d.l({:x => nil, :y => [1,2,3]}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should Hash#& and Hash#|" do
|
167
|
+
@d.l({:y => :z} & :x).should == '((y = z) AND x)'
|
168
|
+
@d.l({:x => :a} & {:y => :z}).should == '((x = a) AND (y = z))'
|
169
|
+
@d.l({:y => :z} | :x).should == '((y = z) OR x)'
|
170
|
+
@d.l({:x => :a} | {:y => :z}).should == '((x = a) OR (y = z))'
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "Array#case and Hash#case" do
|
175
|
+
before do
|
176
|
+
@d = Sequel::Dataset.new(nil)
|
177
|
+
end
|
178
|
+
|
179
|
+
specify "should return SQL CASE expression" do
|
180
|
+
@d.literal({:x=>:y}.case(:z)).should == '(CASE WHEN x THEN y ELSE z END)'
|
181
|
+
@d.literal({:x=>:y}.case(:z, :exp)).should == '(CASE exp WHEN x THEN y ELSE z END)'
|
182
|
+
['(CASE WHEN x THEN y WHEN a THEN b ELSE z END)',
|
183
|
+
'(CASE WHEN a THEN b WHEN x THEN y ELSE z END)'].should(include(@d.literal({:x=>:y, :a=>:b}.case(:z))))
|
184
|
+
@d.literal([[:x, :y]].case(:z)).should == '(CASE WHEN x THEN y ELSE z END)'
|
185
|
+
@d.literal([[:x, :y], [:a, :b]].case(:z)).should == '(CASE WHEN x THEN y WHEN a THEN b ELSE z END)'
|
186
|
+
@d.literal([[:x, :y], [:a, :b]].case(:z, :exp)).should == '(CASE exp WHEN x THEN y WHEN a THEN b ELSE z END)'
|
187
|
+
@d.literal([[:x, :y], [:a, :b]].case(:z, :exp__w)).should == '(CASE exp.w WHEN x THEN y WHEN a THEN b ELSE z END)'
|
188
|
+
end
|
189
|
+
|
190
|
+
specify "should return SQL CASE expression with expression even if nil" do
|
191
|
+
@d.literal({:x=>:y}.case(:z, nil)).should == '(CASE NULL WHEN x THEN y ELSE z END)'
|
192
|
+
end
|
193
|
+
|
194
|
+
specify "should raise an error if an array that isn't all two pairs is used" do
|
195
|
+
proc{[:b].case(:a)}.should raise_error(Sequel::Error)
|
196
|
+
proc{[:b, :c].case(:a)}.should raise_error(Sequel::Error)
|
197
|
+
proc{[[:b, :c], :d].case(:a)}.should raise_error(Sequel::Error)
|
198
|
+
end
|
199
|
+
|
200
|
+
specify "should raise an error if an empty array/hash is used" do
|
201
|
+
proc{[].case(:a)}.should raise_error(Sequel::Error)
|
202
|
+
proc{{}.case(:a)}.should raise_error(Sequel::Error)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe "Array#sql_value_list and #sql_array" do
|
207
|
+
before do
|
208
|
+
@d = Sequel::Dataset.new(nil)
|
209
|
+
end
|
210
|
+
|
211
|
+
specify "should treat the array as an SQL value list instead of conditions when used as a placeholder value" do
|
212
|
+
@d.filter("(a, b) IN ?", [[:x, 1], [:y, 2]]).sql.should == 'SELECT * WHERE ((a, b) IN ((x = 1) AND (y = 2)))'
|
213
|
+
@d.filter("(a, b) IN ?", [[:x, 1], [:y, 2]].sql_value_list).sql.should == 'SELECT * WHERE ((a, b) IN ((x, 1), (y, 2)))'
|
214
|
+
end
|
215
|
+
|
216
|
+
specify "should be no difference when used as a hash value" do
|
217
|
+
@d.filter([:a, :b]=>[[:x, 1], [:y, 2]]).sql.should == 'SELECT * WHERE ((a, b) IN ((x, 1), (y, 2)))'
|
218
|
+
@d.filter([:a, :b]=>[[:x, 1], [:y, 2]].sql_value_list).sql.should == 'SELECT * WHERE ((a, b) IN ((x, 1), (y, 2)))'
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe "String#lit" do
|
223
|
+
before do
|
224
|
+
@ds = ds = Sequel::Database.new[:t]
|
225
|
+
end
|
226
|
+
|
227
|
+
specify "should return an LiteralString object" do
|
228
|
+
'xyz'.lit.should be_a_kind_of(Sequel::LiteralString)
|
229
|
+
'xyz'.lit.to_s.should == 'xyz'
|
230
|
+
end
|
231
|
+
|
232
|
+
specify "should inhibit string literalization" do
|
233
|
+
@ds.update_sql(:stamp => "NOW()".lit).should == "UPDATE t SET stamp = NOW()"
|
234
|
+
end
|
235
|
+
|
236
|
+
specify "should return a PlaceholderLiteralString object if args are given" do
|
237
|
+
a = 'DISTINCT ?'.lit(:a)
|
238
|
+
a.should be_a_kind_of(Sequel::SQL::PlaceholderLiteralString)
|
239
|
+
@ds.literal(a).should == 'DISTINCT a'
|
240
|
+
@ds.quote_identifiers = true
|
241
|
+
@ds.literal(a).should == 'DISTINCT "a"'
|
242
|
+
end
|
243
|
+
|
244
|
+
specify "should handle named placeholders if given a single argument hash" do
|
245
|
+
a = 'DISTINCT :b'.lit(:b=>:a)
|
246
|
+
a.should be_a_kind_of(Sequel::SQL::PlaceholderLiteralString)
|
247
|
+
@ds.literal(a).should == 'DISTINCT a'
|
248
|
+
@ds.quote_identifiers = true
|
249
|
+
@ds.literal(a).should == 'DISTINCT "a"'
|
250
|
+
end
|
251
|
+
|
252
|
+
specify "should treat placeholder literal strings as generic expressions" do
|
253
|
+
a = ':b'.lit(:b=>:a)
|
254
|
+
@ds.literal(a + 1).should == "(a + 1)"
|
255
|
+
@ds.literal(a & :b).should == "(a AND b)"
|
256
|
+
@ds.literal(a.sql_string + :b).should == "(a || b)"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
describe "String#to_sequel_blob" do
|
261
|
+
specify "should return a Blob object" do
|
262
|
+
'xyz'.to_sequel_blob.should be_a_kind_of(::Sequel::SQL::Blob)
|
263
|
+
'xyz'.to_sequel_blob.should == 'xyz'
|
264
|
+
end
|
265
|
+
|
266
|
+
specify "should retain binary data" do
|
267
|
+
"\1\2\3\4".to_sequel_blob.should == "\1\2\3\4"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
describe "#desc" do
|
272
|
+
before do
|
273
|
+
@ds = Sequel::Dataset.new(nil)
|
274
|
+
end
|
275
|
+
|
276
|
+
specify "should format a DESC clause for a column ref" do
|
277
|
+
:test.desc.to_s(@ds).should == 'test DESC'
|
278
|
+
|
279
|
+
:items__price.desc.to_s(@ds).should == 'items.price DESC'
|
280
|
+
end
|
281
|
+
|
282
|
+
specify "should format a DESC clause for a function" do
|
283
|
+
:avg.sql_function(:test).desc.to_s(@ds).should == 'avg(test) DESC'
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
describe "#asc" do
|
288
|
+
before do
|
289
|
+
@ds = Sequel::Dataset.new(nil)
|
290
|
+
end
|
291
|
+
|
292
|
+
specify "should format a ASC clause for a column ref" do
|
293
|
+
:test.asc.to_s(@ds).should == 'test ASC'
|
294
|
+
|
295
|
+
:items__price.asc.to_s(@ds).should == 'items.price ASC'
|
296
|
+
end
|
297
|
+
|
298
|
+
specify "should format a ASC clause for a function" do
|
299
|
+
:avg.sql_function(:test).asc.to_s(@ds).should == 'avg(test) ASC'
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
describe "#as" do
|
304
|
+
before do
|
305
|
+
@ds = Sequel::Dataset.new(nil)
|
306
|
+
end
|
307
|
+
|
308
|
+
specify "should format a AS clause for a column ref" do
|
309
|
+
:test.as(:t).to_s(@ds).should == 'test AS t'
|
310
|
+
|
311
|
+
:items__price.as(:p).to_s(@ds).should == 'items.price AS p'
|
312
|
+
end
|
313
|
+
|
314
|
+
specify "should format a AS clause for a function" do
|
315
|
+
:avg.sql_function(:test).as(:avg).to_s(@ds).should == 'avg(test) AS avg'
|
316
|
+
end
|
317
|
+
|
318
|
+
specify "should format a AS clause for a literal value" do
|
319
|
+
'abc'.as(:abc).to_s(@ds).should == "'abc' AS abc"
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
describe "Column references" do
|
324
|
+
before do
|
325
|
+
@ds = Sequel::Database.new.dataset
|
326
|
+
def @ds.quoted_identifier_append(sql, c)
|
327
|
+
sql << "`#{c}`"
|
328
|
+
end
|
329
|
+
@ds.quote_identifiers = true
|
330
|
+
end
|
331
|
+
|
332
|
+
specify "should be quoted properly" do
|
333
|
+
@ds.literal(:xyz).should == "`xyz`"
|
334
|
+
@ds.literal(:xyz__abc).should == "`xyz`.`abc`"
|
335
|
+
|
336
|
+
@ds.literal(:xyz.as(:x)).should == "`xyz` AS `x`"
|
337
|
+
@ds.literal(:xyz__abc.as(:x)).should == "`xyz`.`abc` AS `x`"
|
338
|
+
|
339
|
+
@ds.literal(:xyz___x).should == "`xyz` AS `x`"
|
340
|
+
@ds.literal(:xyz__abc___x).should == "`xyz`.`abc` AS `x`"
|
341
|
+
end
|
342
|
+
|
343
|
+
specify "should be quoted properly in SQL functions" do
|
344
|
+
@ds.literal(:avg.sql_function(:xyz)).should == "avg(`xyz`)"
|
345
|
+
@ds.literal(:avg.sql_function(:xyz, 1)).should == "avg(`xyz`, 1)"
|
346
|
+
@ds.literal(:avg.sql_function(:xyz).as(:a)).should == "avg(`xyz`) AS `a`"
|
347
|
+
end
|
348
|
+
|
349
|
+
specify "should be quoted properly in ASC/DESC clauses" do
|
350
|
+
@ds.literal(:xyz.asc).should == "`xyz` ASC"
|
351
|
+
@ds.literal(:avg.sql_function(:xyz, 1).desc).should == "avg(`xyz`, 1) DESC"
|
352
|
+
end
|
353
|
+
|
354
|
+
specify "should be quoted properly in a cast function" do
|
355
|
+
@ds.literal(:x.cast(:integer)).should == "CAST(`x` AS integer)"
|
356
|
+
@ds.literal(:x__y.cast('varchar(20)')).should == "CAST(`x`.`y` AS varchar(20))"
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
describe "Blob" do
|
361
|
+
specify "#to_sequel_blob should return self" do
|
362
|
+
blob = "x".to_sequel_blob
|
363
|
+
blob.to_sequel_blob.object_id.should == blob.object_id
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
if RUBY_VERSION < '1.9.0'
|
368
|
+
describe "Symbol#[]" do
|
369
|
+
specify "should format an SQL Function" do
|
370
|
+
ds = Sequel::Dataset.new(nil)
|
371
|
+
ds.literal(:xyz[]).should == 'xyz()'
|
372
|
+
ds.literal(:xyz[1]).should == 'xyz(1)'
|
373
|
+
ds.literal(:xyz[1, 2, :abc[3]]).should == 'xyz(1, 2, abc(3))'
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
describe "Symbol#*" do
|
379
|
+
before do
|
380
|
+
@ds = Sequel::Dataset.new(nil)
|
381
|
+
end
|
382
|
+
|
383
|
+
specify "should format a qualified wildcard if no argument" do
|
384
|
+
:xyz.*.to_s(@ds).should == 'xyz.*'
|
385
|
+
:abc.*.to_s(@ds).should == 'abc.*'
|
386
|
+
end
|
387
|
+
|
388
|
+
specify "should format a filter expression if an argument" do
|
389
|
+
:xyz.*(3).to_s(@ds).should == '(xyz * 3)'
|
390
|
+
:abc.*(5).to_s(@ds).should == '(abc * 5)'
|
391
|
+
end
|
392
|
+
|
393
|
+
specify "should support qualified symbols if no argument" do
|
394
|
+
:xyz__abc.*.to_s(@ds).should == 'xyz.abc.*'
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
describe "Symbol" do
|
399
|
+
before do
|
400
|
+
@ds = Sequel::Dataset.new(nil)
|
401
|
+
@ds.quote_identifiers = true
|
402
|
+
@ds.identifier_input_method = :upcase
|
403
|
+
end
|
404
|
+
|
405
|
+
specify "#identifier should format an identifier" do
|
406
|
+
@ds.literal(:xyz__abc.identifier).should == '"XYZ__ABC"'
|
407
|
+
end
|
408
|
+
|
409
|
+
specify "#qualify should format a qualified column" do
|
410
|
+
@ds.literal(:xyz.qualify(:abc)).should == '"ABC"."XYZ"'
|
411
|
+
end
|
412
|
+
|
413
|
+
specify "#qualify should work on QualifiedIdentifiers" do
|
414
|
+
@ds.literal(:xyz.qualify(:abc).qualify(:def)).should == '"DEF"."ABC"."XYZ"'
|
415
|
+
end
|
416
|
+
|
417
|
+
specify "should be able to qualify an identifier" do
|
418
|
+
@ds.literal(:xyz.identifier.qualify(:xyz__abc)).should == '"XYZ"."ABC"."XYZ"'
|
419
|
+
end
|
420
|
+
|
421
|
+
specify "should be able to specify a schema.table.column" do
|
422
|
+
@ds.literal(:column.qualify(:table.qualify(:schema))).should == '"SCHEMA"."TABLE"."COLUMN"'
|
423
|
+
@ds.literal(:column.qualify(:table__name.identifier.qualify(:schema))).should == '"SCHEMA"."TABLE__NAME"."COLUMN"'
|
424
|
+
end
|
425
|
+
|
426
|
+
specify "should be able to specify order" do
|
427
|
+
@oe = :xyz.desc
|
428
|
+
@oe.class.should == Sequel::SQL::OrderedExpression
|
429
|
+
@oe.descending.should == true
|
430
|
+
@oe = :xyz.asc
|
431
|
+
@oe.class.should == Sequel::SQL::OrderedExpression
|
432
|
+
@oe.descending.should == false
|
433
|
+
end
|
434
|
+
|
435
|
+
specify "should work correctly with objects" do
|
436
|
+
o = Object.new
|
437
|
+
def o.sql_literal(ds) "(foo)" end
|
438
|
+
@ds.literal(:column.qualify(o)).should == '(foo)."COLUMN"'
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
describe "Symbol" do
|
443
|
+
before do
|
444
|
+
@ds = Sequel::Database.new.dataset
|
445
|
+
end
|
446
|
+
|
447
|
+
specify "should support sql_function method" do
|
448
|
+
:COUNT.sql_function('1').to_s(@ds).should == "COUNT('1')"
|
449
|
+
@ds.select(:COUNT.sql_function('1')).sql.should == "SELECT COUNT('1')"
|
450
|
+
end
|
451
|
+
|
452
|
+
specify "should support cast method" do
|
453
|
+
:abc.cast(:integer).to_s(@ds).should == "CAST(abc AS integer)"
|
454
|
+
end
|
455
|
+
|
456
|
+
specify "should support sql array accesses via sql_subscript" do
|
457
|
+
@ds.literal(:abc.sql_subscript(1)).should == "abc[1]"
|
458
|
+
@ds.literal(:abc__def.sql_subscript(1)).should == "abc.def[1]"
|
459
|
+
@ds.literal(:abc.sql_subscript(1)|2).should == "abc[1, 2]"
|
460
|
+
@ds.literal(:abc.sql_subscript(1)[2]).should == "abc[1][2]"
|
461
|
+
end
|
462
|
+
|
463
|
+
specify "should support cast_numeric and cast_string" do
|
464
|
+
x = :abc.cast_numeric
|
465
|
+
x.should be_a_kind_of(Sequel::SQL::NumericExpression)
|
466
|
+
x.to_s(@ds).should == "CAST(abc AS integer)"
|
467
|
+
|
468
|
+
x = :abc.cast_numeric(:real)
|
469
|
+
x.should be_a_kind_of(Sequel::SQL::NumericExpression)
|
470
|
+
x.to_s(@ds).should == "CAST(abc AS real)"
|
471
|
+
|
472
|
+
x = :abc.cast_string
|
473
|
+
x.should be_a_kind_of(Sequel::SQL::StringExpression)
|
474
|
+
x.to_s(@ds).should == "CAST(abc AS varchar(255))"
|
475
|
+
|
476
|
+
x = :abc.cast_string(:varchar)
|
477
|
+
x.should be_a_kind_of(Sequel::SQL::StringExpression)
|
478
|
+
x.to_s(@ds).should == "CAST(abc AS varchar(255))"
|
479
|
+
end
|
480
|
+
|
481
|
+
specify "should allow database independent types when casting" do
|
482
|
+
db = @ds.db
|
483
|
+
def db.cast_type_literal(type)
|
484
|
+
return :foo if type == Integer
|
485
|
+
return :bar if type == String
|
486
|
+
type
|
487
|
+
end
|
488
|
+
:abc.cast(String).to_s(@ds).should == "CAST(abc AS bar)"
|
489
|
+
:abc.cast(String).to_s(@ds).should == "CAST(abc AS bar)"
|
490
|
+
:abc.cast_string.to_s(@ds).should == "CAST(abc AS bar)"
|
491
|
+
:abc.cast_string(Integer).to_s(@ds).should == "CAST(abc AS foo)"
|
492
|
+
:abc.cast_numeric.to_s(@ds).should == "CAST(abc AS foo)"
|
493
|
+
:abc.cast_numeric(String).to_s(@ds).should == "CAST(abc AS bar)"
|
494
|
+
end
|
495
|
+
|
496
|
+
specify "should support SQL EXTRACT function via #extract " do
|
497
|
+
:abc.extract(:year).to_s(@ds).should == "extract(year FROM abc)"
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
describe "Postgres extensions integration" do
|
502
|
+
before do
|
503
|
+
@db = Sequel.mock
|
504
|
+
Sequel.extension(:pg_array, :pg_array_ops, :pg_hstore, :pg_hstore_ops, :pg_json, :pg_range, :pg_range_ops, :pg_row, :pg_row_ops)
|
505
|
+
end
|
506
|
+
|
507
|
+
it "Symbol#pg_array should return an ArrayOp" do
|
508
|
+
@db.literal(:a.pg_array.unnest).should == "unnest(a)"
|
509
|
+
end
|
510
|
+
|
511
|
+
it "Symbol#pg_row should return a PGRowOp" do
|
512
|
+
@db.literal(:a.pg_row[:a]).should == "(a).a"
|
513
|
+
end
|
514
|
+
|
515
|
+
it "Symbol#hstore should return an HStoreOp" do
|
516
|
+
@db.literal(:a.hstore['a']).should == "(a -> 'a')"
|
517
|
+
end
|
518
|
+
|
519
|
+
it "Symbol#pg_range should return a RangeOp" do
|
520
|
+
@db.literal(:a.pg_range.lower).should == "lower(a)"
|
521
|
+
end
|
522
|
+
|
523
|
+
it "Array#pg_array should return a PGArray" do
|
524
|
+
@db.literal([1].pg_array.op.unnest).should == "unnest(ARRAY[1])"
|
525
|
+
@db.literal([1].pg_array(:int4).op.unnest).should == "unnest(ARRAY[1]::int4[])"
|
526
|
+
end
|
527
|
+
|
528
|
+
it "Array#pg_json should return a JSONArray" do
|
529
|
+
@db.literal([1].pg_json).should == "'[1]'::json"
|
530
|
+
end
|
531
|
+
|
532
|
+
it "Array#pg_row should return a ArrayRow" do
|
533
|
+
@db.literal([1].pg_row).should == "ROW(1)"
|
534
|
+
end
|
535
|
+
|
536
|
+
it "Hash#hstore should return an HStore" do
|
537
|
+
@db.literal({'a'=>1}.hstore.op['a']).should == '(\'"a"=>"1"\'::hstore -> \'a\')'
|
538
|
+
end
|
539
|
+
|
540
|
+
it "Hash#pg_json should return an JSONHash" do
|
541
|
+
@db.literal({'a'=>'b'}.pg_json).should == "'{\"a\":\"b\"}'::json"
|
542
|
+
end
|
543
|
+
|
544
|
+
it "Range#pg_range should return an PGRange" do
|
545
|
+
@db.literal((1..2).pg_range).should == "'[1,2]'"
|
546
|
+
@db.literal((1..2).pg_range(:int4range)).should == "'[1,2]'::int4range"
|
547
|
+
end
|
548
|
+
end
|
549
|
+
else
|
550
|
+
skip_warn "core_refinements extension: only works on ruby 2.0+"
|
551
|
+
end
|