sequel_core 2.0.1 → 2.1.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 (40) hide show
  1. data/CHANGELOG +50 -0
  2. data/README +1 -2
  3. data/Rakefile +1 -1
  4. data/bin/sequel +26 -11
  5. data/doc/dataset_filtering.rdoc +9 -2
  6. data/lib/sequel_core/adapters/adapter_skeleton.rb +0 -2
  7. data/lib/sequel_core/adapters/mysql.rb +11 -97
  8. data/lib/sequel_core/adapters/odbc_mssql.rb +1 -1
  9. data/lib/sequel_core/adapters/oracle.rb +1 -1
  10. data/lib/sequel_core/adapters/postgres.rb +33 -17
  11. data/lib/sequel_core/adapters/sqlite.rb +1 -1
  12. data/lib/sequel_core/connection_pool.rb +12 -35
  13. data/lib/sequel_core/core_ext.rb +5 -19
  14. data/lib/sequel_core/core_sql.rb +17 -6
  15. data/lib/sequel_core/database.rb +14 -2
  16. data/lib/sequel_core/dataset/callback.rb +0 -3
  17. data/lib/sequel_core/dataset/convenience.rb +4 -3
  18. data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +0 -21
  19. data/lib/sequel_core/dataset/sequelizer.rb +42 -43
  20. data/lib/sequel_core/dataset/sql.rb +121 -62
  21. data/lib/sequel_core/dataset.rb +20 -4
  22. data/lib/sequel_core/deprecated.rb +0 -6
  23. data/lib/sequel_core/migration.rb +4 -0
  24. data/lib/sequel_core/object_graph.rb +8 -6
  25. data/lib/sequel_core/pretty_table.rb +1 -1
  26. data/lib/sequel_core/schema/sql.rb +2 -0
  27. data/lib/sequel_core/sql.rb +393 -153
  28. data/lib/sequel_core.rb +22 -7
  29. data/spec/adapters/mysql_spec.rb +11 -7
  30. data/spec/adapters/postgres_spec.rb +32 -4
  31. data/spec/blockless_filters_spec.rb +33 -6
  32. data/spec/connection_pool_spec.rb +18 -16
  33. data/spec/core_ext_spec.rb +0 -13
  34. data/spec/core_sql_spec.rb +59 -13
  35. data/spec/database_spec.rb +5 -5
  36. data/spec/dataset_spec.rb +167 -55
  37. data/spec/object_graph_spec.rb +9 -4
  38. data/spec/sequelizer_spec.rb +8 -17
  39. data/spec/spec_helper.rb +4 -3
  40. metadata +2 -2
@@ -103,7 +103,16 @@ module Sequel
103
103
  ]
104
104
  }
105
105
 
106
- attr_accessor :db, :opts, :row_proc
106
+ # The database that corresponds to this dataset
107
+ attr_accessor :db
108
+
109
+ # The hash of options for this dataset, keys are symbols.
110
+ attr_accessor :opts
111
+
112
+ # The row_proc for this database, should be a Proc that takes
113
+ # a single hash argument and returns the object you want to
114
+ # fetch_rows to return.
115
+ attr_accessor :row_proc
107
116
 
108
117
  # Whether to quote identifiers for this dataset
109
118
  attr_writer :quote_identifiers
@@ -158,8 +167,8 @@ module Sequel
158
167
 
159
168
  # Return the dataset as a column with the given alias, so it can be used in the
160
169
  # SELECT clause. This dataset should result in a single row and a single column.
161
- def as(a)
162
- ::Sequel::SQL::ColumnExpr.new(self, 'AS', a)
170
+ def as(aliaz)
171
+ ::Sequel::SQL::AliasedExpression.new(self, aliaz)
163
172
  end
164
173
 
165
174
  # Returns an array with all records in the dataset. If a block is given,
@@ -178,7 +187,7 @@ module Sequel
178
187
  def clone(opts = {})
179
188
  c = super()
180
189
  c.opts = @opts.merge(opts)
