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,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