sequel 2.12.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +62 -0
- data/README.rdoc +3 -3
- data/Rakefile +7 -0
- data/doc/advanced_associations.rdoc +44 -0
- data/doc/release_notes/3.0.0.txt +221 -0
- data/lib/sequel/adapters/amalgalite.rb +208 -0
- data/lib/sequel/adapters/db2.rb +3 -0
- data/lib/sequel/adapters/dbi.rb +9 -0
- data/lib/sequel/adapters/do.rb +0 -4
- data/lib/sequel/adapters/firebird.rb +16 -18
- data/lib/sequel/adapters/informix.rb +5 -3
- data/lib/sequel/adapters/jdbc.rb +24 -20
- data/lib/sequel/adapters/jdbc/h2.rb +15 -4
- data/lib/sequel/adapters/mysql.rb +4 -8
- data/lib/sequel/adapters/odbc.rb +0 -4
- data/lib/sequel/adapters/oracle.rb +0 -4
- data/lib/sequel/adapters/shared/mssql.rb +16 -5
- data/lib/sequel/adapters/shared/mysql.rb +87 -86
- data/lib/sequel/adapters/shared/oracle.rb +92 -3
- data/lib/sequel/adapters/shared/postgres.rb +85 -29
- data/lib/sequel/adapters/shared/progress.rb +8 -3
- data/lib/sequel/adapters/shared/sqlite.rb +53 -23
- data/lib/sequel/adapters/sqlite.rb +4 -7
- data/lib/sequel/adapters/utils/unsupported.rb +3 -3
- data/lib/sequel/connection_pool.rb +18 -25
- data/lib/sequel/core.rb +2 -21
- data/lib/sequel/database.rb +60 -44
- data/lib/sequel/database/schema_generator.rb +26 -31
- data/lib/sequel/database/schema_methods.rb +8 -3
- data/lib/sequel/database/schema_sql.rb +114 -28
- data/lib/sequel/dataset.rb +14 -41
- data/lib/sequel/dataset/convenience.rb +31 -54
- data/lib/sequel/dataset/graph.rb +7 -13
- data/lib/sequel/dataset/sql.rb +43 -54
- data/lib/sequel/extensions/inflector.rb +0 -5
- data/lib/sequel/extensions/schema_dumper.rb +238 -0
- data/lib/sequel/metaprogramming.rb +0 -20
- data/lib/sequel/model.rb +1 -2
- data/lib/sequel/model/base.rb +18 -16
- data/lib/sequel/model/inflections.rb +6 -9
- data/lib/sequel/plugins/caching.rb +0 -6
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/sql.rb +2 -0
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/firebird_spec.rb +35 -8
- data/spec/adapters/mysql_spec.rb +173 -266
- data/spec/adapters/oracle_spec.rb +13 -0
- data/spec/adapters/postgres_spec.rb +127 -227
- data/spec/adapters/sqlite_spec.rb +13 -171
- data/spec/core/connection_pool_spec.rb +15 -4
- data/spec/core/core_sql_spec.rb +14 -170
- data/spec/core/database_spec.rb +50 -132
- data/spec/core/dataset_spec.rb +47 -930
- data/spec/core/expression_filters_spec.rb +12 -0
- data/spec/core/schema_generator_spec.rb +37 -45
- data/spec/core/schema_spec.rb +26 -16
- data/spec/core/spec_helper.rb +0 -25
- data/spec/extensions/inflector_spec.rb +0 -3
- data/spec/extensions/schema_dumper_spec.rb +292 -0
- data/spec/extensions/serialization_spec.rb +9 -0
- data/spec/extensions/single_table_inheritance_spec.rb +6 -1
- data/spec/extensions/spec_helper.rb +1 -3
- data/spec/extensions/validation_helpers_spec.rb +4 -4
- data/spec/integration/database_test.rb +18 -0
- data/spec/integration/dataset_test.rb +112 -1
- data/spec/integration/eager_loader_test.rb +70 -9
- data/spec/integration/prepared_statement_test.rb +2 -2
- data/spec/integration/schema_test.rb +76 -27
- data/spec/integration/spec_helper.rb +0 -14
- data/spec/integration/transaction_test.rb +27 -0
- data/spec/model/associations_spec.rb +0 -36
- data/spec/model/base_spec.rb +18 -123
- data/spec/model/hooks_spec.rb +2 -235
- data/spec/model/inflector_spec.rb +15 -115
- data/spec/model/model_spec.rb +0 -120
- data/spec/model/plugins_spec.rb +0 -70
- data/spec/model/record_spec.rb +35 -93
- data/spec/model/spec_helper.rb +0 -27
- data/spec/model/validations_spec.rb +0 -931
- metadata +9 -14
- data/lib/sequel/deprecated.rb +0 -593
- data/lib/sequel/deprecated_migration.rb +0 -91
- data/lib/sequel/model/deprecated.rb +0 -204
- data/lib/sequel/model/deprecated_hooks.rb +0 -103
- data/lib/sequel/model/deprecated_inflector.rb +0 -335
- data/lib/sequel/model/deprecated_validations.rb +0 -388
- data/spec/core/core_ext_spec.rb +0 -156
- data/spec/core/migration_spec.rb +0 -263
- data/spec/core/pretty_table_spec.rb +0 -58
- data/spec/model/caching_spec.rb +0 -217
- 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
|
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
|
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
|
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
|
-
@
|
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,
|
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
|
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
|
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
|
-
|
182
|
-
|
183
|
-
|
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 =
|
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
|
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')
|
data/lib/sequel/database.rb
CHANGED
@@ -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
|
-
|
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
|
-
#
|
413
|
-
#
|
414
|
-
#
|
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
|
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
|
-
|
428
|
-
|
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
|
-
|
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
|
-
|
456
|
-
|
457
|
-
|
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+\))
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 => :
|
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 => :
|
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 => :
|
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
|