181
- c.instance_variable_set(:@columns, nil) unless (opts.keys & COLUMN_CHANGE_OPTS).empty?
190
+ c.instance_variable_set(:@columns, nil) if c.options_overlap(COLUMN_CHANGE_OPTS)
182
191
  c
183
192
  end
184
193
 
@@ -424,6 +433,13 @@ module Sequel
424
433
  # Add the mutation methods via metaprogramming
425
434
  def_mutation_method(*MUTATION_METHODS)
426
435
 
436
+ protected
437
+
438
+ # Return true if the dataset has a non-nil value for any key in opts.
439
+ def options_overlap(opts)
440
+ !(@opts.collect{|k,v| k unless v.nil?}.compact & opts).empty?
441
+ end
442
+
427
443
  private
428
444
 
429
445
  # Modify the receiver with the results of sending the meth, args, and block
@@ -22,11 +22,5 @@ module Sequel
22
22
  caller.each{|c| @dms.puts(c)} if @pt
23
23
  end
24
24
  end
25
-
26
- # Formats the message with a message that it will be removed in Sequel 2.0.
27
- # This is the method that is added to the classes that include Sequel::Deprecation.
28
- def deprecate(meth, message = nil)
29
- ::Sequel::Deprecation.deprecate("#{meth} is deprecated, and will be removed in Sequel 2.0.#{" #{message}." if message}")
30
- end
31
25
  end
32
26
  end
@@ -22,6 +22,10 @@ module Sequel
22
22
  #
23
23
  # DB = Sequel.open ('sqlite://mydb')
24
24
  # CreateSessions.apply(DB, :up)
25
+ #
26
+ # See Sequel::Schema::Generator for the syntax to use for creating tables,
27
+ # and Sequel::Schema::AlterTableGenerator for the syntax to use when
28
+ # altering existing tables.
25
29
  class Migration
26
30
  # Creates a new instance of the migration and sets the @db attribute.
27
31
  def initialize(db)
@@ -38,11 +38,11 @@ module Sequel
38
38
  # used more than once.
39
39
  # * :join_type - The type of join to use (passed to join_table). Defaults to
40
40
  # :left_outer.
41
- # * :select - Whether to select the columns from the you are joining, and
42
- # include them as a separate hash in the output. With this set to false,
43
- # it is like simply joining the tables. This is designed to be used for
44
- # many_to_many join tables, where the columns are just foreign keys to primary
45
- # keys in other tables.
41
+ # * :select - An array of columns to select. When not used, selects
42
+ # all columns in the given dataset. When set to false, selects no
43
+ # columns and is like simply joining the tables, though graph keeps
44
+ # some metadata about join that makes it important to use graph instead
45
+ # of join.
46
46
  def graph(dataset, join_conditions, options = {})
47
47
  # Allow the use of a model, dataset, or symbol as the first argument
48
48
  # Find the table name/dataset based on the argument
@@ -112,12 +112,14 @@ module Sequel
112
112
  select = opts[:select]
113
113
  column_aliases = graph[:column_aliases]
114
114
  ca_num = graph[:column_alias_num]
115
+ # Which columns to add to the result set
116
+ cols = options[:select] || dataset.columns
115
117
  # If the column hasn't been used yet, don't alias it.
116
118
  # If it has been used, try table_column.
117
119
  # If that has been used, try table_column_N
118
120
  # using the next value of N that we know hasn't been
119
121
  # used
120
- dataset.columns.each do |column|
122
+ cols.each do |column|
121
123
  col_alias, c = if column_aliases[column]
122
124
  tc = :"#{table_alias}_#{column}"
123
125
  if column_aliases[tc]
@@ -65,7 +65,7 @@ module Sequel
65
65
  '+' << columns.map {|c| '-' * sizes[c]}.join('+') << '+'
66
66
  end
67
67
 
68
- metaprivate :column_sizes, :data_line, :format_cell, :header_line, :separator_line
68
+ private_class_method :column_sizes, :data_line, :format_cell, :header_line, :separator_line
69
69
  end
70
70
  end
71
71
 
@@ -241,6 +241,8 @@ module Sequel
241
241
  :boolean
242
242
  when /\A(real|float|double( precision)?)\z/
243
243
  :float
244
+ when /\A(numeric|decimal|money)\z/
245
+ :decimal
244
246
  end
245
247
  end
246
248
 
@@ -1,94 +1,22 @@
1
- # This file holds classes and modules under Sequel that are related to SQL
2
- # creation.
3
-
4
1
  module Sequel
5
2
  # The SQL module holds classes whose instances represent SQL fragments.
6
3
  # It also holds modules that are included in core ruby classes that
7
4
  # make Sequel a friendly DSL.
8
5
  module SQL
9
- # Holds methods that should be called on columns only.
10
- module ColumnMethods
11
- AS = 'AS'.freeze
12
- DESC = 'DESC'.freeze
13
- ASC = 'ASC'.freeze
14
-
15
- # Create an SQL column alias of the receiving column to the given alias.
16
- def as(a)
17
- ColumnExpr.new(self, AS, a)
18
- end
19
-
20
- # Mark the receiving SQL column as sorting in a descending fashion.
21
- def desc
22
- ColumnExpr.new(self, DESC)
23
- end
24
-
25
- # Mark the receiving SQL column as sorting in an ascending fashion (generally a no-op).
26
- def asc
27
- ColumnExpr.new(self, ASC)
28
- end
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.
29
10
 
30
- # Cast the reciever to the given SQL type
31
- def cast_as(t)
32
- t = t.to_s.lit if t.is_a?(Symbol)
33
- Sequel::SQL::Function.new(:cast, self.as(t))
34
- end
35
- end
36
-
37
11
  # Base class for all SQL fragments
38
12
  class Expression
39
- include ColumnMethods
40
-
41
13
  # Returns self, because SQL::Expression already acts like
42
14
  # LiteralString.
43
15
  def lit
44
16
  self
45
17
  end
46
18
  end
47
-
48
- # Represents all columns in a given table, table.* in SQL
49
- class ColumnAll < Expression
50
- # The table containing the columns being selected
51
- attr_reader :table
52
-
53
- # Create an object with the given table
54
- def initialize(table)
55
- @table = table
56
- end
57
-
58
- # ColumnAll expressions are considered equivalent if they
59
- # have the same class and string representation
60
- def ==(x)
61
- x.class == self.class && @table == x.table
62
- end
63
-
64
- # Delegate the creation of the resulting SQL to the given dataset,
65
- # since it may be database dependent.
66
- def to_s(ds)
67
- ds.column_all_sql(self)
68
- end
69
- end
70
-
71
- # Represents a generic column expression, used for specifying order
72
- # and aliasing of columns.
73
- class ColumnExpr < Expression
74
- # Created readers for the left, operator, and right expression.
75
- attr_reader :l, :op, :r
76
19
 
77
- # Sets the attributes for the object to those given.
78
- # The right (r) is not required, it is used when aliasing.
79
- # The left (l) usually specifies the column name, and the
80
- # operator (op) is usually 'ASC', 'DESC', or 'AS'.
81
- def initialize(l, op, r = nil)
82
- @l, @op, @r = l, op, r
83
- end
84
-
85
- # Delegate the creation of the resulting SQL to the given dataset,
86
- # since it may be database dependent.
87
- def to_s(ds)
88
- ds.column_expr_sql(self)
89
- end
90
- end
91
-
92
20
  # Represents a complex SQL expression, with a given operator and one
93
21
  # or more attributes (which may also be ComplexExpressions, forming
94
22
  # a tree). This class is the backbone of the blockless filter support in
@@ -110,6 +38,9 @@ module Sequel
110
38
  # Mathematical Operators used in NumericMethods
111
39
  MATHEMATICAL_OPERATORS = [:+, :-, :/, :*]
112
40
 
41
+ # Mathematical Operators used in NumericMethods
42
+ BITWISE_OPERATORS = [:&, :|, :^, :<<, :>>]
43
+
113
44
  # Inequality Operators used in InequalityMethods
114
45
  INEQUALITY_OPERATORS = [:<, :>, :<=, :>=]
115
46
 
@@ -118,13 +49,14 @@ module Sequel
118
49
 
119
50
  # Operator symbols that take exactly two arguments
120
51
  TWO_ARITY_OPERATORS = [:'=', :'!=', :IS, :'IS NOT', :LIKE, :'NOT LIKE', \
121
- :~, :'!~', :'~*', :'!~*', :IN, :'NOT IN', :ILIKE, :'NOT ILIKE'] + INEQUALITY_OPERATORS
52
+ :~, :'!~', :'~*', :'!~*', :IN, :'NOT IN', :ILIKE, :'NOT ILIKE'] + \
53
+ INEQUALITY_OPERATORS + BITWISE_OPERATORS
122
54
 
