epugh-sequel 0.0.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 (134) hide show
  1. data/README.rdoc +652 -0
  2. data/VERSION.yml +4 -0
  3. data/bin/sequel +104 -0
  4. data/lib/sequel.rb +1 -0
  5. data/lib/sequel/adapters/ado.rb +85 -0
  6. data/lib/sequel/adapters/db2.rb +132 -0
  7. data/lib/sequel/adapters/dbi.rb +101 -0
  8. data/lib/sequel/adapters/do.rb +197 -0
  9. data/lib/sequel/adapters/do/mysql.rb +38 -0
  10. data/lib/sequel/adapters/do/postgres.rb +92 -0
  11. data/lib/sequel/adapters/do/sqlite.rb +31 -0
  12. data/lib/sequel/adapters/firebird.rb +307 -0
  13. data/lib/sequel/adapters/informix.rb +75 -0
  14. data/lib/sequel/adapters/jdbc.rb +485 -0
  15. data/lib/sequel/adapters/jdbc/h2.rb +62 -0
  16. data/lib/sequel/adapters/jdbc/mysql.rb +56 -0
  17. data/lib/sequel/adapters/jdbc/oracle.rb +23 -0
  18. data/lib/sequel/adapters/jdbc/postgresql.rb +101 -0
  19. data/lib/sequel/adapters/jdbc/sqlite.rb +43 -0
  20. data/lib/sequel/adapters/mysql.rb +370 -0
  21. data/lib/sequel/adapters/odbc.rb +184 -0
  22. data/lib/sequel/adapters/openbase.rb +57 -0
  23. data/lib/sequel/adapters/oracle.rb +140 -0
  24. data/lib/sequel/adapters/postgres.rb +453 -0
  25. data/lib/sequel/adapters/shared/mssql.rb +93 -0
  26. data/lib/sequel/adapters/shared/mysql.rb +341 -0
  27. data/lib/sequel/adapters/shared/oracle.rb +62 -0
  28. data/lib/sequel/adapters/shared/postgres.rb +743 -0
  29. data/lib/sequel/adapters/shared/progress.rb +34 -0
  30. data/lib/sequel/adapters/shared/sqlite.rb +263 -0
  31. data/lib/sequel/adapters/sqlite.rb +243 -0
  32. data/lib/sequel/adapters/utils/date_format.rb +21 -0
  33. data/lib/sequel/adapters/utils/stored_procedures.rb +75 -0
  34. data/lib/sequel/adapters/utils/unsupported.rb +62 -0
  35. data/lib/sequel/connection_pool.rb +258 -0
  36. data/lib/sequel/core.rb +204 -0
  37. data/lib/sequel/core_sql.rb +185 -0
  38. data/lib/sequel/database.rb +687 -0
  39. data/lib/sequel/database/schema_generator.rb +324 -0
  40. data/lib/sequel/database/schema_methods.rb +164 -0
  41. data/lib/sequel/database/schema_sql.rb +324 -0
  42. data/lib/sequel/dataset.rb +422 -0
  43. data/lib/sequel/dataset/convenience.rb +237 -0
  44. data/lib/sequel/dataset/prepared_statements.rb +220 -0
  45. data/lib/sequel/dataset/sql.rb +1105 -0
  46. data/lib/sequel/deprecated.rb +529 -0
  47. data/lib/sequel/exceptions.rb +44 -0
  48. data/lib/sequel/extensions/blank.rb +42 -0
  49. data/lib/sequel/extensions/inflector.rb +288 -0
  50. data/lib/sequel/extensions/pagination.rb +96 -0
  51. data/lib/sequel/extensions/pretty_table.rb +78 -0
  52. data/lib/sequel/extensions/query.rb +48 -0
  53. data/lib/sequel/extensions/string_date_time.rb +47 -0
  54. data/lib/sequel/metaprogramming.rb +44 -0
  55. data/lib/sequel/migration.rb +212 -0
  56. data/lib/sequel/model.rb +142 -0
  57. data/lib/sequel/model/association_reflection.rb +263 -0
  58. data/lib/sequel/model/associations.rb +1024 -0
  59. data/lib/sequel/model/base.rb +911 -0
  60. data/lib/sequel/model/deprecated.rb +188 -0
  61. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  62. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  63. data/lib/sequel/model/deprecated_validations.rb +384 -0
  64. data/lib/sequel/model/errors.rb +37 -0
  65. data/lib/sequel/model/exceptions.rb +7 -0
  66. data/lib/sequel/model/inflections.rb +230 -0
  67. data/lib/sequel/model/plugins.rb +74 -0
  68. data/lib/sequel/object_graph.rb +230 -0
  69. data/lib/sequel/plugins/caching.rb +122 -0
  70. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  71. data/lib/sequel/plugins/schema.rb +53 -0
  72. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  73. data/lib/sequel/plugins/validation_class_methods.rb +373 -0
  74. data/lib/sequel/sql.rb +854 -0
  75. data/lib/sequel/version.rb +11 -0
  76. data/lib/sequel_core.rb +1 -0
  77. data/lib/sequel_model.rb +1 -0
  78. data/spec/adapters/ado_spec.rb +46 -0
  79. data/spec/adapters/firebird_spec.rb +376 -0
  80. data/spec/adapters/informix_spec.rb +96 -0
  81. data/spec/adapters/mysql_spec.rb +875 -0
  82. data/spec/adapters/oracle_spec.rb +272 -0
  83. data/spec/adapters/postgres_spec.rb +692 -0
  84. data/spec/adapters/spec_helper.rb +10 -0
  85. data/spec/adapters/sqlite_spec.rb +550 -0
  86. data/spec/core/connection_pool_spec.rb +526 -0
  87. data/spec/core/core_ext_spec.rb +156 -0
  88. data/spec/core/core_sql_spec.rb +528 -0
  89. data/spec/core/database_spec.rb +1214 -0
  90. data/spec/core/dataset_spec.rb +3513 -0
  91. data/spec/core/expression_filters_spec.rb +363 -0
  92. data/spec/core/migration_spec.rb +261 -0
  93. data/spec/core/object_graph_spec.rb +280 -0
  94. data/spec/core/pretty_table_spec.rb +58 -0
  95. data/spec/core/schema_generator_spec.rb +167 -0
  96. data/spec/core/schema_spec.rb +778 -0
  97. data/spec/core/spec_helper.rb +82 -0
  98. data/spec/core/version_spec.rb +7 -0
  99. data/spec/extensions/blank_spec.rb +67 -0
  100. data/spec/extensions/caching_spec.rb +201 -0
  101. data/spec/extensions/hook_class_methods_spec.rb +470 -0
  102. data/spec/extensions/inflector_spec.rb +122 -0
  103. data/spec/extensions/pagination_spec.rb +99 -0
  104. data/spec/extensions/pretty_table_spec.rb +91 -0
  105. data/spec/extensions/query_spec.rb +85 -0
  106. data/spec/extensions/schema_spec.rb +111 -0
  107. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  108. data/spec/extensions/spec_helper.rb +90 -0
  109. data/spec/extensions/string_date_time_spec.rb +93 -0
  110. data/spec/extensions/validation_class_methods_spec.rb +1054 -0
  111. data/spec/integration/dataset_test.rb +160 -0
  112. data/spec/integration/eager_loader_test.rb +683 -0
  113. data/spec/integration/prepared_statement_test.rb +130 -0
  114. data/spec/integration/schema_test.rb +183 -0
  115. data/spec/integration/spec_helper.rb +75 -0
  116. data/spec/integration/type_test.rb +96 -0
  117. data/spec/model/association_reflection_spec.rb +93 -0
  118. data/spec/model/associations_spec.rb +1780 -0
  119. data/spec/model/base_spec.rb +494 -0
  120. data/spec/model/caching_spec.rb +217 -0
  121. data/spec/model/dataset_methods_spec.rb +78 -0
  122. data/spec/model/eager_loading_spec.rb +1165 -0
  123. data/spec/model/hooks_spec.rb +472 -0
  124. data/spec/model/inflector_spec.rb +126 -0
  125. data/spec/model/model_spec.rb +588 -0
  126. data/spec/model/plugins_spec.rb +142 -0
  127. data/spec/model/record_spec.rb +1243 -0
  128. data/spec/model/schema_spec.rb +92 -0
  129. data/spec/model/spec_helper.rb +124 -0
  130. data/spec/model/validations_spec.rb +1080 -0
  131. data/spec/rcov.opts +6 -0
  132. data/spec/spec.opts +0 -0
  133. data/spec/spec_config.rb.example +10 -0
  134. metadata +202 -0
