sequel 2.12.0 → 3.0.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 (91) hide show
  1. data/CHANGELOG +62 -0
  2. data/README.rdoc +3 -3
  3. data/Rakefile +7 -0
  4. data/doc/advanced_associations.rdoc +44 -0
  5. data/doc/release_notes/3.0.0.txt +221 -0
  6. data/lib/sequel/adapters/amalgalite.rb +208 -0
  7. data/lib/sequel/adapters/db2.rb +3 -0
  8. data/lib/sequel/adapters/dbi.rb +9 -0
  9. data/lib/sequel/adapters/do.rb +0 -4
  10. data/lib/sequel/adapters/firebird.rb +16 -18
  11. data/lib/sequel/adapters/informix.rb +5 -3
  12. data/lib/sequel/adapters/jdbc.rb +24 -20
  13. data/lib/sequel/adapters/jdbc/h2.rb +15 -4
  14. data/lib/sequel/adapters/mysql.rb +4 -8
  15. data/lib/sequel/adapters/odbc.rb +0 -4
  16. data/lib/sequel/adapters/oracle.rb +0 -4
  17. data/lib/sequel/adapters/shared/mssql.rb +16 -5
  18. data/lib/sequel/adapters/shared/mysql.rb +87 -86
  19. data/lib/sequel/adapters/shared/oracle.rb +92 -3
  20. data/lib/sequel/adapters/shared/postgres.rb +85 -29
  21. data/lib/sequel/adapters/shared/progress.rb +8 -3
  22. data/lib/sequel/adapters/shared/sqlite.rb +53 -23
  23. data/lib/sequel/adapters/sqlite.rb +4 -7
  24. data/lib/sequel/adapters/utils/unsupported.rb +3 -3
  25. data/lib/sequel/connection_pool.rb +18 -25
  26. data/lib/sequel/core.rb +2 -21
  27. data/lib/sequel/database.rb +60 -44
  28. data/lib/sequel/database/schema_generator.rb +26 -31
  29. data/lib/sequel/database/schema_methods.rb +8 -3
  30. data/lib/sequel/database/schema_sql.rb +114 -28
  31. data/lib/sequel/dataset.rb +14 -41
  32. data/lib/sequel/dataset/convenience.rb +31 -54
  33. data/lib/sequel/dataset/graph.rb +7 -13
  34. data/lib/sequel/dataset/sql.rb +43 -54
  35. data/lib/sequel/extensions/inflector.rb +0 -5
  36. data/lib/sequel/extensions/schema_dumper.rb +238 -0
  37. data/lib/sequel/metaprogramming.rb +0 -20
  38. data/lib/sequel/model.rb +1 -2
  39. data/lib/sequel/model/base.rb +18 -16
  40. data/lib/sequel/model/inflections.rb +6 -9
  41. data/lib/sequel/plugins/caching.rb +0 -6
  42. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  43. data/lib/sequel/sql.rb +2 -0
  44. data/lib/sequel/version.rb +2 -2
  45. data/spec/adapters/firebird_spec.rb +35 -8
  46. data/spec/adapters/mysql_spec.rb +173 -266
  47. data/spec/adapters/oracle_spec.rb +13 -0
  48. data/spec/adapters/postgres_spec.rb +127 -227
  49. data/spec/adapters/sqlite_spec.rb +13 -171
  50. data/spec/core/connection_pool_spec.rb +15 -4
  51. data/spec/core/core_sql_spec.rb +14 -170
  52. data/spec/core/database_spec.rb +50 -132
  53. data/spec/core/dataset_spec.rb +47 -930
  54. data/spec/core/expression_filters_spec.rb +12 -0
  55. data/spec/core/schema_generator_spec.rb +37 -45
  56. data/spec/core/schema_spec.rb +26 -16
  57. data/spec/core/spec_helper.rb +0 -25
  58. data/spec/extensions/inflector_spec.rb +0 -3
  59. data/spec/extensions/schema_dumper_spec.rb +292 -0
  60. data/spec/extensions/serialization_spec.rb +9 -0
  61. data/spec/extensions/single_table_inheritance_spec.rb +6 -1
  62. data/spec/extensions/spec_helper.rb +1 -3
  63. data/spec/extensions/validation_helpers_spec.rb +4 -4
  64. data/spec/integration/database_test.rb +18 -0
  65. data/spec/integration/dataset_test.rb +112 -1
  66. data/spec/integration/eager_loader_test.rb +70 -9
  67. data/spec/integration/prepared_statement_test.rb +2 -2
  68. data/spec/integration/schema_test.rb +76 -27
  69. data/spec/integration/spec_helper.rb +0 -14
  70. data/spec/integration/transaction_test.rb +27 -0
  71. data/spec/model/associations_spec.rb +0 -36
  72. data/spec/model/base_spec.rb +18 -123
  73. data/spec/model/hooks_spec.rb +2 -235
  74. data/spec/model/inflector_spec.rb +15 -115
  75. data/spec/model/model_spec.rb +0 -120
  76. data/spec/model/plugins_spec.rb +0 -70
  77. data/spec/model/record_spec.rb +35 -93
  78. data/spec/model/spec_helper.rb +0 -27
  79. data/spec/model/validations_spec.rb +0 -931
  80. metadata +9 -14
  81. data/lib/sequel/deprecated.rb +0 -593
  82. data/lib/sequel/deprecated_migration.rb +0 -91
  83. data/lib/sequel/model/deprecated.rb +0 -204
  84. data/lib/sequel/model/deprecated_hooks.rb +0 -103
  85. data/lib/sequel/model/deprecated_inflector.rb +0 -335
  86. data/lib/sequel/model/deprecated_validations.rb +0 -388
  87. data/spec/core/core_ext_spec.rb +0 -156
  88. data/spec/core/migration_spec.rb +0 -263
  89. data/spec/core/pretty_table_spec.rb +0 -58
  90. data/spec/model/caching_spec.rb +0 -217
  91. data/spec/model/schema_spec.rb +0 -92