123
55
  # Operator symbols that take one or more arguments
124
56
  N_ARITY_OPERATORS = [:AND, :OR, :'||'] + MATHEMATICAL_OPERATORS
125
57
 
126
58
  # Operator symbols that take one argument
127
- ONE_ARITY_OPERATORS = [:NOT, :NOOP]
59
+ ONE_ARITY_OPERATORS = [:NOT, :NOOP, :'B~']
128
60
 
129
61
  # An array of args for this object
130
62
  attr_reader :args
@@ -168,6 +100,56 @@ module Sequel
168
100
  end
169
101
  end
170
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
+ case self
143
+ when NumericExpression
144
+ NumericExpression.new(:'B~', self)
145
+ when ComplexExpression
146
+ raise(Sequel::Error, "cannot apply #{o} to a non-numeric expression")
147
+ else
148
+ NumericExpression.new(:'B~', self)
149
+ end
150
+ end
151
+ end
152
+
171
153
  # This module includes the methods that are defined on objects that can be
172
154
  # used in a boolean context in SQL (Symbol, LiteralString, SQL::Function,
173
155
  # and SQL::BooleanExpression).
@@ -193,6 +175,64 @@ module Sequel
193
175
  end
194
176
  end
195
177
 
178
+ # Holds methods that are used to cast objects to differen SQL types.
179
+ module CastMethods
180
+ # Cast the reciever to the given SQL type
181
+ def cast(sql_type)
182
+ IrregularFunction.new(:cast, self, :AS, sql_type.to_s.lit)
183
+ end
184
+ alias_method :cast_as, :cast
185
+
186
+ # Cast the reciever to the given SQL type (or integer if none given),
187
+ # and return the result as a NumericExpression.
188
+ def cast_numeric(sql_type = nil)
189
+ cast(sql_type || :integer).sql_number
190
+ end
191
+
192
+ # Cast the reciever to the given SQL type (or text if none given),
193
+ # and return the result as a StringExpression, so you can use +
194
+ # directly on the result for SQL string concatenation.
195
+ def cast_string(sql_type = nil)
196
+ cast(sql_type || :text).sql_string
197
+ end
198
+ end
199
+
200
+ # This module includes the methods that are defined on objects that can be
201
+ # used in a numeric or string context in SQL (Symbol, LiteralString,
202
+ # SQL::Function, and SQL::StringExpression).
203
+ #
204
+ # This defines the >, <, >=, and <= methods.
205
+ module InequalityMethods
206
+ ComplexExpression::INEQUALITY_OPERATORS.each do |o|
207
+ define_method(o) do |ce|
208
+ case ce
209
+ when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
210
+ raise(Error, "cannot apply #{o} to a boolean expression")
211
+ else
212
+ BooleanExpression.new(o, self, ce)
213
+ end
214
+ end
215
+ end
216
+ end
217
+
218
+ # This module augments the default initalize method for the
219
+ # ComplexExpression subclass it is included in, so that
220
+ # attempting to use boolean input when initializing a NumericExpression
221
+ # or StringExpression results in an error.
222
+ module NoBooleanInputMethods
223
+ # Raise an Error if one of the args would be boolean in an SQL
224
+ # context, otherwise call super.
225
+ def initialize(op, *args)
226
+ args.each do |a|
227
+ case a
228
+ when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
229
+ raise(Error, "cannot apply #{op} to a boolean expression")
230
+ end
231
+ end
232
+ super
233
+ end
234
+ end
235
+
196
236
  # This module includes the methods that are defined on objects that can be
