sequel 2.9.0 → 2.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/CHANGELOG +56 -0
  2. data/{README → README.rdoc} +85 -57
  3. data/Rakefile +10 -5
  4. data/bin/sequel +7 -16
  5. data/doc/advanced_associations.rdoc +5 -17
  6. data/doc/cheat_sheet.rdoc +18 -20
  7. data/doc/dataset_filtering.rdoc +8 -32
  8. data/doc/schema.rdoc +20 -0
  9. data/lib/sequel_core.rb +35 -1
  10. data/lib/sequel_core/adapters/ado.rb +1 -1
  11. data/lib/sequel_core/adapters/db2.rb +2 -2
  12. data/lib/sequel_core/adapters/dbi.rb +2 -11
  13. data/lib/sequel_core/adapters/do.rb +205 -0
  14. data/lib/sequel_core/adapters/do/mysql.rb +38 -0
  15. data/lib/sequel_core/adapters/do/postgres.rb +92 -0
  16. data/lib/sequel_core/adapters/do/sqlite.rb +31 -0
  17. data/lib/sequel_core/adapters/firebird.rb +298 -0
  18. data/lib/sequel_core/adapters/informix.rb +10 -1
  19. data/lib/sequel_core/adapters/jdbc.rb +78 -19
  20. data/lib/sequel_core/adapters/jdbc/h2.rb +69 -0
  21. data/lib/sequel_core/adapters/jdbc/mysql.rb +10 -0
  22. data/lib/sequel_core/adapters/jdbc/postgresql.rb +7 -3
  23. data/lib/sequel_core/adapters/mysql.rb +53 -77
  24. data/lib/sequel_core/adapters/odbc.rb +1 -1
  25. data/lib/sequel_core/adapters/openbase.rb +1 -1
  26. data/lib/sequel_core/adapters/oracle.rb +2 -2
  27. data/lib/sequel_core/adapters/postgres.rb +16 -14
  28. data/lib/sequel_core/adapters/shared/mysql.rb +44 -9
  29. data/lib/sequel_core/adapters/shared/oracle.rb +4 -5
  30. data/lib/sequel_core/adapters/shared/postgres.rb +86 -82
  31. data/lib/sequel_core/adapters/shared/sqlite.rb +39 -24
  32. data/lib/sequel_core/adapters/sqlite.rb +11 -1
  33. data/lib/sequel_core/connection_pool.rb +10 -2
  34. data/lib/sequel_core/core_sql.rb +13 -3
  35. data/lib/sequel_core/database.rb +131 -30
  36. data/lib/sequel_core/database/schema.rb +5 -5
  37. data/lib/sequel_core/dataset.rb +31 -6
  38. data/lib/sequel_core/dataset/convenience.rb +11 -11
  39. data/lib/sequel_core/dataset/query.rb +2 -2
  40. data/lib/sequel_core/dataset/sql.rb +6 -6
  41. data/lib/sequel_core/exceptions.rb +4 -0
  42. data/lib/sequel_core/migration.rb +4 -4
  43. data/lib/sequel_core/schema/generator.rb +19 -3
  44. data/lib/sequel_core/schema/sql.rb +24 -20
  45. data/lib/sequel_core/sql.rb +13 -16
  46. data/lib/sequel_core/version.rb +11 -0
  47. data/lib/sequel_model.rb +2 -0
  48. data/lib/sequel_model/base.rb +2 -2
  49. data/lib/sequel_model/hooks.rb +46 -7
  50. data/lib/sequel_model/record.rb +11 -9
  51. data/lib/sequel_model/schema.rb +1 -1
  52. data/lib/sequel_model/validations.rb +72 -61
  53. data/spec/adapters/firebird_spec.rb +371 -0
  54. data/spec/adapters/mysql_spec.rb +118 -62
  55. data/spec/adapters/oracle_spec.rb +5 -5
  56. data/spec/adapters/postgres_spec.rb +33 -18
  57. data/spec/adapters/sqlite_spec.rb +2 -2
  58. data/spec/integration/dataset_test.rb +3 -3
  59. data/spec/integration/schema_test.rb +55 -5
  60. data/spec/integration/spec_helper.rb +11 -0
  61. data/spec/integration/type_test.rb +59 -16
  62. data/spec/sequel_core/connection_pool_spec.rb +14 -0
  63. data/spec/sequel_core/core_sql_spec.rb +24 -14
  64. data/spec/sequel_core/database_spec.rb +96 -11
  65. data/spec/sequel_core/dataset_spec.rb +97 -37
  66. data/spec/sequel_core/expression_filters_spec.rb +51 -40
  67. data/spec/sequel_core/object_graph_spec.rb +2 -2
  68. data/spec/sequel_core/schema_generator_spec.rb +31 -6
  69. data/spec/sequel_core/schema_spec.rb +25 -9
  70. data/spec/sequel_core/spec_helper.rb +4 -1
  71. data/spec/sequel_core/version_spec.rb +7 -0
  72. data/spec/sequel_model/associations_spec.rb +1 -1
  73. data/spec/sequel_model/hooks_spec.rb +68 -13
  74. data/spec/sequel_model/model_spec.rb +4 -4
  75. data/spec/sequel_model/record_spec.rb +22 -0
  76. data/spec/sequel_model/spec_helper.rb +2 -1
  77. data/spec/sequel_model/validations_spec.rb +107 -7
  78. metadata +15 -5
