viking-sequel 3.10.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 (237) hide show
  1. data/CHANGELOG +3134 -0
  2. data/COPYING +19 -0
  3. data/README.rdoc +723 -0
  4. data/Rakefile +193 -0
  5. data/bin/sequel +196 -0
  6. data/doc/advanced_associations.rdoc +644 -0
  7. data/doc/cheat_sheet.rdoc +218 -0
  8. data/doc/dataset_basics.rdoc +106 -0
  9. data/doc/dataset_filtering.rdoc +158 -0
  10. data/doc/opening_databases.rdoc +296 -0
  11. data/doc/prepared_statements.rdoc +104 -0
  12. data/doc/reflection.rdoc +84 -0
  13. data/doc/release_notes/1.0.txt +38 -0
  14. data/doc/release_notes/1.1.txt +143 -0
  15. data/doc/release_notes/1.3.txt +101 -0
  16. data/doc/release_notes/1.4.0.txt +53 -0
  17. data/doc/release_notes/1.5.0.txt +155 -0
  18. data/doc/release_notes/2.0.0.txt +298 -0
  19. data/doc/release_notes/2.1.0.txt +271 -0
  20. data/doc/release_notes/2.10.0.txt +328 -0
  21. data/doc/release_notes/2.11.0.txt +215 -0
  22. data/doc/release_notes/2.12.0.txt +534 -0
  23. data/doc/release_notes/2.2.0.txt +253 -0
  24. data/doc/release_notes/2.3.0.txt +88 -0
  25. data/doc/release_notes/2.4.0.txt +106 -0
  26. data/doc/release_notes/2.5.0.txt +137 -0
  27. data/doc/release_notes/2.6.0.txt +157 -0
  28. data/doc/release_notes/2.7.0.txt +166 -0
  29. data/doc/release_notes/2.8.0.txt +171 -0
  30. data/doc/release_notes/2.9.0.txt +97 -0
  31. data/doc/release_notes/3.0.0.txt +221 -0
  32. data/doc/release_notes/3.1.0.txt +406 -0
  33. data/doc/release_notes/3.10.0.txt +286 -0
  34. data/doc/release_notes/3.2.0.txt +268 -0
  35. data/doc/release_notes/3.3.0.txt +192 -0
  36. data/doc/release_notes/3.4.0.txt +325 -0
  37. data/doc/release_notes/3.5.0.txt +510 -0
  38. data/doc/release_notes/3.6.0.txt +366 -0
  39. data/doc/release_notes/3.7.0.txt +179 -0
  40. data/doc/release_notes/3.8.0.txt +151 -0
  41. data/doc/release_notes/3.9.0.txt +233 -0
  42. data/doc/schema.rdoc +36 -0
  43. data/doc/sharding.rdoc +113 -0
  44. data/doc/virtual_rows.rdoc +205 -0
  45. data/lib/sequel.rb +1 -0
  46. data/lib/sequel/adapters/ado.rb +90 -0
  47. data/lib/sequel/adapters/ado/mssql.rb +30 -0
  48. data/lib/sequel/adapters/amalgalite.rb +176 -0
  49. data/lib/sequel/adapters/db2.rb +139 -0
  50. data/lib/sequel/adapters/dbi.rb +113 -0
  51. data/lib/sequel/adapters/do.rb +188 -0
  52. data/lib/sequel/adapters/do/mysql.rb +49 -0
  53. data/lib/sequel/adapters/do/postgres.rb +91 -0
  54. data/lib/sequel/adapters/do/sqlite.rb +40 -0
  55. data/lib/sequel/adapters/firebird.rb +283 -0
  56. data/lib/sequel/adapters/informix.rb +77 -0
  57. data/lib/sequel/adapters/jdbc.rb +587 -0
  58. data/lib/sequel/adapters/jdbc/as400.rb +58 -0
  59. data/lib/sequel/adapters/jdbc/h2.rb +133 -0
  60. data/lib/sequel/adapters/jdbc/mssql.rb +57 -0
  61. data/lib/sequel/adapters/jdbc/mysql.rb +78 -0
  62. data/lib/sequel/adapters/jdbc/oracle.rb +50 -0
  63. data/lib/sequel/adapters/jdbc/postgresql.rb +108 -0
  64. data/lib/sequel/adapters/jdbc/sqlite.rb +55 -0
  65. data/lib/sequel/adapters/mysql.rb +421 -0
  66. data/lib/sequel/adapters/odbc.rb +143 -0
  67. data/lib/sequel/adapters/odbc/mssql.rb +42 -0
  68. data/lib/sequel/adapters/openbase.rb +64 -0
  69. data/lib/sequel/adapters/oracle.rb +131 -0
  70. data/lib/sequel/adapters/postgres.rb +504 -0
  71. data/lib/sequel/adapters/shared/mssql.rb +490 -0
  72. data/lib/sequel/adapters/shared/mysql.rb +498 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +195 -0
  74. data/lib/sequel/adapters/shared/postgres.rb +830 -0
  75. data/lib/sequel/adapters/shared/progress.rb +44 -0
  76. data/lib/sequel/adapters/shared/sqlite.rb +389 -0
  77. data/lib/sequel/adapters/sqlite.rb +224 -0
  78. data/lib/sequel/adapters/utils/stored_procedures.rb +84 -0
  79. data/lib/sequel/connection_pool.rb +99 -0
  80. data/lib/sequel/connection_pool/sharded_single.rb +84 -0
  81. data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
  82. data/lib/sequel/connection_pool/single.rb +29 -0
  83. data/lib/sequel/connection_pool/threaded.rb +150 -0
  84. data/lib/sequel/core.rb +293 -0
  85. data/lib/sequel/core_sql.rb +241 -0
  86. data/lib/sequel/database.rb +1079 -0
  87. data/lib/sequel/database/schema_generator.rb +327 -0
  88. data/lib/sequel/database/schema_methods.rb +203 -0
  89. data/lib/sequel/database/schema_sql.rb +320 -0
  90. data/lib/sequel/dataset.rb +32 -0
  91. data/lib/sequel/dataset/actions.rb +441 -0
  92. data/lib/sequel/dataset/features.rb +86 -0
  93. data/lib/sequel/dataset/graph.rb +254 -0
  94. data/lib/sequel/dataset/misc.rb +119 -0
  95. data/lib/sequel/dataset/mutation.rb +64 -0
  96. data/lib/sequel/dataset/prepared_statements.rb +227 -0
  97. data/lib/sequel/dataset/query.rb +709 -0
  98. data/lib/sequel/dataset/sql.rb +996 -0
  99. data/lib/sequel/exceptions.rb +51 -0
  100. data/lib/sequel/extensions/blank.rb +43 -0
  101. data/lib/sequel/extensions/inflector.rb +242 -0
  102. data/lib/sequel/extensions/looser_typecasting.rb +21 -0
  103. data/lib/sequel/extensions/migration.rb +239 -0
  104. data/lib/sequel/extensions/named_timezones.rb +61 -0
  105. data/lib/sequel/extensions/pagination.rb +100 -0
  106. data/lib/sequel/extensions/pretty_table.rb +82 -0
  107. data/lib/sequel/extensions/query.rb +52 -0
  108. data/lib/sequel/extensions/schema_dumper.rb +271 -0
  109. data/lib/sequel/extensions/sql_expr.rb +122 -0
  110. data/lib/sequel/extensions/string_date_time.rb +46 -0
  111. data/lib/sequel/extensions/thread_local_timezones.rb +48 -0
  112. data/lib/sequel/metaprogramming.rb +9 -0
  113. data/lib/sequel/model.rb +120 -0
  114. data/lib/sequel/model/associations.rb +1514 -0
  115. data/lib/sequel/model/base.rb +1069 -0
  116. data/lib/sequel/model/default_inflections.rb +45 -0
  117. data/lib/sequel/model/errors.rb +39 -0
  118. data/lib/sequel/model/exceptions.rb +21 -0
  119. data/lib/sequel/model/inflections.rb +162 -0
  120. data/lib/sequel/model/plugins.rb +70 -0
  121. data/lib/sequel/plugins/active_model.rb +59 -0
  122. data/lib/sequel/plugins/association_dependencies.rb +103 -0
  123. data/lib/sequel/plugins/association_proxies.rb +41 -0
  124. data/lib/sequel/plugins/boolean_readers.rb +53 -0
  125. data/lib/sequel/plugins/caching.rb +141 -0
  126. data/lib/sequel/plugins/class_table_inheritance.rb +214 -0
  127. data/lib/sequel/plugins/composition.rb +138 -0
  128. data/lib/sequel/plugins/force_encoding.rb +72 -0
  129. data/lib/sequel/plugins/hook_class_methods.rb +126 -0
  130. data/lib/sequel/plugins/identity_map.rb +116 -0
  131. data/lib/sequel/plugins/instance_filters.rb +98 -0
  132. data/lib/sequel/plugins/instance_hooks.rb +57 -0
  133. data/lib/sequel/plugins/lazy_attributes.rb +77 -0
  134. data/lib/sequel/plugins/many_through_many.rb +208 -0
  135. data/lib/sequel/plugins/nested_attributes.rb +206 -0
  136. data/lib/sequel/plugins/optimistic_locking.rb +81 -0
  137. data/lib/sequel/plugins/rcte_tree.rb +281 -0
  138. data/lib/sequel/plugins/schema.rb +66 -0
  139. data/lib/sequel/plugins/serialization.rb +166 -0
  140. data/lib/sequel/plugins/single_table_inheritance.rb +74 -0
  141. data/lib/sequel/plugins/subclasses.rb +45 -0
  142. data/lib/sequel/plugins/tactical_eager_loading.rb +61 -0
  143. data/lib/sequel/plugins/timestamps.rb +87 -0
  144. data/lib/sequel/plugins/touch.rb +118 -0
  145. data/lib/sequel/plugins/typecast_on_load.rb +72 -0
  146. data/lib/sequel/plugins/validation_class_methods.rb +405 -0
  147. data/lib/sequel/plugins/validation_helpers.rb +223 -0
  148. data/lib/sequel/sql.rb +1020 -0
  149. data/lib/sequel/timezones.rb +161 -0
  150. data/lib/sequel/version.rb +12 -0
  151. data/lib/sequel_core.rb +1 -0
  152. data/lib/sequel_model.rb +1 -0
  153. data/spec/adapters/firebird_spec.rb +407 -0
  154. data/spec/adapters/informix_spec.rb +97 -0
  155. data/spec/adapters/mssql_spec.rb +403 -0
  156. data/spec/adapters/mysql_spec.rb +1019 -0
  157. data/spec/adapters/oracle_spec.rb +286 -0
  158. data/spec/adapters/postgres_spec.rb +969 -0
  159. data/spec/adapters/spec_helper.rb +51 -0
  160. data/spec/adapters/sqlite_spec.rb +432 -0
  161. data/spec/core/connection_pool_spec.rb +808 -0
  162. data/spec/core/core_sql_spec.rb +417 -0
  163. data/spec/core/database_spec.rb +1662 -0
  164. data/spec/core/dataset_spec.rb +3827 -0
  165. data/spec/core/expression_filters_spec.rb +595 -0
  166. data/spec/core/object_graph_spec.rb +296 -0
  167. data/spec/core/schema_generator_spec.rb +159 -0
  168. data/spec/core/schema_spec.rb +830 -0
  169. data/spec/core/spec_helper.rb +56 -0
  170. data/spec/core/version_spec.rb +7 -0
  171. data/spec/extensions/active_model_spec.rb +76 -0
  172. data/spec/extensions/association_dependencies_spec.rb +127 -0
  173. data/spec/extensions/association_proxies_spec.rb +50 -0
  174. data/spec/extensions/blank_spec.rb +67 -0
  175. data/spec/extensions/boolean_readers_spec.rb +92 -0
  176. data/spec/extensions/caching_spec.rb +250 -0
  177. data/spec/extensions/class_table_inheritance_spec.rb +252 -0
  178. data/spec/extensions/composition_spec.rb +194 -0
  179. data/spec/extensions/force_encoding_spec.rb +117 -0
  180. data/spec/extensions/hook_class_methods_spec.rb +470 -0
  181. data/spec/extensions/identity_map_spec.rb +202 -0
  182. data/spec/extensions/inflector_spec.rb +181 -0
  183. data/spec/extensions/instance_filters_spec.rb +55 -0
  184. data/spec/extensions/instance_hooks_spec.rb +133 -0
  185. data/spec/extensions/lazy_attributes_spec.rb +153 -0
  186. data/spec/extensions/looser_typecasting_spec.rb +39 -0
  187. data/spec/extensions/many_through_many_spec.rb +884 -0
  188. data/spec/extensions/migration_spec.rb +332 -0
  189. data/spec/extensions/named_timezones_spec.rb +72 -0
  190. data/spec/extensions/nested_attributes_spec.rb +396 -0
  191. data/spec/extensions/optimistic_locking_spec.rb +100 -0
  192. data/spec/extensions/pagination_spec.rb +99 -0
  193. data/spec/extensions/pretty_table_spec.rb +91 -0
  194. data/spec/extensions/query_spec.rb +85 -0
  195. data/spec/extensions/rcte_tree_spec.rb +205 -0
  196. data/spec/extensions/schema_dumper_spec.rb +357 -0
  197. data/spec/extensions/schema_spec.rb +127 -0
  198. data/spec/extensions/serialization_spec.rb +209 -0
  199. data/spec/extensions/single_table_inheritance_spec.rb +96 -0
  200. data/spec/extensions/spec_helper.rb +91 -0
  201. data/spec/extensions/sql_expr_spec.rb +89 -0
  202. data/spec/extensions/string_date_time_spec.rb +93 -0
  203. data/spec/extensions/subclasses_spec.rb +52 -0
  204. data/spec/extensions/tactical_eager_loading_spec.rb +65 -0
  205. data/spec/extensions/thread_local_timezones_spec.rb +45 -0
  206. data/spec/extensions/timestamps_spec.rb +150 -0
  207. data/spec/extensions/touch_spec.rb +155 -0
  208. data/spec/extensions/typecast_on_load_spec.rb +69 -0
  209. data/spec/extensions/validation_class_methods_spec.rb +984 -0
  210. data/spec/extensions/validation_helpers_spec.rb +438 -0
  211. data/spec/integration/associations_test.rb +281 -0
  212. data/spec/integration/database_test.rb +26 -0
  213. data/spec/integration/dataset_test.rb +963 -0
  214. data/spec/integration/eager_loader_test.rb +734 -0
  215. data/spec/integration/model_test.rb +130 -0
  216. data/spec/integration/plugin_test.rb +814 -0
  217. data/spec/integration/prepared_statement_test.rb +213 -0
  218. data/spec/integration/schema_test.rb +361 -0
  219. data/spec/integration/spec_helper.rb +73 -0
  220. data/spec/integration/timezone_test.rb +55 -0
  221. data/spec/integration/transaction_test.rb +122 -0
  222. data/spec/integration/type_test.rb +96 -0
  223. data/spec/model/association_reflection_spec.rb +175 -0
  224. data/spec/model/associations_spec.rb +2633 -0
  225. data/spec/model/base_spec.rb +418 -0
  226. data/spec/model/dataset_methods_spec.rb +78 -0
  227. data/spec/model/eager_loading_spec.rb +1391 -0
  228. data/spec/model/hooks_spec.rb +240 -0
  229. data/spec/model/inflector_spec.rb +26 -0
  230. data/spec/model/model_spec.rb +593 -0
  231. data/spec/model/plugins_spec.rb +236 -0
  232. data/spec/model/record_spec.rb +1500 -0
  233. data/spec/model/spec_helper.rb +97 -0
  234. data/spec/model/validations_spec.rb +153 -0
  235. data/spec/rcov.opts +6 -0
  236. data/spec/spec_config.rb.example +10 -0
  237. metadata +346 -0
