sequel 3.23.0 → 3.24.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 +64 -0
- data/doc/association_basics.rdoc +43 -5
- data/doc/model_hooks.rdoc +64 -27
- data/doc/prepared_statements.rdoc +8 -4
- data/doc/reflection.rdoc +8 -2
- data/doc/release_notes/3.23.0.txt +1 -1
- data/doc/release_notes/3.24.0.txt +420 -0
- data/lib/sequel/adapters/db2.rb +8 -1
- data/lib/sequel/adapters/firebird.rb +25 -9
- data/lib/sequel/adapters/informix.rb +4 -19
- data/lib/sequel/adapters/jdbc.rb +34 -17
- data/lib/sequel/adapters/jdbc/h2.rb +5 -0
- data/lib/sequel/adapters/jdbc/informix.rb +31 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
- data/lib/sequel/adapters/jdbc/mysql.rb +9 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +46 -0
- data/lib/sequel/adapters/postgres.rb +30 -1
- data/lib/sequel/adapters/shared/access.rb +10 -0
- data/lib/sequel/adapters/shared/informix.rb +45 -0
- data/lib/sequel/adapters/shared/mssql.rb +82 -8
- data/lib/sequel/adapters/shared/mysql.rb +25 -7
- data/lib/sequel/adapters/shared/postgres.rb +39 -6
- data/lib/sequel/adapters/shared/sqlite.rb +57 -5
- data/lib/sequel/adapters/sqlite.rb +8 -3
- data/lib/sequel/adapters/swift/mysql.rb +9 -0
- data/lib/sequel/ast_transformer.rb +190 -0
- data/lib/sequel/core.rb +1 -1
- data/lib/sequel/database/misc.rb +6 -0
- data/lib/sequel/database/query.rb +33 -3
- data/lib/sequel/database/schema_methods.rb +6 -2
- data/lib/sequel/dataset/features.rb +6 -0
- data/lib/sequel/dataset/prepared_statements.rb +17 -2
- data/lib/sequel/dataset/query.rb +17 -0
- data/lib/sequel/dataset/sql.rb +2 -53
- data/lib/sequel/exceptions.rb +4 -0
- data/lib/sequel/extensions/to_dot.rb +95 -83
- data/lib/sequel/model.rb +5 -0
- data/lib/sequel/model/associations.rb +80 -14
- data/lib/sequel/model/base.rb +182 -55
- data/lib/sequel/model/exceptions.rb +3 -1
- data/lib/sequel/plugins/association_pks.rb +6 -4
- data/lib/sequel/plugins/defaults_setter.rb +58 -0
- data/lib/sequel/plugins/many_through_many.rb +8 -3
- data/lib/sequel/plugins/prepared_statements.rb +140 -0
- data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
- data/lib/sequel/plugins/prepared_statements_safe.rb +72 -0
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
- data/lib/sequel/sql.rb +8 -0
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +43 -18
- data/spec/core/connection_pool_spec.rb +56 -77
- data/spec/core/database_spec.rb +25 -0
- data/spec/core/dataset_spec.rb +127 -16
- data/spec/core/expression_filters_spec.rb +13 -0
- data/spec/core/schema_spec.rb +6 -1
- data/spec/extensions/association_pks_spec.rb +7 -0
- data/spec/extensions/defaults_setter_spec.rb +64 -0
- data/spec/extensions/many_through_many_spec.rb +60 -4
- data/spec/extensions/nested_attributes_spec.rb +1 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
- data/spec/extensions/prepared_statements_safe_spec.rb +69 -0
- data/spec/extensions/prepared_statements_spec.rb +72 -0
- data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
- data/spec/extensions/to_dot_spec.rb +3 -5
- data/spec/integration/associations_test.rb +155 -1
- data/spec/integration/dataset_test.rb +8 -1
- data/spec/integration/plugin_test.rb +119 -0
- data/spec/integration/prepared_statement_test.rb +72 -1
- data/spec/integration/schema_test.rb +66 -8
- data/spec/integration/transaction_test.rb +40 -0
- data/spec/model/associations_spec.rb +349 -8
- data/spec/model/base_spec.rb +59 -0
- data/spec/model/hooks_spec.rb +161 -0
- data/spec/model/record_spec.rb +24 -0
- metadata +21 -4
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "prepared_statements_with_pk plugin" do
|
4
|
+
before do
|
5
|
+
@c = Class.new(Sequel::Model(:people))
|
6
|
+
@c.columns :id, :name, :i
|
7
|
+
@ds = ds = @c.dataset
|
8
|
+
def ds.fetch_rows(sql)
|
9
|
+
db << {:server=>@opts[:server] || :read_only}.merge(opts)[:server]
|
10
|
+
super{|h|}
|
11
|
+
yield(:id=>1, :name=>'foo', :i=>2)
|
12
|
+
end
|
13
|
+
@c.plugin :prepared_statements_with_pk
|
14
|
+
@p = @c.load(:id=>1, :name=>'foo', :i=>2)
|
15
|
+
@c.db.execute 'foo'
|
16
|
+
@sqls = @c.db.sqls
|
17
|
+
@sqls.clear
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "should load the prepared_statements plugin" do
|
21
|
+
@c.plugins.should include(Sequel::Plugins::PreparedStatements)
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "should correctly lookup by primary key from dataset" do
|
25
|
+
@c.dataset.filter(:name=>'foo')[1].should == @p
|
26
|
+
@sqls.should == [:read_only, "SELECT * FROM people WHERE ((name = 'foo') AND (id = 1)) LIMIT 1"]
|
27
|
+
end
|
28
|
+
|
29
|
+
specify "should still work correctly if there are multiple conflicting variables" do
|
30
|
+
@c.dataset.filter(:name=>'foo').or(:name=>'bar')[1].should == @p
|
31
|
+
@sqls.should == [:read_only, "SELECT * FROM people WHERE (((name = 'foo') OR (name = 'bar')) AND (id = 1)) LIMIT 1"]
|
32
|
+
end
|
33
|
+
|
34
|
+
specify "should still work correctly if the primary key is used elsewhere in the query" do
|
35
|
+
@c.dataset.filter{id > 2}[1].should == @p
|
36
|
+
@sqls.should == [:read_only, "SELECT * FROM people WHERE ((id > 2) AND (id = 1)) LIMIT 1"]
|
37
|
+
end
|
38
|
+
end
|
@@ -2,9 +2,7 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
2
|
|
3
3
|
describe Sequel::Model, "to_dot extension" do
|
4
4
|
def dot(ds)
|
5
|
-
|
6
|
-
ds.send(:_to_dot, a, "", 0, ds, 0)
|
7
|
-
a[2..-1]
|
5
|
+
Sequel::ToDot.new(ds).instance_variable_get(:@dot)[4...-1]
|
8
6
|
end
|
9
7
|
|
10
8
|
before do
|
@@ -123,7 +121,7 @@ END
|
|
123
121
|
end
|
124
122
|
|
125
123
|
it "should handle SQL::Subscript" do
|
126
|
-
dot(@ds.select(:a.sql_subscript(1))).should == ["1 -> 2 [label=\"select\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"Subscript
|
124
|
+
dot(@ds.select(:a.sql_subscript(1))).should == ["1 -> 2 [label=\"select\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"Subscript\"];", "3 -> 4 [label=\"f\"];", "4 [label=\":a\"];", "3 -> 5 [label=\"sub\"];", "5 [label=\"Array\"];", "5 -> 6 [label=\"0\"];", "6 [label=\"1\"];"]
|
127
125
|
end
|
128
126
|
|
129
127
|
it "should handle SQL::WindowFunction" do
|
@@ -135,7 +133,7 @@ END
|
|
135
133
|
end
|
136
134
|
|
137
135
|
it "should handle JOIN ON" do
|
138
|
-
dot(@ds.from(:a).join(:d, :b=>:c)).should == ["1 -> 2 [label=\"from\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\":a\"];", "1 -> 4 [label=\"join\"];", "4 [label=\"Array\"];", "4 -> 5 [label=\"0\"];", "5 [label=\"INNER JOIN ON\"];", "5 -> 6 [label=\"table\"];", "6 [label=\":d\"];", "5 -> 7 [label=\"on\"];", "7 [label=\"
|
136
|
+
dot(@ds.from(:a).join(:d, :b=>:c)).should == ["1 -> 2 [label=\"from\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\":a\"];", "1 -> 4 [label=\"join\"];", "4 [label=\"Array\"];", "4 -> 5 [label=\"0\"];", "5 [label=\"INNER JOIN ON\"];", "5 -> 6 [label=\"table\"];", "6 [label=\":d\"];", "5 -> 7 [label=\"on\"];", "7 [label=\"ComplexExpression: =\"];", "7 -> 8 [label=\"0\"];", "8 [label=\"QualifiedIdentifier\"];", "8 -> 9 [label=\"table\"];", "9 [label=\"\\\"d\\\"\"];", "8 -> 10 [label=\"column\"];", "10 [label=\"\\\"b\\\"\"];", "7 -> 11 [label=\"1\"];", "11 [label=\"QualifiedIdentifier\"];", "11 -> 12 [label=\"table\"];", "12 [label=\"\\\"a\\\"\"];", "11 -> 13 [label=\"column\"];", "13 [label=\"\\\"c\\\"\"];"]
|
139
137
|
end
|
140
138
|
|
141
139
|
it "should handle JOIN USING" do
|
@@ -22,7 +22,7 @@ shared_examples_for "regular and composite key associations" do
|
|
22
22
|
@tag.albums.should == [@album]
|
23
23
|
end
|
24
24
|
|
25
|
-
specify "should work correctly
|
25
|
+
specify "should work correctly with prepared_statements_association plugin" do
|
26
26
|
@album.update(:artist => @artist)
|
27
27
|
@album.add_tag(@tag)
|
28
28
|
|
@@ -30,6 +30,17 @@ shared_examples_for "regular and composite key associations" do
|
|
30
30
|
@artist.reload
|
31
31
|
@tag.reload
|
32
32
|
|
33
|
+
[Tag, Album, Artist].each{|x| x.plugin :prepared_statements_associations}
|
34
|
+
@album.artist.should == @artist
|
35
|
+
@artist.albums.should == [@album]
|
36
|
+
@album.tags.should == [@tag]
|
37
|
+
@tag.albums.should == [@album]
|
38
|
+
end
|
39
|
+
|
40
|
+
specify "should work correctly when filtering by associations" do
|
41
|
+
@album.update(:artist => @artist)
|
42
|
+
@album.add_tag(@tag)
|
43
|
+
|
33
44
|
Artist.filter(:albums=>@album).all.should == [@artist]
|
34
45
|
Album.filter(:artist=>@artist).all.should == [@album]
|
35
46
|
Album.filter(:tags=>@tag).all.should == [@album]
|
@@ -37,7 +48,146 @@ shared_examples_for "regular and composite key associations" do
|
|
37
48
|
Album.filter(:artist=>@artist, :tags=>@tag).all.should == [@album]
|
38
49
|
@artist.albums_dataset.filter(:tags=>@tag).all.should == [@album]
|
39
50
|
end
|
51
|
+
|
52
|
+
specify "should work correctly when excluding by associations" do
|
53
|
+
@album.update(:artist => @artist)
|
54
|
+
@album.add_tag(@tag)
|
55
|
+
album, artist, tag = @pr.call
|
56
|
+
|
57
|
+
Artist.exclude(:albums=>@album).all.should == [artist]
|
58
|
+
Album.exclude(:artist=>@artist).all.should == [album]
|
59
|
+
Album.exclude(:tags=>@tag).all.should == [album]
|
60
|
+
Tag.exclude(:albums=>@album).all.should == [tag]
|
61
|
+
Album.exclude(:artist=>@artist, :tags=>@tag).all.should == [album]
|
62
|
+
end
|
63
|
+
|
64
|
+
specify "should work correctly when filtering by multiple associations" do
|
65
|
+
album, artist, tag = @pr.call
|
66
|
+
@album.update(:artist => @artist)
|
67
|
+
@album.add_tag(@tag)
|
68
|
+
|
69
|
+
Artist.filter(:albums=>[@album, album]).all.should == [@artist]
|
70
|
+
Album.filter(:artist=>[@artist, artist]).all.should == [@album]
|
71
|
+
Album.filter(:tags=>[@tag, tag]).all.should == [@album]
|
72
|
+
Tag.filter(:albums=>[@album, album]).all.should == [@tag]
|
73
|
+
Album.filter(:artist=>[@artist, artist], :tags=>[@tag, tag]).all.should == [@album]
|
74
|
+
@artist.albums_dataset.filter(:tags=>[@tag, tag]).all.should == [@album]
|
75
|
+
|
76
|
+
album.add_tag(tag)
|
77
|
+
|
78
|
+
Artist.filter(:albums=>[@album, album]).all.should == [@artist]
|
79
|
+
Album.filter(:artist=>[@artist, artist]).all.should == [@album]
|
80
|
+
Album.filter(:tags=>[@tag, tag]).all.sort_by{|x| x.pk}.should == [@album, album]
|
81
|
+
Tag.filter(:albums=>[@album, album]).all.sort_by{|x| x.pk}.should == [@tag, tag]
|
82
|
+
Album.filter(:artist=>[@artist, artist], :tags=>[@tag, tag]).all.should == [@album]
|
83
|
+
|
84
|
+
album.update(:artist => artist)
|
85
|
+
|
86
|
+
Artist.filter(:albums=>[@album, album]).all.sort_by{|x| x.pk}.should == [@artist, artist]
|
87
|
+
Album.filter(:artist=>[@artist, artist]).all.sort_by{|x| x.pk}.should == [@album, album]
|
88
|
+
Album.filter(:tags=>[@tag, tag]).all.sort_by{|x| x.pk}.should == [@album, album]
|
89
|
+
Tag.filter(:albums=>[@album, album]).all.sort_by{|x| x.pk}.should == [@tag, tag]
|
90
|
+
Album.filter(:artist=>[@artist, artist], :tags=>[@tag, tag]).all.sort_by{|x| x.pk}.should == [@album, album]
|
91
|
+
end
|
92
|
+
|
93
|
+
specify "should work correctly when excluding by multiple associations" do
|
94
|
+
album, artist, tag = @pr.call
|
95
|
+
|
96
|
+
Artist.exclude(:albums=>[@album, album]).all.sort_by{|x| x.pk}.should == [@artist, artist]
|
97
|
+
Album.exclude(:artist=>[@artist, artist]).all.sort_by{|x| x.pk}.should == [@album, album]
|
98
|
+
Album.exclude(:tags=>[@tag, tag]).all.sort_by{|x| x.pk}.should == [@album, album]
|
99
|
+
Tag.exclude(:albums=>[@album, album]).all.sort_by{|x| x.pk}.should == [@tag, tag]
|
100
|
+
Album.exclude(:artist=>[@artist, artist], :tags=>[@tag, tag]).all.sort_by{|x| x.pk}.should == [@album, album]
|
101
|
+
|
102
|
+
@album.update(:artist => @artist)
|
103
|
+
@album.add_tag(@tag)
|
104
|
+
|
105
|
+
Artist.exclude(:albums=>[@album, album]).all.sort_by{|x| x.pk}.should == [artist]
|
106
|
+
Album.exclude(:artist=>[@artist, artist]).all.sort_by{|x| x.pk}.should == [album]
|
107
|
+
Album.exclude(:tags=>[@tag, tag]).all.sort_by{|x| x.pk}.should == [album]
|
108
|
+
Tag.exclude(:albums=>[@album, album]).all.sort_by{|x| x.pk}.should == [tag]
|
109
|
+
Album.exclude(:artist=>[@artist, artist], :tags=>[@tag, tag]).all.sort_by{|x| x.pk}.should == [album]
|
110
|
+
|
111
|
+
album.add_tag(tag)
|
112
|
+
|
113
|
+
Artist.exclude(:albums=>[@album, album]).all.should == [artist]
|
114
|
+
Album.exclude(:artist=>[@artist, artist]).all.should == [album]
|
115
|
+
Album.exclude(:tags=>[@tag, tag]).all.should == []
|
116
|
+
Tag.exclude(:albums=>[@album, album]).all.should == []
|
117
|
+
Album.exclude(:artist=>[@artist, artist], :tags=>[@tag, tag]).all.should == [album]
|
118
|
+
|
119
|
+
album.update(:artist => artist)
|
120
|
+
|
121
|
+
Artist.exclude(:albums=>[@album, album]).all.should == []
|
122
|
+
Album.exclude(:artist=>[@artist, artist]).all.should == []
|
123
|
+
Album.exclude(:tags=>[@tag, tag]).all.should == []
|
124
|
+
Tag.exclude(:albums=>[@album, album]).all.should == []
|
125
|
+
Album.exclude(:artist=>[@artist, artist], :tags=>[@tag, tag]).all.should == []
|
126
|
+
end
|
40
127
|
|
128
|
+
specify "should work correctly when excluding by associations in regards to NULL values" do
|
129
|
+
Artist.exclude(:albums=>@album).all.should == [@artist]
|
130
|
+
Album.exclude(:artist=>@artist).all.should == [@album]
|
131
|
+
Album.exclude(:tags=>@tag).all.should == [@album]
|
132
|
+
Tag.exclude(:albums=>@album).all.should == [@tag]
|
133
|
+
Album.exclude(:artist=>@artist, :tags=>@tag).all.should == [@album]
|
134
|
+
|
135
|
+
@album.update(:artist => @artist)
|
136
|
+
@artist.albums_dataset.exclude(:tags=>@tag).all.should == [@album]
|
137
|
+
end
|
138
|
+
|
139
|
+
specify "should handle NULL values in join table correctly when filtering/excluding many_to_many associations" do
|
140
|
+
@ins.call
|
141
|
+
Album.exclude(:tags=>@tag).all.should == [@album]
|
142
|
+
@album.add_tag(@tag)
|
143
|
+
Album.filter(:tags=>@tag).all.should == [@album]
|
144
|
+
album, artist, tag = @pr.call
|
145
|
+
Album.exclude(:tags=>@tag).all.should == [album]
|
146
|
+
Album.exclude(:tags=>tag).all.sort_by{|x| x.pk}.should == [@album, album]
|
147
|
+
end
|
148
|
+
|
149
|
+
specify "should work correctly when filtering by association datasets" do
|
150
|
+
album, artist, tag = @pr.call
|
151
|
+
@album.update(:artist => @artist)
|
152
|
+
@album.add_tag(@tag)
|
153
|
+
album.add_tag(tag)
|
154
|
+
album.update(:artist => artist)
|
155
|
+
|
156
|
+
Artist.filter(:albums=>Album.dataset).all.sort_by{|x| x.pk}.should == [@artist, artist]
|
157
|
+
Artist.filter(:albums=>Album.dataset.filter(Array(Album.primary_key).zip(Array(album.pk)))).all.sort_by{|x| x.pk}.should == [artist]
|
158
|
+
Artist.filter(:albums=>Album.dataset.filter(1=>0)).all.sort_by{|x| x.pk}.should == []
|
159
|
+
Album.filter(:artist=>Artist.dataset).all.sort_by{|x| x.pk}.should == [@album, album]
|
160
|
+
Album.filter(:artist=>Artist.dataset.filter(Array(Artist.primary_key).zip(Array(artist.pk)))).all.sort_by{|x| x.pk}.should == [album]
|
161
|
+
Album.filter(:artist=>Artist.dataset.filter(1=>0)).all.sort_by{|x| x.pk}.should == []
|
162
|
+
Album.filter(:tags=>Tag.dataset).all.sort_by{|x| x.pk}.should == [@album, album]
|
163
|
+
Album.filter(:tags=>Tag.dataset.filter(Array(Tag.primary_key).zip(Array(tag.pk)))).all.sort_by{|x| x.pk}.should == [album]
|
164
|
+
Album.filter(:tags=>Tag.dataset.filter(1=>0)).all.sort_by{|x| x.pk}.should == []
|
165
|
+
Tag.filter(:albums=>Album.dataset).all.sort_by{|x| x.pk}.should == [@tag, tag]
|
166
|
+
Tag.filter(:albums=>Album.dataset.filter(Array(Album.primary_key).zip(Array(album.pk)))).all.sort_by{|x| x.pk}.should == [tag]
|
167
|
+
Tag.filter(:albums=>Album.dataset.filter(1=>0)).all.sort_by{|x| x.pk}.should == []
|
168
|
+
end
|
169
|
+
|
170
|
+
specify "should work correctly when excluding by association datasets" do
|
171
|
+
album, artist, tag = @pr.call
|
172
|
+
@album.update(:artist => @artist)
|
173
|
+
@album.add_tag(@tag)
|
174
|
+
album.add_tag(tag)
|
175
|
+
album.update(:artist => artist)
|
176
|
+
|
177
|
+
Artist.exclude(:albums=>Album.dataset).all.sort_by{|x| x.pk}.should == []
|
178
|
+
Artist.exclude(:albums=>Album.dataset.filter(Array(Album.primary_key).zip(Array(album.pk)))).all.sort_by{|x| x.pk}.should == [@artist]
|
179
|
+
Artist.exclude(:albums=>Album.dataset.filter(1=>0)).all.sort_by{|x| x.pk}.should == [@artist, artist]
|
180
|
+
Album.exclude(:artist=>Artist.dataset).all.sort_by{|x| x.pk}.should == []
|
181
|
+
Album.exclude(:artist=>Artist.dataset.filter(Array(Artist.primary_key).zip(Array(artist.pk)))).all.sort_by{|x| x.pk}.should == [@album]
|
182
|
+
Album.exclude(:artist=>Artist.dataset.filter(1=>0)).all.sort_by{|x| x.pk}.should == [@album, album]
|
183
|
+
Album.exclude(:tags=>Tag.dataset).all.sort_by{|x| x.pk}.should == []
|
184
|
+
Album.exclude(:tags=>Tag.dataset.filter(Array(Tag.primary_key).zip(Array(tag.pk)))).all.sort_by{|x| x.pk}.should == [@album]
|
185
|
+
Album.exclude(:tags=>Tag.dataset.filter(1=>0)).all.sort_by{|x| x.pk}.should == [@album, album]
|
186
|
+
Tag.exclude(:albums=>Album.dataset).all.sort_by{|x| x.pk}.should == []
|
187
|
+
Tag.exclude(:albums=>Album.dataset.filter(Array(Album.primary_key).zip(Array(album.pk)))).all.sort_by{|x| x.pk}.should == [@tag]
|
188
|
+
Tag.exclude(:albums=>Album.dataset.filter(1=>0)).all.sort_by{|x| x.pk}.should == [@tag, tag]
|
189
|
+
end
|
190
|
+
|
41
191
|
specify "should have remove methods work" do
|
42
192
|
@album.update(:artist => @artist)
|
43
193
|
@album.add_tag(@tag)
|
@@ -167,6 +317,8 @@ describe "Sequel::Model Simple Associations" do
|
|
167
317
|
@album = Album.create(:name=>'Al')
|
168
318
|
@artist = Artist.create(:name=>'Ar')
|
169
319
|
@tag = Tag.create(:name=>'T')
|
320
|
+
@pr = lambda{[Album.create(:name=>'Al2'),Artist.create(:name=>'Ar2'),Tag.create(:name=>'T2')]}
|
321
|
+
@ins = lambda{@db[:albums_tags].insert(:tag_id=>@tag.id)}
|
170
322
|
end
|
171
323
|
after do
|
172
324
|
@db.drop_table(:albums_tags, :tags, :albums, :artists)
|
@@ -333,6 +485,8 @@ describe "Sequel::Model Composite Key Associations" do
|
|
333
485
|
@album = Album.create(:name=>'Al', :id1=>1, :id2=>2)
|
334
486
|
@artist = Artist.create(:name=>'Ar', :id1=>3, :id2=>4)
|
335
487
|
@tag = Tag.create(:name=>'T', :id1=>5, :id2=>6)
|
488
|
+
@pr = lambda{[Album.create(:name=>'Al2', :id1=>11, :id2=>12),Artist.create(:name=>'Ar2', :id1=>13, :id2=>14),Tag.create(:name=>'T2', :id1=>15, :id2=>16)]}
|
489
|
+
@ins = lambda{@db[:albums_tags].insert(:tag_id1=>@tag.id1, :tag_id2=>@tag.id2)}
|
336
490
|
end
|
337
491
|
after do
|
338
492
|
@db.drop_table(:albums_tags, :tags, :albums, :artists)
|
@@ -86,6 +86,13 @@ describe "Simple Dataset operations" do
|
|
86
86
|
specify "should alias columns correctly" do
|
87
87
|
@ds.select(:id___x, :number___n).first.should == {:x=>1, :n=>10}
|
88
88
|
end
|
89
|
+
|
90
|
+
specify "should handle true/false properly" do
|
91
|
+
@ds.filter(Sequel::TRUE).select_map(:number).should == [10]
|
92
|
+
@ds.filter(Sequel::FALSE).select_map(:number).should == []
|
93
|
+
@ds.filter(true).select_map(:number).should == [10]
|
94
|
+
@ds.filter(false).select_map(:number).should == []
|
95
|
+
end
|
89
96
|
end
|
90
97
|
|
91
98
|
describe Sequel::Dataset do
|
@@ -471,7 +478,7 @@ describe Sequel::SQL::Constants do
|
|
471
478
|
@c2 = proc{|v| v.is_a?(Date) ? v : Date.parse(v) }
|
472
479
|
end
|
473
480
|
after do
|
474
|
-
@db.drop_table(:constants)
|
481
|
+
@db.drop_table(:constants) if @db.table_exists?(:constants)
|
475
482
|
end
|
476
483
|
|
477
484
|
cspecify "should have working CURRENT_DATE", [:odbc, :mssql], [:jdbc, :sqlite] do
|
@@ -196,6 +196,12 @@ describe "Many Through Many Plugin" do
|
|
196
196
|
Artist[3].albums.map{|x| x.name}.sort.should == %w'B C'
|
197
197
|
Artist[4].albums.map{|x| x.name}.sort.should == %w'B D'
|
198
198
|
|
199
|
+
Artist.plugin :prepared_statements_associations
|
200
|
+
Artist[1].albums.map{|x| x.name}.sort.should == %w'A D'
|
201
|
+
Artist[2].albums.map{|x| x.name}.sort.should == %w'A C'
|
202
|
+
Artist[3].albums.map{|x| x.name}.sort.should == %w'B C'
|
203
|
+
Artist[4].albums.map{|x| x.name}.sort.should == %w'B D'
|
204
|
+
|
199
205
|
Artist.filter(:id=>1).eager(:albums).all.map{|x| x.albums.map{|a| a.name}}.flatten.sort.should == %w'A D'
|
200
206
|
Artist.filter(:id=>2).eager(:albums).all.map{|x| x.albums.map{|a| a.name}}.flatten.sort.should == %w'A C'
|
201
207
|
Artist.filter(:id=>3).eager(:albums).all.map{|x| x.albums.map{|a| a.name}}.flatten.sort.should == %w'B C'
|
@@ -210,6 +216,20 @@ describe "Many Through Many Plugin" do
|
|
210
216
|
Artist.filter(:albums=>@album2).all.map{|a| a.name}.sort.should == %w'3 4'
|
211
217
|
Artist.filter(:albums=>@album3).all.map{|a| a.name}.sort.should == %w'2 3'
|
212
218
|
Artist.filter(:albums=>@album4).all.map{|a| a.name}.sort.should == %w'1 4'
|
219
|
+
|
220
|
+
Artist.exclude(:albums=>@album1).all.map{|a| a.name}.sort.should == %w'3 4'
|
221
|
+
Artist.exclude(:albums=>@album2).all.map{|a| a.name}.sort.should == %w'1 2'
|
222
|
+
Artist.exclude(:albums=>@album3).all.map{|a| a.name}.sort.should == %w'1 4'
|
223
|
+
Artist.exclude(:albums=>@album4).all.map{|a| a.name}.sort.should == %w'2 3'
|
224
|
+
|
225
|
+
Artist.filter(:albums=>[@album1, @album3]).all.map{|a| a.name}.sort.should == %w'1 2 3'
|
226
|
+
Artist.filter(:albums=>[@album2, @album4]).all.map{|a| a.name}.sort.should == %w'1 3 4'
|
227
|
+
|
228
|
+
Artist.exclude(:albums=>[@album1, @album3]).all.map{|a| a.name}.sort.should == %w'4'
|
229
|
+
Artist.exclude(:albums=>[@album2, @album4]).all.map{|a| a.name}.sort.should == %w'2'
|
230
|
+
|
231
|
+
Artist.filter(:albums=>Album.filter(:id=>[@album1.id, @album3.id])).all.map{|a| a.name}.sort.should == %w'1 2 3'
|
232
|
+
Artist.exclude(:albums=>Album.filter(:id=>[@album1.id, @album3.id])).all.map{|a| a.name}.sort.should == %w'4'
|
213
233
|
end
|
214
234
|
|
215
235
|
specify "should handle typical case with 3 join tables" do
|
@@ -219,6 +239,12 @@ describe "Many Through Many Plugin" do
|
|
219
239
|
Artist[3].related_artists.map{|x| x.name}.sort.should == %w'2 3 4'
|
220
240
|
Artist[4].related_artists.map{|x| x.name}.sort.should == %w'1 3 4'
|
221
241
|
|
242
|
+
Artist.plugin :prepared_statements_associations
|
243
|
+
Artist[1].related_artists.map{|x| x.name}.sort.should == %w'1 2 4'
|
244
|
+
Artist[2].related_artists.map{|x| x.name}.sort.should == %w'1 2 3'
|
245
|
+
Artist[3].related_artists.map{|x| x.name}.sort.should == %w'2 3 4'
|
246
|
+
Artist[4].related_artists.map{|x| x.name}.sort.should == %w'1 3 4'
|
247
|
+
|
222
248
|
Artist.filter(:id=>1).eager(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 2 4'
|
223
249
|
Artist.filter(:id=>2).eager(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 2 3'
|
224
250
|
Artist.filter(:id=>3).eager(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'2 3 4'
|
@@ -233,6 +259,17 @@ describe "Many Through Many Plugin" do
|
|
233
259
|
Artist.filter(:related_artists=>@artist2).all.map{|a| a.name}.sort.should == %w'1 2 3'
|
234
260
|
Artist.filter(:related_artists=>@artist3).all.map{|a| a.name}.sort.should == %w'2 3 4'
|
235
261
|
Artist.filter(:related_artists=>@artist4).all.map{|a| a.name}.sort.should == %w'1 3 4'
|
262
|
+
|
263
|
+
Artist.exclude(:related_artists=>@artist1).all.map{|a| a.name}.sort.should == %w'3'
|
264
|
+
Artist.exclude(:related_artists=>@artist2).all.map{|a| a.name}.sort.should == %w'4'
|
265
|
+
Artist.exclude(:related_artists=>@artist3).all.map{|a| a.name}.sort.should == %w'1'
|
266
|
+
Artist.exclude(:related_artists=>@artist4).all.map{|a| a.name}.sort.should == %w'2'
|
267
|
+
|
268
|
+
Artist.filter(:related_artists=>[@artist1, @artist4]).all.map{|a| a.name}.sort.should == %w'1 2 3 4'
|
269
|
+
Artist.exclude(:related_artists=>[@artist1, @artist4]).all.map{|a| a.name}.sort.should == %w''
|
270
|
+
|
271
|
+
Artist.filter(:related_artists=>Artist.filter(:id=>@artist1.id)).all.map{|a| a.name}.sort.should == %w'1 2 4'
|
272
|
+
Artist.exclude(:related_artists=>Artist.filter(:id=>@artist1.id)).all.map{|a| a.name}.sort.should == %w'3'
|
236
273
|
end
|
237
274
|
|
238
275
|
specify "should handle extreme case with 5 join tables" do
|
@@ -251,6 +288,12 @@ describe "Many Through Many Plugin" do
|
|
251
288
|
Artist[3].related_albums.map{|x| x.name}.sort.should == %w'A B D'
|
252
289
|
Artist[4].related_albums.map{|x| x.name}.sort.should == %w'B D'
|
253
290
|
|
291
|
+
Artist.plugin :prepared_statements_associations
|
292
|
+
Artist[1].related_albums.map{|x| x.name}.sort.should == %w'A B C'
|
293
|
+
Artist[2].related_albums.map{|x| x.name}.sort.should == %w'A B C D'
|
294
|
+
Artist[3].related_albums.map{|x| x.name}.sort.should == %w'A B D'
|
295
|
+
Artist[4].related_albums.map{|x| x.name}.sort.should == %w'B D'
|
296
|
+
|
254
297
|
Artist.filter(:id=>1).eager(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B C'
|
255
298
|
Artist.filter(:id=>2).eager(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B C D'
|
256
299
|
Artist.filter(:id=>3).eager(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B D'
|
@@ -265,6 +308,20 @@ describe "Many Through Many Plugin" do
|
|
265
308
|
Artist.filter(:related_albums=>@album2).all.map{|a| a.name}.sort.should == %w'1 2 3 4'
|
266
309
|
Artist.filter(:related_albums=>@album3).all.map{|a| a.name}.sort.should == %w'1 2'
|
267
310
|
Artist.filter(:related_albums=>@album4).all.map{|a| a.name}.sort.should == %w'2 3 4'
|
311
|
+
|
312
|
+
Artist.exclude(:related_albums=>@album1).all.map{|a| a.name}.sort.should == %w'4'
|
313
|
+
Artist.exclude(:related_albums=>@album2).all.map{|a| a.name}.sort.should == %w''
|
314
|
+
Artist.exclude(:related_albums=>@album3).all.map{|a| a.name}.sort.should == %w'3 4'
|
315
|
+
Artist.exclude(:related_albums=>@album4).all.map{|a| a.name}.sort.should == %w'1'
|
316
|
+
|
317
|
+
Artist.filter(:related_albums=>[@album1, @album3]).all.map{|a| a.name}.sort.should == %w'1 2 3'
|
318
|
+
Artist.filter(:related_albums=>[@album3, @album4]).all.map{|a| a.name}.sort.should == %w'1 2 3 4'
|
319
|
+
|
320
|
+
Artist.exclude(:related_albums=>[@album1, @album3]).all.map{|a| a.name}.sort.should == %w'4'
|
321
|
+
Artist.exclude(:related_albums=>[@album2, @album4]).all.map{|a| a.name}.sort.should == %w''
|
322
|
+
|
323
|
+
Artist.filter(:related_albums=>Album.filter(:id=>[@album1.id, @album3.id])).all.map{|a| a.name}.sort.should == %w'1 2 3'
|
324
|
+
Artist.exclude(:related_albums=>Album.filter(:id=>[@album1.id, @album3.id])).all.map{|a| a.name}.sort.should == %w'4'
|
268
325
|
end
|
269
326
|
end
|
270
327
|
|
@@ -1321,3 +1378,65 @@ describe "Sequel::Plugins::Tree" do
|
|
1321
1378
|
end
|
1322
1379
|
end
|
1323
1380
|
end
|
1381
|
+
|
1382
|
+
describe "Sequel::Plugins::PreparedStatements" do
|
1383
|
+
before do
|
1384
|
+
@db = INTEGRATION_DB
|
1385
|
+
@db.create_table!(:ps_test) do
|
1386
|
+
primary_key :id
|
1387
|
+
String :name
|
1388
|
+
Integer :i
|
1389
|
+
end
|
1390
|
+
@c = Class.new(Sequel::Model(@db[:ps_test]))
|
1391
|
+
@foo = @c.create(:name=>'foo', :i=>10)
|
1392
|
+
@bar = @c.create(:name=>'bar', :i=>20)
|
1393
|
+
@c.plugin :prepared_statements_with_pk
|
1394
|
+
end
|
1395
|
+
after do
|
1396
|
+
@db.drop_table(:ps_test)
|
1397
|
+
end
|
1398
|
+
|
1399
|
+
it "should work with looking up using Model.[]" do
|
1400
|
+
@c[@foo.id].should == @foo
|
1401
|
+
@c[@bar.id].should == @bar
|
1402
|
+
@c[0].should == nil
|
1403
|
+
end
|
1404
|
+
|
1405
|
+
it "should work with looking up using Dataset#with_pk" do
|
1406
|
+
@c.dataset.with_pk(@foo.id).should == @foo
|
1407
|
+
@c.dataset.with_pk(@bar.id).should == @bar
|
1408
|
+
@c.dataset.with_pk(0).should == nil
|
1409
|
+
|
1410
|
+
@c.dataset.filter(:i=>0).with_pk(@foo.id).should == nil
|
1411
|
+
@c.dataset.filter(:i=>10).with_pk(@foo.id).should == @foo
|
1412
|
+
@c.dataset.filter(:i=>20).with_pk(@bar.id).should == @bar
|
1413
|
+
@c.dataset.filter(:name=>'foo').with_pk(@foo.id).should == @foo
|
1414
|
+
@c.dataset.filter(:name=>'bar').with_pk(@bar.id).should == @bar
|
1415
|
+
@c.dataset.filter(:name=>'baz').with_pk(@bar.id).should == nil
|
1416
|
+
end
|
1417
|
+
|
1418
|
+
it "should work with Model#destroy" do
|
1419
|
+
@foo.destroy
|
1420
|
+
@bar.destroy
|
1421
|
+
@c[@foo.id].should == nil
|
1422
|
+
@c[@bar.id].should == nil
|
1423
|
+
end
|
1424
|
+
|
1425
|
+
it "should work with Model#update" do
|
1426
|
+
@foo.update(:name=>'foo2', :i=>30)
|
1427
|
+
@c[@foo.id].should == @c.load(:id=>@foo.id, :name=>'foo2', :i=>30)
|
1428
|
+
@foo.update(:name=>'foo3')
|
1429
|
+
@c[@foo.id].should == @c.load(:id=>@foo.id, :name=>'foo3', :i=>30)
|
1430
|
+
@foo.update(:i=>40)
|
1431
|
+
@c[@foo.id].should == @c.load(:id=>@foo.id, :name=>'foo3', :i=>40)
|
1432
|
+
end
|
1433
|
+
|
1434
|
+
it "should work with Model#create" do
|
1435
|
+
o = @c.create(:name=>'foo2', :i=>30)
|
1436
|
+
@c[o.id].should == @c.load(:id=>o.id, :name=>'foo2', :i=>30)
|
1437
|
+
o = @c.create(:name=>'foo2')
|
1438
|
+
@c[o.id].should == @c.load(:id=>o.id, :name=>'foo2', :i=>nil)
|
1439
|
+
o = @c.create(:i=>30)
|
1440
|
+
@c[o.id].should == @c.load(:id=>o.id, :name=>nil, :i=>30)
|
1441
|
+
end
|
1442
|
+
end
|
@@ -251,7 +251,7 @@ describe "Bound Argument Types" do
|
|
251
251
|
@ds.filter(:t=>@ds.ba(:$x, :timestamp)).prepare(:first, :ps_time).call(:x=>@vs[:t])[:t].should == @vs[:t]
|
252
252
|
end
|
253
253
|
|
254
|
-
cspecify "should handle blob type", [:swift] do
|
254
|
+
cspecify "should handle blob type", [:swift], [:odbc] do
|
255
255
|
@ds.filter(:file=>@ds.ba(:$x, :bytea)).prepare(:first, :ps_blob).call(:x=>@vs[:file])[:file].should == @vs[:file]
|
256
256
|
end
|
257
257
|
|
@@ -268,3 +268,74 @@ describe "Bound Argument Types" do
|
|
268
268
|
end
|
269
269
|
end unless INTEGRATION_DB.adapter_scheme == :swift && INTEGRATION_DB.database_type == :postgres
|
270
270
|
|
271
|
+
describe "Dataset#unbind" do
|
272
|
+
before do
|
273
|
+
@ds = ds = INTEGRATION_DB[:items]
|
274
|
+
@ct = proc do |t, v|
|
275
|
+
INTEGRATION_DB.create_table!(:items) do
|
276
|
+
column :c, t
|
277
|
+
end
|
278
|
+
ds.insert(:c=>v)
|
279
|
+
end
|
280
|
+
@u = proc{|ds| ds, bv = ds.unbind; ds.call(:first, bv)}
|
281
|
+
end
|
282
|
+
after do
|
283
|
+
INTEGRATION_DB.drop_table(:items) rescue nil
|
284
|
+
end
|
285
|
+
|
286
|
+
specify "should unbind values assigned to equality and inequality statements" do
|
287
|
+
@ct[Integer, 10]
|
288
|
+
@u[@ds.filter(:c=>10)].should == {:c=>10}
|
289
|
+
@u[@ds.exclude(:c=>10)].should == nil
|
290
|
+
@u[@ds.filter{c < 10}].should == nil
|
291
|
+
@u[@ds.filter{c <= 10}].should == {:c=>10}
|
292
|
+
@u[@ds.filter{c > 10}].should == nil
|
293
|
+
@u[@ds.filter{c >= 10}].should == {:c=>10}
|
294
|
+
end
|
295
|
+
|
296
|
+
cspecify "should handle numerics and strings", [:odbc], [:swift, :sqlite] do
|
297
|
+
@ct[Integer, 10]
|
298
|
+
@u[@ds.filter(:c=>10)].should == {:c=>10}
|
299
|
+
@ct[Float, 0.0]
|
300
|
+
@u[@ds.filter{c < 1}].should == {:c=>0.0}
|
301
|
+
@ct[String, 'foo']
|
302
|
+
@u[@ds.filter(:c=>'foo')].should == {:c=>'foo'}
|
303
|
+
|
304
|
+
INTEGRATION_DB.create_table!(:items) do
|
305
|
+
BigDecimal :c, :size=>[15,2]
|
306
|
+
end
|
307
|
+
@ds.insert(:c=>BigDecimal.new('1.1'))
|
308
|
+
@u[@ds.filter{c > 0}].should == {:c=>BigDecimal.new('1.1')}
|
309
|
+
end
|
310
|
+
|
311
|
+
cspecify "should handle dates and times", [:sqlite], [:do], [:jdbc, :mssql], [:tinytds] do
|
312
|
+
@ct[Date, Date.today]
|
313
|
+
@u[@ds.filter(:c=>Date.today)].should == {:c=>Date.today}
|
314
|
+
t = Time.now
|
315
|
+
@ct[Time, t]
|
316
|
+
@u[@ds.filter{c < t + 1}][:c].to_i.should == t.to_i
|
317
|
+
end
|
318
|
+
|
319
|
+
specify "should handle QualifiedIdentifiers" do
|
320
|
+
@ct[Integer, 10]
|
321
|
+
@u[@ds.filter{items__c > 1}].should == {:c=>10}
|
322
|
+
end
|
323
|
+
|
324
|
+
specify "should handle deep nesting" do
|
325
|
+
INTEGRATION_DB.create_table!(:items) do
|
326
|
+
Integer :a
|
327
|
+
Integer :b
|
328
|
+
Integer :c
|
329
|
+
Integer :d
|
330
|
+
end
|
331
|
+
@ds.insert(:a=>2, :b=>0, :c=>3, :d=>5)
|
332
|
+
@u[@ds.filter{a > 1}.and{b < 2}.or(:c=>3).and({~{:d=>4}=>1}.case(0) => 1)].should == {:a=>2, :b=>0, :c=>3, :d=>5}
|
333
|
+
@u[@ds.filter{a > 1}.and{b < 2}.or(:c=>3).and({~{:d=>5}=>1}.case(0) => 1)].should == nil
|
334
|
+
end
|
335
|
+
|
336
|
+
specify "should handle case where the same variable has the same value in multiple places " do
|
337
|
+
@ct[Integer, 1]
|
338
|
+
@u[@ds.filter{c > 1}.or{c < 1}.invert].should == {:c=>1}
|
339
|
+
@u[@ds.filter{c > 1}.or{c < 1}].should == nil
|
340
|
+
end
|
341
|
+
end
|