@@ -55,15 +55,15 @@ module Sequel
55
55
  # end
56
56
  #
57
57
  # See Schema::Generator.
58
- def create_table(name, generator=nil, &block)
59
- generator ||= Schema::Generator.new(self, &block)
60
- create_table_sql_list(name, *generator.create_info).flatten.each {|sql| execute_ddl(sql)}
58
+ def create_table(name, options={}, &block)
59
+ options = {:generator=>options} if options.is_a?(Schema::Generator)
60
+ create_table_sql_list(name, *((options[:generator] || Schema::Generator.new(self, &block)).create_info << options)).flatten.each {|sql| execute_ddl(sql)}
61
61
  end
62
62
 
63
63
  # Forcibly creates a table. If the table already exists it is dropped.
64
- def create_table!(name, generator=nil, &block)
64
+ def create_table!(name, options={}, &block)
65
65
  drop_table(name) rescue nil
66
- create_table(name, generator, &block)
66
+ create_table(name, options, &block)
67
67
  end
68
68
 
69
69
  # Creates a view, replacing it if it already exists:
@@ -71,6 +71,12 @@ module Sequel
71
71
 
72
72
  # The database that corresponds to this dataset
73
73
  attr_accessor :db
74
+
75
+ # Set the method to call on identifiers going into the database for this dataset
76
+ attr_accessor :identifier_input_method
77
+
78
+ # Set the method to call on identifiers coming the database for this dataset
79
+ attr_accessor :identifier_output_method
74
80
 
75
81
  # The hash of options for this dataset, keys are symbols.
76
82
  attr_accessor :opts
@@ -83,9 +89,6 @@ module Sequel
83
89
  # fetch_rows to return.
84
90
  attr_accessor :row_proc
85
91
 
86
- # Whether to upcase identifiers for this dataset
87
- attr_writer :upcase_identifiers
88
-
89
92
  # Constructs a new instance of a dataset with an associated database and
90
93
  # options. Datasets are usually constructed by invoking Database methods:
91
94
  #
@@ -100,7 +103,8 @@ module Sequel
100
103
  def initialize(db, opts = nil)
101
104
  @db = db
102
105
  @quote_identifiers = db.quote_identifiers? if db.respond_to?(:quote_identifiers?)
103
- @upcase_identifiers = db.upcase_identifiers? if db.respond_to?(:upcase_identifiers?)
106
+ @identifier_input_method = db.identifier_input_method if db.respond_to?(:identifier_input_method)
107
+ @identifier_output_method = db.identifier_output_method if db.respond_to?(:identifier_output_method)
104
108
  @opts = opts || {}
