sequel 3.21.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.
Files changed (104) hide show
  1. data/CHANGELOG +112 -0
  2. data/README.rdoc +15 -1
  3. data/doc/association_basics.rdoc +159 -40
  4. data/doc/model_hooks.rdoc +64 -27
  5. data/doc/prepared_statements.rdoc +8 -4
  6. data/doc/reflection.rdoc +8 -2
  7. data/doc/release_notes/3.22.0.txt +39 -0
  8. data/doc/release_notes/3.23.0.txt +172 -0
  9. data/doc/release_notes/3.24.0.txt +420 -0
  10. data/doc/virtual_rows.rdoc +2 -2
  11. data/lib/sequel/adapters/ado.rb +2 -1
  12. data/lib/sequel/adapters/db2.rb +8 -1
  13. data/lib/sequel/adapters/firebird.rb +25 -9
  14. data/lib/sequel/adapters/informix.rb +4 -19
  15. data/lib/sequel/adapters/jdbc/h2.rb +5 -0
  16. data/lib/sequel/adapters/jdbc/informix.rb +31 -0
  17. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  18. data/lib/sequel/adapters/jdbc/mssql.rb +0 -32
  19. data/lib/sequel/adapters/jdbc/mysql.rb +9 -0
  20. data/lib/sequel/adapters/jdbc/sqlserver.rb +46 -0
  21. data/lib/sequel/adapters/jdbc.rb +39 -20
  22. data/lib/sequel/adapters/odbc.rb +2 -0
  23. data/lib/sequel/adapters/oracle.rb +12 -0
  24. data/lib/sequel/adapters/postgres.rb +30 -1
  25. data/lib/sequel/adapters/shared/access.rb +10 -0
  26. data/lib/sequel/adapters/shared/informix.rb +45 -0
  27. data/lib/sequel/adapters/shared/mssql.rb +106 -11
  28. data/lib/sequel/adapters/shared/mysql.rb +25 -7
  29. data/lib/sequel/adapters/shared/postgres.rb +39 -6
  30. data/lib/sequel/adapters/shared/sqlite.rb +57 -5
  31. data/lib/sequel/adapters/sqlite.rb +8 -3
  32. data/lib/sequel/adapters/swift/mysql.rb +9 -0
  33. data/lib/sequel/adapters/tinytds.rb +4 -3
  34. data/lib/sequel/ast_transformer.rb +190 -0
  35. data/lib/sequel/core.rb +1 -1
  36. data/lib/sequel/database/connecting.rb +1 -1
  37. data/lib/sequel/database/misc.rb +6 -0
  38. data/lib/sequel/database/query.rb +33 -3
  39. data/lib/sequel/database/schema_methods.rb +13 -4
  40. data/lib/sequel/dataset/features.rb +6 -0
  41. data/lib/sequel/dataset/prepared_statements.rb +17 -2
  42. data/lib/sequel/dataset/query.rb +17 -0
  43. data/lib/sequel/dataset/sql.rb +2 -53
  44. data/lib/sequel/exceptions.rb +4 -0
  45. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  46. data/lib/sequel/extensions/migration.rb +4 -3
  47. data/lib/sequel/extensions/to_dot.rb +95 -83
  48. data/lib/sequel/model/associations.rb +234 -32
  49. data/lib/sequel/model/base.rb +187 -60
  50. data/lib/sequel/model/exceptions.rb +3 -1
  51. data/lib/sequel/model.rb +5 -0
  52. data/lib/sequel/plugins/association_pks.rb +6 -4
  53. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  54. data/lib/sequel/plugins/identity_map.rb +2 -2
  55. data/lib/sequel/plugins/many_through_many.rb +33 -3
  56. data/lib/sequel/plugins/prepared_statements.rb +140 -0
  57. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  58. data/lib/sequel/plugins/prepared_statements_safe.rb +72 -0
  59. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  60. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  61. data/lib/sequel/plugins/single_table_inheritance.rb +2 -0
  62. data/lib/sequel/plugins/xml_serializer.rb +1 -1
  63. data/lib/sequel/sql.rb +8 -0
  64. data/lib/sequel/version.rb +1 -1
  65. data/spec/adapters/mssql_spec.rb +36 -0
  66. data/spec/adapters/mysql_spec.rb +6 -0
  67. data/spec/adapters/postgres_spec.rb +43 -18
  68. data/spec/adapters/spec_helper.rb +5 -0
  69. data/spec/core/connection_pool_spec.rb +56 -77
  70. data/spec/core/database_spec.rb +33 -0
  71. data/spec/core/dataset_spec.rb +127 -16
  72. data/spec/core/expression_filters_spec.rb +13 -0
  73. data/spec/core/schema_spec.rb +13 -1
  74. data/spec/core/spec_helper.rb +5 -0
  75. data/spec/extensions/association_pks_spec.rb +7 -0
  76. data/spec/extensions/columns_introspection_spec.rb +91 -0
  77. data/spec/extensions/defaults_setter_spec.rb +64 -0
  78. data/spec/extensions/many_through_many_spec.rb +77 -0
  79. data/spec/extensions/migration_spec.rb +17 -17
  80. data/spec/extensions/nested_attributes_spec.rb +1 -0
  81. data/spec/extensions/prepared_statements_associations_spec.rb +126 -0
  82. data/spec/extensions/prepared_statements_safe_spec.rb +69 -0
  83. data/spec/extensions/prepared_statements_spec.rb +72 -0
  84. data/spec/extensions/prepared_statements_with_pk_spec.rb +38 -0
  85. data/spec/extensions/serialization_modification_detection_spec.rb +36 -0
  86. data/spec/extensions/single_table_inheritance_spec.rb +11 -0
  87. data/spec/extensions/spec_helper.rb +3 -1
  88. data/spec/extensions/to_dot_spec.rb +3 -5
  89. data/spec/extensions/xml_serializer_spec.rb +12 -0
  90. data/spec/integration/associations_test.rb +212 -0
  91. data/spec/integration/dataset_test.rb +8 -1
  92. data/spec/integration/plugin_test.rb +134 -0
  93. data/spec/integration/prepared_statement_test.rb +72 -1
  94. data/spec/integration/schema_test.rb +66 -8
  95. data/spec/integration/spec_helper.rb +5 -0
  96. data/spec/integration/transaction_test.rb +40 -0
  97. data/spec/integration/type_test.rb +7 -0
  98. data/spec/model/associations_spec.rb +463 -5
  99. data/spec/model/base_spec.rb +59 -0
  100. data/spec/model/eager_loading_spec.rb +269 -1
  101. data/spec/model/hooks_spec.rb +161 -0
  102. data/spec/model/record_spec.rb +30 -0
  103. data/spec/model/spec_helper.rb +5 -0
  104. metadata +29 -4