197
237
  # used in a numeric context in SQL (Symbol, LiteralString, SQL::Function,
198
238
  # and SQL::NumericExpression).
@@ -213,6 +253,29 @@ module Sequel
213
253
  end
214
254
  end
215
255
 
256
+ # Methods that create OrderedExpressions, used for sorting by columns
257
+ # or more complex expressions.
258
+ module OrderMethods
259
+ # Mark the receiving SQL column as sorting in a descending fashion.
260
+ def desc
261
+ OrderedExpression.new(self)
262
+ end
263
+
264
+ # Mark the receiving SQL column as sorting in an ascending fashion (generally a no-op).
265
+ def asc
266
+ OrderedExpression.new(self, false)
267
+ end
268
+ end
269
+
270
+ # Methods that created QualifiedIdentifiers, used for qualifying column
271
+ # names with a table or table names with a schema.
272
+ module QualifyingMethods
273
+ # Qualify the current object with the given table/schema.
274
+ def qualify(ts)
275
+ QualifiedIdentifier.new(ts, self)
276
+ end
277
+ end
278
+
216
279
  # This module includes the methods that are defined on objects that can be
217
280
  # used in a numeric context in SQL (Symbol, LiteralString, SQL::Function,
218
281
  # and SQL::StringExpression).
@@ -243,41 +306,7 @@ module Sequel
243
306
  end