105
109
  @row_proc = nil
106
110
  @transform = nil
@@ -221,7 +225,7 @@ module Sequel
221
225
  # Inserts values into the associated table. The returned value is generally
222
226
  # the value of the primary key for the inserted row, but that is adapter dependent.
223
227
  def insert(*values)
224
- execute_dui(insert_sql(*values))
228
+ execute_insert(insert_sql(*values))
225
229
  end
226
230
 
227
231
  # Returns a string representation of the dataset including the class name
@@ -419,9 +423,13 @@ module Sequel
419
423
  end
420
424
  end
421
425
 
426
+ def upcase_identifiers=(v)
427
+ @identifier_input_method = v ? :upcase : nil
428
+ end
429
+
422
430
  # Whether this dataset upcases identifiers.
423
431
  def upcase_identifiers?
424
- @upcase_identifiers
432
+ @identifier_input_method == :upcase
425
433
  end
426
434
 
427
435
  # Updates values for the dataset. The returned value is generally the
@@ -468,6 +476,17 @@ module Sequel
468
476
  def execute_dui(sql, opts={}, &block)
469
477
  @db.execute_dui(sql, {:server=>@opts[:server] || :default}.merge(opts), &block)
470
478
  end
479
+
480
+ # Execute the given SQL on the database using execute_insert.
481
+ def execute_insert(sql, opts={}, &block)
482
+ @db.execute_insert(sql, {:server=>@opts[:server] || :default}.merge(opts), &block)
483
+ end
484
+
485
+ # Modify the identifier returned from the database based on the
486
+ # identifier_output_method.
487
+ def input_identifier(v)
488
+ (i = identifier_input_method) ? v.to_s.send(i) : v.to_s
489
+ end
471
490
 
472
491
  # Modify the receiver with the results of sending the meth, args, and block
473
492
  # to the receiver and merging the options of the resulting dataset into
@@ -477,5 +496,11 @@ module Sequel
477
496
  @opts.merge!(copy.opts)
478
497
  self
479
498
  end
499
+
500
+ # Modify the identifier returned from the database based on the
501
+ # identifier_output_method.
502
+ def output_identifier(v)
503
+ (i = identifier_output_method) ? v.to_s.send(i).to_sym : v.to_sym
504
+ end
480
505
  end
481
506
  end
@@ -1,7 +1,7 @@
1
1
  module Sequel
2
2
  class Dataset
3
3
  COMMA_SEPARATOR = ', '.freeze
4
- COUNT_OF_ALL_AS_COUNT = :count['*'.lit].as(:count)
4
+ COUNT_OF_ALL_AS_COUNT = SQL::Function.new(:count, '*'.lit).as(:count)
5
5
 
6
6
  # Returns the first record matching the conditions.
7
7
  def [](*conditions)
@@ -16,7 +16,7 @@ module Sequel
16
16
 
17
17
  # Returns the average value for the given column.
18
18
  def avg(column)
19
- get(:avg[column])
19
+ get(SQL::Function.new(:avg, column))
20
20
  end
21
21
 
22
22
  # Returns true if no records exists in the dataset
@@ -40,11 +40,11 @@ module Sequel
40
40
  # ds.first(:id=>2) => {:id=>2}
41
41
  # ds.first("id = 3") => {:id=>3}
42
42
  # ds.first("id = ?", 4) => {:id=>4}
43
- # ds.first{:id > 2} => {:id=>5}
44
- # ds.order(:id).first{:id > 2} => {:id=>3}
45
- # ds.first{:id > 2} => {:id=>5}
46
- # ds.first("id > ?", 4){:id < 6) => {:id=>5}
47
- # ds.order(:id).first(2){:id < 2} => [{:id=>1}]
43
+ # ds.first{|o| o.id > 2} => {:id=>5}
44
+ # ds.order(:id).first{|o| o.id > 2} => {:id=>3}
45
+ # ds.first{|o| o.id > 2} => {:id=>5}
46
+ # ds.first("id > ?", 4){|o| o.id < 6} => {:id=>5}
47
+ # ds.order(:id).first(2){|o| o.id < 2} => [{:id=>1}]
48
48
  def first(*args, &block)