@@ -0,0 +1,36 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "serialization_modification_detection plugin" do
4
+ before do
5
+ @c = Class.new(Sequel::Model(:items))
6
+ @c.class_eval do
7
+ columns :id, :h
8
+ plugin :serialization, :yaml, :h
9
+ plugin :serialization_modification_detection
10
+ end
11
+ @o1 = @c.new
12
+ @o2 = @c.load(:id=>1, :h=>"--- {}\n\n")
13
+ MODEL_DB.reset
14
+ end
15
+
16
+ it "should not detect columns that haven't been changed" do
17
+ @o2.changed_columns.should == []
18
+ @o2.h.should == {}
19
+ @o2.h[1] = 2
20
+ @o2.h.clear
21
+ @o2.changed_columns.should == []
22
+ end
23
+
24
+ it "should detect columns that have been changed" do
25
+ @o2.changed_columns.should == []
26
+ @o2.h.should == {}
27
+ @o2.h[1] = 2
28
+ @o2.changed_columns.should == [:h]
29
+ end
30
+
31
+ it "should report correct changed_columns after saving" do
32
+ @o2.h[1] = 2
33
+ @o2.save_changes
34
+ @o2.changed_columns.should == []
35
+ end
36
+ end
@@ -54,6 +54,17 @@ describe Sequel::Model, "#sti_key" do
54
54
  StiTest.all.collect{|x| x.class}.should == [StiTest, StiTestSub1, StiTestSub2]