@@ -5,7 +5,7 @@ module Sequel
5
5
  # Top level module for holding all SQLite-related modules and classes
6
6
  # for Sequel.
7
7
  module SQLite
8
- # Database class for PostgreSQL databases used with Sequel and the
8
+ # Database class for SQLite databases used with Sequel and the
9
9
  # ruby-sqlite3 driver.
10
10
  class Database < Sequel::Database
11
11
  UNIX_EPOCH_TIME_FORMAT = /\A\d+\z/.freeze
@@ -87,10 +87,6 @@ module Sequel
87
87
  # in progress on the connection, always yielding a connection inside a transaction
88
88
  # transaction.
89
89
  def transaction(opts={})
90
- unless opts.is_a?(Hash)
91
- Deprecation.deprecate('Passing an argument other than a Hash to Database#transaction', "Use DB.transaction(:server=>#{opts.inspect})")
92
- opts = {:server=>opts}
93
- end
94
90
  synchronize(opts[:server]) do |conn|
95
91
  return yield(conn) if conn.transaction_active?
96
92
  begin
@@ -110,7 +106,7 @@ module Sequel
110
106
  private
111
107
 
112
108
  # Log the SQL and the arguments, and yield an available connection. Rescue
113
- # any SQLite3::Exceptions and turn the into DatabaseErrors.
109
+ # any SQLite3::Exceptions and turn them into DatabaseErrors.
114
110
  def _execute(sql, opts)
115
111
  begin
116
112
  log_info(sql, opts[:arguments])
@@ -120,7 +116,7 @@ module Sequel
120
116
  end
121
117
  end
122
118
 
123
- # SQLite does not need the pool to convert exceptions.
119
+ # The SQLite adapter does not need the pool to convert exceptions.
124
120
  # Also, force the max connections to 1 if a memory database is being
125
121
  # used, as otherwise each connection gets a separate database.
126
122
  def connection_pool_default_options
@@ -230,6 +226,7 @@ module Sequel
230
226
 
231
227
  private
232
228
 
229
+ # Quote the string using the adapter class method.
233
230
  def literal_string(v)
