sequel 2.12.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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