244
307
  end
245
308
 
246
- # This module includes the methods that are defined on objects that can be
247
- # used in a numeric or string context in SQL (Symbol, LiteralString,
248
- # SQL::Function, and SQL::StringExpression).
249
- #
250
- # This defines the >, <, >=, and <= methods.
251
- module InequalityMethods
252
- ComplexExpression::INEQUALITY_OPERATORS.each do |o|
253
- define_method(o) do |ce|
254
- case ce
255
- when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
256
- raise(Error, "cannot apply #{o} to a boolean expression")
257
- else
258
- BooleanExpression.new(o, self, ce)
259
- end
260
- end
261
- end
262
- end
263
-
264
- # This module augments the default initalize method for the
265
- # ComplexExpression subclass it is included in, so that
266
- # attempting to use boolean input when initializing a NumericExpression
267
- # or StringExpression results in an error.
268
- module NoBooleanInputMethods
269
- # Raise an Error if one of the args would be boolean in an SQL
270
- # context, otherwise call super.
271
- def initialize(op, *args)
272
- args.each do |a|
273
- case a
274
- when BooleanExpression, TrueClass, FalseClass, NilClass, Hash, Array
275
- raise(Error, "cannot apply #{op} to a boolean expression")
276
- end
277
- end
278
- super
279
- end
280
- end
309
+ ### Modules that include other modules ###
281
310
 
282
311
  # This module includes other Sequel::SQL::*Methods modules and is
283
312
  # included in other classes that are could be either booleans,
@@ -300,6 +329,16 @@ module Sequel
300
329
  include StringMethods
301
330
  include InequalityMethods
302
331
 
332
+ # Extract a datetime_part (e.g. year, month) from self:
333
+ #
334
+ # :date.extract(:year) # SQL: extract(year FROM date)
335
+ #
336
+ # Also has the benefit of returning the result as a
337
+ # NumericExpression instead of a generic ComplexExpression.
338
+ def extract(datetime_part)
339
+ IrregularFunction.new(:extract, datetime_part.to_s.lit, :FROM, self).sql_number
340
+ end
341
+
303
342
  # Return a BooleanExpression representation of self.
304
343
  def sql_boolean
305
344
  BooleanExpression.new(:NOOP, self)
@@ -316,6 +355,48 @@ module Sequel
316
355
  end
317
356
  end
318
357
 