@@ -0,0 +1,363 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ context "Blockless Ruby Filters" do
4
+ before do
5
+ db = Sequel::Database.new
6
+ db.quote_identifiers = false
7
+ @d = db[:items]
8
+ def @d.l(*args, &block)
9
+ literal(filter_expr(*args, &block))
10
+ end
11
+ def @d.lit(*args)
12
+ literal(*args)
13
+ end
14
+ end
15
+
16
+ it "should support boolean columns directly" do
17
+ @d.l(:x).should == 'x'
18
+ end
19
+
20
+ it "should support NOT via Symbol#~" do
21
+ @d.l(~:x).should == 'NOT x'
22
+ end
23
+
24
+ it "should support qualified columns" do
25
+ @d.l(:x__y).should == 'x.y'
26
+ @d.l(~:x__y).should == 'NOT x.y'
27
+ end
28
+
29
+ it "should support NOT with SQL functions" do
30
+ @d.l(~:is_blah.sql_function).should == 'NOT is_blah()'
31
+ @d.l(~:is_blah.sql_function(:x)).should == 'NOT is_blah(x)'
32
+ @d.l(~:is_blah.sql_function(:x__y)).should == 'NOT is_blah(x.y)'
33
+ @d.l(~:is_blah.sql_function(:x, :x__y)).should == 'NOT is_blah(x, x.y)'
34
+ end
35
+
36
+ it "should handle multiple ~" do
37
+ @d.l(~~:x).should == 'x'
38
+ @d.l(~~~:x).should == 'NOT x'
39
+ @d.l(~~(:x & :y)).should == '(x AND y)'
40
+ @d.l(~~(:x | :y)).should == '(x OR y)'
41
+ end
42
+
43
+ it "should support = via Hash" do
44
+ @d.l(:x => 100).should == '(x = 100)'
45
+ @d.l(:x => 'a').should == '(x = \'a\')'
46
+ @d.l(:x => true).should == '(x IS TRUE)'
47
+ @d.l(:x => false).should == '(x IS FALSE)'
48
+ @d.l(:x => nil).should == '(x IS NULL)'
49
+ @d.l(:x => [1,2,3]).should == '(x IN (1, 2, 3))'
50
+ end
51
+
52
+ it "should support != via Hash#~" do
53
+ @d.l(~{:x => 100}).should == '(x != 100)'
54
+ @d.l(~{:x => 'a'}).should == '(x != \'a\')'
55
+ @d.l(~{:x => true}).should == '(x IS NOT TRUE)'
56
+ @d.l(~{:x => false}).should == '(x IS NOT FALSE)'
57
+ @d.l(~{:x => nil}).should == '(x IS NOT NULL)'
58
+ end
59
+
60
+ it "should support ~ via Hash and Regexp (if supported by database)" do
61
+ @d.l(:x => /blah/).should == '(x ~ \'blah\')'
62
+ end
63
+
64
+ it "should support !~ via Hash#~ and Regexp" do
65
+ @d.l(~{:x => /blah/}).should == '(x !~ \'blah\')'
66
+ end
67
+
68
+ it "should support LIKE via Symbol#like" do
69
+ @d.l(:x.like('a')).should == '(x LIKE \'a\')'
70
+ @d.l(:x.like(/a/)).should == '(x ~ \'a\')'
71
+ @d.l(:x.like('a', 'b')).should == '((x LIKE \'a\') OR (x LIKE \'b\'))'
72
+ @d.l(:x.like(/a/, /b/i)).should == '((x ~ \'a\') OR (x ~* \'b\'))'
73
+ @d.l(:x.like('a', /b/)).should == '((x LIKE \'a\') OR (x ~ \'b\'))'
74
+ end
75
+
76
+ it "should support NOT LIKE via Symbol#like and Symbol#~" do
77
+ @d.l(~:x.like('a')).should == '(x NOT LIKE \'a\')'
78
+ @d.l(~:x.like(/a/)).should == '(x !~ \'a\')'
79
+ @d.l(~:x.like('a', 'b')).should == '((x NOT LIKE \'a\') AND (x NOT LIKE \'b\'))'
80
+ @d.l(~:x.like(/a/, /b/i)).should == '((x !~ \'a\') AND (x !~* \'b\'))'
81
+ @d.l(~:x.like('a', /b/)).should == '((x NOT LIKE \'a\') AND (x !~ \'b\'))'
82
+ end
83
+
84
+ it "should support ILIKE via Symbol#ilike" do
85
+ @d.l(:x.ilike('a')).should == '(x ILIKE \'a\')'
86
+ @d.l(:x.ilike(/a/)).should == '(x ~* \'a\')'
87
+ @d.l(:x.ilike('a', 'b')).should == '((x ILIKE \'a\') OR (x ILIKE \'b\'))'
88
+ @d.l(:x.ilike(/a/, /b/i)).should == '((x ~* \'a\') OR (x ~* \'b\'))'
89
+ @d.l(:x.ilike('a', /b/)).should == '((x ILIKE \'a\') OR (x ~* \'b\'))'
90
+ end
91
+
92
+ it "should support NOT ILIKE via Symbol#ilike and Symbol#~" do
93
+ @d.l(~:x.ilike('a')).should == '(x NOT ILIKE \'a\')'
94
+ @d.l(~:x.ilike(/a/)).should == '(x !~* \'a\')'
95
+ @d.l(~:x.ilike('a', 'b')).should == '((x NOT ILIKE \'a\') AND (x NOT ILIKE \'b\'))'
96
+ @d.l(~:x.ilike(/a/, /b/i)).should == '((x !~* \'a\') AND (x !~* \'b\'))'
97
+ @d.l(~:x.ilike('a', /b/)).should == '((x NOT ILIKE \'a\') AND (x !~* \'b\'))'
98
+ end
99
+
100
+ it "should support negating ranges via Hash#~ and Range" do
101
+ @d.l(~{:x => 1..5}).should == '((x < 1) OR (x > 5))'
102
+ @d.l(~{:x => 1...5}).should == '((x < 1) OR (x >= 5))'
103
+ end
104
+
105
+ it "should support negating NOT IN via Hash#~ and Dataset or Array" do
106
+ @d.l(~{:x => @d.select(:i)}).should == '(x NOT IN (SELECT i FROM items))'
107
+ @d.l(~{:x => [1,2,3]}).should == '(x NOT IN (1, 2, 3))'
108
+ end
109
+
110
+ it "should support + - * / via Symbol#+,-,*,/" do
111
+ @d.l(:x + 1 > 100).should == '((x + 1) > 100)'
112
+ @d.l((:x * :y) < 100.01).should == '((x * y) < 100.01)'
113
+ @d.l((:x - :y/2) >= 100000000000000000000000000000000000).should == '((x - (y / 2)) >= 100000000000000000000000000000000000)'
114
+ @d.l((((:x - :y)/(:x + :y))*:z) <= 100).should == '((((x - y) / (x + y)) * z) <= 100)'
115
+ @d.l(~((((:x - :y)/(:x + :y))*:z) <= 100)).should == '((((x - y) / (x + y)) * z) > 100)'
116
+ end
117
+
118
+ it "should not allow negation of string expressions" do
119
+ proc{~:x.sql_string}.should raise_error
120
+ proc{~([:x, :y].sql_string_join)}.should raise_error
121
+ end
122
+
123
+ it "should not allow mathematical or string operations on true, false, or nil" do
124
+ proc{:x + 1}.should_not raise_error
125
+ proc{:x - true}.should raise_error(Sequel::Error)
126
+ proc{:x / false}.should raise_error(Sequel::Error)
127
+ proc{:x * nil}.should raise_error(Sequel::Error)
128
+ proc{[:x, nil].sql_string_join}.should raise_error(Sequel::Error)
129
+ end
130
+
131
+ it "should not allow mathematical or string operations on boolean complex expressions" do
132
+ proc{:x + (:y + 1)}.should_not raise_error
133
+ proc{:x - (~:y)}.should raise_error(Sequel::Error)
134
+ proc{:x / (:y & :z)}.should raise_error(Sequel::Error)
135
+ proc{:x * (:y | :z)}.should raise_error(Sequel::Error)
136
+ proc{:x + :y.like('a')}.should raise_error(Sequel::Error)
137
+ proc{:x - :y.like(/a/)}.should raise_error(Sequel::Error)
138
+ proc{:x * :y.like(/a/i)}.should raise_error(Sequel::Error)
139
+ proc{:x + ~:y.like('a')}.should raise_error(Sequel::Error)
140
+ proc{:x - ~:y.like(/a/)}.should raise_error(Sequel::Error)
141
+ proc{:x * ~:y.like(/a/i)}.should raise_error(Sequel::Error)
142
+ proc{[:x, ~:y.like(/a/i)].sql_string_join}.should raise_error(Sequel::Error)
143
+ end
144
+
145
+ it "should support AND conditions via &" do
146
+ @d.l(:x & :y).should == '(x AND y)'
147
+ @d.l(:x.sql_boolean & :y).should == '(x AND y)'
148
+ @d.l(:x & :y & :z).should == '((x AND y) AND z)'
149
+ @d.l(:x & {:y => :z}).should == '(x AND (y = z))'
150
+ @d.l({:y => :z} & :x).should == '((y = z) AND x)'
151
+ @d.l({:x => :a} & {:y => :z}).should == '((x = a) AND (y = z))'
152
+ @d.l((:x + 200 < 0) & (:y - 200 < 0)).should == '(((x + 200) < 0) AND ((y - 200) < 0))'
153
+ @d.l(:x & ~:y).should == '(x AND NOT y)'
154
+ @d.l(~:x & :y).should == '(NOT x AND y)'
155
+ @d.l(~:x & ~:y).should == '(NOT x AND NOT y)'
156
+ end
157
+
158
+ it "should support OR conditions via |" do
159
+ @d.l(:x | :y).should == '(x OR y)'
160
+ @d.l(:x.sql_boolean | :y).should == '(x OR y)'
161
+ @d.l(:x | :y | :z).should == '((x OR y) OR z)'
162
+ @d.l(:x | {:y => :z}).should == '(x OR (y = z))'
163
+ @d.l({:y => :z} | :x).should == '((y = z) OR x)'
164
+ @d.l({:x => :a} | {:y => :z}).should == '((x = a) OR (y = z))'
165
+ @d.l((:x.sql_number > 200) | (:y.sql_number < 200)).should == '((x > 200) OR (y < 200))'
166
+ end
167
+
168
+ it "should support & | combinations" do
169
+ @d.l((:x | :y) & :z).should == '((x OR y) AND z)'
170
+ @d.l(:x | (:y & :z)).should == '(x OR (y AND z))'
171
+ @d.l((:x & :w) | (:y & :z)).should == '((x AND w) OR (y AND z))'
172
+ end
173
+
174
+ it "should support & | with ~" do
175
+ @d.l(~((:x | :y) & :z)).should == '((NOT x AND NOT y) OR NOT z)'
176
+ @d.l(~(:x | (:y & :z))).should == '(NOT x AND (NOT y OR NOT z))'
177
+ @d.l(~((:x & :w) | (:y & :z))).should == '((NOT x OR NOT w) AND (NOT y OR NOT z))'
178
+ @d.l(~((:x.sql_number > 200) | (:y & :z))).should == '((x <= 200) AND (NOT y OR NOT z))'
179
+ end
180
+
181
+ it "should support LiteralString" do
182
+ @d.l('x'.lit).should == '(x)'
183
+ @d.l(~'x'.lit).should == 'NOT x'
184
+ @d.l(~~'x'.lit).should == 'x'
185
+ @d.l(~(('x'.lit | :y) & :z)).should == '((NOT x AND NOT y) OR NOT z)'
186
+ @d.l(~(:x | 'y'.lit)).should == '(NOT x AND NOT y)'
187
+ @d.l(~('x'.lit & 'y'.lit)).should == '(NOT x OR NOT y)'
188
+ @d.l({'y'.lit => 'z'.lit} & 'x'.lit).should == '((y = z) AND x)'
189
+ @d.l(('x'.lit > 200) & ('y'.lit < 200)).should == '((x > 200) AND (y < 200))'
190
+ @d.l(~('x'.lit + 1 > 100)).should == '((x + 1) <= 100)'
191
+ @d.l('x'.lit.like(/a/)).should == '(x ~ \'a\')'
192
+ @d.l('x'.lit + 1 > 100).should == '((x + 1) > 100)'
193
+ @d.l(('x'.lit * :y) < 100.01).should == '((x * y) < 100.01)'
194
+ @d.l(('x'.lit - :y/2) >= 100000000000000000000000000000000000).should == '((x - (y / 2)) >= 100000000000000000000000000000000000)'
195
+ @d.l(('z'.lit * (('x'.lit / :y)/(:x + :y))) <= 100).should == '((z * ((x / y) / (x + y))) <= 100)'
196
+ @d.l(~(((('x'.lit - :y)/(:x + :y))*:z) <= 100)).should == '((((x - y) / (x + y)) * z) > 100)'
197
+ end
198
+
199
+ it "should support hashes by ANDing the conditions" do
200
+ @d.l(:x => 100, :y => 'a')[1...-1].split(' AND ').sort.should == ['(x = 100)', '(y = \'a\')']
201
+ @d.l(:x => true, :y => false)[1...-1].split(' AND ').sort.should == ['(x IS TRUE)', '(y IS FALSE)']
202
+ @d.l(:x => nil, :y => [1,2,3])[1...-1].split(' AND ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
203
+ end
204
+
205
+ it "should support sql_negate on hashes" do
206
+ @d.l({:x => 100, :y => 'a'}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x != 100)', '(y != \'a\')']
207
+ @d.l({:x => true, :y => false}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x IS NOT TRUE)', '(y IS NOT FALSE)']
208
+ @d.l({:x => nil, :y => [1,2,3]}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
209
+ end
210
+
211
+ it "should support ~ on hashes" do
212
+ @d.l(~{:x => 100, :y => 'a'})[1...-1].split(' OR ').sort.should == ['(x != 100)', '(y != \'a\')']
213
+ @d.l(~{:x => true, :y => false})[1...-1].split(' OR ').sort.should == ['(x IS NOT TRUE)', '(y IS NOT FALSE)']
214
+ @d.l(~{:x => nil, :y => [1,2,3]})[1...-1].split(' OR ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
215
+ end
216
+
217
+ it "should support sql_or on hashes" do
218
+ @d.l({:x => 100, :y => 'a'}.sql_or)[1...-1].split(' OR ').sort.should == ['(x = 100)', '(y = \'a\')']
219
+ @d.l({:x => true, :y => false}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS TRUE)', '(y IS FALSE)']
220
+ @d.l({:x => nil, :y => [1,2,3]}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
221
+ end
222
+
223
+ it "should support arrays with all two pairs the same as hashes" do
224
+ @d.l([[:x, 100],[:y, 'a']]).should == '((x = 100) AND (y = \'a\'))'
225
+ @d.l([[:x, true], [:y, false]]).should == '((x IS TRUE) AND (y IS FALSE))'
226
+ @d.l([[:x, nil], [:y, [1,2,3]]]).should == '((x IS NULL) AND (y IN (1, 2, 3)))'
227
+ end
228
+
229
+ it "should support sql_negate on arrays with all two pairs" do
230
+ @d.l([[:x, 100],[:y, 'a']].sql_negate).should == '((x != 100) AND (y != \'a\'))'
231
+ @d.l([[:x, true], [:y, false]].sql_negate).should == '((x IS NOT TRUE) AND (y IS NOT FALSE))'
232
+ @d.l([[:x, nil], [:y, [1,2,3]]].sql_negate).should == '((x IS NOT NULL) AND (y NOT IN (1, 2, 3)))'
233
+ end
234
+
235
+ it "should support ~ on arrays with all two pairs" do
236
+ @d.l(~[[:x, 100],[:y, 'a']]).should == '((x != 100) OR (y != \'a\'))'
237
+ @d.l(~[[:x, true], [:y, false]]).should == '((x IS NOT TRUE) OR (y IS NOT FALSE))'
238
+ @d.l(~[[:x, nil], [:y, [1,2,3]]]).should == '((x IS NOT NULL) OR (y NOT IN (1, 2, 3)))'
239
+ end
240
+
241
+ it "should support sql_or on arrays with all two pairs" do
242
+ @d.l([[:x, 100],[:y, 'a']].sql_or).should == '((x = 100) OR (y = \'a\'))'
243
+ @d.l([[:x, true], [:y, false]].sql_or).should == '((x IS TRUE) OR (y IS FALSE))'
244
+ @d.l([[:x, nil], [:y, [1,2,3]]].sql_or).should == '((x IS NULL) OR (y IN (1, 2, 3)))'
245
+ end
246
+
247
+ it "should support Array#sql_string_join for concatenation of SQL strings" do
248
+ @d.lit([:x].sql_string_join).should == '(x)'
249
+ @d.lit([:x].sql_string_join(', ')).should == '(x)'
250
+ @d.lit([:x, :y].sql_string_join).should == '(x || y)'
251
+ @d.lit([:x, :y].sql_string_join(', ')).should == "(x || ', ' || y)"
252
+ @d.lit([:x.sql_function(1), :y.sql_subscript(1)].sql_string_join).should == '(x(1) || y[1])'
253
+ @d.lit([:x.sql_function(1), 'y.z'.lit].sql_string_join(', ')).should == "(x(1) || ', ' || y.z)"
254
+ @d.lit([:x, 1, :y].sql_string_join).should == "(x || '1' || y)"
255
+ @d.lit([:x, 1, :y].sql_string_join(', ')).should == "(x || ', ' || '1' || ', ' || y)"
256
+ @d.lit([:x, 1, :y].sql_string_join(:y__z)).should == "(x || y.z || '1' || y.z || y)"
257
+ @d.lit([:x, 1, :y].sql_string_join(1)).should == "(x || '1' || '1' || '1' || y)"
258
+ @d.lit([:x, :y].sql_string_join('y.x || x.y'.lit)).should == "(x || y.x || x.y || y)"
259
+ @d.lit([[:x, :y].sql_string_join, [:a, :b].sql_string_join].sql_string_join).should == "((x || y) || (a || b))"
260
+ end
261
+
262
+ it "should support StringExpression#+ for concatenation of SQL strings" do
263
+ @d.lit(:x.sql_string + :y).should == '(x || y)'
264
+ @d.lit([:x].sql_string_join + :y).should == '((x) || y)'
265
+ @d.lit([:x, :z].sql_string_join(' ') + :y).should == "((x || ' ' || z) || y)"
266
+ end
267
+
268
+ it "should be supported inside blocks" do
269
+ @d.l{[[:x, nil], [:y, [1,2,3]]].sql_or}.should == '((x IS NULL) OR (y IN (1, 2, 3)))'
270
+ @d.l{~[[:x, nil], [:y, [1,2,3]]]}.should == '((x IS NOT NULL) OR (y NOT IN (1, 2, 3)))'
271
+ @d.l{~(((('x'.lit - :y)/(:x + :y))*:z) <= 100)}.should == '((((x - y) / (x + y)) * z) > 100)'
272
+ @d.l{{:x => :a} & {:y => :z}}.should == '((x = a) AND (y = z))'
273
+ end
274
+
275
+ it "should support &, |, ^, ~, <<, and >> for NumericExpressions" do
276
+ @d.l(:x.sql_number & 1 > 100).should == '((x & 1) > 100)'
277
+ @d.l(:x.sql_number | 1 > 100).should == '((x | 1) > 100)'
278
+ @d.l(:x.sql_number ^ 1 > 100).should == '((x ^ 1) > 100)'
279
+ @d.l(~:x.sql_number > 100).should == '(~x > 100)'
280
+ @d.l(:x.sql_number << 1 > 100).should == '((x << 1) > 100)'
281
+ @d.l(:x.sql_number >> 1 > 100).should == '((x >> 1) > 100)'
282
+ @d.l((:x + 1) & 1 > 100).should == '(((x + 1) & 1) > 100)'
283
+ @d.l((:x + 1) | 1 > 100).should == '(((x + 1) | 1) > 100)'
284
+ @d.l((:x + 1) ^ 1 > 100).should == '(((x + 1) ^ 1) > 100)'
285
+ @d.l(~(:x + 1) > 100).should == '(~(x + 1) > 100)'
286
+ @d.l((:x + 1) << 1 > 100).should == '(((x + 1) << 1) > 100)'
287
+ @d.l((:x + 1) >> 1 > 100).should == '(((x + 1) >> 1) > 100)'
288
+ @d.l((:x + 1) & (:x + 2) > 100).should == '(((x + 1) & (x + 2)) > 100)'
289
+ end
290
+
291
+ it "should raise an error if use a Bitwise method on a ComplexExpression that isn't a NumericExpression" do
292
+ proc{(:x + 1) & (:x & 2)}.should raise_error(Sequel::Error)
293
+ end
294
+
295
+ it "should raise an error if use a Boolean method on a ComplexExpression that isn't a BooleanExpression" do
296
+ proc{:x & (:x + 2)}.should raise_error(Sequel::Error)
297
+ end
298
+
299
+ it "should raise an error if attempting to invert a ComplexExpression that isn't a BooleanExpression" do
300
+ proc{Sequel::SQL::BooleanExpression.invert(:x + 2)}.should raise_error(Sequel::Error)
301
+ end
302
+
303
+ it "should return self on .lit" do
304
+ y = :x + 1
305
+ y.lit.should == y
306
+ end
307
+
308
+ it "should raise an error if trying to create an invalid complex expression" do
309
+ proc{Sequel::SQL::ComplexExpression.new(:BANG, 1, 2)}.should raise_error(Sequel::Error)
310
+ end
311
+
312
+ it "should raise an error if trying to literalize an invalid complex expression" do
313
+ ce = :x + 1
314
+ ce.instance_variable_set(:@op, :BANG)
315
+ proc{@d.lit(ce)}.should raise_error(Sequel::Error)
316
+ end
317
+
318
+ it "should support equality comparison of two expressions" do
319
+ e1 = ~:comment.like('%:hidden:%')
320
+ e2 = ~:comment.like('%:hidden:%')
321
+ e1.should == e2
322
+ end
323
+
324
+ if RUBY_VERSION < '1.9.0'
325
+ it "should not allow inequality operations on true, false, or nil" do
326
+ proc{:x > 1}.should_not raise_error
327
+ proc{:x < true}.should raise_error(Sequel::Error)
328
+ proc{:x >= false}.should raise_error(Sequel::Error)
329
+ proc{:x <= nil}.should raise_error(Sequel::Error)
330
+ end
331
+
332
+ it "should not allow inequality operations on boolean complex expressions" do
333
+ proc{:x > (:y > 5)}.should raise_error(Sequel::Error)
334
+ proc{:x < (:y < 5)}.should raise_error(Sequel::Error)
335
+ proc{:x >= (:y >= 5)}.should raise_error(Sequel::Error)
336
+ proc{:x <= (:y <= 5)}.should raise_error(Sequel::Error)
337
+ proc{:x > {:y => nil}}.should raise_error(Sequel::Error)
338
+ proc{:x < ~{:y => nil}}.should raise_error(Sequel::Error)
339
+ proc{:x >= {:y => 5}}.should raise_error(Sequel::Error)
340
+ proc{:x <= ~{:y => 5}}.should raise_error(Sequel::Error)
341
+ proc{:x >= {:y => [1,2,3]}}.should raise_error(Sequel::Error)
342
+ proc{:x <= ~{:y => [1,2,3]}}.should raise_error(Sequel::Error)
343
+ end
344
+
345
+ it "should support >, <, >=, and <= via Symbol#>,<,>=,<=" do
346
+ @d.l(:x > 100).should == '(x > 100)'
347
+ @d.l(:x < 100.01).should == '(x < 100.01)'
348
+ @d.l(:x >= 100000000000000000000000000000000000).should == '(x >= 100000000000000000000000000000000000)'
349
+ @d.l(:x <= 100).should == '(x <= 100)'
350
+ end
351
+
352
+ it "should support negation of >, <, >=, and <= via Symbol#~" do
353
+ @d.l(~(:x > 100)).should == '(x <= 100)'
354
+ @d.l(~(:x < 100.01)).should == '(x >= 100.01)'
355
+ @d.l(~(:x >= 100000000000000000000000000000000000)).should == '(x < 100000000000000000000000000000000000)'
356
+ @d.l(~(:x <= 100)).should == '(x > 100)'
357
+ end
358
+
359
+ it "should support double negation via ~" do
360
+ @d.l(~~(:x > 100)).should == '(x > 100)'
361
+ end
362
+ end
363
+ end
@@ -0,0 +1,261 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ context "Migration classes" do
4
+ setup do
5
+ Sequel::Migration.descendants.clear
6
+ end
7
+
8
+ specify "should be registred in Migration.descendants" do
9
+ @class = Class.new(Sequel::Migration)
10
+
11
+ Sequel::Migration.descendants.should == [@class]
12
+ end
13
+
14
+ specify "should be registered in the right order" do
15
+ @c1 = Class.new(Sequel::Migration)
16
+ @c2 = Class.new(Sequel::Migration)
17
+ @c3 = Class.new(Sequel::Migration)
18
+
19
+ Sequel::Migration.descendants.should == [@c1, @c2, @c3]
20
+ end
21
+ end
22
+
23
+ context "Migration#apply" do
24
+ setup do
25
+ @c = Class.new do
26
+ define_method(:one) {|x| [1111, x]}
27
+ define_method(:two) {|x| [2222, x]}
28
+ end
29
+ @db = @c.new
30
+
31
+ @migration = Class.new(Sequel::Migration) do
32
+ define_method(:up) {one(3333)}
33
+ define_method(:down) {two(4444)}
34
+ end
35
+ end
36
+
37
+ specify "should raise for an invalid direction" do
38
+ proc {@migration.apply(@db, :hahaha)}.should raise_error(ArgumentError)
39
+ end
40
+
41
+ specify "should apply the up direction correctly" do
42
+ @migration.apply(@db, :up).should == [1111, 3333]
43
+ end
44
+
45
+ specify "should apply the down direction correctly" do
46
+ @migration.apply(@db, :down).should == [2222, 4444]
47
+ end
48
+ end
49
+
50
+ class DummyMigrationDataset
51
+ attr_reader :from
52
+
53
+ def initialize(x); @from = x; end
54
+
55
+ @@version = nil
56
+
57
+ def version; @@version; end
58
+ def version=(x); @@version = x; end
59
+ def first; @@version ? {:version => @@version} : nil; end
60
+ def update(h); @@version = h[:version]; end
61
+ def <<(h); @@version = h[:version]; end
62
+ end
63
+
64
+ class DummyMigrationDB
65
+ attr_reader :creates, :drops, :table_created
66
+
67
+ def initialize
68
+ @creates = []
69
+ @drops = []
70
+ end
71
+
72
+ def create(x); @creates << x; end
73
+ def drop(x); @drops << x; end
74
+
75
+ def [](x); DummyMigrationDataset.new(x); end
76
+
77
+ def create_table(x); raise if @table_created == x; @table_created = x; end
78
+ def table_exists?(x); @table_created == x; end
79
+
80
+ def transaction; yield; end
81
+ end
82
+
83
+ MIGRATION_001 = %[
84
+ class CreateSessions < Sequel::Migration
85
+ def up
86
+ create(1111)
87
+ end
88
+
89
+ def down
90
+ drop(1111)
91
+ end
92
+ end
93
+ ]
94
+
95
+ MIGRATION_002 = %[
96
+ class CreateNodes < Sequel::Migration
97
+ def up
98
+ create(2222)
99
+ end
100
+
101
+ def down
102
+ drop(2222)
103
+ end
104
+ end
105
+ ]
106
+
107
+ MIGRATION_003 = %[
108
+ class CreateUsers < Sequel::Migration
109
+ def up
110
+ create(3333)
111
+ end
112
+
113
+ def down
114
+ drop(3333)
115
+ end
116
+ end
117
+ ]
118
+
119
+ MIGRATION_005 = %[
120
+ class CreateAttributes < Sequel::Migration
121
+ def up
122
+ create(5555)
123
+ end
124
+
125
+ def down
126
+ drop(5555)
127
+ end
128
+ end
129
+ ]
130
+
131
+ context "Sequel::Migrator" do
132
+ setup do
133
+ @db = DummyMigrationDB.new
134
+
135
+ File.open('001_create_sessions.rb', 'w') {|f| f << MIGRATION_001}
136
+ File.open('002_create_nodes.rb', 'w') {|f| f << MIGRATION_002}
137
+ File.open('003_create_users.rb', 'w') {|f| f << MIGRATION_003}
138
+ File.open('005_create_attributes.rb', 'w') {|f| f << MIGRATION_005}
139
+
140
+ @db[:schema_info].version = nil
141
+ end
142
+
143
+ teardown do
144
+ Object.send(:remove_const, "CreateSessions") if Object.const_defined?("CreateSessions")
145
+ Object.send(:remove_const, "CreateNodes") if Object.const_defined?("CreateNodes")
146
+ Object.send(:remove_const, "CreateUsers") if Object.const_defined?("CreateUsers")
147
+ Object.send(:remove_const, "CreateAttributes") if Object.const_defined?("CreateAttributes")
148
+
149
+ File.delete('001_create_sessions.rb')
150
+ File.delete('002_create_nodes.rb')
151
+ File.delete('003_create_users.rb')
152
+ File.delete('005_create_attributes.rb')
153
+ end
154
+
155
+ specify "should return the list of files for a specified version range" do
156
+ Sequel::Migrator.migration_files('.', 1..1).should == \
157
+ ['./001_create_sessions.rb']
158
+
159
+ Sequel::Migrator.migration_files('.', 1..3).should == \
160
+ ['./001_create_sessions.rb', './002_create_nodes.rb', './003_create_users.rb']
161
+
162
+ Sequel::Migrator.migration_files('.', 3..5).should == \
163
+ ['./003_create_users.rb', './005_create_attributes.rb']
164
+
165
+ Sequel::Migrator.migration_files('.', 7..8).should == []
166
+ end
167
+
168
+ specify "should return the latest version available" do
169
+ Sequel::Migrator.latest_migration_version('.').should == 5
170
+ end
171
+
172
+ specify "should load the migration classes for the specified range" do
173
+ Sequel::Migrator.migration_classes('.', 3, 0, :up).should == \
174
+ [CreateSessions, CreateNodes, CreateUsers]
175
+ end
176
+
177
+ specify "should load the migration classes for the specified range" do
178
+ Sequel::Migrator.migration_classes('.', 0, 5, :down).should == \
179
+ [CreateAttributes, CreateUsers, CreateNodes, CreateSessions]
180
+ end
181
+
182
+ specify "should start from current + 1 for the up direction" do
183
+ Sequel::Migrator.migration_classes('.', 3, 1, :up).should == \
184
+ [CreateNodes, CreateUsers]
185
+ end
186
+
187
+ specify "should end on current + 1 for the down direction" do
188
+ Sequel::Migrator.migration_classes('.', 2, 5, :down).should == \
189
+ [CreateAttributes, CreateUsers]
190
+ end
191
+
192
+ specify "should automatically create the schema_info table" do
193
+ @db.table_exists?(:schema_info).should be_false
194
+ Sequel::Migrator.schema_info_dataset(@db)
195
+ @db.table_exists?(:schema_info).should be_true
196
+
197
+ # should not raise if table already exists
198
+ proc {Sequel::Migrator.schema_info_dataset(@db)}.should_not raise_error
199
+ end
200
+
201
+ specify "should return a dataset for the schema_info table" do
202
+ d = Sequel::Migrator.schema_info_dataset(@db)
203
+ d.from.should == :schema_info
204
+ end
205
+
206
+ specify "should get the migration version stored in the database" do
207
+ # default is 0
208
+ Sequel::Migrator.get_current_migration_version(@db).should == 0
209
+
210
+ Sequel::Migrator.schema_info_dataset(@db) << {:version => 4321}
211
+
212
+ Sequel::Migrator.get_current_migration_version(@db).should == 4321
213
+ end
214
+
215
+ specify "should set the migration version stored in the database" do
216
+ Sequel::Migrator.get_current_migration_version(@db).should == 0
217
+ Sequel::Migrator.set_current_migration_version(@db, 6666)
218
+ Sequel::Migrator.get_current_migration_version(@db).should == 6666
219
+ end
220
+
221
+ specify "should apply migrations correctly in the up direction" do
222
+ Sequel::Migrator.apply(@db, '.', 3, 2)
223
+ @db.creates.should == [3333]
224
+
225
+ Sequel::Migrator.get_current_migration_version(@db).should == 3
226
+
227
+ Sequel::Migrator.apply(@db, '.', 5)
228
+ @db.creates.should == [3333, 5555]
229
+
230
+ Sequel::Migrator.get_current_migration_version(@db).should == 5
231
+ end
232
+
233
+ specify "should apply migrations correctly in the down direction" do
234
+ Sequel::Migrator.apply(@db, '.', 1, 5)
235
+ @db.drops.should == [5555, 3333, 2222]
236
+
237
+ Sequel::Migrator.get_current_migration_version(@db).should == 1
238
+ end
239
+
240
+ specify "should apply migrations up to the latest version if no target is given" do
241
+ Sequel::Migrator.apply(@db, '.')
242
+ @db.creates.should == [1111, 2222, 3333, 5555]
243
+
244
+ Sequel::Migrator.get_current_migration_version(@db).should == 5
245
+ end
246
+
247
+ specify "should apply migrations down to 0 version correctly" do
248
+ Sequel::Migrator.apply(@db, '.', 0, 5)
249
+ @db.drops.should == [5555, 3333, 2222, 1111]
250
+
251
+ Sequel::Migrator.get_current_migration_version(@db).should == 0
252
+ end
253
+
254
+ specify "should return the target version" do
255
+ Sequel::Migrator.apply(@db, '.', 3, 2).should == 3
256
+
257
+ Sequel::Migrator.apply(@db, '.', 0).should == 0
258
+
259
+ Sequel::Migrator.apply(@db, '.').should == 5
260
+ end
261
+ end