234
231
  "'#{::SQLite3::Database.quote(v)}'"
235
232
  end
@@ -17,9 +17,9 @@ class Sequel::Dataset
17
17
  # Since EXCEPT and INTERSECT are not supported, and order shouldn't matter
18
18
  # when UNION is used, don't worry about parantheses. This may potentially
19
19
  # give incorrect results if UNION ALL is used.
20
- def select_compounds_sql(sql, opts)
21
- return unless opts[:compounds]
22
- opts[:compounds].each do |type, dataset, all|
20
+ def select_compounds_sql(sql)
21
+ return unless @opts[:compounds]
22
+ @opts[:compounds].each do |type, dataset, all|
23
23
  sql << " #{type.to_s.upcase}#{' ALL' if all} #{subselect_sql(dataset)}"
24
24
  end
25
25
  end
@@ -49,11 +49,9 @@ class Sequel::ConnectionPool
49
49
  @servers += opts[:servers].keys - @servers if opts[:servers]
50
50
  @available_connections = Hash.new{|h,k| h[:default]}
51
51
  @allocated = Hash.new{|h,k| h[:default]}
52
- @created_count = Hash.new{|h,k| h[:default]}
53
52
  @servers.each do |s|
54
53
  @available_connections[s] = []
55
54
  @allocated[s] = {}
56
- @created_count[s] = 0
57
55
  end
58
56
  @timeout = opts[:pool_timeout] || 5
59
57
  @sleep_time = opts[:pool_sleep_time] || 0.001
@@ -75,7 +73,7 @@ class Sequel::ConnectionPool
75
73
  # The total number of connections opened for the given server, should
76
74
  # be equal to available_connections.length + allocated.length
77
75
  def created_count(server=:default)
78
- @created_count[server]
76
+ @allocated[server].length + @available_connections[server].length
79
77
  end
80
78
  alias size created_count
81
79
 
@@ -102,20 +100,22 @@ class Sequel::ConnectionPool
102
100
  if conn = owned_connection(t, server)
103
101
  return yield(conn)
104
102
  end
105
- until conn = acquire(t, server)
106
- raise(::Sequel::PoolTimeout) if Time.new > timeout
107
- sleep sleep_time
108
- end
109
103
  begin
104
+ until conn = acquire(t, server)
105
+ raise(::Sequel::PoolTimeout) if Time.new > timeout
106
+ sleep sleep_time
107
+ end
110
108
  yield conn
111
109
  rescue Sequel::DatabaseDisconnectError => dde
112
- remove(t, conn, server)
110
+ remove(t, conn, server) if conn
113
111
  raise
114
112
  ensure
115
- release(t, conn, server) unless dde
113
+ @mutex.synchronize{release(t, server)} if conn && !dde
116
114
  end
115
+ rescue StandardError => e
116
+ raise e
117
117
  rescue Exception => e
118
- raise(@convert_exceptions && !e.is_a?(StandardError) ? RuntimeError.new(e.message) : e)
118
+ raise(@convert_exceptions ? RuntimeError.new(e.message) : e)
119
119
  end
120
120
  end
121
121
 
@@ -130,7 +130,6 @@ class Sequel::ConnectionPool
130
130
  @available_connections.each do |server, conns|
131
131
  conns.each{|c| block.call(c)} if block
132
132
  conns.clear
133
- set_created_count(server, allocated(server).length)
134
133
  end
135
134
  end
136
135
  end
@@ -156,7 +155,11 @@ class Sequel::ConnectionPool
156
155
  # Creates a new connection to the given server if the size of the pool for
157
156
  # the server is less than the maximum size of the pool.
158
157
  def make_new(server)
159
- if @created_count[server] < @max_size
158
+ if (n = created_count(server)) >= @max_size
159
+ allocated(server).keys.reject{|t| t.alive?}.each{|t| release(t, server)}
160
+ n = nil
161
+ end
162
+ if (n || created_count(server)) < @max_size
160
163
  raise(Sequel::Error, "No connection proc specified") unless @connection_proc