49
49
  ds = block ? filter(&block) : self
50
50
 
@@ -97,12 +97,12 @@ module Sequel
97
97
 
98
98
  # Returns the maximum value for the given column.
99
99
  def max(column)
100
- get(:max[column])
100
+ get(SQL::Function.new(:max, column))
101
101
  end
102
102
 
103
103
  # Returns the minimum value for the given column.
104
104
  def min(column)
105
- get(:min[column])
105
+ get(SQL::Function.new(:min, column))
106
106
  end
107
107
 
108
108
  # Inserts multiple records into the associated table. This method can be
@@ -170,7 +170,7 @@ module Sequel
170
170
  # Returns a Range object made from the minimum and maximum values for the
171
171
  # given column.
172
172
  def range(column)
173
- if r = select(:min[column].as(:v1), :max[column].as(:v2)).first
173
+ if r = select(SQL::Function.new(:min, column).as(:v1), SQL::Function.new(:max, column).as(:v2)).first
174
174
  (r[:v1]..r[:v2])
175
175
  end
176
176
  end
@@ -191,7 +191,7 @@ module Sequel
191
191
 
192
192
  # Returns the sum for the given column.
193
193
  def sum(column)
194
- get(:sum[column])
194
+ get(SQL::Function.new(:sum, column))
195
195
  end
196
196
 
197
197
  # Returns true if the table exists. Will raise an error
@@ -5,13 +5,13 @@ module Sequel
5
5
  #
6
6
  # dataset = DB[:items].query do
7
7
  # select :x, :y, :z
8
- # filter((:x > 1) & (:y > 2))
8
+ # filter{|o| (o.x > 1) & (o.y > 2)}
9
9
  # order :z.desc
10
10
  # end
11
11
  #
12
12
  # Which is the same as:
13
13
  #
14
- # dataset = DB[:items].select(:x, :y, :z).filter((:x > 1) & (:y > 2)).order(:z.desc)
14
+ # dataset = DB[:items].select(:x, :y, :z).filter{|o| (o.x > 1) & (o.y > 2)}.order(:z.desc)
15
15
  #
16
16
  # Note that inside a call to query, you cannot call each, insert, update,
17
17
  # or delete (or any method that calls those), or Sequel will raise an
@@ -76,7 +76,7 @@ module Sequel
76
76
 
77
77
  # Formats a DELETE statement using the given options and dataset options.
78
78
  #
79
- # dataset.filter(:price >= 100).delete_sql #=>
79
+ # dataset.filter{|o| o.price >= 100}.delete_sql #=>
80
80
  # "DELETE FROM items WHERE (price >= 100)"
81
81
  def delete_sql(opts = nil)
82
82
  opts = opts ? @opts.merge(opts) : @opts
@@ -163,13 +163,13 @@ module Sequel
163
163
  # "SELECT * FROM items WHERE price < 100"
164
164
  # dataset.filter(:active).sql #=>
165
165
  # "SELECT * FROM items WHERE :active
166
- # dataset.filter(:price < 100).sql #=>
166
+ # dataset.filter{|o| o.price < 100}.sql #=>
167
167
  # "SELECT * FROM items WHERE (price < 100)"
168
168
  #
169
169
  # Multiple filter calls can be chained for scoping:
170
170
  #
171
171
  # software = dataset.filter(:category => 'software')
172
- # software.filter(price < 100).sql #=>
172
+ # software.filter{|o| o.price < 100}.sql #=>
173
173
  # "SELECT * FROM items WHERE ((category = 'software') AND (price < 100))"
174
174
  #
175
175
  # See doc/dataset_filters.rdoc for more examples and details.
