viking-sequel 3.10.0

Sign up to get free protection for your applications and to get access to all the features.
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,1020 @@
1
+ module Sequel
2
+ if RUBY_VERSION < '1.9.0'
3
+ # If on Ruby 1.8, create a Sequel::BasicObject class that is similar to the
4
+ # the Ruby 1.9 BasicObject class. This is used in a few places where proxy
5
+ # objects are needed that respond to any method call.
6
+ class BasicObject
7
+ # The instance methods to not remove from the class when removing
8
+ # other methods.
9
+ KEEP_METHODS = %w"__id__ __send__ __metaclass__ instance_eval == equal? initialize"
10
+
11
+ # Remove all but the most basic instance methods from the class. A separate
12
+ # method so that it can be called again if necessary if you load libraries
13
+ # after Sequel that add instance methods to Object.
14
+ def self.remove_methods!
15
+ ((private_instance_methods + instance_methods) - KEEP_METHODS).each{|m| undef_method(m)}
16
+ end
17
+ remove_methods!
18
+ end
19
+ else
20
+ # If on 1.9, create a Sequel::BasicObject class that is just like the
21
+ # default BasicObject class, except that missing constants are resolved in
22
+ # Object. This allows the virtual row support to work with classes
23
+ # without prefixing them with ::, such as:
24
+ #
25
+ # DB[:bonds].filter{maturity_date > Time.now}
26
+ class BasicObject < ::BasicObject
27
+ # Lookup missing constants in ::Object
28
+ def self.const_missing(name)
29
+ ::Object.const_get(name)
30
+ end
31
+
32
+ # No-op method on ruby 1.9, which has a real BasicObject class.
33
+ def self.remove_methods!
34
+ end
35
+ end
36
+ end
37
+
38
+ class LiteralString < ::String
39
+ end
40
+
41
+ # The SQL module holds classes whose instances represent SQL fragments.
42
+ # It also holds modules that are included in core ruby classes that
43
+ # make Sequel a friendly DSL.
44
+ module SQL
45
+
46
+ ### Parent Classes ###
47
+
48
+ # Classes/Modules aren't an alphabetical order due to the fact that
49
+ # some reference constants defined in others at load time.
50
+
51
+ # Base class for all SQL fragments
52
+ class Expression
53
+ # all instance variables declared to be readers are to be used for comparison.
54
+ def self.attr_reader(*args)
55
+ super
56
+ comparison_attrs.concat args
57
+ end
58
+
59
+ def self.comparison_attrs
60
+ @comparison_attrs ||= self == Expression ? [] : superclass.comparison_attrs.clone
61
+ end
62
+
63
+ # Create a to_s instance method that takes a dataset, and calls
64
+ # the method provided on the dataset with args as the argument (self by default).
65
+ # Used to DRY up some code.
66
+ def self.to_s_method(meth, args=:self) # :nodoc:
67
+ class_eval("def to_s(ds); ds.#{meth}(#{args}) end", __FILE__, __LINE__)
68
+ end
69
+ private_class_method :to_s_method
70
+
71
+ # Returns self, because SQL::Expression already acts like
72
+ # LiteralString.
73
+ def lit
74
+ self
75
+ end
76
+
77
+ # Alias for to_s
78
+ def sql_literal(ds)
79
+ to_s(ds)
80
+ end
81
+
82
+ # Returns true if the receiver is the same expression as the
83
+ # the +other+ expression.
84
+ def eql?(other)
85
+ other.is_a?(self.class) && !self.class.comparison_attrs.find {|a| send(a) != other.send(a)}
86
+ end
87
+ alias == eql?
88
+ end
89
+
90
+ # Represents a complex SQL expression, with a given operator and one
91
+ # or more attributes (which may also be ComplexExpressions, forming
92
+ # a tree). This class is the backbone of the blockless filter support in
93
+ # Sequel.
94
+ #
95
+ # This is an abstract class that is not that useful by itself. The
96
+ # subclasses BooleanExpression, NumericExpression, and StringExpression
97
+ # define the behavior of the DSL via operators.
98
+ class ComplexExpression < Expression
99
+ # A hash of the opposite for each operator symbol, used for inverting
100
+ # objects.
101
+ OPERTATOR_INVERSIONS = {:AND => :OR, :OR => :AND, :< => :>=, :> => :<=,
102
+ :<= => :>, :>= => :<, :'=' => :'!=' , :'!=' => :'=', :LIKE => :'NOT LIKE',
103
+ :'NOT LIKE' => :LIKE, :~ => :'!~', :'!~' => :~, :IN => :'NOT IN',
104
+ :'NOT IN' => :IN, :IS => :'IS NOT', :'IS NOT' => :IS, :'~*' => :'!~*',
105
+ :'!~*' => :'~*', :NOT => :NOOP, :NOOP => :NOT, :ILIKE => :'NOT ILIKE',
106
+ :'NOT ILIKE'=>:ILIKE}
107
+
108
+ # Standard Mathematical Operators used in NumericMethods
109
+ MATHEMATICAL_OPERATORS = [:+, :-, :/, :*]
110
+
111
+ # Bitwise Mathematical Operators used in NumericMethods
112
+ BITWISE_OPERATORS = [:&, :|, :^, :<<, :>>]
113
+
114
+ # Inequality Operators used in InequalityMethods
115
+ INEQUALITY_OPERATORS = [:<, :>, :<=, :>=]
116
+
117
+ # Hash of ruby operator symbols to SQL operators, used in BooleanMethods
118
+ BOOLEAN_OPERATOR_METHODS = {:& => :AND, :| =>:OR}
119
+
120
+ # Operators that use IS, used for special casing to override literal true/false values
121
+ IS_OPERATORS = [:IS, :'IS NOT']
122
+
123
+ # Operator symbols that take exactly two arguments
124
+ TWO_ARITY_OPERATORS = [:'=', :'!=', :LIKE, :'NOT LIKE', \
125
+ :~, :'!~', :'~*', :'!~*', :IN, :'NOT IN', :ILIKE, :'NOT ILIKE'] + \
126
+ INEQUALITY_OPERATORS + BITWISE_OPERATORS + IS_OPERATORS
127
+
128
+ # Operator symbols that take one or more arguments
129
+ N_ARITY_OPERATORS = [:AND, :OR, :'||'] + MATHEMATICAL_OPERATORS
130
+
131
+ # Operator symbols that take one argument
132
+ ONE_ARITY_OPERATORS = [:NOT, :NOOP, :'B~']
133
+
134
+ # An array of args for this object
135
+ attr_reader :args
136
+
137
+ # The operator symbol for this object
138
+ attr_reader :op
139
+
140
+ # Set the operator symbol and arguments for this object to the ones given.
141
+ # Convert all args that are hashes or arrays with all two pairs to BooleanExpressions.
142
+ # Raise an error if the operator doesn't allow boolean input and a boolean argument is given.
143
+ # Raise an error if the wrong number of arguments for a given operator is used.
144
+ def initialize(op, *args)
145
+ args.map!{|a| Sequel.condition_specifier?(a) ? SQL::BooleanExpression.from_value_pairs(a) : a}
146
+ case op
147
+ when *N_ARITY_OPERATORS
148
+ raise(Error, "The #{op} operator requires at least 1 argument") unless args.length >= 1
149
+ old_args = args
150
+ args = []
151
+ old_args.each{|a| a.is_a?(self.class) && a.op == op ? args.concat(a.args) : args.push(a)}
152
+ when *TWO_ARITY_OPERATORS
153
+ raise(Error, "The #{op} operator requires precisely 2 arguments") unless args.length == 2
154
+ when *ONE_ARITY_OPERATORS
155
+ raise(Error, "The #{op} operator requires a single argument") unless args.length == 1
156
+ else
157
+ raise(Error, "Invalid operator #{op}")
158
+ end
159
+ @op = op
160
+ @args = args
161
+ end
162
+
163
+ to_s_method :complex_expression_sql, '@op, @args'
164
+ end
165
+
166
+ # The base class for expressions that can be used in multiple places in
167
+ # the SQL query.
168
+ class GenericExpression < Expression
169
+ end
170
+
171
+ ### Modules ###
172
+
173
+ # Methods that create aliased identifiers
174
+ module AliasMethods
175
+ # Create an SQL column alias of the receiving column or expression to the given alias.
176
+ def as(aliaz)
177
+ AliasedExpression.new(self, aliaz)
178
+ end
179
+ end
180
+
181
+ # This defines the bitwise methods: &, |, ^, ~, <<, and >>. Because these
182
+ # methods overlap with the standard BooleanMethods methods, and they only
183
+ # make sense for numbers, they are only included in NumericExpression.
184
+ module BitwiseMethods
185
+ ComplexExpression::BITWISE_OPERATORS.each do |o|
186
+ define_method(o) do |ce|
187
+ case ce
188
+ when BooleanExpression, StringExpression
189
+ raise(Sequel::Error, "cannot apply #{o} to a non-numeric expression")
190
+ else
191
+ NumericExpression.new(o, self, ce)
192
+ end
193
+ end
194
+ end
195
+
196
+ # Do the bitwise compliment of the self
197
+ def ~
198
+ NumericExpression.new(:'B~', self)
199
+ end
200
+ end
201
+
202
+ # This module includes the methods that are defined on objects that can be
203
+ # used in a boolean context in SQL (Symbol, LiteralString, SQL::Function,
204
+ # and SQL::BooleanExpression).
205
+ #
206
+ # This defines the ~ (NOT), & (AND), and | (OR) methods.
207
+ module BooleanMethods
208
+ # Create a new BooleanExpression with NOT, representing the inversion of whatever self represents.
209
+ def ~
210
+ BooleanExpression.invert(self)
211
+ end
212
+
213
+ ComplexExpression::BOOLEAN_OPERATOR_METHODS.each do |m, o|
214
+ define_method(m) do |ce|
215
+ case ce
216
+ when NumericExpression, StringExpression
217
+ raise(Sequel::Error, "cannot apply #{o} to a non-boolean expression")
218
+ else
219
+ BooleanExpression.new(o, self, ce)
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ # Holds methods that are used to cast objects to differen SQL types.
226
+ module CastMethods
227
+ # Cast the reciever to the given SQL type. You can specify a ruby class as a type,
228
+ # and it is handled similarly to using a database independent type in the schema methods.
229
+ def cast(sql_type)
230
+ Cast.new(self, sql_type)
231
+ end
232
+
233
+ # Cast the reciever to the given SQL type (or the database's default integer type if none given),
234
+ # and return the result as a NumericExpression.
235
+ def cast_numeric(sql_type = nil)
236
+ cast(sql_type || Integer).sql_number
237
+ end
238
+
239
+ # Cast the reciever to the given SQL type (or the database's default string type if none given),
240
+ # and return the result as a StringExpression, so you can use +
241
+ # directly on the result for SQL string concatenation.
242
+ def cast_string(sql_type = nil)
243
+ cast(sql_type || String).sql_string
244
+ end
245
+ end
246
+
247
+ # Adds methods that allow you to treat an object as an instance of a specific
248
+ # ComplexExpression subclass. This is useful if another library
249
+ # overrides the methods defined by Sequel.
250
+ #
251
+ # For example, if Symbol#/ is overridden to produce a string (for
252
+ # example, to make file system path creation easier), the
253
+ # following code will not do what you want:
254
+ #
255
+ # :price/10 > 100
256
+ #
257
+ # In that case, you need to do the following:
258
+ #
259
+ # :price.sql_number/10 > 100
260
+ module ComplexExpressionMethods
261
+ # Extract a datetime_part (e.g. year, month) from self:
262
+ #
263
+ # :date.extract(:year) # SQL: extract(year FROM "date")
264
+ #
265
+ # Also has the benefit of returning the result as a
266
+ # NumericExpression instead of a generic ComplexExpression.
267
+ #
268
+ # The extract function is in the SQL standard, but it doesn't
269
+ # doesn't use the standard function calling convention.
270
+ def extract(datetime_part)
271
+ Function.new(:extract, PlaceholderLiteralString.new("#{datetime_part} FROM ?", [self])).sql_number
272
+ end
273
+
274
+ # Return a BooleanExpression representation of self.
275
+ def sql_boolean
276
+ BooleanExpression.new(:NOOP, self)
277
+ end
278
+
279
+ # Return a NumericExpression representation of self.
280
+ def sql_number
281
+ NumericExpression.new(:NOOP, self)
282
+ end
283
+
284
+ # Return a StringExpression representation of self.
285
+ def sql_string
286
+ StringExpression.new(:NOOP, self)
287
+ end
288
+ end
289
+
290
+ # Includes a method that returns Identifiers.
291
+ module IdentifierMethods
292
+ # Return self wrapped as an identifier.
293
+ def identifier
294
+ Identifier.new(self)
295
+ end
296
+ end
297
+
298
+ # This module includes the methods that are defined on objects that can be
299
+ # used in a numeric or string context in SQL (Symbol (except on ruby 1.9), LiteralString,
300
+ # SQL::Function, and SQL::StringExpression).
301
+ #
302
+ # This defines the >, <, >=, and <= methods.
303
+ module InequalityMethods
304
+ ComplexExpression::INEQUALITY_OPERATORS.each do |o|
305
+ define_method(o) do |ce|
306
+ case ce
307
+ when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
308
+ raise(Error, "cannot apply #{o} to a boolean expression")
309
+ else
310
+ BooleanExpression.new(o, self, ce)
311
+ end
312
+ end
313
+ end
314
+ end
315
+
316
+ # This module augments the default initalize method for the
317
+ # ComplexExpression subclass it is included in, so that
318
+ # attempting to use boolean input when initializing a NumericExpression
319
+ # or StringExpression results in an error.
320
+ module NoBooleanInputMethods
321
+ # Raise an Error if one of the args would be boolean in an SQL
322
+ # context, otherwise call super.
323
+ def initialize(op, *args)
324
+ args.each do |a|
325
+ case a
326
+ when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
327
+ raise(Error, "cannot apply #{op} to a boolean expression")
328
+ end
329
+ end
330
+ super
331
+ end
332
+ end
333
+
334
+ # This module includes the methods that are defined on objects that can be
335
+ # used in a numeric context in SQL (Symbol, LiteralString, SQL::Function,
336
+ # and SQL::NumericExpression).
337
+ #
338
+ # This defines the +, -, *, and / methods.
339
+ module NumericMethods
340
+ ComplexExpression::MATHEMATICAL_OPERATORS.each do |o|
341
+ define_method(o) do |ce|
342
+ case ce
343
+ when BooleanExpression, StringExpression
344
+ raise(Sequel::Error, "cannot apply #{o} to a non-numeric expression")
345
+ else
346
+ NumericExpression.new(o, self, ce)
347
+ end
348
+ end
349
+ end
350
+ end
351
+
352
+ # Methods that create OrderedExpressions, used for sorting by columns
353
+ # or more complex expressions.
354
+ module OrderMethods
355
+ # Mark the receiving SQL column as sorting in a descending fashion.
356
+ def desc
357
+ OrderedExpression.new(self)
358
+ end
359
+
360
+ # Mark the receiving SQL column as sorting in an ascending fashion (generally a no-op).
361
+ def asc
362
+ OrderedExpression.new(self, false)
363
+ end
364
+ end
365
+
366
+ # Methods that created QualifiedIdentifiers, used for qualifying column
367
+ # names with a table or table names with a schema.
368
+ module QualifyingMethods
369
+ # Qualify the current object with the given table/schema.
370
+ def qualify(ts)
371
+ QualifiedIdentifier.new(ts, self)
372
+ end
373
+ end
374
+
375
+ # This module includes the methods that are defined on objects that can be
376
+ # used in a string context in SQL (Symbol, LiteralString, SQL::Function,
377
+ # and SQL::StringExpression).
378
+ #
379
+ # This defines the like (LIKE) and ilike methods, used for pattern matching.
380
+ # like is case sensitive (if the database supports it), ilike is case insensitive.
381
+ module StringMethods
382
+ # Create a BooleanExpression case insensitive pattern match of self
383
+ # with the given patterns. See StringExpression.like.
384
+ def ilike(*ces)
385
+ StringExpression.like(self, *(ces << {:case_insensitive=>true}))
386
+ end
387
+
388
+ # Create a BooleanExpression case sensitive (if the database supports it) pattern match of self with
389
+ # the given patterns. See StringExpression.like.
390
+ def like(*ces)
391
+ StringExpression.like(self, *ces)
392
+ end
393
+ end
394
+
395
+ # This module is included in StringExpression and can be included elsewhere
396
+ # to allow the use of the + operator to represent concatenation of SQL
397
+ # Strings:
398
+ #
399
+ # :x.sql_string + :y => # SQL: x || y
400
+ module StringConcatenationMethods
401
+ def +(ce)
402
+ StringExpression.new(:'||', self, ce)
403
+ end
404
+ end
405
+
406
+ # Methods that create Subscripts (SQL array accesses).
407
+ module SubscriptMethods
408
+ # Return an SQL array subscript with the given arguments.
409
+ #
410
+ # :array.sql_subscript(1) # SQL: array[1]
411
+ # :array.sql_subscript(1, 2) # SQL: array[1, 2]
412
+ def sql_subscript(*sub)
413
+ Subscript.new(self, sub.flatten)
414
+ end
415
+ end
416
+
417
+ ### Classes ###
418
+
419
+ # Represents an aliasing of an expression/column to a given name.
420
+ class AliasedExpression < Expression
421
+ # The expression to alias
422
+ attr_reader :expression
423
+
424
+ # The alias to use for the expression, not alias since that is
425
+ # a keyword in ruby.
426
+ attr_reader :aliaz
427
+
428
+ # Create an object with the given expression and alias.
429
+ def initialize(expression, aliaz)
430
+ @expression, @aliaz = expression, aliaz
431
+ end
432
+
433
+ to_s_method :aliased_expression_sql
434
+ end
435
+
436
+ # Blob is used to represent binary data in the Ruby environment that is
437
+ # stored as a blob type in the database. Sequel represents binary data as a Blob object because
438
+ # certain database engines require binary data to be escaped.
439
+ class Blob < ::String
440
+ # Returns self
441
+ def to_sequel_blob
442
+ self
443
+ end
444
+ end
445
+
446
+ # Subclass of ComplexExpression where the expression results
447
+ # in a boolean value in SQL.
448
+ class BooleanExpression < ComplexExpression
449
+ include BooleanMethods
450
+
451
+ # Take pairs of values (e.g. a hash or array of arrays of two pairs)
452
+ # and converts it to a BooleanExpression. The operator and args
453
+ # used depends on the case of the right (2nd) argument:
454
+ #
455
+ # * 0..10 - left >= 0 AND left <= 10
456
+ # * [1,2] - left IN (1,2)
457
+ # * nil - left IS NULL
458
+ # * /as/ - left ~ 'as'
459
+ # * :blah - left = blah
460
+ # * 'blah' - left = 'blah'
461
+ #
462
+ # If multiple arguments are given, they are joined with the op given (AND
463
+ # by default, OR possible). If negate is set to true,
464
+ # all subexpressions are inverted before used. Therefore, the following
465
+ # expressions are equivalent:
466
+ #
467
+ # ~from_value_pairs(hash)
468
+ # from_value_pairs(hash, :OR, true)
469
+ def self.from_value_pairs(pairs, op=:AND, negate=false)
470
+ pairs = pairs.collect do |l,r|
471
+ ce = case r
472
+ when Range
473
+ new(:AND, new(:>=, l, r.begin), new(r.exclude_end? ? :< : :<=, l, r.end))
474
+ when Array, ::Sequel::Dataset, SQLArray
475
+ new(:IN, l, r)
476
+ when NegativeBooleanConstant
477
+ new(:"IS NOT", l, r.constant)
478
+ when BooleanConstant
479
+ new(:IS, l, r.constant)
480
+ when NilClass, TrueClass, FalseClass
481
+ new(:IS, l, r)
482
+ when Regexp
483
+ StringExpression.like(l, r)
484
+ else
485
+ new(:'=', l, r)
486
+ end
487
+ negate ? invert(ce) : ce
488
+ end
489
+ pairs.length == 1 ? pairs.at(0) : new(op, *pairs)
490
+ end
491
+
492
+ # Invert the expression, if possible. If the expression cannot
493
+ # be inverted, raise an error. An inverted expression should match everything that the
494
+ # uninverted expression did not match, and vice-versa, except for possible issues with
495
+ # SQL NULL (i.e. 1 == NULL is NULL and 1 != NULL is also NULL).
496
+ def self.invert(ce)
497
+ case ce
498
+ when BooleanExpression
499
+ case op = ce.op
500
+ when :AND, :OR
501
+ BooleanExpression.new(OPERTATOR_INVERSIONS[op], *ce.args.collect{|a| BooleanExpression.invert(a)})
502
+ else
503
+ BooleanExpression.new(OPERTATOR_INVERSIONS[op], *ce.args.dup)
504
+ end
505
+ when StringExpression, NumericExpression
506
+ raise(Sequel::Error, "cannot invert #{ce.inspect}")
507
+ else
508
+ BooleanExpression.new(:NOT, ce)
509
+ end
510
+ end
511
+ end
512
+
513
+ # Represents an SQL CASE expression, used for conditions.
514
+ class CaseExpression < GenericExpression
515
+ # An array of all two pairs with the first element specifying the
516
+ # condition and the second element specifying the result.
517
+ attr_reader :conditions
518
+
519
+ # The default value if no conditions are true
520
+ attr_reader :default
521
+
522
+ # The expression to test the conditions against
523
+ attr_reader :expression
524
+
525
+ # Create an object with the given conditions and
526
+ # default value.
527
+ def initialize(conditions, default, expression = nil)
528
+ raise(Sequel::Error, 'CaseExpression conditions must be a hash or array of all two pairs') unless Sequel.condition_specifier?(conditions)
529
+ @conditions, @default, @expression = conditions.to_a, default, expression
530
+ end
531
+
532
+ to_s_method :case_expression_sql
533
+ end
534
+
535
+ # Represents a cast of an SQL expression to a specific type.
536
+ class Cast < GenericExpression
537
+ # The expression to cast
538
+ attr_reader :expr
539
+
540
+ # The type to which to cast the expression
541
+ attr_reader :type
542
+
543
+ # Set the attributes to the given arguments
544
+ def initialize(expr, type)
545
+ @expr = expr
546
+ @type = type
547
+ end
548
+
549
+ to_s_method :cast_sql, '@expr, @type'
550
+ end
551
+
552
+ # Represents all columns in a given table, table.* in SQL
553
+ class ColumnAll < Expression
554
+ # The table containing the columns being selected
555
+ attr_reader :table
556
+
557
+ # Create an object with the given table
558
+ def initialize(table)
559
+ @table = table
560
+ end
561
+
562
+ # ColumnAll expressions are considered equivalent if they
563
+ # have the same class and string representation
564
+ def ==(x)
565
+ x.class == self.class and @table == x.table
566
+ end
567
+
568
+ to_s_method :column_all_sql
569
+ end
570
+
571
+ class ComplexExpression
572
+ include AliasMethods
573
+ include CastMethods
574
+ include OrderMethods
575
+ include SubscriptMethods
576
+ end
577
+
578
+ # Represents constants or psuedo-constants (e.g. CURRENT_DATE) in SQL.
579
+ class Constant < GenericExpression
580
+ # Create an object with the given table
581
+ def initialize(constant)
582
+ @constant = constant
583
+ end
584
+
585
+ to_s_method :constant_sql, '@constant'
586
+ end
587
+
588
+ # Represents boolean constants such as NULL, NOTNULL, TRUE, and FALSE.
589
+ class BooleanConstant < Constant
590
+ # The underlying constant related for this object.
591
+ attr_reader :constant
592
+
593
+ to_s_method :boolean_constant_sql, '@constant'
594
+ end
595
+
596
+ # Represents inverse boolean constants (currently only NOTNULL). A
597
+ # special class to allow for special behavior.
598
+ class NegativeBooleanConstant < BooleanConstant
599
+ to_s_method :negative_boolean_constant_sql, '@constant'
600
+ end
601
+
602
+ # Holds default generic constants that can be referenced. These
603
+ # are included in the Sequel top level module and are also available
604
+ # in this module which can be required at the top level to get
605
+ # direct access to the constants.
606
+ module Constants
607
+ CURRENT_DATE = Constant.new(:CURRENT_DATE)
608
+ CURRENT_TIME = Constant.new(:CURRENT_TIME)
609
+ CURRENT_TIMESTAMP = Constant.new(:CURRENT_TIMESTAMP)
610
+ SQLTRUE = TRUE = BooleanConstant.new(true)
611
+ SQLFALSE = FALSE = BooleanConstant.new(false)
612
+ NULL = BooleanConstant.new(nil)
613
+ NOTNULL = NegativeBooleanConstant.new(nil)
614
+ end
615
+
616
+ # Represents an SQL function call.
617
+ class Function < GenericExpression
618
+ # The array of arguments to pass to the function (may be blank)
619
+ attr_reader :args
620
+
621
+ # The SQL function to call
622
+ attr_reader :f
623
+
624
+ # Set the attributes to the given arguments
625
+ def initialize(f, *args)
626
+ @f, @args = f, args
627
+ end
628
+
629
+ # Functions are considered equivalent if they
630
+ # have the same class, function, and arguments.
631
+ def ==(x)
632
+ x.class == self.class && @f == x.f && @args == x.args
633
+ end
634
+
635
+ to_s_method :function_sql
636
+ end
637
+
638
+ class GenericExpression
639
+ include AliasMethods
640
+ include BooleanMethods
641
+ include CastMethods
642
+ include ComplexExpressionMethods
643
+ include InequalityMethods
644
+ include NumericMethods
645
+ include OrderMethods
646
+ include StringMethods
647
+ include SubscriptMethods
648
+ end
649
+
650
+ # Represents an identifier (column or table). Can be used
651
+ # to specify a Symbol with multiple underscores should not be
652
+ # split, or for creating an identifier without using a symbol.
653
+ class Identifier < GenericExpression
654
+ include QualifyingMethods
655
+
656
+ # The table and column to reference
657
+ attr_reader :value
658
+
659
+ # Set the value to the given argument
660
+ def initialize(value)
661
+ @value = value
662
+ end
663
+
664
+ to_s_method :quote_identifier, '@value'
665
+ end
666
+
667
+ # Represents an SQL JOIN clause, used for joining tables.
668
+ class JoinClause < Expression
669
+ # The type of join to do
670
+ attr_reader :join_type
671
+
672
+ # The actual table to join
673
+ attr_reader :table
674
+
675
+ # The table alias to use for the join, if any
676
+ attr_reader :table_alias
677
+
678
+ # Create an object with the given join_type, table, and table alias
679
+ def initialize(join_type, table, table_alias = nil)
680
+ @join_type, @table, @table_alias = join_type, table, table_alias
681
+ end
682
+
683
+ to_s_method :join_clause_sql
684
+ end
685
+
686
+ # Represents an SQL JOIN table ON conditions clause.
687
+ class JoinOnClause < JoinClause
688
+ # The conditions for the join
689
+ attr_reader :on
690
+
691
+ # Create an object with the ON conditions and call super with the
692
+ # remaining args.
693
+ def initialize(on, *args)
694
+ @on = on
695
+ super(*args)
696
+ end
697
+
698
+ to_s_method :join_on_clause_sql
699
+ end
700
+
701
+ # Represents an SQL JOIN table USING (columns) clause.
702
+ class JoinUsingClause < JoinClause
703
+ # The columns that appear in both tables that should be equal
704
+ # for the conditions to match.
705
+ attr_reader :using
706
+
707
+ # Create an object with the given USING conditions and call super
708
+ # with the remaining args.
709
+ def initialize(using, *args)
710
+ @using = using
711
+ super(*args)
712
+ end
713
+
714
+ to_s_method :join_using_clause_sql
715
+ end
716
+
717
+ # Represents a literal string with placeholders and arguments.
718
+ # This is necessary to ensure delayed literalization of the arguments
719
+ # required for the prepared statement support
720
+ class PlaceholderLiteralString < Expression
721
+ # The arguments that will be subsituted into the placeholders.
722
+ # Either an array of unnamed placeholders (which will be substituted in
723
+ # order for ? characters), or a hash of named placeholders (which will be
724
+ # substituted for :key phrases).
725
+ attr_reader :args
726
+
727
+ # The literal string containing placeholders
728
+ attr_reader :str
729
+
730
+ # Whether to surround the expression with parantheses
731
+ attr_reader :parens
732
+
733
+ # Create an object with the given string, placeholder arguments, and parens flag.
734
+ def initialize(str, args, parens=false)
735
+ @str = str
736
+ @args = args.is_a?(Array) && args.length == 1 && (v = args.at(0)).is_a?(Hash) ? v : args
737
+ @parens = parens
738
+ end
739
+
740
+ to_s_method :placeholder_literal_string_sql
741
+ end
742
+
743
+ # Subclass of ComplexExpression where the expression results
744
+ # in a numeric value in SQL.
745
+ class NumericExpression < ComplexExpression
746
+ include BitwiseMethods
747
+ include NumericMethods
748
+ include InequalityMethods
749
+ include NoBooleanInputMethods
750
+ end
751
+
752
+ # Represents a column/expression to order the result set by.
753
+ class OrderedExpression < Expression
754
+ # The expression to order the result set by.
755
+ attr_reader :expression
756
+
757
+ # Whether the expression should order the result set in a descending manner
758
+ attr_reader :descending
759
+
760
+ # Set the expression and descending attributes to the given values.
761
+ def initialize(expression, descending = true)
762
+ @expression, @descending = expression, descending
763
+ end
764
+
765
+ # Return a copy that is ASC
766
+ def asc
767
+ OrderedExpression.new(@expression, false)
768
+ end
769
+
770
+ # Return a copy that is DESC
771
+ def desc
772
+ OrderedExpression.new(@expression)
773
+ end
774
+
775
+ # Return an inverted expression, changing ASC to DESC and vice versa
776
+ def invert
777
+ OrderedExpression.new(@expression, !@descending)
778
+ end
779
+
780
+ to_s_method :ordered_expression_sql
781
+ end
782
+
783
+ # Represents a qualified (column with table or table with schema) reference.
784
+ class QualifiedIdentifier < GenericExpression
785
+ include QualifyingMethods
786
+
787
+ # The column to reference
788
+ attr_reader :column
789
+
790
+ # The table to reference
791
+ attr_reader :table
792
+
793
+ # Set the table and column to the given arguments
794
+ def initialize(table, column)
795
+ @table, @column = table, column
796
+ end
797
+
798
+ to_s_method :qualified_identifier_sql
799
+ end
800
+
801
+ # Subclass of ComplexExpression where the expression results
802
+ # in a text/string/varchar value in SQL.
803
+ class StringExpression < ComplexExpression
804
+ include StringMethods
805
+ include StringConcatenationMethods
806
+ include InequalityMethods
807
+ include NoBooleanInputMethods
808
+
809
+ # Map of [regexp, case_insenstive] to ComplexExpression operator
810
+ LIKE_MAP = {[true, true]=>:'~*', [true, false]=>:~, [false, true]=>:ILIKE, [false, false]=>:LIKE}
811
+
812
+ # Creates a SQL pattern match exprssion. left (l) is the SQL string we
813
+ # are matching against, and ces are the patterns we are matching.
814
+ # The match succeeds if any of the patterns match (SQL OR). Patterns
815
+ # can be given as strings or regular expressions. Strings will cause
816
+ # the SQL LIKE operator to be used, and should be supported by most
817
+ # databases. Regular expressions will probably only work on MySQL
818
+ # and PostgreSQL, and SQL regular expression syntax is not fully compatible
819
+ # with ruby regular expression syntax, so be careful if using regular
820
+ # expressions.
821
+ #
822
+ # The pattern match will be case insensitive if the last argument is a hash
823
+ # with a key of :case_insensitive that is not false or nil. Also,
824
+ # if a case insensitive regular expression is used (//i), that particular
825
+ # pattern which will always be case insensitive.
826
+ def self.like(l, *ces)
827
+ l, lre, lci = like_element(l)
828
+ lci = (ces.last.is_a?(Hash) ? ces.pop : {})[:case_insensitive] ? true : lci
829
+ ces.collect! do |ce|
830
+ r, rre, rci = like_element(ce)
831
+ BooleanExpression.new(LIKE_MAP[[lre||rre, lci||rci]], l, r)
832
+ end
833
+ ces.length == 1 ? ces.at(0) : BooleanExpression.new(:OR, *ces)
834
+ end
835
+
836
+ # An array of three parts:
837
+ # * The object to use
838
+ # * Whether it is a regular expression
839
+ # * Whether it is case insensitive
840
+ def self.like_element(re) # :nodoc:
841
+ if re.is_a?(Regexp)
842
+ [re.source, true, re.casefold?]
843
+ else
844
+ [re, false, false]
845
+ end
846
+ end
847
+ private_class_method :like_element
848
+ end
849
+
850
+ # Represents an SQL array. Added so it is possible to deal with a
851
+ # ruby array of all two pairs as an SQL array instead of an ordered
852
+ # hash-like conditions specifier.
853
+ class SQLArray < Expression
854
+ # The array of objects this SQLArray wraps
855
+ attr_reader :array
856
+ alias to_a array
857
+
858
+ # Create an object with the given array.
859
+ def initialize(array)
860
+ @array = array
861
+ end
862
+
863
+ to_s_method :array_sql, '@array'
864
+ end
865
+
866
+ # Represents an SQL array access, with multiple possible arguments.
867
+ class Subscript < GenericExpression
868
+ # The SQL array column
869
+ attr_reader :f
870
+
871
+ # The array of subscripts to use (should be an array of numbers)
872
+ attr_reader :sub
873
+
874
+ # Set the array column and subscripts to the given arguments
875
+ def initialize(f, sub)
876
+ @f, @sub = f, sub
877
+ end
878
+
879
+ # Create a new subscript appending the given subscript(s)
880
+ # the the current array of subscripts.
881
+ def |(sub)
882
+ Subscript.new(@f, @sub + Array(sub))
883
+ end
884
+
885
+ to_s_method :subscript_sql
886
+ end
887
+
888
+ # The purpose of this class is to allow the easy creation of SQL identifiers and functions
889
+ # without relying on methods defined on Symbol. This is useful if another library defines
890
+ # the methods defined by Sequel, or if you are running on ruby 1.9.
891
+ #
892
+ # An instance of this class is yielded to the block supplied to filter, order, and select.
893
+ # If the block doesn't take an argument, the block is instance_evaled in the context of
894
+ # a new instance of this class.
895
+ #
896
+ # VirtualRow uses method_missing to return Identifiers, QualifiedIdentifiers, Functions, or WindowFunctions,
897
+ # depending on how it is called. If a block is not given, creates one of the following objects:
898
+ # * Function - returned if any arguments are supplied, using the method name
899
+ # as the function name, and the arguments as the function arguments.
900
+ # * QualifiedIdentifier - returned if the method name contains __, with the
901
+ # table being the part before __, and the column being the part after.
902
+ # * Identifier - returned otherwise, using the method name.
903
+ # If a block is given, it returns either a Function or WindowFunction, depending on the first
904
+ # argument to the method. Note that the block is currently not called by the code, though
905
+ # this may change in a future version. If the first argument is:
906
+ # * no arguments given - uses a Function with no arguments.
907
+ # * :* - uses a Function with a literal wildcard argument (*), mostly useful for COUNT.
908
+ # * :distinct - uses a Function that prepends DISTINCT to the rest of the arguments, mostly
909
+ # useful for aggregate functions.
910
+ # * :over - uses a WindowFunction. If a second argument is provided, it should be a hash
911
+ # of options which are passed to Window (e.g. :window, :partition, :order, :frame). The
912
+ # arguments to the function itself should be specified as :*=>true for a wildcard, or via
913
+ # the :args option.
914
+ #
915
+ # Examples:
916
+ #
917
+ # ds = DB[:t]
918
+ # # Argument yielded to block
919
+ # ds.filter{|r| r.name < 2} # SELECT * FROM t WHERE (name < 2)
920
+ # # Block without argument (instance_eval)
921
+ # ds.filter{name < 2} # SELECT * FROM t WHERE (name < 2)
922
+ # # Qualified identifiers
923
+ # ds.filter{table__column + 1 < 2} # SELECT * FROM t WHERE ((table.column + 1) < 2)
924
+ # # Functions
925
+ # ds.filter{is_active(1, 'arg2')} # SELECT * FROM t WHERE is_active(1, 'arg2')
926
+ # ds.select{version{}} # SELECT version() FROM t
927
+ # ds.select{count(:*){}} # SELECT count(*) FROM t
928
+ # ds.select{count(:distinct, col1){}} # SELECT count(DISTINCT col1) FROM t
929
+ # # Window Functions
930
+ # ds.select{rank(:over){}} # SELECT rank() OVER () FROM t
931
+ # ds.select{count(:over, :*=>true){}} # SELECT count(*) OVER () FROM t
932
+ # ds.select{sum(:over, :args=>col1, :partition=>col2, :order=>col3){}} # SELECT sum(col1) OVER (PARTITION BY col2 ORDER BY col3) FROM t
933
+ class VirtualRow < BasicObject
934
+ WILDCARD = LiteralString.new('*').freeze
935
+ QUESTION_MARK = LiteralString.new('?').freeze
936
+ COMMA_SEPARATOR = LiteralString.new(', ').freeze
937
+ DOUBLE_UNDERSCORE = '__'.freeze
938
+
939
+ # Return Identifiers, QualifiedIdentifiers, Functions, or WindowFunctions, depending
940
+ # on arguments and whether a block is provided. Does not currently call the block.
941
+ # See the class level documentation.
942
+ def method_missing(m, *args, &block)
943
+ if block
944
+ if args.empty?
945
+ Function.new(m)
946
+ else
947
+ case arg = args.shift
948
+ when :*
949
+ Function.new(m, WILDCARD)
950
+ when :distinct
951
+ Function.new(m, PlaceholderLiteralString.new("DISTINCT #{args.map{QUESTION_MARK}.join(COMMA_SEPARATOR)}", args))
952
+ when :over
953
+ opts = args.shift || {}
954
+ fun_args = ::Kernel.Array(opts[:*] ? WILDCARD : opts[:args])
955
+ WindowFunction.new(Function.new(m, *fun_args), Window.new(opts))
956
+ else
957
+ raise Error, 'unsupported VirtualRow method argument used with block'
958
+ end
959
+ end
960
+ elsif args.empty?
961
+ table, column = m.to_s.split(DOUBLE_UNDERSCORE, 2)
962
+ column ? QualifiedIdentifier.new(table, column) : Identifier.new(m)
963
+ else
964
+ Function.new(m, *args)
965
+ end
966
+ end
967
+ end
968
+
969
+ # A window is part of a window function specifying the window over which the function operates.
970
+ # It is separated from the WindowFunction class because it also can be used separately on
971
+ # some databases.
972
+ class Window < Expression
973
+ # The options for this window. Options currently used are:
974
+ # * :frame - if specified, should be :all or :rows. :all always operates over all rows in the
975
+ # partition, while :rows excludes the current row's later peers. The default is to include
976
+ # all previous rows in the partition up to the current row's last peer.
977
+ # * :order - order on the column(s) given
978
+ # * :partition - partition/group on the column(s) given
979
+ # * :window - base results on a previously specified named window
980
+ attr_reader :opts
981
+
982
+ # Set the options to the options given
983
+ def initialize(opts={})
984
+ @opts = opts
985
+ end
986
+
987
+ to_s_method :window_sql, '@opts'
988
+ end
989
+
990
+ # A WindowFunction is a grouping of a function with a window over which it operates.
991
+ class WindowFunction < GenericExpression
992
+ # The function to use, should be an SQL::Function.
993
+ attr_reader :function
994
+
995
+ # The window to use, should be an SQL::Window.
996
+ attr_reader :window
997
+
998
+ # Set the function and window.
999
+ def initialize(function, window)
1000
+ @function, @window = function, window
1001
+ end
1002
+
1003
+ to_s_method :window_function_sql, '@function, @window'
1004
+ end
1005
+ end
1006
+
1007
+ # LiteralString is used to represent literal SQL expressions. A
1008
+ # LiteralString is copied verbatim into an SQL statement. Instances of
1009
+ # LiteralString can be created by calling String#lit.
1010
+ class LiteralString
1011
+ include SQL::OrderMethods
1012
+ include SQL::ComplexExpressionMethods
1013
+ include SQL::BooleanMethods
1014
+ include SQL::NumericMethods
1015
+ include SQL::StringMethods
1016
+ include SQL::InequalityMethods
1017
+ end
1018
+
1019
+ include SQL::Constants
1020
+ end