161
164
  begin
162
165
  conn = @connection_proc.call(server)
@@ -166,7 +169,6 @@ class Sequel::ConnectionPool
166
169
  raise e
167
170
  end
168
171
  raise(Sequel::DatabaseConnectionError, "Connection parameters not valid") unless conn
169
- set_created_count(server, @created_count[server] + 1)
170
172
  conn
171
173
  end
172
174
  end
@@ -178,27 +180,18 @@ class Sequel::ConnectionPool
178
180
  end
179
181
 
180
182
  # Releases the connection assigned to the supplied thread and server.
181
- def release(thread, conn, server)
182
- @mutex.synchronize do
183
- allocated(server).delete(thread)
184
- available_connections(server) << conn
185
- end
183
+ # You must already have the mutex before you call this.
184
+ def release(thread, server)
185
+ available_connections(server) << allocated(server).delete(thread)
186
186
  end
187
187
 
188
188
  # Removes the currently allocated connection from the connection pool.
189
189
  def remove(thread, conn, server)
190
190
  @mutex.synchronize do
191
191
  allocated(server).delete(thread)
192
- set_created_count(server, @created_count[server] - 1)
193
192
  @disconnection_proc.call(conn) if @disconnection_proc
194
193
  end
195
194
  end
196
-
197
- # Set the created count for the given server type
198
- def set_created_count(server, value)
199
- server = :default unless @created_count.include?(server)
200
- @created_count[server] = value
201
- end
202
195
  end
203
196
 
204
197
  # A SingleThreadedPool acts as a replacement for a ConnectionPool for use
data/lib/sequel/core.rb CHANGED
@@ -34,32 +34,13 @@
34
34
  #
35
35
  # Sequel.datetime_class = DateTime
36
36
  #
37
- # Sequel currently does not use instance_eval for virtual row blocks by default
38
- # (e.g. the block passed to Dataset#filter, #select, #order and other similar
39
- # methods). If you want to use instance_eval for these blocks, don't have any
40
- # block arguments, and set:
41
- #
42
- # Sequel.virtual_row_instance_eval = true
43
- #
44
- # When this is set, you can do:
45
- #
46
- # dataset.filter{|o| o.column > 0} # no instance_eval
47
- # dataset.filter{column > 0} # instance eval
48
- #
49
- # When the virtual_row_instance_eval is false, using a virtual row block without a block
50
- # argument will generate a deprecation message.
51
- #
52
- # The option to not use instance_eval for a block with no arguments will be removed in Sequel 3.0.
53
- # If you have any virtual row blocks that you don't want to use instance_eval for,
54
- # make sure the blocks have block arguments.
55
- #
56
37
  # You can set the SEQUEL_NO_CORE_EXTENSIONS constant or environment variable to have
57
38
  # Sequel not extend the core classes.
58
39
  module Sequel
59
40
  @convert_tinyint_to_bool = true
60
41
  @convert_two_digit_years = true
61
42
  @datetime_class = Time
62
- @virtual_row_instance_eval = false
43
+ @virtual_row_instance_eval = true
63
44
 
64
45
  class << self
65
46
  attr_accessor :convert_tinyint_to_bool, :convert_two_digit_years, :datetime_class, :virtual_row_instance_eval
@@ -211,7 +192,7 @@ module Sequel
211
192
 
212
193
  private_class_method :adapter_method, :def_adapter_method
213
194
 
214
- require(%w"metaprogramming sql connection_pool exceptions dataset database version deprecated")
195
+ require(%w"metaprogramming sql connection_pool exceptions dataset database version")
215
196
  require(%w"schema_generator schema_methods schema_sql", 'database')
216
197
  require(%w"convenience graph prepared_statements sql", 'dataset')
217
198
  require('core_sql') if !defined?(::SEQUEL_NO_CORE_EXTENSIONS) && !ENV.has_key?('SEQUEL_NO_CORE_EXTENSIONS')
@@ -77,10 +77,6 @@ module Sequel
77
77
  @identifier_input_method = nil
78
78
  @identifier_output_method = nil