@@ -0,0 +1,595 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ Regexp.send(:include, Sequel::SQL::StringMethods)
4
+ String.send(:include, Sequel::SQL::StringMethods)
5
+
6
+ context "Blockless Ruby Filters" do
7
+ before do
8
+ db = Sequel::Database.new
9
+ db.quote_identifiers = false
10
+ @d = db[:items]
11
+ def @d.l(*args, &block)
12
+ literal(filter_expr(*args, &block))
13
+ end
14
+ def @d.lit(*args)
15
+ literal(*args)
16
+ end
17
+ end
18
+
19
+ it "should support boolean columns directly" do
20
+ @d.l(:x).should == 'x'
21
+ end
22
+
23
+ it "should support NOT via Symbol#~" do
24
+ @d.l(~:x).should == 'NOT x'
25
+ end
26
+
27
+ it "should support qualified columns" do
28
+ @d.l(:x__y).should == 'x.y'
29
+ @d.l(~:x__y).should == 'NOT x.y'
30
+ end
31
+
32
+ it "should support NOT with SQL functions" do
33
+ @d.l(~:is_blah.sql_function).should == 'NOT is_blah()'
34
+ @d.l(~:is_blah.sql_function(:x)).should == 'NOT is_blah(x)'
35
+ @d.l(~:is_blah.sql_function(:x__y)).should == 'NOT is_blah(x.y)'
36
+ @d.l(~:is_blah.sql_function(:x, :x__y)).should == 'NOT is_blah(x, x.y)'
37
+ end
38
+
39
+ it "should handle multiple ~" do
40
+ @d.l(~~:x).should == 'x'
41
+ @d.l(~~~:x).should == 'NOT x'
42
+ @d.l(~~(:x & :y)).should == '(x AND y)'
43
+ @d.l(~~(:x | :y)).should == '(x OR y)'
44
+ end
45
+
46
+ it "should support = via Hash" do
47
+ @d.l(:x => 100).should == '(x = 100)'
48
+ @d.l(:x => 'a').should == '(x = \'a\')'
49
+ @d.l(:x => true).should == '(x IS TRUE)'
50
+ @d.l(:x => false).should == '(x IS FALSE)'
51
+ @d.l(:x => nil).should == '(x IS NULL)'
52
+ @d.l(:x => [1,2,3]).should == '(x IN (1, 2, 3))'
53
+ end
54
+
55
+ it "should use = 't' and != 't' OR IS NULL if IS TRUE is not supported" do
56
+ @d.meta_def(:supports_is_true?){false}
57
+ @d.l(:x => true).should == "(x = 't')"
58
+ @d.l(~{:x => true}).should == "((x != 't') OR (x IS NULL))"
59
+ @d.l(:x => false).should == "(x = 'f')"
60
+ @d.l(~{:x => false}).should == "((x != 'f') OR (x IS NULL))"
61
+ end
62
+
63
+ it "should support != via Hash#~" do
64
+ @d.l(~{:x => 100}).should == '(x != 100)'
65
+ @d.l(~{:x => 'a'}).should == '(x != \'a\')'
66
+ @d.l(~{:x => true}).should == '(x IS NOT TRUE)'
67
+ @d.l(~{:x => false}).should == '(x IS NOT FALSE)'
68
+ @d.l(~{:x => nil}).should == '(x IS NOT NULL)'
69
+ end
70
+
71
+ it "should support ~ via Hash and Regexp (if supported by database)" do
72
+ @d.l(:x => /blah/).should == '(x ~ \'blah\')'
73
+ end
74
+
75
+ it "should support !~ via Hash#~ and Regexp" do
76
+ @d.l(~{:x => /blah/}).should == '(x !~ \'blah\')'
77
+ end
78
+
79
+ it "should support LIKE via Symbol#like" do
80
+ @d.l(:x.like('a')).should == '(x LIKE \'a\')'
81
+ @d.l(:x.like(/a/)).should == '(x ~ \'a\')'
82
+ @d.l(:x.like('a', 'b')).should == '((x LIKE \'a\') OR (x LIKE \'b\'))'
83
+ @d.l(:x.like(/a/, /b/i)).should == '((x ~ \'a\') OR (x ~* \'b\'))'
84
+ @d.l(:x.like('a', /b/)).should == '((x LIKE \'a\') OR (x ~ \'b\'))'
85
+
86
+ @d.l('a'.like(:x)).should == "('a' LIKE x)"
87
+ @d.l('a'.like(:x, 'b')).should == "(('a' LIKE x) OR ('a' LIKE 'b'))"
88
+ @d.l('a'.like(:x, /b/)).should == "(('a' LIKE x) OR ('a' ~ 'b'))"
89
+ @d.l('a'.like(:x, /b/i)).should == "(('a' LIKE x) OR ('a' ~* 'b'))"
90
+
91
+ @d.l(/a/.like(:x)).should == "('a' ~ x)"
92
+ @d.l(/a/.like(:x, 'b')).should == "(('a' ~ x) OR ('a' ~ 'b'))"
93
+ @d.l(/a/.like(:x, /b/)).should == "(('a' ~ x) OR ('a' ~ 'b'))"
94
+ @d.l(/a/.like(:x, /b/i)).should == "(('a' ~ x) OR ('a' ~* 'b'))"
95
+
96
+ @d.l(/a/i.like(:x)).should == "('a' ~* x)"
97
+ @d.l(/a/i.like(:x, 'b')).should == "(('a' ~* x) OR ('a' ~* 'b'))"
98
+ @d.l(/a/i.like(:x, /b/)).should == "(('a' ~* x) OR ('a' ~* 'b'))"
99
+ @d.l(/a/i.like(:x, /b/i)).should == "(('a' ~* x) OR ('a' ~* 'b'))"
100
+ end
101
+
102
+ it "should support NOT LIKE via Symbol#like and Symbol#~" do
103
+ @d.l(~:x.like('a')).should == '(x NOT LIKE \'a\')'
104
+ @d.l(~:x.like(/a/)).should == '(x !~ \'a\')'
105
+ @d.l(~:x.like('a', 'b')).should == '((x NOT LIKE \'a\') AND (x NOT LIKE \'b\'))'
106
+ @d.l(~:x.like(/a/, /b/i)).should == '((x !~ \'a\') AND (x !~* \'b\'))'
107
+ @d.l(~:x.like('a', /b/)).should == '((x NOT LIKE \'a\') AND (x !~ \'b\'))'
108
+
109
+ @d.l(~'a'.like(:x)).should == "('a' NOT LIKE x)"
110
+ @d.l(~'a'.like(:x, 'b')).should == "(('a' NOT LIKE x) AND ('a' NOT LIKE 'b'))"
111
+ @d.l(~'a'.like(:x, /b/)).should == "(('a' NOT LIKE x) AND ('a' !~ 'b'))"
112
+ @d.l(~'a'.like(:x, /b/i)).should == "(('a' NOT LIKE x) AND ('a' !~* 'b'))"
113
+
114
+ @d.l(~/a/.like(:x)).should == "('a' !~ x)"
115
+ @d.l(~/a/.like(:x, 'b')).should == "(('a' !~ x) AND ('a' !~ 'b'))"
116
+ @d.l(~/a/.like(:x, /b/)).should == "(('a' !~ x) AND ('a' !~ 'b'))"
117
+ @d.l(~/a/.like(:x, /b/i)).should == "(('a' !~ x) AND ('a' !~* 'b'))"
118
+
119
+ @d.l(~/a/i.like(:x)).should == "('a' !~* x)"
120
+ @d.l(~/a/i.like(:x, 'b')).should == "(('a' !~* x) AND ('a' !~* 'b'))"
121
+ @d.l(~/a/i.like(:x, /b/)).should == "(('a' !~* x) AND ('a' !~* 'b'))"
122
+ @d.l(~/a/i.like(:x, /b/i)).should == "(('a' !~* x) AND ('a' !~* 'b'))"
123
+ end
124
+
125
+ it "should support ILIKE via Symbol#ilike" do
126
+ @d.l(:x.ilike('a')).should == '(x ILIKE \'a\')'
127
+ @d.l(:x.ilike(/a/)).should == '(x ~* \'a\')'
128
+ @d.l(:x.ilike('a', 'b')).should == '((x ILIKE \'a\') OR (x ILIKE \'b\'))'
129
+ @d.l(:x.ilike(/a/, /b/i)).should == '((x ~* \'a\') OR (x ~* \'b\'))'
130
+ @d.l(:x.ilike('a', /b/)).should == '((x ILIKE \'a\') OR (x ~* \'b\'))'
131
+
132
+ @d.l('a'.ilike(:x)).should == "('a' ILIKE x)"
133
+ @d.l('a'.ilike(:x, 'b')).should == "(('a' ILIKE x) OR ('a' ILIKE 'b'))"
134
+ @d.l('a'.ilike(:x, /b/)).should == "(('a' ILIKE x) OR ('a' ~* 'b'))"
135
+ @d.l('a'.ilike(:x, /b/i)).should == "(('a' ILIKE x) OR ('a' ~* 'b'))"
136
+
137
+ @d.l(/a/.ilike(:x)).should == "('a' ~* x)"
138
+ @d.l(/a/.ilike(:x, 'b')).should == "(('a' ~* x) OR ('a' ~* 'b'))"
139
+ @d.l(/a/.ilike(:x, /b/)).should == "(('a' ~* x) OR ('a' ~* 'b'))"
140
+ @d.l(/a/.ilike(:x, /b/i)).should == "(('a' ~* x) OR ('a' ~* 'b'))"
141
+
142
+ @d.l(/a/i.ilike(:x)).should == "('a' ~* x)"
143
+ @d.l(/a/i.ilike(:x, 'b')).should == "(('a' ~* x) OR ('a' ~* 'b'))"
144
+ @d.l(/a/i.ilike(:x, /b/)).should == "(('a' ~* x) OR ('a' ~* 'b'))"
145
+ @d.l(/a/i.ilike(:x, /b/i)).should == "(('a' ~* x) OR ('a' ~* 'b'))"
146
+ end
147
+
148
+ it "should support NOT ILIKE via Symbol#ilike and Symbol#~" do
149
+ @d.l(~:x.ilike('a')).should == '(x NOT ILIKE \'a\')'
150
+ @d.l(~:x.ilike(/a/)).should == '(x !~* \'a\')'
151
+ @d.l(~:x.ilike('a', 'b')).should == '((x NOT ILIKE \'a\') AND (x NOT ILIKE \'b\'))'
152
+ @d.l(~:x.ilike(/a/, /b/i)).should == '((x !~* \'a\') AND (x !~* \'b\'))'
153
+ @d.l(~:x.ilike('a', /b/)).should == '((x NOT ILIKE \'a\') AND (x !~* \'b\'))'
154
+
155
+ @d.l(~'a'.ilike(:x)).should == "('a' NOT ILIKE x)"
156
+ @d.l(~'a'.ilike(:x, 'b')).should == "(('a' NOT ILIKE x) AND ('a' NOT ILIKE 'b'))"
157
+ @d.l(~'a'.ilike(:x, /b/)).should == "(('a' NOT ILIKE x) AND ('a' !~* 'b'))"
158
+ @d.l(~'a'.ilike(:x, /b/i)).should == "(('a' NOT ILIKE x) AND ('a' !~* 'b'))"
159
+
160
+ @d.l(~/a/.ilike(:x)).should == "('a' !~* x)"
161
+ @d.l(~/a/.ilike(:x, 'b')).should == "(('a' !~* x) AND ('a' !~* 'b'))"
162
+ @d.l(~/a/.ilike(:x, /b/)).should == "(('a' !~* x) AND ('a' !~* 'b'))"
163
+ @d.l(~/a/.ilike(:x, /b/i)).should == "(('a' !~* x) AND ('a' !~* 'b'))"
164
+
165
+ @d.l(~/a/i.ilike(:x)).should == "('a' !~* x)"
166
+ @d.l(~/a/i.ilike(:x, 'b')).should == "(('a' !~* x) AND ('a' !~* 'b'))"
167
+ @d.l(~/a/i.ilike(:x, /b/)).should == "(('a' !~* x) AND ('a' !~* 'b'))"
168
+ @d.l(~/a/i.ilike(:x, /b/i)).should == "(('a' !~* x) AND ('a' !~* 'b'))"
169
+ end
170
+
171
+ it "should support negating ranges via Hash#~ and Range" do
172
+ @d.l(~{:x => 1..5}).should == '((x < 1) OR (x > 5))'
173
+ @d.l(~{:x => 1...5}).should == '((x < 1) OR (x >= 5))'
174
+ end
175
+
176
+ it "should support negating NOT IN via Hash#~ and Dataset or Array" do
177
+ @d.l(~{:x => @d.select(:i)}).should == '(x NOT IN (SELECT i FROM items))'
178
+ @d.l(~{:x => [1,2,3]}).should == '(x NOT IN (1, 2, 3))'
179
+ end
180
+
181
+ it "should support + - * / via Symbol#+,-,*,/" do
182
+ @d.l(:x + 1 > 100).should == '((x + 1) > 100)'
183
+ @d.l((:x * :y) < 100.01).should == '((x * y) < 100.01)'
184
+ @d.l((:x - :y/2) >= 100000000000000000000000000000000000).should == '((x - (y / 2)) >= 100000000000000000000000000000000000)'
185
+ @d.l((((:x - :y)/(:x + :y))*:z) <= 100).should == '((((x - y) / (x + y)) * z) <= 100)'
186
+ @d.l(~((((:x - :y)/(:x + :y))*:z) <= 100)).should == '((((x - y) / (x + y)) * z) > 100)'
187
+ end
188
+
189
+ it "should not allow negation of string expressions" do
190
+ proc{~:x.sql_string}.should raise_error
191
+ proc{~([:x, :y].sql_string_join)}.should raise_error
192
+ end
193
+
194
+ it "should not allow mathematical or string operations on true, false, or nil" do
195
+ proc{:x + 1}.should_not raise_error
196
+ proc{:x - true}.should raise_error(Sequel::Error)
197
+ proc{:x / false}.should raise_error(Sequel::Error)
198
+ proc{:x * nil}.should raise_error(Sequel::Error)
199
+ proc{[:x, nil].sql_string_join}.should raise_error(Sequel::Error)
200
+ end
201
+
202
+ it "should not allow mathematical or string operations on boolean complex expressions" do
203
+ proc{:x + (:y + 1)}.should_not raise_error
204
+ proc{:x - (~:y)}.should raise_error(Sequel::Error)
205
+ proc{:x / (:y & :z)}.should raise_error(Sequel::Error)
206
+ proc{:x * (:y | :z)}.should raise_error(Sequel::Error)
207
+ proc{:x + :y.like('a')}.should raise_error(Sequel::Error)
208
+ proc{:x - :y.like(/a/)}.should raise_error(Sequel::Error)
209
+ proc{:x * :y.like(/a/i)}.should raise_error(Sequel::Error)
210
+ proc{:x + ~:y.like('a')}.should raise_error(Sequel::Error)
211
+ proc{:x - ~:y.like(/a/)}.should raise_error(Sequel::Error)
212
+ proc{:x * ~:y.like(/a/i)}.should raise_error(Sequel::Error)
213
+ proc{[:x, ~:y.like(/a/i)].sql_string_join}.should raise_error(Sequel::Error)
214
+ end
215
+
216
+ it "should support AND conditions via &" do
217
+ @d.l(:x & :y).should == '(x AND y)'
218
+ @d.l(:x.sql_boolean & :y).should == '(x AND y)'
219
+ @d.l(:x & :y & :z).should == '(x AND y AND z)'
220
+ @d.l(:x & {:y => :z}).should == '(x AND (y = z))'
221
+ @d.l({:y => :z} & :x).should == '((y = z) AND x)'
222
+ @d.l({:x => :a} & {:y => :z}).should == '((x = a) AND (y = z))'
223
+ @d.l((:x + 200 < 0) & (:y - 200 < 0)).should == '(((x + 200) < 0) AND ((y - 200) < 0))'
224
+ @d.l(:x & ~:y).should == '(x AND NOT y)'
225
+ @d.l(~:x & :y).should == '(NOT x AND y)'
226
+ @d.l(~:x & ~:y).should == '(NOT x AND NOT y)'
227
+ end
228
+
229
+ it "should support OR conditions via |" do
230
+ @d.l(:x | :y).should == '(x OR y)'
231
+ @d.l(:x.sql_boolean | :y).should == '(x OR y)'
232
+ @d.l(:x | :y | :z).should == '(x OR y OR z)'
233
+ @d.l(:x | {:y => :z}).should == '(x OR (y = z))'
234
+ @d.l({:y => :z} | :x).should == '((y = z) OR x)'
235
+ @d.l({:x => :a} | {:y => :z}).should == '((x = a) OR (y = z))'
236
+ @d.l((:x.sql_number > 200) | (:y.sql_number < 200)).should == '((x > 200) OR (y < 200))'
237
+ end
238
+
239
+ it "should support & | combinations" do
240
+ @d.l((:x | :y) & :z).should == '((x OR y) AND z)'
241
+ @d.l(:x | (:y & :z)).should == '(x OR (y AND z))'
242
+ @d.l((:x & :w) | (:y & :z)).should == '((x AND w) OR (y AND z))'
243
+ end
244
+
245
+ it "should support & | with ~" do
246
+ @d.l(~((:x | :y) & :z)).should == '((NOT x AND NOT y) OR NOT z)'
247
+ @d.l(~(:x | (:y & :z))).should == '(NOT x AND (NOT y OR NOT z))'
248
+ @d.l(~((:x & :w) | (:y & :z))).should == '((NOT x OR NOT w) AND (NOT y OR NOT z))'
249
+ @d.l(~((:x.sql_number > 200) | (:y & :z))).should == '((x <= 200) AND (NOT y OR NOT z))'
250
+ end
251
+
252
+ it "should support LiteralString" do
253
+ @d.l('x'.lit).should == '(x)'
254
+ @d.l(~'x'.lit).should == 'NOT x'
255
+ @d.l(~~'x'.lit).should == 'x'
256
+ @d.l(~(('x'.lit | :y) & :z)).should == '((NOT x AND NOT y) OR NOT z)'
257
+ @d.l(~(:x | 'y'.lit)).should == '(NOT x AND NOT y)'
258
+ @d.l(~('x'.lit & 'y'.lit)).should == '(NOT x OR NOT y)'
259
+ @d.l({'y'.lit => 'z'.lit} & 'x'.lit).should == '((y = z) AND x)'
260
+ @d.l(('x'.lit > 200) & ('y'.lit < 200)).should == '((x > 200) AND (y < 200))'
261
+ @d.l(~('x'.lit + 1 > 100)).should == '((x + 1) <= 100)'
262
+ @d.l('x'.lit.like(/a/)).should == '(x ~ \'a\')'
263
+ @d.l('x'.lit + 1 > 100).should == '((x + 1) > 100)'
264
+ @d.l(('x'.lit * :y) < 100.01).should == '((x * y) < 100.01)'
265
+ @d.l(('x'.lit - :y/2) >= 100000000000000000000000000000000000).should == '((x - (y / 2)) >= 100000000000000000000000000000000000)'
266
+ @d.l(('z'.lit * (('x'.lit / :y)/(:x + :y))) <= 100).should == '((z * (x / y / (x + y))) <= 100)'
267
+ @d.l(~(((('x'.lit - :y)/(:x + :y))*:z) <= 100)).should == '((((x - y) / (x + y)) * z) > 100)'
268
+ end
269
+
270
+ it "should support hashes by ANDing the conditions" do
271
+ @d.l(:x => 100, :y => 'a')[1...-1].split(' AND ').sort.should == ['(x = 100)', '(y = \'a\')']
272
+ @d.l(:x => true, :y => false)[1...-1].split(' AND ').sort.should == ['(x IS TRUE)', '(y IS FALSE)']
273
+ @d.l(:x => nil, :y => [1,2,3])[1...-1].split(' AND ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
274
+ end
275
+
276
+ it "should support sql_expr on hashes" do
277
+ @d.l({:x => 100, :y => 'a'}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x = 100)', '(y = \'a\')']
278
+ @d.l({:x => true, :y => false}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x IS TRUE)', '(y IS FALSE)']
279
+ @d.l({:x => nil, :y => [1,2,3]}.sql_expr)[1...-1].split(' AND ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
280
+ end
281
+
282
+ it "should support sql_negate on hashes" do
283
+ @d.l({:x => 100, :y => 'a'}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x != 100)', '(y != \'a\')']
284
+ @d.l({:x => true, :y => false}.sql_negate)[1...-1].split(' AND ').sort.should == ['(x IS NOT TRUE)', '(y IS NOT FALSE)']
285
+ @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))']
286
+ end
287
+
288
+ it "should support ~ on hashes" do
289
+ @d.l(~{:x => 100, :y => 'a'})[1...-1].split(' OR ').sort.should == ['(x != 100)', '(y != \'a\')']
290
+ @d.l(~{:x => true, :y => false})[1...-1].split(' OR ').sort.should == ['(x IS NOT TRUE)', '(y IS NOT FALSE)']
291
+ @d.l(~{:x => nil, :y => [1,2,3]})[1...-1].split(' OR ').sort.should == ['(x IS NOT NULL)', '(y NOT IN (1, 2, 3))']
292
+ end
293
+
294
+ it "should support sql_or on hashes" do
295
+ @d.l({:x => 100, :y => 'a'}.sql_or)[1...-1].split(' OR ').sort.should == ['(x = 100)', '(y = \'a\')']
296
+ @d.l({:x => true, :y => false}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS TRUE)', '(y IS FALSE)']
297
+ @d.l({:x => nil, :y => [1,2,3]}.sql_or)[1...-1].split(' OR ').sort.should == ['(x IS NULL)', '(y IN (1, 2, 3))']
298
+ end
299
+
300
+ it "should support arrays with all two pairs the same as hashes" do
301
+ @d.l([[:x, 100],[:y, 'a']]).should == '((x = 100) AND (y = \'a\'))'
302
+ @d.l([[:x, true], [:y, false]]).should == '((x IS TRUE) AND (y IS FALSE))'
303
+ @d.l([[:x, nil], [:y, [1,2,3]]]).should == '((x IS NULL) AND (y IN (1, 2, 3)))'
304
+ end
305
+
306
+ it "should support sql_expr on arrays with all two pairs" do
307
+ @d.l([[:x, 100],[:y, 'a']].sql_expr).should == '((x = 100) AND (y = \'a\'))'
308
+ @d.l([[:x, true], [:y, false]].sql_expr).should == '((x IS TRUE) AND (y IS FALSE))'
309
+ @d.l([[:x, nil], [:y, [1,2,3]]].sql_expr).should == '((x IS NULL) AND (y IN (1, 2, 3)))'
310
+ end
311
+
312
+ it "should support sql_negate on arrays with all two pairs" do
313
+ @d.l([[:x, 100],[:y, 'a']].sql_negate).should == '((x != 100) AND (y != \'a\'))'
314
+ @d.l([[:x, true], [:y, false]].sql_negate).should == '((x IS NOT TRUE) AND (y IS NOT FALSE))'
315
+ @d.l([[:x, nil], [:y, [1,2,3]]].sql_negate).should == '((x IS NOT NULL) AND (y NOT IN (1, 2, 3)))'
316
+ end
317
+
318
+ it "should support ~ on arrays with all two pairs" do
319
+ @d.l(~[[:x, 100],[:y, 'a']]).should == '((x != 100) OR (y != \'a\'))'
320
+ @d.l(~[[:x, true], [:y, false]]).should == '((x IS NOT TRUE) OR (y IS NOT FALSE))'
321
+ @d.l(~[[:x, nil], [:y, [1,2,3]]]).should == '((x IS NOT NULL) OR (y NOT IN (1, 2, 3)))'
322
+ end
323
+
324
+ it "should support sql_or on arrays with all two pairs" do
325
+ @d.l([[:x, 100],[:y, 'a']].sql_or).should == '((x = 100) OR (y = \'a\'))'
326
+ @d.l([[:x, true], [:y, false]].sql_or).should == '((x IS TRUE) OR (y IS FALSE))'
327
+ @d.l([[:x, nil], [:y, [1,2,3]]].sql_or).should == '((x IS NULL) OR (y IN (1, 2, 3)))'
328
+ end
329
+
330
+ it "should emulate columns for array values" do
331
+ @d.l([:x, :y]=>[[1,2], [3,4]].sql_array).should == '((x, y) IN ((1, 2), (3, 4)))'
332
+ @d.l([:x, :y, :z]=>[[1,2,5], [3,4,6]]).should == '((x, y, z) IN ((1, 2, 5), (3, 4, 6)))'
333
+ end
334
+
335
+ it "should emulate multiple column in if not supported" do
336
+ @d.meta_def(:supports_multiple_column_in?){false}
337
+ @d.l([:x, :y]=>[[1,2], [3,4]].sql_array).should == '(((x = 1) AND (y = 2)) OR ((x = 3) AND (y = 4)))'
338
+ @d.l([:x, :y, :z]=>[[1,2,5], [3,4,6]]).should == '(((x = 1) AND (y = 2) AND (z = 5)) OR ((x = 3) AND (y = 4) AND (z = 6)))'
339
+ end
340
+
341
+ it "should support Array#sql_string_join for concatenation of SQL strings" do
342
+ @d.lit([:x].sql_string_join).should == '(x)'
343
+ @d.lit([:x].sql_string_join(', ')).should == '(x)'
344
+ @d.lit([:x, :y].sql_string_join).should == '(x || y)'
345
+ @d.lit([:x, :y].sql_string_join(', ')).should == "(x || ', ' || y)"
346
+ @d.lit([:x.sql_function(1), :y.sql_subscript(1)].sql_string_join).should == '(x(1) || y[1])'
347
+ @d.lit([:x.sql_function(1), 'y.z'.lit].sql_string_join(', ')).should == "(x(1) || ', ' || y.z)"
348
+ @d.lit([:x, 1, :y].sql_string_join).should == "(x || '1' || y)"
349
+ @d.lit([:x, 1, :y].sql_string_join(', ')).should == "(x || ', ' || '1' || ', ' || y)"
350
+ @d.lit([:x, 1, :y].sql_string_join(:y__z)).should == "(x || y.z || '1' || y.z || y)"
351
+ @d.lit([:x, 1, :y].sql_string_join(1)).should == "(x || '1' || '1' || '1' || y)"
352
+ @d.lit([:x, :y].sql_string_join('y.x || x.y'.lit)).should == "(x || y.x || x.y || y)"
353
+ @d.lit([[:x, :y].sql_string_join, [:a, :b].sql_string_join].sql_string_join).should == "(x || y || a || b)"
354
+ end
355
+
356
+ it "should support StringExpression#+ for concatenation of SQL strings" do
357
+ @d.lit(:x.sql_string + :y).should == '(x || y)'
358
+ @d.lit([:x].sql_string_join + :y).should == '(x || y)'
359
+ @d.lit([:x, :z].sql_string_join(' ') + :y).should == "(x || ' ' || z || y)"
360
+ end
361
+
362
+ it "should be supported inside blocks" do
363
+ @d.l{[[:x, nil], [:y, [1,2,3]]].sql_or}.should == '((x IS NULL) OR (y IN (1, 2, 3)))'
364
+ @d.l{~[[:x, nil], [:y, [1,2,3]]]}.should == '((x IS NOT NULL) OR (y NOT IN (1, 2, 3)))'
365
+ @d.l{~(((('x'.lit - :y)/(:x + :y))*:z) <= 100)}.should == '((((x - y) / (x + y)) * z) > 100)'
366
+ @d.l{{:x => :a} & {:y => :z}}.should == '((x = a) AND (y = z))'
367
+ end
368
+
369
+ it "should support &, |, ^, ~, <<, and >> for NumericExpressions" do
370
+ @d.l(:x.sql_number & 1 > 100).should == '((x & 1) > 100)'
371
+ @d.l(:x.sql_number | 1 > 100).should == '((x | 1) > 100)'
372
+ @d.l(:x.sql_number ^ 1 > 100).should == '((x ^ 1) > 100)'
373
+ @d.l(~:x.sql_number > 100).should == '(~x > 100)'
374
+ @d.l(:x.sql_number << 1 > 100).should == '((x << 1) > 100)'
375
+ @d.l(:x.sql_number >> 1 > 100).should == '((x >> 1) > 100)'
376
+ @d.l((:x + 1) & 1 > 100).should == '(((x + 1) & 1) > 100)'
377
+ @d.l((:x + 1) | 1 > 100).should == '(((x + 1) | 1) > 100)'
378
+ @d.l((:x + 1) ^ 1 > 100).should == '(((x + 1) ^ 1) > 100)'
379
+ @d.l(~(:x + 1) > 100).should == '(~(x + 1) > 100)'
380
+ @d.l((:x + 1) << 1 > 100).should == '(((x + 1) << 1) > 100)'
381
+ @d.l((:x + 1) >> 1 > 100).should == '(((x + 1) >> 1) > 100)'
382
+ @d.l((:x + 1) & (:x + 2) > 100).should == '(((x + 1) & (x + 2)) > 100)'
383
+ end
384
+
385
+ it "should raise an error if use a Bitwise method on a ComplexExpression that isn't a NumericExpression" do
386
+ proc{(:x + 1) & (:x & 2)}.should raise_error(Sequel::Error)
387
+ end
388
+
389
+ it "should raise an error if use a Boolean method on a ComplexExpression that isn't a BooleanExpression" do
390
+ proc{:x & (:x + 2)}.should raise_error(Sequel::Error)
391
+ end
392
+
393
+ it "should raise an error if attempting to invert a ComplexExpression that isn't a BooleanExpression" do
394
+ proc{Sequel::SQL::BooleanExpression.invert(:x + 2)}.should raise_error(Sequel::Error)
395
+ end
396
+
397
+ it "should return self on .lit" do
398
+ y = :x + 1
399
+ y.lit.should == y
400
+ end
401
+
402
+ it "should return have .sql_literal operate like .to_s" do
403
+ y = :x + 1
404
+ y.sql_literal(@d).should == '(x + 1)'
405
+ y.sql_literal(@d).should == y.to_s(@d)
406
+ y.sql_literal(@d).should == @d.literal(y)
407
+ end
408
+
409
+ it "should support SQL::Constants" do
410
+ @d.l({:x => Sequel::NULL}).should == '(x IS NULL)'
411
+ @d.l({:x => Sequel::NOTNULL}).should == '(x IS NOT NULL)'
412
+ @d.l({:x => Sequel::TRUE}).should == '(x IS TRUE)'
413
+ @d.l({:x => Sequel::FALSE}).should == '(x IS FALSE)'
414
+ @d.l({:x => Sequel::SQLTRUE}).should == '(x IS TRUE)'
415
+ @d.l({:x => Sequel::SQLFALSE}).should == '(x IS FALSE)'
416
+ end
417
+
418
+ it "should support negation of SQL::Constants" do
419
+ @d.l(~{:x => Sequel::NULL}).should == '(x IS NOT NULL)'
420
+ @d.l(~{:x => Sequel::NOTNULL}).should == '(x IS NULL)'
421
+ @d.l(~{:x => Sequel::TRUE}).should == '(x IS NOT TRUE)'
422
+ @d.l(~{:x => Sequel::FALSE}).should == '(x IS NOT FALSE)'
423
+ @d.l(~{:x => Sequel::SQLTRUE}).should == '(x IS NOT TRUE)'
424
+ @d.l(~{:x => Sequel::SQLFALSE}).should == '(x IS NOT FALSE)'
425
+ end
426
+
427
+ it "should raise an error if trying to create an invalid complex expression" do
428
+ proc{Sequel::SQL::ComplexExpression.new(:BANG, 1, 2)}.should raise_error(Sequel::Error)
429
+ end
430
+
431
+ it "should raise an error if trying to literalize an invalid complex expression" do
432
+ ce = :x + 1
433
+ ce.instance_variable_set(:@op, :BANG)
434
+ proc{@d.lit(ce)}.should raise_error(Sequel::Error)
435
+ end
436
+
437
+ it "should support equality comparison of two expressions" do
438
+ e1 = ~:comment.like('%:hidden:%')
439
+ e2 = ~:comment.like('%:hidden:%')
440
+ e1.should == e2
441
+ end
442
+
443
+ if RUBY_VERSION < '1.9.0'
444
+ it "should not allow inequality operations on true, false, or nil" do
445
+ proc{:x > 1}.should_not raise_error
446
+ proc{:x < true}.should raise_error(Sequel::Error)
447
+ proc{:x >= false}.should raise_error(Sequel::Error)
448
+ proc{:x <= nil}.should raise_error(Sequel::Error)
449
+ end
450
+
451
+ it "should not allow inequality operations on boolean complex expressions" do
452
+ proc{:x > (:y > 5)}.should raise_error(Sequel::Error)
453
+ proc{:x < (:y < 5)}.should raise_error(Sequel::Error)
454
+ proc{:x >= (:y >= 5)}.should raise_error(Sequel::Error)
455
+ proc{:x <= (:y <= 5)}.should raise_error(Sequel::Error)
456
+ proc{:x > {:y => nil}}.should raise_error(Sequel::Error)
457
+ proc{:x < ~{:y => nil}}.should raise_error(Sequel::Error)
458
+ proc{:x >= {:y => 5}}.should raise_error(Sequel::Error)
459
+ proc{:x <= ~{:y => 5}}.should raise_error(Sequel::Error)
460
+ proc{:x >= {:y => [1,2,3]}}.should raise_error(Sequel::Error)
461
+ proc{:x <= ~{:y => [1,2,3]}}.should raise_error(Sequel::Error)
462
+ end
463
+
464
+ it "should support >, <, >=, and <= via Symbol#>,<,>=,<=" do
465
+ @d.l(:x > 100).should == '(x > 100)'
466
+ @d.l(:x < 100.01).should == '(x < 100.01)'
467
+ @d.l(:x >= 100000000000000000000000000000000000).should == '(x >= 100000000000000000000000000000000000)'
468
+ @d.l(:x <= 100).should == '(x <= 100)'
469
+ end
470
+
471
+ it "should support negation of >, <, >=, and <= via Symbol#~" do
472
+ @d.l(~(:x > 100)).should == '(x <= 100)'
473
+ @d.l(~(:x < 100.01)).should == '(x >= 100.01)'
474
+ @d.l(~(:x >= 100000000000000000000000000000000000)).should == '(x < 100000000000000000000000000000000000)'
475
+ @d.l(~(:x <= 100)).should == '(x > 100)'
476
+ end
477
+
478
+ it "should support double negation via ~" do
479
+ @d.l(~~(:x > 100)).should == '(x > 100)'
480
+ end
481
+ end
482
+ end
483
+
484
+ context Sequel::SQL::VirtualRow do
485
+ before do
486
+ db = Sequel::Database.new
487
+ db.quote_identifiers = true
488
+ @d = db[:items]
489
+ @d.meta_def(:supports_window_functions?){true}
490
+ def @d.l(*args, &block)
491
+ literal(filter_expr(*args, &block))
492
+ end
493
+ end
494
+
495
+ it "should treat methods without arguments as identifiers" do
496
+ @d.l{column}.should == '"column"'
497
+ end
498
+
499
+ it "should treat methods without arguments that have embedded double underscores as qualified identifiers" do
500
+ @d.l{table__column}.should == '"table"."column"'
501
+ end
502
+
503
+ it "should treat methods with arguments as functions with the arguments" do
504
+ @d.l{function(arg1, 10, 'arg3')}.should == 'function("arg1", 10, \'arg3\')'
505
+ end
506
+
507
+ it "should treat methods with a block and no arguments as a function call with no arguments" do
508
+ @d.l{version{}}.should == 'version()'
509
+ end
510
+
511
+ it "should treat methods with a block and a leading argument :* as a function call with the SQL wildcard" do
512
+ @d.l{count(:*){}}.should == 'count(*)'
513
+ end
514
+
515
+ it "should treat methods with a block and a leading argument :distinct as a function call with DISTINCT and the additional method arguments" do
516
+ @d.l{count(:distinct, column1){}}.should == 'count(DISTINCT "column1")'
517
+ @d.l{count(:distinct, column1, column2){}}.should == 'count(DISTINCT "column1", "column2")'
518
+ end
519
+
520
+ it "should raise an error if an unsupported argument is used with a block" do
521
+ proc{@d.l{count(:blah){}}}.should raise_error(Sequel::Error)
522
+ end
523
+
524
+ it "should treat methods with a block and a leading argument :over as a window function call" do
525
+ @d.l{rank(:over){}}.should == 'rank() OVER ()'
526
+ end
527
+
528
+ it "should support :partition options for window function calls" do
529
+ @d.l{rank(:over, :partition=>column1){}}.should == 'rank() OVER (PARTITION BY "column1")'
530
+ @d.l{rank(:over, :partition=>[column1, column2]){}}.should == 'rank() OVER (PARTITION BY "column1", "column2")'
531
+ end
532
+
533
+ it "should support :args options for window function calls" do
534
+ @d.l{avg(:over, :args=>column1){}}.should == 'avg("column1") OVER ()'
535
+ @d.l{avg(:over, :args=>[column1, column2]){}}.should == 'avg("column1", "column2") OVER ()'
536
+ end
537
+
538
+ it "should support :order option for window function calls" do
539
+ @d.l{rank(:over, :order=>column1){}}.should == 'rank() OVER (ORDER BY "column1")'
540
+ @d.l{rank(:over, :order=>[column1, column2]){}}.should == 'rank() OVER (ORDER BY "column1", "column2")'
541
+ end
542
+
543
+ it "should support :window option for window function calls" do
544
+ @d.l{rank(:over, :window=>:win){}}.should == 'rank() OVER ("win")'
545
+ end
546
+
547
+ it "should support :*=>true option for window function calls" do
548
+ @d.l{count(:over, :* =>true){}}.should == 'count(*) OVER ()'
549
+ end
550
+
551
+ it "should support :frame=>:all option for window function calls" do
552
+ @d.l{rank(:over, :frame=>:all){}}.should == 'rank() OVER (ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)'
553
+ end
554
+
555
+ it "should support :frame=>:rows option for window function calls" do
556
+ @d.l{rank(:over, :frame=>:rows){}}.should == 'rank() OVER (ROWS UNBOUNDED PRECEDING)'
557
+ end
558
+
559
+ it "should raise an error if an invalid :frame option is used" do
560
+ proc{@d.l{rank(:over, :frame=>:blah){}}}.should raise_error(Sequel::Error)
561
+ end
562
+
563
+ it "should support all these options together" do
564
+ @d.l{count(:over, :* =>true, :partition=>a, :order=>b, :window=>:win, :frame=>:rows){}}.should == 'count(*) OVER ("win" PARTITION BY "a" ORDER BY "b" ROWS UNBOUNDED PRECEDING)'
565
+ end
566
+
567
+ it "should raise an error if window functions are not supported" do
568
+ @d.meta_def(:supports_window_functions?){false}
569
+ proc{@d.l{count(:over, :* =>true, :partition=>a, :order=>b, :window=>:win, :frame=>:rows){}}}.should raise_error(Sequel::Error)
570
+ proc{Sequel::Dataset.new(nil).filter{count(:over, :* =>true, :partition=>a, :order=>b, :window=>:win, :frame=>:rows){}}.sql}.should raise_error(Sequel::Error)
571
+ end
572
+
573
+ it "should deal with classes without requiring :: prefix" do
574
+ @d.l{date < Date.today}.should == "(\"date\" < '#{Date.today}')"
575
+ @d.l{date < Sequel::CURRENT_DATE}.should == "(\"date\" < CURRENT_DATE)"
576
+ @d.l{num < Math::PI.to_i}.should == "(\"num\" < 3)"
577
+ end
578
+
579
+ it "should deal with methods added to Object after requiring Sequel" do
580
+ class Object
581
+ def adsoiwemlsdaf; 42; end
582
+ end
583
+ Sequel::BasicObject.remove_methods!
584
+ @d.l{a > adsoiwemlsdaf}.should == '("a" > "adsoiwemlsdaf")'
585
+ end
586
+
587
+ it "should deal with private methods added to Kernel after requiring Sequel" do
588
+ module Kernel
589
+ private
590
+ def adsoiwemlsdaf2; 42; end
591
+ end
592
+ Sequel::BasicObject.remove_methods!
593
+ @d.l{a > adsoiwemlsdaf2}.should == '("a" > "adsoiwemlsdaf2")'
594
+ end
595
+ end