55
55
  end
56
56
 
57
+ it "should return rows with the correct class for subclasses based on the polymorphic_key value" do
58
+ class ::StiTestSub1Sub < StiTestSub1
59
+ end
60
+ ds = StiTestSub1.dataset
61
+ def ds.fetch_rows(sql)
62
+ yield({:kind=>'StiTestSub1'})
63
+ yield({:kind=>'StiTestSub1Sub'})
64
+ end
65
+ StiTestSub1.all.collect{|x| x.class}.should == [StiTestSub1, StiTestSub1Sub]
66
+ end
67
+
57
68
  it "should fallback to the main class if the given class does not exist" do
58
69
  def @ds.fetch_rows(sql)
59
70
  yield({:kind=>'StiTestSub3'})
@@ -8,9 +8,11 @@ unless Sequel.const_defined?('Model')
8
8
  require 'sequel/model'
9
9
  end
10
10
 
11
- Sequel.extension(*%w'string_date_time inflector pagination query pretty_table blank migration schema_dumper looser_typecasting sql_expr thread_local_timezones to_dot')
11
+ Sequel.extension(*%w'string_date_time inflector pagination query pretty_table blank migration schema_dumper looser_typecasting sql_expr thread_local_timezones to_dot columns_introspection')
12
12
  {:hook_class_methods=>[], :schema=>[], :validation_class_methods=>[]}.each{|p, opts| Sequel::Model.plugin(p, *opts)}
13
13
 
14
+ Sequel::Dataset.introspect_all_columns if ENV['SEQUEL_COLUMNS_INTROSPECTION']
15
+
14
16
  def skip_warn(s)
15
17
  warn "Skipping test of #{s}" if ENV["SKIPPED_TEST_WARN"]
16
18
  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
- a = []
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: a\"];", "3 -> 4 [label=\"f\"];", "4 [label=\":a\"];", "3 -> 5 [label=\"sub\"];", "5 [label=\"Array\"];", "5 -> 6 [label=\"0\"];", "6 [label=\"1\"];"]
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=\"Array\"];", "7 -> 8 [label=\"0\"];", "8 [label=\"Array\"];", "8 -> 9 [label=\"0\"];", "9 [label=\"QualifiedIdentifier\"];", "9 -> 10 [label=\"table\"];", "10 [label=\"\\\"d\\\"\"];", "9 -> 11 [label=\"column\"];", "11 [label=\"\\\"b\\\"\"];", "8 -> 12 [label=\"1\"];", "12 [label=\"QualifiedIdentifier\"];", "12 -> 13 [label=\"table\"];", "13 [label=\"\\\"a\\\"\"];", "12 -> 14 [label=\"column\"];", "14 [label=\"\\\"c\\\"\"];"]
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
@@ -36,6 +36,18 @@ describe "Sequel::Plugins::XmlSerializer" do
36
36
  Album.from_xml(@album.to_xml).should == @album
37
37
  end
38
38
 
39
+ it "should round trip successfully for namespaced models" do
40
+ module XmlSerializerTest
41
+ class Artist < Sequel::Model
42
+ plugin :xml_serializer
43
+ columns :id, :name
44
+ @db_schema = {:id=>{:type=>:integer}, :name=>{:type=>:string}}
45
+ end
46
+ end
47
+ artist = XmlSerializerTest::Artist.load(:id=>2, :name=>'YJM')
48
+ XmlSerializerTest::Artist.from_xml(artist.to_xml).should == artist
49
+ end
50
+
39
51
  it "should round trip successfully with empty strings" do
40
52
  artist = Artist.load(:id=>2, :name=>'')
41
53
  Artist.from_xml(artist.to_xml).should == artist