79
79
  @quote_identifiers = nil
80
- if opts.include?(:upcase_identifiers)
81
- Deprecation.deprecate('The :upcase_identifiers Database option', 'Use the :identifier_input_method => :upcase option instead')
82
- @identifier_input_method = opts[:upcase_identifiers] ? :upcase : ""
83
- end
84
80
  @pool = (@single_threaded ? SingleThreadedPool : ConnectionPool).new(connection_pool_default_options.merge(opts), &block)
85
81
  @pool.connection_proc = proc{|server| connect(server)} unless block
86
82
  @pool.disconnection_proc = proc{|conn| disconnect_connection(conn)} unless opts[:disconnection_proc]
@@ -225,8 +221,7 @@ module Sequel
225
221
 
226
222
  # Executes the supplied SQL statement string.
227
223
  def <<(sql)
228
- Deprecation.deprecate('Passing an array argument to Database#<<', 'Use array.each{|x| database << x}') if Array === sql
229
- execute_ddl((Array === sql) ? sql.to_sql : sql)
224
+ execute_ddl(sql)
230
225
  end
231
226
 
232
227
  # Returns a dataset from the database. If the first argument is a string,
@@ -249,11 +244,27 @@ module Sequel
249
244
  prepared_statements[ps_name].call(hash)
250
245
  end
251
246
 
247
+ # Cast the given type to a literal type
248
+ def cast_type_literal(type)
249
+ type_literal(:type=>type)
250
+ end
251
+
252
252
  # Connects to the database. This method should be overridden by descendants.
253
253
  def connect
254
254
  raise NotImplementedError, "#connect should be overridden by adapters"
255
255
  end
256
256
 
257
+ # The database type for this database object, the same as the adapter scheme
258
+ # by default. Should be overridden in adapters (especially shared adapters)
259
+ # to be the correct type, so that even if two separate Database objects are
260
+ # using different adapters you can tell that they are using the same database
261
+ # type. Even better, you can tell that two Database objects that are using
262
+ # the same adapter are connecting to different database types (think JDBC or
263
+ # DataObjects).
264
+ def database_type
265
+ self.class.adapter_scheme
266
+ end
267
+
257
268
  # Returns a blank dataset for this database
258
269
  def dataset
259
270
  ds = Sequel::Dataset.new(self)
@@ -409,9 +420,9 @@ module Sequel
409
420
  end
410
421
 
411
422
  # Parse the schema from the database.
412
- # If the table_name is not given, returns the schema for all tables as a hash.
413
- # If the table_name is given, returns the schema for a single table as an
414
- # array with all members being arrays of length 2. Available options are:
423
+ # Returns the schema for the given table as an array with all members being arrays of length 2,
424
+ # the first member being the column name, and the second member being a hash of column information.
425
+ # Available options are:
415
426
  #
416
427
  # * :reload - Get fresh information from the database, instead of using
417
428
  # cached information. If table_name is blank, :reload should be used
@@ -420,46 +431,24 @@ module Sequel
420
431
  # that have been requested explicitly.
421
432
  # * :schema - An explicit schema to use. It may also be implicitly provided
422
433
  # via the table name.
423
- def schema(table = nil, opts={})
424
- Deprecation.deprecate('Calling Database#schema without a table argument', 'Use database.tables.inject({}){|h, m| h[m] = database.schema(m); h}') unless table
434
+ def schema(table, opts={})
425
435
  raise(Error, 'schema parsing is not implemented on this database') unless respond_to?(:schema_parse_table, true)
426
436
 
427
- if table
428
- sch, table_name = schema_and_table(table)
429
- quoted_name = quote_schema_table(table)
430
- end
437
+ sch, table_name = schema_and_table(table)
438
+ quoted_name = quote_schema_table(table)
431
439
  opts = opts.merge(:schema=>sch) if sch && !opts.include?(:schema)
432
- if opts[:reload] && @schemas
433
- if table_name
434
- @schemas.delete(quoted_name)
435
- else
436
- @schemas = nil
437
- end
438
- end
439
-
440
- if @schemas
441
- if table_name
442
- return @schemas[quoted_name] if @schemas[quoted_name]
443
- else
444
- return @schemas
445
- end
446
- end
447
440
 
