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.
- 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
|