@@ -572,8 +572,8 @@ module Sequel
572
572
  # being quoted, returns name as a string. If identifiers are being quoted
573
573
  # quote the name with quoted_identifier.
574
574
  def quote_identifier(name)
575
- name = name.to_s
576
- name = name.upcase if upcase_identifiers?
575
+ return name if name.is_a?(LiteralString)
576
+ name = input_identifier(name)
577
577
  name = quoted_identifier(name) if quote_identifiers?
578
578
  name
579
579
  end
@@ -590,7 +590,7 @@ module Sequel
590
590
  # should be overridden by subclasses to provide quoting not matching the
591
591
  # SQL standard, such as backtick (used by MySQL and SQLite).
592
592
  def quoted_identifier(name)
593
- "\"#{name}\""
593
+ "\"#{name.to_s.gsub('"', '""')}\""
594
594
  end
595
595
 
596
596
  # Returns a copy of the dataset with the order reversed. If no order is
@@ -31,6 +31,10 @@ module Sequel
31
31
  # Generic error raised by the database adapters, indicating a
32
32
  # problem originating from the database server.
33
33
  class DatabaseError < Error; end
34
+
35
+ # Error raised when the Sequel is unable to connect to the database with the
36
+ # connection parameters it was given.
37
+ class DatabaseConnectionError < DatabaseError; end
34
38
 
35
39
  # Error that should be raised by adapters when they determine that the connection
36
40
  # to the database has been lost. Instructs the connection pool code to
@@ -6,9 +6,9 @@ module Sequel
6
6
  # def up
7
7
  # create_table :sessions do
8
8
  # primary_key :id
9
- # varchar :session_id, :size => 32, :unique => true
10
- # timestamp :created_at
11
- # text :data
9
+ # String :session_id, :size => 32, :unique => true
10
+ # DateTime :created_at
11
+ # text :data
12
12
  # end
13
13
  # end
14
14
  #
@@ -21,7 +21,7 @@ module Sequel
21
21
  # class AlterItems < Sequel::Migration
22
22
  # def up
23
23
  # alter_table :items do
24
- # add_column :category, :text, :default => 'ruby'
24
+ # add_column :category, String, :default => 'ruby'
25
25
  # end
26
26
  # end
27
27
  #
@@ -13,6 +13,10 @@ module Sequel
13
13
  # allowing users to specify column type as a method instead of using
14
14
  # the column method, which makes for a nicer DSL.
15
15
  class Generator
16
+ # Classes specifying generic types that Sequel will convert to database-specific types.
17
+ GENERIC_TYPES=[String, Integer, Fixnum, Bignum, Float, Numeric, BigDecimal,
18
+ Date, DateTime, Time, File, TrueClass, FalseClass]
19
+
16
20
  # Set the database in which to create the table, and evaluate the block
17
21
  # in the context of this object.
18
22
  def initialize(db, &block)
@@ -23,6 +27,16 @@ module Sequel
23
27
  instance_eval(&block) if block
24
28
  end
25
29
 
30
+ # Add a method for each of the given types that creates a column
31
+ # with that type as a constant. Types given should either already
32
+ # be constants/classes or a capitalized string/symbol with the same name
33
+ # as a constant/class.
34
+ def self.add_type_method(*types)
35
+ types.each do |type|
36
+ class_eval "def #{type}(name, opts={}); column(name, #{type}, opts); end"
37
+ end
38
+ end
39
+
26
40
  # Add a unnamed constraint to the DDL, specified by the given block
27
41
  # or args.
28
42
  def check(*args, &block)
@@ -87,10 +101,10 @@ module Sequel
87
101
  when NilClass
88
102
  opts
89
103
  else
90
- raise(Error, "The seconds argument to foreign_key should be a Hash, Symbol, or nil")
104
+ raise(Error, "The second argument to foreign_key should be a Hash, Symbol, or nil")
91
105
  end
92
106
  return composite_foreign_key(name, opts) if name.is_a?(Array)