448
- raise(Error, '#tables does not exist, you must provide a specific table to #schema') if table.nil? && !respond_to?(:tables, true)
441
+ @schemas.delete(quoted_name) if opts[:reload] && @schemas
442
+ return @schemas[quoted_name] if @schemas && @schemas[quoted_name]
449
443
 
450
444
  @schemas ||= Hash.new do |h,k|
451
445
  quote_name = quote_schema_table(k)
452
446
  h[quote_name] if h.include?(quote_name)
453
447
  end
454
448
 
455
- if table_name
456
- cols = schema_parse_table(table_name, opts)
457
- raise(Error, 'schema parsing returned no columns, table probably doesn\'t exist') if cols.nil? || cols.empty?
458
- @schemas[quoted_name] = cols
459
- else
460
- tables.each{|t| @schemas[quote_schema_table(t)] = schema_parse_table(t.to_s, opts)}
461
- @schemas
462
- end
449
+ cols = schema_parse_table(table_name, opts)
450
+ raise(Error, 'schema parsing returned no columns, table probably doesn\'t exist') if cols.nil? || cols.empty?
451
+ @schemas[quoted_name] = cols
463
452
  end
464
453
 
465
454
  # Returns true if the database is using a single-threaded connection pool.
@@ -500,10 +489,6 @@ module Sequel
500
489
  # current transaction. Should be overridden for databases that support nested
501
490
  # transactions.
502
491
  def transaction(opts={})
503
- unless opts.is_a?(Hash)
504
- Deprecation.deprecate('Passing an argument other than a Hash to Database#transaction', "Use DB.transaction(:server=>#{opts.inspect})")
505
- opts = {:server=>opts}
506
- end
507
492
  synchronize(opts[:server]) do |conn|
508
493
  return yield(conn) if @transactions.include?(Thread.current)
509
494
  log_info(begin_transaction_sql)
@@ -579,6 +564,7 @@ module Sequel
579
564
  # strings with all whitespace, and ones that respond
580
565
  # true to empty?
581
566
  def blank_object?(obj)
567
+ return obj.blank? if obj.respond_to?(:blank?)
582
568
  case obj
583
569
  when NilClass, FalseClass
584
570
  true
@@ -622,6 +608,31 @@ module Sequel
622
608
  :downcase
623
609
  end
624
610
 
611
+ # Return a Method object for the dataset's output_identifier_method.
612
+ # Used in metadata parsing to make sure the returned information is in the
613
+ # correct format.
614
+ def input_identifier_meth
615
+ dataset.method(:input_identifier)
616
+ end
617
+
618
+ # Return a dataset that uses the default identifier input and output methods
619
+ # for this database. Used when parsing metadata so that column symbols are
620
+ # returned as expected.
621
+ def metadata_dataset
622
+ return @metadata_dataset if @metadata_dataset
623
+ ds = dataset
624
+ ds.identifier_input_method = identifier_input_method_default
625
+ ds.identifier_output_method = identifier_output_method_default
626
+ @metadata_dataset = ds
627
+ end
628
+
629
+ # Return a Method object for the dataset's output_identifier_method.
630
+ # Used in metadata parsing to make sure the returned information is in the
631
+ # correct format.
632
+ def output_identifier_meth
633
+ dataset.method(:output_identifier)
634
+ end
635
+
625
636
  # Whether to quote identifiers by default for this database, true
626
637
  # by default.
627
638
  def quote_identifiers_default
@@ -661,6 +672,11 @@ module Sequel
661
672
  schema_utility_dataset.schema_and_table(table_name)
662
673
  end
663
674
 
675
+ # Return true if the given column schema represents an autoincrementing primary key.
676
+ def schema_autoincrementing_primary_key?(schema)
677
+ !!schema[:primary_key]
678
+ end
679
+
664
680
  # Match the database's column type to a ruby type via a
665
681
  # regular expression. The following ruby types are supported:
666
682
  # integer, string, date, datetime, boolean, and float.
@@ -684,7 +700,7 @@ module Sequel
684
700
  :boolean
685
701
  when /\A(real|float|double( precision)?)\z/io
686
702
  :float
687
- when /\A(numeric(\(\d+,\d+\))?|decimal|money)\z/io
703
+ when /\A(((numeric|decimal)(\(\d+,\d+\))?)|money)\z/io
688
704
  :decimal
689
705
  when /bytea|blob/io
690
706
  :blob
@@ -17,14 +17,25 @@ module Sequel
17
17
  GENERIC_TYPES=[String, Integer, Fixnum, Bignum, Float, Numeric, BigDecimal,
18
18
  Date, DateTime, Time, File, TrueClass, FalseClass]
19
19
 
20
+ # Return the columns created by this generator
21
+ attr_reader :columns
22
+
23
+ # Return the constraints created by this generator
24
+ attr_reader :constraints
25
+
26
+ # Return the indexes created by this generator
27
+ attr_reader :indexes
28
+
20
29
  # Set the database in which to create the table, and evaluate the block
21
30
  # in the context of this object.
22
31
  def initialize(db, &block)
23
32
  @db = db
24
33
  @columns = []
25
34
  @indexes = []
35
+ @constraints = []
26
36
  @primary_key = nil
27
37
  instance_eval(&block) if block
38
+ @columns.unshift(@primary_key) if @primary_key && !has_column?(primary_key_name)
28
39
  end
29
40
 
30
41
  # Add a method for each of the given types that creates a column
@@ -33,7 +44,7 @@ module Sequel
33
44
  # as a constant/class.
34
45
  def self.add_type_method(*types)
35
46
  types.each do |type|
36
- class_eval "def #{type}(name, opts={}); column(name, #{type}, opts); end"
47
+ class_eval("def #{type}(name, opts={}); column(name, #{type}, opts); end", __FILE__, __LINE__)
37
48
  end
38
49
  end
39
50
 
@@ -72,24 +83,16 @@ module Sequel
72
83
  # * :unsigned - Make the column type unsigned, only useful for integer
73
84
  # columns.
74
85
  def column(name, type, opts = {})
75
- @columns << {:name => name, :type => type}.merge(opts)
86
+ columns << {:name => name, :type => type}.merge(opts)
76
87
  index(name) if opts[:index]
77
88
  end
78
89
 
79
90
  # Adds a named constraint (or unnamed if name is nil) to the DDL,
80
91
  # with the given block or args.
81
92
  def constraint(name, *args, &block)
82
- @columns << {:name => name, :type => :check, :check => block || args,
83
- :constraint_type => :check}
93
+ constraints << {:name => name, :type => :check, :check => block || args}
84
94
  end
85
95
 
86
- # Return the DDL created by the generator as a array of two elements,
87
- # the first being the columns and the second being the indexes.
88
- def create_info
89
- @columns.unshift(@primary_key) if @primary_key && !has_column?(primary_key_name)
90
- [@columns, @indexes]
91
- end
92
-
93
96
  # Add a foreign key in the table that references another table to the DDL. See column
94
97
  # for available options.
95
98
  def foreign_key(name, table=nil, opts = {})
@@ -106,7 +109,7 @@ module Sequel
106
109
  return composite_foreign_key(name, opts) if name.is_a?(Array)
107
110
  column(name, Integer, opts)
108
111
  end
109
-
112
+
110
113
  # Add a full text index on the given columns to the DDL.
111
114
  def full_text_index(columns, opts = {})
112
115
  index(columns, opts.merge(:type => :full_text))
@@ -114,7 +117,7 @@ module Sequel
114
117
 
115
118
  # True if the DDL includes the creation of a column with the given name.
116
119
  def has_column?(name)
117
- @columns.any?{|c| c[:name] == name}
120
+ columns.any?{|c| c[:name] == name}
118
121
  end
119
122
 
120
123
  # Add an index on the given column(s) with the given options to the DDL.
