sequel 2.2.0 → 2.3.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 (98) hide show
  1. data/CHANGELOG +1551 -4
  2. data/README +306 -19
  3. data/Rakefile +84 -56
  4. data/bin/sequel +106 -0
  5. data/doc/cheat_sheet.rdoc +225 -0
  6. data/doc/dataset_filtering.rdoc +182 -0
  7. data/lib/sequel_core.rb +136 -0
  8. data/lib/sequel_core/adapters/adapter_skeleton.rb +54 -0
  9. data/lib/sequel_core/adapters/ado.rb +80 -0
  10. data/lib/sequel_core/adapters/db2.rb +148 -0
  11. data/lib/sequel_core/adapters/dbi.rb +117 -0
  12. data/lib/sequel_core/adapters/informix.rb +78 -0
  13. data/lib/sequel_core/adapters/jdbc.rb +186 -0
  14. data/lib/sequel_core/adapters/jdbc/mysql.rb +55 -0
  15. data/lib/sequel_core/adapters/jdbc/postgresql.rb +66 -0
  16. data/lib/sequel_core/adapters/jdbc/sqlite.rb +47 -0
  17. data/lib/sequel_core/adapters/mysql.rb +231 -0
  18. data/lib/sequel_core/adapters/odbc.rb +155 -0
  19. data/lib/sequel_core/adapters/odbc_mssql.rb +106 -0
  20. data/lib/sequel_core/adapters/openbase.rb +64 -0
  21. data/lib/sequel_core/adapters/oracle.rb +170 -0
  22. data/lib/sequel_core/adapters/postgres.rb +199 -0
  23. data/lib/sequel_core/adapters/shared/mysql.rb +275 -0
  24. data/lib/sequel_core/adapters/shared/postgres.rb +351 -0
  25. data/lib/sequel_core/adapters/shared/sqlite.rb +146 -0
  26. data/lib/sequel_core/adapters/sqlite.rb +138 -0
  27. data/lib/sequel_core/connection_pool.rb +194 -0
  28. data/lib/sequel_core/core_ext.rb +203 -0
  29. data/lib/sequel_core/core_sql.rb +184 -0
  30. data/lib/sequel_core/database.rb +471 -0
  31. data/lib/sequel_core/database/schema.rb +156 -0
  32. data/lib/sequel_core/dataset.rb +457 -0
  33. data/lib/sequel_core/dataset/callback.rb +13 -0
  34. data/lib/sequel_core/dataset/convenience.rb +245 -0
  35. data/lib/sequel_core/dataset/pagination.rb +96 -0
  36. data/lib/sequel_core/dataset/query.rb +41 -0
  37. data/lib/sequel_core/dataset/schema.rb +15 -0
  38. data/lib/sequel_core/dataset/sql.rb +889 -0
  39. data/lib/sequel_core/deprecated.rb +26 -0
  40. data/lib/sequel_core/exceptions.rb +42 -0
  41. data/lib/sequel_core/migration.rb +187 -0
  42. data/lib/sequel_core/object_graph.rb +216 -0
  43. data/lib/sequel_core/pretty_table.rb +71 -0
  44. data/lib/sequel_core/schema.rb +2 -0
  45. data/lib/sequel_core/schema/generator.rb +239 -0
  46. data/lib/sequel_core/schema/sql.rb +325 -0
  47. data/lib/sequel_core/sql.rb +812 -0
  48. data/lib/sequel_model.rb +5 -1
  49. data/lib/sequel_model/association_reflection.rb +3 -8
  50. data/lib/sequel_model/base.rb +15 -10
  51. data/lib/sequel_model/inflector.rb +3 -5
  52. data/lib/sequel_model/plugins.rb +1 -1
  53. data/lib/sequel_model/record.rb +11 -3
  54. data/lib/sequel_model/schema.rb +4 -4
  55. data/lib/sequel_model/validations.rb +6 -1
  56. data/spec/adapters/ado_spec.rb +17 -0
  57. data/spec/adapters/informix_spec.rb +96 -0
  58. data/spec/adapters/mysql_spec.rb +764 -0
  59. data/spec/adapters/oracle_spec.rb +222 -0
  60. data/spec/adapters/postgres_spec.rb +441 -0
  61. data/spec/adapters/spec_helper.rb +7 -0
  62. data/spec/adapters/sqlite_spec.rb +400 -0
  63. data/spec/integration/dataset_test.rb +51 -0
  64. data/spec/integration/eager_loader_test.rb +702 -0
  65. data/spec/integration/schema_test.rb +102 -0
  66. data/spec/integration/spec_helper.rb +44 -0
  67. data/spec/integration/type_test.rb +43 -0
  68. data/spec/rcov.opts +2 -0
  69. data/spec/sequel_core/connection_pool_spec.rb +363 -0
  70. data/spec/sequel_core/core_ext_spec.rb +156 -0
  71. data/spec/sequel_core/core_sql_spec.rb +427 -0
  72. data/spec/sequel_core/database_spec.rb +964 -0
  73. data/spec/sequel_core/dataset_spec.rb +2977 -0
  74. data/spec/sequel_core/expression_filters_spec.rb +346 -0
  75. data/spec/sequel_core/migration_spec.rb +261 -0
  76. data/spec/sequel_core/object_graph_spec.rb +234 -0
  77. data/spec/sequel_core/pretty_table_spec.rb +58 -0
  78. data/spec/sequel_core/schema_generator_spec.rb +122 -0
  79. data/spec/sequel_core/schema_spec.rb +497 -0
  80. data/spec/sequel_core/spec_helper.rb +51 -0
  81. data/spec/{association_reflection_spec.rb → sequel_model/association_reflection_spec.rb} +6 -6
  82. data/spec/{associations_spec.rb → sequel_model/associations_spec.rb} +47 -18
  83. data/spec/{base_spec.rb → sequel_model/base_spec.rb} +2 -1
  84. data/spec/{caching_spec.rb → sequel_model/caching_spec.rb} +0 -0
  85. data/spec/{dataset_methods_spec.rb → sequel_model/dataset_methods_spec.rb} +13 -1
  86. data/spec/{eager_loading_spec.rb → sequel_model/eager_loading_spec.rb} +75 -14
  87. data/spec/{hooks_spec.rb → sequel_model/hooks_spec.rb} +4 -4
  88. data/spec/sequel_model/inflector_spec.rb +119 -0
  89. data/spec/{model_spec.rb → sequel_model/model_spec.rb} +30 -11
  90. data/spec/{plugins_spec.rb → sequel_model/plugins_spec.rb} +0 -0
  91. data/spec/{record_spec.rb → sequel_model/record_spec.rb} +47 -6
  92. data/spec/{schema_spec.rb → sequel_model/schema_spec.rb} +18 -4
  93. data/spec/{spec_helper.rb → sequel_model/spec_helper.rb} +3 -2
  94. data/spec/{validations_spec.rb → sequel_model/validations_spec.rb} +37 -17
  95. data/spec/spec_config.rb +9 -0
  96. data/spec/spec_config.rb.example +10 -0
  97. metadata +110 -37
  98. data/spec/inflector_spec.rb +0 -34
