sequel 3.23.0 → 3.24.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|