93
- column(name, :integer, opts)
107
+ column(name, Integer, opts)
94
108
  end
95
109
 
96
110
  # Add a full text index on the given columns to the DDL.
@@ -173,6 +187,8 @@ module Sequel
173
187
  @columns << {:type => :check, :constraint_type => :foreign_key,
174
188
  :name => nil, :columns => columns }.merge(opts)
175
189
  end
190
+
191
+ add_type_method(*GENERIC_TYPES)
176
192
  end
177
193
 
178
194
  # Schema::AlterTableGenerator is an internal class that the user is not expected
@@ -222,7 +238,7 @@ module Sequel
222
238
  # use the composite key syntax even if it is only one column.
223
239
  def add_foreign_key(name, table, opts = {})
224
240
  return add_composite_foreign_key(name, table, opts) if name.is_a?(Array)
225
- add_column(name, :integer, {:table=>table}.merge(opts))
241
+ add_column(name, Integer, {:table=>table}.merge(opts))
226
242
  end
227
243
 
228
244
  # Add a full text index on the given columns to the DDL for the table.
@@ -12,7 +12,11 @@ module Sequel
12
12
  SET_DEFAULT = 'SET DEFAULT'.freeze
13
13
  SET_NULL = 'SET NULL'.freeze
14
14
  TYPES = Hash.new {|h, k| k}
15
- TYPES[:double] = 'double precision'
15
+ TYPES.merge!(:double=>'double precision', String=>'varchar',
16
+ Integer=>'integer', Fixnum=>'integer', Bignum=>'bigint',
17
+ Float=>'double precision', BigDecimal=>'numeric', Numeric=>'numeric',
18
+ Date=>'date', DateTime=>'timestamp', Time=>'timestamp', File=>'blob',
19
+ TrueClass=>'boolean', FalseClass=>'boolean')
16
20
  UNDERSCORE = '_'.freeze
17
21
  UNIQUE = ' UNIQUE'.freeze
18
22
  UNSIGNED = ' UNSIGNED'.freeze
@@ -110,7 +114,7 @@ module Sequel
110
114
  # Array of SQL DDL statements, the first for creating a table with the given
111
115
  # name and column specifications, and the others for specifying indexes on
112
116
  # the table.
113
- def create_table_sql_list(name, columns, indexes = nil)
117
+ def create_table_sql_list(name, columns, indexes = nil, options = {})
114
118
  sql = ["CREATE TABLE #{quote_schema_table(name)} (#{column_list_sql(columns)})"]
115
119
  sql.concat(index_list_sql_list(name, indexes)) if indexes && !indexes.empty?
116
120
  sql
@@ -215,6 +219,8 @@ module Sequel
215
219
  # * :schema - An explicit schema to use. It may also be implicitly provided
216
220
  # via the table name.
217
221
  def schema(table = nil, opts={})
222
+ raise(Error, 'schema parsing is not implemented on this database') unless respond_to?(:schema_parse_table, true)
223
+
218
224
  if table
219
225
  sch, table_name = schema_and_table(table)
220
226
  quoted_name = quote_schema_table(table)
@@ -236,29 +242,20 @@ module Sequel
236
242
  end
237
243
  end
238
244
 
245
+ raise(Error, '#tables does not exist, you must provide a specific table to #schema') if table.nil? && !respond_to?(:tables, true)
246
+
239
247
  @schemas ||= Hash.new do |h,k|
240
248
  quote_name = quote_schema_table(k)
241
249
  h[quote_name] if h.include?(quote_name)
242
250
  end
243
251
 
244
252
  if table_name
245
- if respond_to?(:schema_parse_table, true)
246
- cols = schema_parse_table(table_name, opts)
247
- raise(Error, 'schema parsing returned no columns, table probably doesn\'t exist') if cols.blank?
248
- @schemas[quoted_name] = cols
249
- else
250
- raise Error, 'schema parsing is not implemented on this database'
251
- end
253
+ cols = schema_parse_table(table_name, opts)
254
+ raise(Error, 'schema parsing returned no columns, table probably doesn\'t exist') if cols.blank?
255
+ @schemas[quoted_name] = cols
252
256
  else