@@ -124,7 +127,7 @@ module Sequel
124
127
  # * :unique - Make the index unique, so duplicate values are not allowed.
125
128
  # * :where - Create a partial index (only supported by some databases)
126
129
  def index(columns, opts = {})
127
- @indexes << {:columns => Array(columns)}.merge(opts)
130
+ indexes << {:columns => Array(columns)}.merge(opts)
128
131
  end
129
132
 
130
133
  # Add a column with the given type, name, and opts to the DDL. See column for available
@@ -171,8 +174,7 @@ module Sequel
171
174
 
172
175
  # Add a unique constraint on the given columns to the DDL.
173
176
  def unique(columns, opts = {})
174
- @columns << {:type => :check, :constraint_type => :unique,
175
- :name => nil, :columns => Array(columns)}.merge(opts)
177
+ constraints << {:type => :unique, :columns => Array(columns)}.merge(opts)
176
178
  end
177
179
 
178
180
  private
@@ -180,14 +182,12 @@ module Sequel
180
182
  # Add a composite primary key constraint
181
183
  def composite_primary_key(columns, *args)
182
184
  opts = args.pop || {}
183
- @columns << {:type => :check, :constraint_type => :primary_key,
184
- :name => nil, :columns => columns}.merge(opts)
185
+ constraints << {:type => :primary_key, :columns => columns}.merge(opts)
185
186
  end
186
187
 
187
188
  # Add a composite foreign key constraint
188
189
  def composite_foreign_key(columns, opts)
189
- @columns << {:type => :check, :constraint_type => :foreign_key,
190
- :name => nil, :columns => columns }.merge(opts)
190
+ constraints << {:type => :foreign_key, :columns => columns}.merge(opts)
191
191
  end
192
192
 
193
193
  add_type_method(*GENERIC_TYPES)
@@ -220,13 +220,11 @@ module Sequel
220
220
  # Add a constraint with the given name and args to the DDL for the table.
221
221
  # See Generator#constraint.
222
222
  def add_constraint(name, *args, &block)
223
- @operations << {:op => :add_constraint, :name => name, :type => :check, \
224
- :constraint_type => :check, :check => block || args}
223
+ @operations << {:op => :add_constraint, :name => name, :type => :check, :check => block || args}
225
224
  end
226
225
 
227
226
  def add_unique_constraint(columns, opts = {})
228
- @operations << {:op => :add_constraint, :type => :check,
229
- :constraint_type => :unique, :columns => Array(columns)}.merge(opts)
227
+ @operations << {:op => :add_constraint, :type => :unique, :columns => Array(columns)}.merge(opts)
230
228
  end
231
229
 
232
230
  # Add a foreign key with the given name and referencing the given table
@@ -280,8 +278,8 @@ module Sequel
280
278
  end
281
279
 
282
280
  # Remove an index from the DDL for the table.
283
- def drop_index(columns)
284
- @operations << {:op => :drop_index, :columns => Array(columns)}
281
+ def drop_index(columns, options={})
282
+ @operations << {:op => :drop_index, :columns => Array(columns)}.merge(options)
285
283
  end
286
284
 
287
285
  # Modify a column's name in the DDL for the table.
@@ -308,15 +306,12 @@ module Sequel
308
306
 
309
307
  # Add a composite primary key constraint
310
308
  def add_composite_primary_key(columns, opts)
311
- @operations << {:op => :add_constraint, :type => :check,
312
- :constraint_type => :primary_key, :columns => columns}.merge(opts)
309
+ @operations << {:op => :add_constraint, :type => :primary_key, :columns => columns}.merge(opts)
313
310
  end
314
311
 
315
312
  # Add a composite foreign key constraint
316
313
  def add_composite_foreign_key(columns, table, opts)
317
- @operations << {:op => :add_constraint, :type => :check,
318
- :constraint_type => :foreign_key, :columns => columns,
319
- :table => table}.merge(opts)
314
+ @operations << {:op => :add_constraint, :type => :foreign_key, :columns => columns, :table => table}.merge(opts)
320
315
  end
321
316
  end
322
317
  end