@@ -22,6 +22,172 @@ 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 with prepared_statements_association plugin" do
26
+ @album.update(:artist => @artist)
27
+ @album.add_tag(@tag)
28
+
29
+ @album.reload
30
+ @artist.reload
31
+ @tag.reload
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
+
44
+ Artist.filter(:albums=>@album).all.should == [@artist]
45
+ Album.filter(:artist=>@artist).all.should == [@album]
46
+ Album.filter(:tags=>@tag).all.should == [@album]
47
+ Tag.filter(:albums=>@album).all.should == [@tag]
48
+ Album.filter(:artist=>@artist, :tags=>@tag).all.should == [@album]
49
+ @artist.albums_dataset.filter(:tags=>@tag).all.should == [@album]
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
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
+
25
191
  specify "should have remove methods work" do
26
192
  @album.update(:artist => @artist)
27
193
  @album.add_tag(@tag)
@@ -151,6 +317,8 @@ describe "Sequel::Model Simple Associations" do
151
317
  @album = Album.create(:name=>'Al')
152
318
  @artist = Artist.create(:name=>'Ar')
153
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)}
154
322
  end
155
323
  after do
156
324
  @db.drop_table(:albums_tags, :tags, :albums, :artists)
@@ -216,6 +384,48 @@ describe "Sequel::Model Simple Associations" do
216
384
  @tag.reload.albums.should == []
217
385
  end
218
386
 
387
+ specify "should handle dynamic callbacks for regular loading" do
388
+ @artist.add_album(@album)
389
+
390
+ @artist.albums.should == [@album]
391
+ @artist.albums(proc{|ds| ds.exclude(:id=>@album.id)}).should == []
392
+ @artist.albums(proc{|ds| ds.filter(:id=>@album.id)}).should == [@album]
393
+
394
+ @album.artist.should == @artist
395
+ @album.artist(proc{|ds| ds.exclude(:id=>@artist.id)}).should == nil
396
+ @album.artist(proc{|ds| ds.filter(:id=>@artist.id)}).should == @artist
397
+
398
+ if RUBY_VERSION >= '1.8.7'
399
+ @artist.albums{|ds| ds.exclude(:id=>@album.id)}.should == []
400
+ @artist.albums{|ds| ds.filter(:id=>@album.id)}.should == [@album]
401
+ @album.artist{|ds| ds.exclude(:id=>@artist.id)}.should == nil
402
+ @album.artist{|ds| ds.filter(:id=>@artist.id)}.should == @artist
403
+ end
404
+ end
405
+
406
+ specify "should handle dynamic callbacks for eager loading via eager and eager_graph" do
407
+ @artist.add_album(@album)
408
+ @album.add_tag(@tag)
409
+ album2 = @artist.add_album(:name=>'Foo')
410
+ tag2 = album2.add_tag(:name=>'T2')
411
+
412
+ artist = Artist.eager(:albums=>:tags).all.first
413
+ artist.albums.should == [@album, album2]
414
+ artist.albums.map{|x| x.tags}.should == [[@tag], [tag2]]
415
+
416
+ artist = Artist.eager_graph(:albums=>:tags).all.first
417
+ artist.albums.should == [@album, album2]
418
+ artist.albums.map{|x| x.tags}.should == [[@tag], [tag2]]
419
+
420
+ artist = Artist.eager(:albums=>{proc{|ds| ds.where(:id=>album2.id)}=>:tags}).all.first
421
+ artist.albums.should == [album2]
422
+ artist.albums.first.tags.should == [tag2]
423
+
424
+ artist = Artist.eager_graph(:albums=>{proc{|ds| ds.where(:id=>album2.id)}=>:tags}).all.first
425
+ artist.albums.should == [album2]
426
+ artist.albums.first.tags.should == [tag2]
427
+ end
428
+
219
429
  specify "should have remove method raise an error for one_to_many records if the object isn't already associated" do
220
430
  proc{@artist.remove_album(@album.id)}.should raise_error(Sequel::Error)
221
431
  proc{@artist.remove_album(@album)}.should raise_error(Sequel::Error)