253
- if respond_to?(:schema_parse_tables, true)
254
- @schemas.merge!(schema_parse_tables(opts))
255
- elsif respond_to?(:schema_parse_table, true) and respond_to?(:tables, true)
256
- tables.each{|t| @schemas[quote_identifier(t)] = schema_parse_table(t.to_s, opts)}
257
- @schemas
258
- else
259
- @schemas = nil
260
- raise Error, 'schema parsing is not implemented on this database'
261
- end
257
+ tables.each{|t| @schemas[quote_schema_table(t)] = schema_parse_table(t.to_s, opts)}
258
+ @schemas
262
259
  end
263
260
  end
264
261
 
@@ -273,6 +270,12 @@ module Sequel
273
270
  def remove_cached_schema(table)
274
271
  @schemas.delete(quote_schema_table(table)) if @schemas
275
272
  end
273
+
274
+ # Remove the cached schema_utility_dataset, because the identifier
275
+ # quoting has changed.
276
+ def reset_schema_utility_dataset
277
+ @schema_utility_dataset = nil
278
+ end
276
279
 
277
280
  # Match the database's column type to a ruby type via a
278
281
  # regular expression. The following ruby types are supported:
@@ -306,9 +309,10 @@ module Sequel
306
309
 
307
310
  # SQL fragment specifying the type of a given column.
308
311
  def type_literal(column)
309
- column[:size] ||= 255 if column[:type] == :varchar
312
+ type = type_literal_base(column)
313
+ column[:size] ||= 255 if type.to_s == 'varchar'
310
314
  elements = column[:size] || column[:elements]
311
- "#{type_literal_base(column)}#{literal(Array(elements)) if elements}#{UNSIGNED if column[:unsigned]}"
315
+ "#{type}#{literal(Array(elements)) if elements}#{UNSIGNED if column[:unsigned]}"
312
316
  end
313
317
 
314
318
  # SQL fragment specifying the base type of a given column,
@@ -334,11 +334,6 @@ module Sequel
334
334
  #
335
335
  # :price.sql_number/10 > 100
336
336
  module ComplexExpressionMethods
337
- include BooleanMethods
338
- include NumericMethods
339
- include StringMethods
340
- include InequalityMethods
341
-
342
337
  # Extract a datetime_part (e.g. year, month) from self:
343
338
  #
344
339
  # :date.extract(:year) # SQL: extract(year FROM date)
@@ -365,23 +360,21 @@ module Sequel
365
360
  end
366
361
  end
367
362
 
368
- module SpecificExpressionMethods
363
+ class ComplexExpression
369
364
  include AliasMethods
370
365
  include CastMethods
371
366
  include OrderMethods
372
367
  end
373
368
 
374
- module GenericExpressionMethods
375
- include SpecificExpressionMethods
376
- include ComplexExpressionMethods
377
- end
378
-
379
- class ComplexExpression
380
- include SpecificExpressionMethods
381
- end
382
-
383
369
  class GenericExpression
384
- include GenericExpressionMethods
370
+ include AliasMethods
371
+ include CastMethods
372
+ include OrderMethods
373
+ include ComplexExpressionMethods
374
+ include BooleanMethods
375
+ include NumericMethods
376
+ include StringMethods
377
+ include InequalityMethods
385
378
  end
386
379
 
387
380
  ### Classes ###
@@ -864,5 +857,9 @@ module Sequel
864
857
  class LiteralString < ::String
865
858
  include SQL::OrderMethods
866
859
  include SQL::ComplexExpressionMethods
860
+ include SQL::BooleanMethods
861
+ include SQL::NumericMethods
862
+ include SQL::StringMethods
863
+ include SQL::InequalityMethods
867
864
  end
868
865
  end