358
+ module SpecificExpressionMethods
359
+ include AliasMethods
360
+ include CastMethods
361
+ include OrderMethods
362
+ end
363
+
364
+ module GenericExpressionMethods
365
+ include SpecificExpressionMethods
366
+ include ComplexExpressionMethods
367
+ end
368
+
369
+ class ComplexExpression
370
+ include SpecificExpressionMethods
371
+ end
372
+
373
+ class GenericExpression
374
+ include GenericExpressionMethods
375
+ end
376
+
377
+ ### Classes ###
378
+
379
+ # Represents an aliasing of an expression/column to a given name.
380
+ class AliasedExpression < SpecificExpression
381
+ # The expression to alias
382
+ attr_reader :expression
383
+
384
+ # The alias to use for the expression, not alias since that is
385
+ # a keyword in ruby.
386
+ attr_reader :aliaz
387
+
388
+ # default value.
389
+ def initialize(expression, aliaz)
390
+ @expression, @aliaz = expression, aliaz
391
+ end
392
+
393
+ # Delegate the creation of the resulting SQL to the given dataset,
394
+ # since it may be database dependent.
395
+ def to_s(ds)
396
+ ds.aliased_expression_sql(self)
397
+ end
398
+ end
399
+
319
400
  # Subclass of ComplexExpression where the expression results
320
401
  # in a boolean value in SQL.
321
402
  class BooleanExpression < ComplexExpression
@@ -378,49 +459,54 @@ module Sequel
378
459
  end
379
460
  end
380
461
 
381
- # Subclass of ComplexExpression where the expression results
382
- # in a numeric value in SQL.
383
- class NumericExpression < ComplexExpression
384
- include NumericMethods
385
- include InequalityMethods
386
- include NoBooleanInputMethods
462
+ # Represents an SQL CASE expression, used for conditions.
463
+ class CaseExpression < GenericExpression
464
+ # An array of all two pairs with the first element specifying the
465
+ # condition and the second element specifying the result.
466
+ attr_reader :conditions
467
+
468
+ # The default value if no conditions are true
469
+ attr_reader :default
470
+
471
+ # Create an object with the given conditions and
472
+ # default value.
473
+ def initialize(conditions, default)
474
+ raise(Sequel::Error, 'CaseExpression conditions must be an array with all_two_pairs') unless Array === conditions and conditions.all_two_pairs?
475
+ @conditions, @default = conditions, default
476
+ end
477
+
478
+ # Delegate the creation of the resulting SQL to the given dataset,
479
+ # since it may be database dependent.
480
+ def to_s(ds)
481
+ ds.case_expression_sql(self)
482
+ end
387
483
  end
388
484
 
389
- # Subclass of ComplexExpression where the expression results
390
- # in a text/string/varchar value in SQL.
391
- class StringExpression < ComplexExpression
392
- include StringMethods
393
- include StringConcatenationMethods
394
- include InequalityMethods
395
- include NoBooleanInputMethods
396
-
397
- # Creates a SQL pattern match exprssion. left (l) is the SQL string we
398
- # are matching against, and ces are the patterns we are matching.
399
- # The match succeeds if any of the patterns match (SQL OR). Patterns
400
- # can be given as strings or regular expressions. Strings will cause
401
- # the SQL LIKE operator to be used, and should be supported by most
402
- # databases. Regular expressions will probably only work on MySQL
403
- # and PostgreSQL, and SQL regular expression syntax is not fully compatible
404
- # with ruby regular expression syntax, so be careful if using regular
405
- # expressions.
406
- #
407
- # The pattern match will be case insensitive if the last argument is a hash
408
- # with a key of :case_insensitive that is not false or nil. Also,
409
- # if a case insensitive regular expression is used (//i), that particular
410
- # pattern which will always be case insensitive.
411
- def self.like(l, *ces)
412
- case_insensitive = ces.extract_options![:case_insensitive]
413
- ces.collect! do |ce|
414
- op, expr = Regexp === ce ? [ce.casefold? || case_insensitive ? :'~*' : :~, ce.source] : [case_insensitive ? :ILIKE : :LIKE, ce.to_s]
415
- BooleanExpression.new(op, l, expr)
416
- end
417
- ces.length == 1 ? ces.at(0) : BooleanExpression.new(:OR, *ces)
485
+ # Represents all columns in a given table, table.* in SQL
486
+ class ColumnAll < SpecificExpression
487
+ # The table containing the columns being selected
488
+ attr_reader :table
489
+
490
+ # Create an object with the given table
491
+ def initialize(table)
492
+ @table = table
493
+ end
494
+
495
+ # ColumnAll expressions are considered equivalent if they
496
+ # have the same class and string representation
497
+ def ==(x)
498
+ x.class == self.class && @table == x.table
499
+ end
500
+
501
+ # Delegate the creation of the resulting SQL to the given dataset,
502
+ # since it may be database dependent.
503
+ def to_s(ds)
504
+ ds.column_all_sql(self)
418
505
  end