@@ -0,0 +1,812 @@
1
+ module Sequel
2
+ # The SQL module holds classes whose instances represent SQL fragments.
3
+ # It also holds modules that are included in core ruby classes that
4
+ # make Sequel a friendly DSL.
5
+ module SQL
6
+ ### Parent Classes ###
7
+
8
+ # Classes/Modules aren't an alphabetical order due to the fact that
9
+ # some reference constants defined in others at load time.
10
+
11
+ # Base class for all SQL fragments
12
+ class Expression
13
+ # Returns self, because SQL::Expression already acts like
14
+ # LiteralString.
15
+ def lit
16
+ self
17
+ end
18
+ end
19
+
20
+ # Represents a complex SQL expression, with a given operator and one
21
+ # or more attributes (which may also be ComplexExpressions, forming
22
+ # a tree). This class is the backbone of the blockless filter support in
23
+ # Sequel.
24
+ #
25
+ # This is an abstract class that is not that useful by itself. The
26
+ # subclasses BooleanExpression, NumericExpression, and StringExpression
27
+ # define the behavior of the DSL via operators.
28
+ class ComplexExpression < Expression
29
+ # A hash of the opposite for each operator symbol, used for inverting
30
+ # objects.
31
+ OPERTATOR_INVERSIONS = {:AND => :OR, :OR => :AND, :< => :>=, :> => :<=,
32
+ :<= => :>, :>= => :<, :'=' => :'!=' , :'!=' => :'=', :LIKE => :'NOT LIKE',
33
+ :'NOT LIKE' => :LIKE, :~ => :'!~', :'!~' => :~, :IN => :'NOT IN',
34
+ :'NOT IN' => :IN, :IS => :'IS NOT', :'IS NOT' => :IS, :'~*' => :'!~*',
35
+ :'!~*' => :'~*', :NOT => :NOOP, :NOOP => :NOT, :ILIKE => :'NOT ILIKE',
36
+ :'NOT ILIKE'=>:ILIKE}
37
+
38
+ # Mathematical Operators used in NumericMethods
39
+ MATHEMATICAL_OPERATORS = [:+, :-, :/, :*]
40
+
41
+ # Mathematical Operators used in NumericMethods
42
+ BITWISE_OPERATORS = [:&, :|, :^, :<<, :>>]
43
+
44
+ # Inequality Operators used in InequalityMethods
45
+ INEQUALITY_OPERATORS = [:<, :>, :<=, :>=]
46
+
47
+ # Hash of ruby operator symbols to SQL operators, used in BooleanMethods
48
+ BOOLEAN_OPERATOR_METHODS = {:& => :AND, :| =>:OR}
49
+
50
+ # Operator symbols that take exactly two arguments
51
+ TWO_ARITY_OPERATORS = [:'=', :'!=', :IS, :'IS NOT', :LIKE, :'NOT LIKE', \
52
+ :~, :'!~', :'~*', :'!~*', :IN, :'NOT IN', :ILIKE, :'NOT ILIKE'] + \
53
+ INEQUALITY_OPERATORS + BITWISE_OPERATORS
54
+
55
+ # Operator symbols that take one or more arguments
56
+ N_ARITY_OPERATORS = [:AND, :OR, :'||'] + MATHEMATICAL_OPERATORS
57
+
58
+ # Operator symbols that take one argument
59
+ ONE_ARITY_OPERATORS = [:NOT, :NOOP, :'B~']
60
+
61
+ # An array of args for this object
62
+ attr_reader :args
63
+
64
+ # The operator symbol for this object
65
+ attr_reader :op
66
+
67
+ # Set the operator symbol and arguments for this object to the ones given.
68
+ # Convert all args that are hashes or arrays with all two pairs to ComplexExpressions.
69
+ # Raise an error if the operator doesn't allow boolean input and a boolean argument is given.
70
+ # Raise an error if the wrong number of arguments for a given operator is used.
71
+ def initialize(op, *args)
72
+ args.collect! do |a|
73
+ case a
74
+ when Hash
75
+ a.sql_expr
76
+ when Array
77
+ a.all_two_pairs? ? a.sql_expr : a
78
+ else
79
+ a
80
+ end
81
+ end
82
+ case op
83
+ when *N_ARITY_OPERATORS
84
+ raise(Error, "The #{op} operator requires at least 1 argument") unless args.length >= 1
85
+ when *TWO_ARITY_OPERATORS
86
+ raise(Error, "The #{op} operator requires precisely 2 arguments") unless args.length == 2
87
+ when *ONE_ARITY_OPERATORS
88
+ raise(Error, "The #{op} operator requires a single argument") unless args.length == 1
89
+ else
90
+ raise(Error, "Invalid operator #{op}")
91
+ end
92
+ @op = op
93
+ @args = args
94
+ end
95
+
96
+ # Delegate the creation of the resulting SQL to the given dataset,
97
+ # since it may be database dependent.
98
+ def to_s(ds)
99
+ ds.complex_expression_sql(@op, @args)
100
+ end
101
+ end
102
+
103
+ # The base class for expressions that can be used in multiple places in
104
+ # the SQL query.
105
+ class GenericExpression < Expression
106
+ end
107
+
108
+ # The base class for expressions that are specific and can only be used
109
+ # in a certain place in the SQL query (ordering, selecting).
110
+ class SpecificExpression < Expression
111
+ end
112
+
113
+ ### Modules ###
114
+
115
+ # Methods the create aliased identifiers
116
+ module AliasMethods
117
+ # Create an SQL column alias of the receiving column to the given alias.
118
+ def as(aliaz)
119
+ AliasedExpression.new(self, aliaz)
120
+ end
121
+ end
122
+
123
+ # This defines the bitwise methods &, |, ^, ~, <<, and >>. Because these
124
+ # methods overlap with the standard BooleanMethods methods, and they only
125
+ # make sense for numbers, they are only included in NumericExpression.
126
+ module BitwiseMethods
127
+ ComplexExpression::BITWISE_OPERATORS.each do |o|
128
+ define_method(o) do |ce|
129
+ case ce
130
+ when NumericExpression
131
+ NumericExpression.new(o, self, ce)
132
+ when ComplexExpression
133
+ raise(Sequel::Error, "cannot apply #{o} to a non-numeric expression")
134
+ else
135
+ NumericExpression.new(o, self, ce)
136
+ end
137
+ end
138
+ end
139
+
140
+ # Do the bitwise compliment of the self
141
+ def ~
142
+ NumericExpression.new(:'B~', self)
143
+ end
144
+ end
145
+
146
+ # This module includes the methods that are defined on objects that can be
147
+ # used in a boolean context in SQL (Symbol, LiteralString, SQL::Function,
148
+ # and SQL::BooleanExpression).
149
+ #
150
+ # This defines the ~ (NOT), & (AND), and | (OR) methods.
151
+ module BooleanMethods
152
+ # Create a new BooleanExpression with NOT, representing the inversion of whatever self represents.
153
+ def ~
154
+ BooleanExpression.invert(self)
155
+ end
156
+
157
+ ComplexExpression::BOOLEAN_OPERATOR_METHODS.each do |m, o|
158
+ define_method(m) do |ce|
159
+ case ce
160
+ when BooleanExpression
161
+ BooleanExpression.new(o, self, ce)
162
+ when ComplexExpression
163
+ raise(Sequel::Error, "cannot apply #{o} to a non-boolean expression")
164
+ else
165
+ BooleanExpression.new(o, self, ce)
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ # Holds methods that are used to cast objects to differen SQL types.
172
+ module CastMethods
173
+ # Cast the reciever to the given SQL type
174
+ def cast(sql_type)
175
+ IrregularFunction.new(:cast, self, :AS, sql_type.to_s.lit)
176
+ end
177
+ alias_method :cast_as, :cast
178
+
179
+ # Cast the reciever to the given SQL type (or integer if none given),
180
+ # and return the result as a NumericExpression.
181
+ def cast_numeric(sql_type = nil)
182
+ cast(sql_type || :integer).sql_number
183
+ end
184
+
185
+ # Cast the reciever to the given SQL type (or text if none given),
186
+ # and return the result as a StringExpression, so you can use +
187
+ # directly on the result for SQL string concatenation.
188
+ def cast_string(sql_type = nil)
189
+ cast(sql_type || :text).sql_string
190
+ end
191
+ end
192
+
193
+ # Includes a method that returns Identifiers.
194
+ module IdentifierMethods
195
+ # Return self wrapped as an identifier.
196
+ def identifier
197
+ Identifier.new(self)
198
+ end
199
+ end
200
+
201
+ # This module includes the methods that are defined on objects that can be
202
+ # used in a numeric or string context in SQL (Symbol, LiteralString,
203
+ # SQL::Function, and SQL::StringExpression).
204
+ #
205
+ # This defines the >, <, >=, and <= methods.
206
+ module InequalityMethods
207
+ ComplexExpression::INEQUALITY_OPERATORS.each do |o|
208
+ define_method(o) do |ce|
209
+ case ce
210
+ when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
211
+ raise(Error, "cannot apply #{o} to a boolean expression")
212
+ else
213
+ BooleanExpression.new(o, self, ce)
214
+ end
215
+ end
216
+ end
217
+ end
218
+
219
+ # This module augments the default initalize method for the
220
+ # ComplexExpression subclass it is included in, so that
221
+ # attempting to use boolean input when initializing a NumericExpression
222
+ # or StringExpression results in an error.
223
+ module NoBooleanInputMethods
224
+ # Raise an Error if one of the args would be boolean in an SQL
225
+ # context, otherwise call super.
226
+ def initialize(op, *args)
227
+ args.each do |a|
228
+ case a
229
+ when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
230
+ raise(Error, "cannot apply #{op} to a boolean expression")
231
+ end
232
+ end
233
+ super
234
+ end
235
+ end
236
+
237
+ # This module includes the methods that are defined on objects that can be
238
+ # used in a numeric context in SQL (Symbol, LiteralString, SQL::Function,
239
+ # and SQL::NumericExpression).
240
+ #
241
+ # This defines the +, -, *, and / methods.
242
+ module NumericMethods
243
+ ComplexExpression::MATHEMATICAL_OPERATORS.each do |o|
244
+ define_method(o) do |ce|
245
+ case ce
246
+ when NumericExpression
247
+ NumericExpression.new(o, self, ce)
248
+ when ComplexExpression
249
+ raise(Sequel::Error, "cannot apply #{o} to a non-numeric expression")
250
+ else
251
+ NumericExpression.new(o, self, ce)
252
+ end
253
+ end
254
+ end
255
+ end
256
+
257
+ # Methods that create OrderedExpressions, used for sorting by columns
258
+ # or more complex expressions.
259
+ module OrderMethods
260
+ # Mark the receiving SQL column as sorting in a descending fashion.
261
+ def desc
262
+ OrderedExpression.new(self)
263
+ end
264
+
265
+ # Mark the receiving SQL column as sorting in an ascending fashion (generally a no-op).
266
+ def asc
267
+ OrderedExpression.new(self, false)
268
+ end
269
+ end
270
+
271
+ # Methods that created QualifiedIdentifiers, used for qualifying column
272
+ # names with a table or table names with a schema.
273
+ module QualifyingMethods
274
+ # Qualify the current object with the given table/schema.
275
+ def qualify(ts)
276
+ QualifiedIdentifier.new(ts, self)
277
+ end
278
+ end
279
+
280
+ # This module includes the methods that are defined on objects that can be
281
+ # used in a numeric context in SQL (Symbol, LiteralString, SQL::Function,
282
+ # and SQL::StringExpression).
283
+ #
284
+ # This defines the like (LIKE) method, used for pattern matching.
285
+ module StringMethods
286
+ # Create a BooleanExpression case insensitive pattern match of self
287
+ # with the given patterns. See StringExpression.like.
288
+ def ilike(*ces)
289
+ StringExpression.like(self, *(ces << {:case_insensitive=>true}))
290
+ end
291
+
292
+ # Create a BooleanExpression case sensitive pattern match of self with
293
+ # the given patterns. See StringExpression.like.
294
+ def like(*ces)
295
+ StringExpression.like(self, *ces)
296
+ end
297
+ end
298
+
299
+ # This module is included in StringExpression and can be included elsewhere
300
+ # to allow the use of the + operator to represent concatenation of SQL
301
+ # Strings:
302
+ #
303
+ # :x.sql_string + :y => # SQL: x || y
304
+ module StringConcatenationMethods
305
+ def +(ce)
306
+ StringExpression.new(:'||', self, ce)
307
+ end
308
+ end
309
+
310
+ ### Modules that include other modules ###
311
+
312
+ # This module includes other Sequel::SQL::*Methods modules and is
313
+ # included in other classes that are could be either booleans,
314
+ # strings, or numbers. It also adds three methods so that
315
+ # can specify behavior in case one of the operator methods has
316
+ # been overridden (such as Symbol#/).
317
+ #
318
+ # For example, if Symbol#/ is overridden to produce a string (for
319
+ # example, to make file system path creation easier), the
320
+ # following code will not do what you want:
321
+ #
322
+ # :price/10 > 100
323
+ #
324
+ # In that case, you need to do the following:
325
+ #
326
+ # :price.sql_number/10 > 100
327
+ module ComplexExpressionMethods
328
+ include BooleanMethods
329
+ include NumericMethods
330
+ include StringMethods
331
+ include InequalityMethods
332
+
333
+ # Extract a datetime_part (e.g. year, month) from self:
334
+ #
335
+ # :date.extract(:year) # SQL: extract(year FROM date)
336
+ #
337
+ # Also has the benefit of returning the result as a
338
+ # NumericExpression instead of a generic ComplexExpression.
339
+ def extract(datetime_part)
340
+ IrregularFunction.new(:extract, datetime_part.to_s.lit, :FROM, self).sql_number
341
+ end
342
+
343
+ # Return a BooleanExpression representation of self.
344
+ def sql_boolean
345
+ BooleanExpression.new(:NOOP, self)
346
+ end
347
+
348
+ # Return a NumericExpression representation of self.
349
+ def sql_number
350
+ NumericExpression.new(:NOOP, self)
351
+ end
352
+
353
+ # Return a StringExpression representation of self.
354
+ def sql_string
355
+ StringExpression.new(:NOOP, self)
356
+ end
357
+ end
358
+
359
+ module SpecificExpressionMethods
360
+ include AliasMethods
361
+ include CastMethods
362
+ include OrderMethods
363
+ end
364
+
365
+ module GenericExpressionMethods
366
+ include SpecificExpressionMethods
367
+ include ComplexExpressionMethods
368
+ end
369
+
370
+ class ComplexExpression
371
+ include SpecificExpressionMethods
372
+ end
373
+
374
+ class GenericExpression
375
+ include GenericExpressionMethods
376
+ end
377
+
378
+ ### Classes ###
379
+
380
+ # Represents an aliasing of an expression/column to a given name.
381
+ class AliasedExpression < SpecificExpression
382
+ # The expression to alias
383
+ attr_reader :expression
384
+
385
+ # The alias to use for the expression, not alias since that is
386
+ # a keyword in ruby.
387
+ attr_reader :aliaz
388
+
389
+ # Create an object with the given expression and alias.
390
+ def initialize(expression, aliaz)
391
+ @expression, @aliaz = expression, aliaz
392
+ end
393
+
394
+ # Delegate the creation of the resulting SQL to the given dataset,
395
+ # since it may be database dependent.
396
+ def to_s(ds)
397
+ ds.aliased_expression_sql(self)
398
+ end
399
+ end
400
+
401
+ # Blob is used to represent binary data in the Ruby environment that is
402
+ # stored as a blob type in the database. In PostgreSQL, the blob type is
403
+ # called bytea. Sequel represents binary data as a Blob object because
404
+ # certain database engines, such as PostgreSQL, require binary data to be
405
+ # escaped.
406
+ class Blob < ::String
407
+ # return self.
408
+ def to_blob
409
+ self
410
+ end
411
+ end
412
+
413
+ # Subclass of ComplexExpression where the expression results
414
+ # in a boolean value in SQL.
415
+ class BooleanExpression < ComplexExpression
416
+ include BooleanMethods
417
+
418
+ # Take pairs of values (e.g. a hash or array of arrays of two pairs)
419
+ # and converts it to a BooleanExpression. The operator and args
420
+ # used depends on the case of the right (2nd) argument:
421
+ #
422
+ # * 0..10 - left >= 0 AND left <= 10
423
+ # * [1,2] - left IN (1,2)
424
+ # * nil - left IS NULL
425
+ # * /as/ - left ~ 'as'
426
+ # * :blah - left = blah
427
+ # * 'blah' - left = 'blah'
428
+ #
429
+ # If multiple arguments are given, they are joined with the op given (AND
430
+ # by default, OR possible). If negate is set to true,
431
+ # all subexpressions are inverted before used. Therefore, the following
432
+ # expressions are equivalent:
433
+ #
434
+ # ~from_value_pairs(hash)
435
+ # from_value_pairs(hash, :OR, true)
436
+ def self.from_value_pairs(pairs, op=:AND, negate=false)
437
+ pairs = pairs.collect do |l,r|
438
+ ce = case r
439
+ when Range
440
+ new(:AND, new(:>=, l, r.begin), new(r.exclude_end? ? :< : :<=, l, r.end))
441
+ when Array, ::Sequel::Dataset
442
+ new(:IN, l, r)
443
+ when NilClass
444
+ new(:IS, l, r)
445
+ when Regexp
446
+ StringExpression.like(l, r)
447
+ else
448
+ new(:'=', l, r)
449
+ end
450
+ negate ? invert(ce) : ce
451
+ end
452
+ pairs.length == 1 ? pairs.at(0) : new(op, *pairs)
453
+ end
454
+
455
+ # Invert the expression, if possible. If the expression cannot
456
+ # be inverted, raise an error. An inverted expression should match everything that the
457
+ # uninverted expression did not match, and vice-versa.
458
+ def self.invert(ce)
459
+ case ce
460
+ when BooleanExpression
461
+ case op = ce.op
462
+ when :AND, :OR
463
+ BooleanExpression.new(OPERTATOR_INVERSIONS[op], *ce.args.collect{|a| BooleanExpression.invert(a)})
464
+ else
465
+ BooleanExpression.new(OPERTATOR_INVERSIONS[op], *ce.args.dup)
466
+ end
467
+ when ComplexExpression
468
+ raise(Sequel::Error, "operator #{ce.op} cannot be inverted")
469
+ else
470
+ BooleanExpression.new(:NOT, ce)
471
+ end
472
+ end
473
+ end
474
+
475
+ # Represents an SQL CASE expression, used for conditions.
476
+ class CaseExpression < GenericExpression
477
+ # An array of all two pairs with the first element specifying the
478
+ # condition and the second element specifying the result.
479
+ attr_reader :conditions
480
+
481
+ # The default value if no conditions are true
482
+ attr_reader :default
483
+
484
+ # Create an object with the given conditions and
485
+ # default value.
486
+ def initialize(conditions, default)
487
+ raise(Sequel::Error, 'CaseExpression conditions must be an array with all_two_pairs') unless Array === conditions and conditions.all_two_pairs?
488
+ @conditions, @default = conditions, default
489
+ end
490
+
491
+ # Delegate the creation of the resulting SQL to the given dataset,
492
+ # since it may be database dependent.
493
+ def to_s(ds)
494
+ ds.case_expression_sql(self)
495
+ end
496
+ end
497
+
498
+ # Represents all columns in a given table, table.* in SQL
499
+ class ColumnAll < SpecificExpression
500
+ # The table containing the columns being selected
501
+ attr_reader :table
502
+
503
+ # Create an object with the given table
504
+ def initialize(table)
505
+ @table = table
506
+ end
507
+
508
+ # ColumnAll expressions are considered equivalent if they
509
+ # have the same class and string representation
510
+ def ==(x)
511
+ x.class == self.class && @table == x.table
512
+ end
513
+
514
+ # Delegate the creation of the resulting SQL to the given dataset,
515
+ # since it may be database dependent.
516
+ def to_s(ds)
517
+ ds.column_all_sql(self)
518
+ end
519
+ end
520
+
521
+ # Represents an SQL function call.
522
+ class Function < GenericExpression
523
+ # The array of arguments to pass to the function (may be blank)
524
+ attr_reader :args
525
+
526
+ # The SQL function to call
527
+ attr_reader :f
528
+
529
+ # Set the attributes to the given arguments
530
+ def initialize(f, *args)
531
+ @f, @args = f, args
532
+ end
533
+
534
+ # Functions are considered equivalent if they
535
+ # have the same class, function, and arguments.
536
+ def ==(x)
537
+ x.class == self.class && @f == x.f && @args == x.args
538
+ end
539
+
540
+ # Delegate the creation of the resulting SQL to the given dataset,
541
+ # since it may be database dependent.
542
+ def to_s(ds)
543
+ ds.function_sql(self)
544
+ end
545
+ end
546
+
547
+ # Represents an identifier (column or table). Can be used
548
+ # to specify a Symbol with multiple underscores should not be
549
+ # split, or for creating an identifier without using a symbol.
550
+ class Identifier < GenericExpression
551
+ include QualifyingMethods
552
+
553
+ # The table and column to reference
554
+ attr_reader :value
555
+
556
+ # Set the value to the given argument
557
+ def initialize(value)
558
+ @value = value
559
+ end
560
+
561
+ # Delegate the creation of the resulting SQL to the given dataset,
562
+ # since it may be database dependent.
563
+ def to_s(ds)
564
+ ds.quote_identifier(@value)
565
+ end
566
+ end
567
+
568
+ # IrregularFunction is used for the SQL EXTRACT and CAST functions,
569
+ # which don't use regular function calling syntax. The IrregularFunction
570
+ # replaces the commas the regular function uses with a custom
571
+ # join string.
572
+ #
573
+ # This shouldn't be used directly, see CastMethods#cast and
574
+ # ComplexExpressionMethods#extract.
575
+ class IrregularFunction < Function
576
+ # The arguments to pass to the function (may be blank)
577
+ attr_reader :arg1, :arg2
578
+
579
+ # The SQL function to call
580
+ attr_reader :f
581
+
582
+ # The literal string to use in place of a comma to join arguments
583
+ attr_reader :joiner
584
+
585
+ # Set the attributes to the given arguments
586
+ def initialize(f, arg1, joiner, arg2)
587
+ @f, @arg1, @joiner, @arg2 = f, arg1, joiner, arg2
588
+ end
589
+
590
+ # Delegate the creation of the resulting SQL to the given dataset,
591
+ # since it may be database dependent.
592
+ def to_s(ds)
593
+ ds.irregular_function_sql(self)
594
+ end
595
+ end
596
+
597
+ # Represents an SQL JOIN clause, used for joining tables.
598
+ class JoinClause < SpecificExpression
599
+ # The type of join to do
600
+ attr_reader :join_type
601
+
602
+ # The actual table to join
603
+ attr_reader :table
604
+
605
+ # The table alias to use for the join, if any
606
+ attr_reader :table_alias
607
+
608
+ # Create an object with the given conditions and
609
+ # default value.
610
+ def initialize(join_type, table, table_alias = nil)
611
+ @join_type, @table, @table_alias = join_type, table, table_alias
612
+ end
613
+
614
+ # Delegate the creation of the resulting SQL to the given dataset,
615
+ # since it may be database dependent.
616
+ def to_s(ds)
617
+ ds.join_clause_sql(self)
618
+ end
619
+ end
620
+
621
+ # Represents an SQL JOIN table ON conditions clause.
622
+ class JoinOnClause < JoinClause
623
+ # The conditions for the join
624
+ attr_reader :on
625
+
626
+ # Create an object with the given conditions and
627
+ # default value.
628
+ def initialize(on, *args)
629
+ @on = on
630
+ super(*args)
631
+ end
632
+
633
+ # Delegate the creation of the resulting SQL to the given dataset,
634
+ # since it may be database dependent.
635
+ def to_s(ds)
636
+ ds.join_on_clause_sql(self)
637
+ end
638
+ end
639
+
640
+ # Represents an SQL JOIN table USING (columns) clause.
641
+ class JoinUsingClause < JoinClause
642
+ # The columns that appear both tables that should be equal
643
+ # for the conditions to match.
644
+ attr_reader :using
645
+
646
+ # Create an object with the given conditions and
647
+ # default value.
648
+ def initialize(using, *args)
649
+ @using = using
650
+ super(*args)
651
+ end
652
+
653
+ # Delegate the creation of the resulting SQL to the given dataset,
654
+ # since it may be database dependent.
655
+ def to_s(ds)
656
+ ds.join_using_clause_sql(self)
657
+ end
658
+ end
659
+
660
+ # Subclass of ComplexExpression where the expression results
661
+ # in a numeric value in SQL.
662
+ class NumericExpression < ComplexExpression
663
+ include BitwiseMethods
664
+ include NumericMethods
665
+ include InequalityMethods
666
+ include NoBooleanInputMethods
667
+ end
668
+
669
+ # Represents a column/expression to order the result set by.
670
+ class OrderedExpression < SpecificExpression
671
+ # The expression to order the result set by.
672
+ attr_reader :expression
673
+
674
+ # Whether the expression should order the result set in a descending manner
675
+ attr_reader :descending
676
+
677
+ # Set the expression and descending attributes to the given values.
678
+ def initialize(expression, descending = true)
679
+ @expression, @descending = expression, descending
680
+ end
681
+
682
+ # Delegate the creation of the resulting SQL to the given dataset,
683
+ # since it may be database dependent.
684
+ def to_s(ds)
685
+ ds.ordered_expression_sql(self)
686
+ end
687
+ end
688
+
689
+ # Represents a qualified (column with table) reference. Used when
690
+ # joining tables to disambiguate columns.
691
+ class QualifiedIdentifier < GenericExpression
692
+ # The table and column to reference
693
+ attr_reader :table, :column
694
+
695
+ # Set the attributes to the given arguments
696
+ def initialize(table, column)
697
+ @table, @column = table, column
698
+ end
699
+
700
+ # Delegate the creation of the resulting SQL to the given dataset,
701
+ # since it may be database dependent.
702
+ def to_s(ds)
703
+ ds.qualified_identifier_sql(self)
704
+ end
705
+ end
706
+
707
+ # Subclass of ComplexExpression where the expression results
708
+ # in a text/string/varchar value in SQL.
709
+ class StringExpression < ComplexExpression
710
+ include StringMethods
711
+ include StringConcatenationMethods
712
+ include InequalityMethods
713
+ include NoBooleanInputMethods
714
+
715
+ # Creates a SQL pattern match exprssion. left (l) is the SQL string we
716
+ # are matching against, and ces are the patterns we are matching.
717
+ # The match succeeds if any of the patterns match (SQL OR). Patterns
718
+ # can be given as strings or regular expressions. Strings will cause
719
+ # the SQL LIKE operator to be used, and should be supported by most
720
+ # databases. Regular expressions will probably only work on MySQL
721
+ # and PostgreSQL, and SQL regular expression syntax is not fully compatible
722
+ # with ruby regular expression syntax, so be careful if using regular
723
+ # expressions.
724
+ #
725
+ # The pattern match will be case insensitive if the last argument is a hash
726
+ # with a key of :case_insensitive that is not false or nil. Also,
727
+ # if a case insensitive regular expression is used (//i), that particular
728
+ # pattern which will always be case insensitive.
729
+ def self.like(l, *ces)
730
+ case_insensitive = ces.extract_options![:case_insensitive]
731
+ ces.collect! do |ce|
732
+ op, expr = Regexp === ce ? [ce.casefold? || case_insensitive ? :'~*' : :~, ce.source] : [case_insensitive ? :ILIKE : :LIKE, ce.to_s]
733
+ BooleanExpression.new(op, l, expr)
734
+ end
735
+ ces.length == 1 ? ces.at(0) : BooleanExpression.new(:OR, *ces)
736
+ end
737
+ end
738
+
739
+ # Represents an SQL array access, with multiple possible arguments.
740
+ class Subscript < GenericExpression
741
+ # The SQL array column
742
+ attr_reader :f
743
+
744
+ # The array of subscripts to use (should be an array of numbers)
745
+ attr_reader :sub
746
+
747
+ # Set the attributes to the given arguments
748
+ def initialize(f, sub)
749
+ @f, @sub = f, sub
750
+ end
751
+
752
+ # Create a new subscript appending the given subscript(s)
753
+ # the the current array of subscripts.
754
+ def |(sub)
755
+ Subscript.new(@f, @sub + Array(sub))
756
+ end
757
+
758
+ # Delegate the creation of the resulting SQL to the given dataset,
759
+ # since it may be database dependent.
760
+ def to_s(ds)
761
+ ds.subscript_sql(self)
762
+ end
763
+ end
764
+
765
+ if RUBY_VERSION >= '1.9.0'
766
+ class VirtualRow < BasicObject
767
+ end
768
+ else
769
+ class VirtualRow
770
+ (instance_methods - %w"__id__ __send__ instance_eval == equal?").each{|m| undef_method(m)}
771
+ end
772
+ end
773
+
774
+ # An instance of this class is yielded to the block supplied to filter.
775
+ # Useful if another library also defines the operator methods that
776
+ # Sequel defines for symbols.
777
+ #
778
+ # Examples:
779
+ #
780
+ # ds = DB[:t]
781
+ # ds.filter{|r| r.name < 2} # SELECT * FROM t WHERE (name < 2)
782
+ # ds.filter{|r| r.table__column + 1 < 2} # SELECT * FROM t WHERE ((table.column + 1) < 2)
783
+ # ds.filter{|r| r.is_active(1, 'arg2')} # SELECT * FROM t WHERE is_active(1, 'arg2')
784
+ class VirtualRow
785
+ # Can return Identifiers, QualifiedIdentifiers, or Functions:
786
+ #
787
+ # * Function - returned if any arguments are supplied, using the method name
788
+ # as the function name, and the arguments as the function arguments.
789
+ # * QualifiedIdentifier - returned if the method name contains __, with the
790
+ # table being the part before __, and the column being the part after.
791
+ # * Identifier - returned otherwise, using the method name.
792
+ def method_missing(m, *args)
793
+ if args.empty?
794
+ table, column = m.to_s.split('__', 2)
795
+ column ? QualifiedIdentifier.new(table, column) : Identifier.new(m)
796
+ else
797
+ Function.new(m, *args)
798
+ end
799
+ end
800
+ end
801
+ end
802
+
803
+ # LiteralString is used to represent literal SQL expressions. A
804
+ # LiteralString is copied verbatim into an SQL statement. Instances of
805
+ # LiteralString can be created by calling String#lit.
806
+ # LiteralStrings can use all of the SQL::ColumnMethods and the
807
+ # SQL::ComplexExpressionMethods.
808
+ class LiteralString < ::String
809
+ include SQL::OrderMethods
810
+ include SQL::ComplexExpressionMethods
811
+ end
812
+ end