@@ -275,6 +485,8 @@ describe "Sequel::Model Composite Key Associations" do
275
485
  @album = Album.create(:name=>'Al', :id1=>1, :id2=>2)
276
486
  @artist = Artist.create(:name=>'Ar', :id1=>3, :id2=>4)
277
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)}
278
490
  end
279
491
  after do
280
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'
@@ -205,6 +211,25 @@ describe "Many Through Many Plugin" do
205
211
  Artist.filter(:artists__id=>2).eager_graph(:albums).all.map{|x| x.albums.map{|a| a.name}}.flatten.sort.should == %w'A C'
206
212
  Artist.filter(:artists__id=>3).eager_graph(:albums).all.map{|x| x.albums.map{|a| a.name}}.flatten.sort.should == %w'B C'
207
213
  Artist.filter(:artists__id=>4).eager_graph(:albums).all.map{|x| x.albums.map{|a| a.name}}.flatten.sort.should == %w'B D'
214
+
215
+ Artist.filter(:albums=>@album1).all.map{|a| a.name}.sort.should == %w'1 2'
216
+ Artist.filter(:albums=>@album2).all.map{|a| a.name}.sort.should == %w'3 4'
217
+ Artist.filter(:albums=>@album3).all.map{|a| a.name}.sort.should == %w'2 3'
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'
208
233
  end
209
234
 
210
235
  specify "should handle typical case with 3 join tables" do
@@ -214,6 +239,12 @@ describe "Many Through Many Plugin" do
214
239
  Artist[3].related_artists.map{|x| x.name}.sort.should == %w'2 3 4'
215
240
  Artist[4].related_artists.map{|x| x.name}.sort.should == %w'1 3 4'
216
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
+
217
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'
218
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'
219
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'
@@ -223,6 +254,22 @@ describe "Many Through Many Plugin" do
223
254
  Artist.filter(:artists__id=>2).eager_graph(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 2 3'
224
255
  Artist.filter(:artists__id=>3).eager_graph(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'2 3 4'
225
256
  Artist.filter(:artists__id=>4).eager_graph(:related_artists).all.map{|x| x.related_artists.map{|a| a.name}}.flatten.sort.should == %w'1 3 4'
257
+
258
+ Artist.filter(:related_artists=>@artist1).all.map{|a| a.name}.sort.should == %w'1 2 4'
259
+ Artist.filter(:related_artists=>@artist2).all.map{|a| a.name}.sort.should == %w'1 2 3'
260
+ Artist.filter(:related_artists=>@artist3).all.map{|a| a.name}.sort.should == %w'2 3 4'
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'
226
273
  end
227
274
 
228
275
  specify "should handle extreme case with 5 join tables" do
@@ -241,6 +288,12 @@ describe "Many Through Many Plugin" do
241
288
  Artist[3].related_albums.map{|x| x.name}.sort.should == %w'A B D'
242
289
  Artist[4].related_albums.map{|x| x.name}.sort.should == %w'B D'
243
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
+
244
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'
245
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'
246
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'
@@ -250,6 +303,25 @@ describe "Many Through Many Plugin" do
250
303
  Artist.filter(:artists__id=>2).eager_graph(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B C D'
251
304
  Artist.filter(:artists__id=>3).eager_graph(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'A B D'
252
305
  Artist.filter(:artists__id=>4).eager_graph(:related_albums).all.map{|x| x.related_albums.map{|a| a.name}}.flatten.sort.should == %w'B D'
306
+
307
+ Artist.filter(:related_albums=>@album1).all.map{|a| a.name}.sort.should == %w'1 2 3'
308
+ Artist.filter(:related_albums=>@album2).all.map{|a| a.name}.sort.should == %w'1 2 3 4'
309
+ Artist.filter(:related_albums=>@album3).all.map{|a| a.name}.sort.should == %w'1 2'
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'
253
325
  end
254
326
  end
255
327
 
@@ -1306,3 +1378,65 @@ describe "Sequel::Plugins::Tree" do
1306
1378
  end
1307
1379
  end
1308
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