419
506
  end
420
507
 
421
508
  # Represents an SQL function call.
422
- class Function < Expression
423
- include ComplexExpressionMethods
509
+ class Function < GenericExpression
424
510
  # The array of arguments to pass to the function (may be blank)
425
511
  attr_reader :args
426
512
 
@@ -445,9 +531,130 @@ module Sequel
445
531
  end
446
532
  end
447
533
 
534
+ # IrregularFunction is used for the SQL EXTRACT and CAST functions,
535
+ # which don't use regular function calling syntax. The IrregularFunction
536
+ # replaces the commas the regular function uses with a custom
537
+ # join string.
538
+ #
539
+ # This shouldn't be used directly, see CastMethods#cast and
540
+ # ComplexExpressionMethods#extract.
541
+ class IrregularFunction < Function
542
+ # The arguments to pass to the function (may be blank)
543
+ attr_reader :arg1, :arg2
544
+
545
+ # The SQL function to call
546
+ attr_reader :f
547
+
548
+ # The literal string to use in place of a comma to join arguments
549
+ attr_reader :joiner
550
+
551
+ # Set the attributes to the given arguments
552
+ def initialize(f, arg1, joiner, arg2)
553
+ @f, @arg1, @joiner, @arg2 = f, arg1, joiner, arg2
554
+ end
555
+
556
+ # Delegate the creation of the resulting SQL to the given dataset,
557
+ # since it may be database dependent.
558
+ def to_s(ds)
559
+ ds.irregular_function_sql(self)
560
+ end
561
+ end
562
+
563
+ # Represents an SQL JOIN clause, used for joining tables.
564
+ class JoinClause < SpecificExpression
565
+ # The type of join to do
566
+ attr_reader :join_type
567
+
568
+ # The actual table to join
569
+ attr_reader :table
570
+
571
+ # The table alias to use for the join, if any
572
+ attr_reader :table_alias
573
+
574
+ # Create an object with the given conditions and
575
+ # default value.
576
+ def initialize(join_type, table, table_alias = nil)
577
+ @join_type, @table, @table_alias = join_type, table, table_alias
578
+ end
579
+
580
+ # Delegate the creation of the resulting SQL to the given dataset,
581
+ # since it may be database dependent.
582
+ def to_s(ds)
583
+ ds.join_clause_sql(self)
584
+ end
585
+ end
586
+
587
+ # Represents an SQL JOIN table ON conditions clause.
588
+ class JoinOnClause < JoinClause
589
+ # The conditions for the join
590
+ attr_reader :on
591
+
592
+ # Create an object with the given conditions and
593
+ # default value.
594
+ def initialize(on, *args)
595
+ @on = on
596
+ super(*args)
597
+ end
598
+
599
+ # Delegate the creation of the resulting SQL to the given dataset,
600
+ # since it may be database dependent.
601
+ def to_s(ds)
602
+ ds.join_on_clause_sql(self)
603
+ end
604
+ end
605
+
606
+ # Represents an SQL JOIN table USING (columns) clause.
607
+ class JoinUsingClause < JoinClause
608
+ # The columns that appear both tables that should be equal
609
+ # for the conditions to match.
610
+ attr_reader :using
611
+
612
+ # Create an object with the given conditions and
613
+ # default value.
614
+ def initialize(using, *args)
615
+ @using = using
616
+ super(*args)
617
+ end
618
+
619
+ # Delegate the creation of the resulting SQL to the given dataset,
620
+ # since it may be database dependent.
621
+ def to_s(ds)
622
+ ds.join_using_clause_sql(self)
623
+ end
624
+ end
625
+
626
+ # Subclass of ComplexExpression where the expression results
627
+ # in a numeric value in SQL.
628
+ class NumericExpression < ComplexExpression
629
+ include BitwiseMethods
630
+ include NumericMethods
631
+ include InequalityMethods
632
+ include NoBooleanInputMethods
633
+ end
634
+
635
+ # Represents a column/expression to order the result set by.
636
+ class OrderedExpression < SpecificExpression
637
+ # The expression to order the result set by.
638
+ attr_reader :expression
639
+
640
+ # Whether the expression should order the result set in a descening manner
641
+ attr_reader :descending
642
+
643
+ # default value.
644
+ def initialize(expression, descending = true)
645
+ @expression, @descending = expression, descending
646
+ end
647
+
648
+ # Delegate the creation of the resulting SQL to the given dataset,
649
+ # since it may be database dependent.
650
+ def to_s(ds)
651
+ ds.ordered_expression_sql(self)
652
+ end
653
+ end
654
+
448
655
  # Represents a qualified (column with table) reference. Used when
449
656
  # joining tables to disambiguate columns.
450
- class QualifiedColumnRef < Expression
657
+ class QualifiedIdentifier < GenericExpression
451
658
  # The table and column to reference
452
659
  attr_reader :table, :column
453
660
 
@@ -459,12 +666,44 @@ module Sequel
459
666
  # Delegate the creation of the resulting SQL to the given dataset,
460
667
  # since it may be database dependent.
461
668
  def to_s(ds)
462
- ds.qualified_column_ref_sql(self)
669
+ ds.qualified_identifier_sql(self)
463
670
  end
464
671
  end
465
672
 
673
+ # Subclass of ComplexExpression where the expression results
674
+ # in a text/string/varchar value in SQL.
675
+ class StringExpression < ComplexExpression
676
+ include StringMethods
677
+ include StringConcatenationMethods
678
+ include InequalityMethods
679
+ include NoBooleanInputMethods
680
+
681
+ # Creates a SQL pattern match exprssion. left (l) is the SQL string we
682
+ # are matching against, and ces are the patterns we are matching.
683
+ # The match succeeds if any of the patterns match (SQL OR). Patterns
684
+ # can be given as strings or regular expressions. Strings will cause
685
+ # the SQL LIKE operator to be used, and should be supported by most
686
+ # databases. Regular expressions will probably only work on MySQL
687
+ # and PostgreSQL, and SQL regular expression syntax is not fully compatible
688
+ # with ruby regular expression syntax, so be careful if using regular
689
+ # expressions.
690
+ #
691
+ # The pattern match will be case insensitive if the last argument is a hash
692
+ # with a key of :case_insensitive that is not false or nil. Also,
693
+ # if a case insensitive regular expression is used (//i), that particular
694
+ # pattern which will always be case insensitive.
695
+ def self.like(l, *ces)
696
+ case_insensitive = ces.extract_options![:case_insensitive]
697
+ ces.collect! do |ce|
698
+ op, expr = Regexp === ce ? [ce.casefold? || case_insensitive ? :'~*' : :~, ce.source] : [case_insensitive ? :ILIKE : :LIKE, ce.to_s]
699
+ BooleanExpression.new(op, l, expr)
700
+ end
701
+ ces.length == 1 ? ces.at(0) : BooleanExpression.new(:OR, *ces)
702
+ end
703
+ end
704
+
466
705
  # Represents an SQL array access, with multiple possible arguments.
467
- class Subscript < Expression
706
+ class Subscript < GenericExpression
468
707
  # The SQL array column
469
708
  attr_reader :f
470
709
 
@@ -496,6 +735,7 @@ module Sequel
496
735
  # LiteralStrings can use all of the SQL::ColumnMethods and the
497
736
  # SQL::ComplexExpressionMethods.
498
737
  class LiteralString < ::String
738
+ include SQL::OrderMethods
499
739
  include SQL::ComplexExpressionMethods
500
740
  end
501
741
  end