sequel 3.33.0 → 3.34.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 +140 -0
- data/Rakefile +7 -0
- data/bin/sequel +22 -2
- data/doc/dataset_basics.rdoc +1 -1
- data/doc/mass_assignment.rdoc +3 -1
- data/doc/querying.rdoc +28 -4
- data/doc/reflection.rdoc +23 -3
- data/doc/release_notes/3.34.0.txt +671 -0
- data/doc/schema_modification.rdoc +18 -2
- data/doc/virtual_rows.rdoc +49 -0
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/ibmdb.rb +9 -4
- data/lib/sequel/adapters/jdbc.rb +9 -4
- data/lib/sequel/adapters/jdbc/h2.rb +8 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +43 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +19 -0
- data/lib/sequel/adapters/mock.rb +24 -3
- data/lib/sequel/adapters/mysql.rb +29 -50
- data/lib/sequel/adapters/mysql2.rb +13 -28
- data/lib/sequel/adapters/oracle.rb +8 -2
- data/lib/sequel/adapters/postgres.rb +115 -20
- data/lib/sequel/adapters/shared/db2.rb +1 -1
- data/lib/sequel/adapters/shared/mssql.rb +14 -3
- data/lib/sequel/adapters/shared/mysql.rb +59 -11
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/postgres.rb +127 -30
- data/lib/sequel/adapters/shared/sqlite.rb +55 -38
- data/lib/sequel/adapters/sqlite.rb +9 -3
- data/lib/sequel/adapters/swift.rb +2 -2
- data/lib/sequel/adapters/swift/mysql.rb +0 -5
- data/lib/sequel/adapters/swift/postgres.rb +10 -0
- data/lib/sequel/ast_transformer.rb +4 -0
- data/lib/sequel/connection_pool.rb +8 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +17 -0
- data/lib/sequel/connection_pool/single.rb +5 -0
- data/lib/sequel/connection_pool/threaded.rb +14 -0
- data/lib/sequel/core.rb +24 -3
- data/lib/sequel/database/connecting.rb +24 -14
- data/lib/sequel/database/dataset_defaults.rb +1 -0
- data/lib/sequel/database/misc.rb +16 -25
- data/lib/sequel/database/query.rb +20 -2
- data/lib/sequel/database/schema_generator.rb +2 -2
- data/lib/sequel/database/schema_methods.rb +120 -23
- data/lib/sequel/dataset/actions.rb +91 -18
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/prepared_statements.rb +6 -2
- data/lib/sequel/dataset/sql.rb +68 -51
- data/lib/sequel/extensions/_pretty_table.rb +79 -0
- data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +18 -13
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/extensions/null_dataset.rb +90 -0
- data/lib/sequel/extensions/pg_array.rb +460 -0
- data/lib/sequel/extensions/pg_array_ops.rb +220 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +174 -0
- data/lib/sequel/extensions/pg_hstore.rb +296 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
- data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
- data/lib/sequel/extensions/pretty_table.rb +5 -71
- data/lib/sequel/extensions/query_literals.rb +79 -0
- data/lib/sequel/extensions/schema_caching.rb +76 -0
- data/lib/sequel/extensions/schema_dumper.rb +227 -31
- data/lib/sequel/extensions/select_remove.rb +35 -0
- data/lib/sequel/extensions/sql_expr.rb +4 -110
- data/lib/sequel/extensions/to_dot.rb +1 -1
- data/lib/sequel/model.rb +11 -2
- data/lib/sequel/model/associations.rb +35 -7
- data/lib/sequel/model/base.rb +159 -36
- data/lib/sequel/no_core_ext.rb +2 -0
- data/lib/sequel/plugins/caching.rb +25 -18
- data/lib/sequel/plugins/composition.rb +1 -1
- data/lib/sequel/plugins/hook_class_methods.rb +1 -1
- data/lib/sequel/plugins/identity_map.rb +11 -3
- data/lib/sequel/plugins/instance_filters.rb +10 -0
- data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
- data/lib/sequel/plugins/nested_attributes.rb +4 -3
- data/lib/sequel/plugins/prepared_statements.rb +3 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +5 -1
- data/lib/sequel/plugins/schema.rb +7 -2
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/static_cache.rb +99 -0
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/sql.rb +417 -7
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +12 -15
- data/spec/adapters/mysql_spec.rb +81 -23
- data/spec/adapters/postgres_spec.rb +444 -77
- data/spec/adapters/spec_helper.rb +2 -0
- data/spec/adapters/sqlite_spec.rb +8 -8
- data/spec/core/connection_pool_spec.rb +85 -0
- data/spec/core/database_spec.rb +29 -5
- data/spec/core/dataset_spec.rb +171 -3
- data/spec/core/expression_filters_spec.rb +364 -0
- data/spec/core/mock_adapter_spec.rb +17 -3
- data/spec/core/schema_spec.rb +133 -0
- data/spec/extensions/association_dependencies_spec.rb +13 -13
- data/spec/extensions/caching_spec.rb +26 -3
- data/spec/extensions/class_table_inheritance_spec.rb +2 -2
- data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +23 -94
- data/spec/extensions/force_encoding_spec.rb +4 -2
- data/spec/extensions/hook_class_methods_spec.rb +5 -2
- data/spec/extensions/identity_map_spec.rb +17 -0
- data/spec/extensions/instance_filters_spec.rb +1 -1
- data/spec/extensions/lazy_attributes_spec.rb +2 -2
- data/spec/extensions/list_spec.rb +4 -4
- data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
- data/spec/extensions/migration_spec.rb +6 -2
- data/spec/extensions/nested_attributes_spec.rb +20 -0
- data/spec/extensions/null_dataset_spec.rb +85 -0
- data/spec/extensions/optimistic_locking_spec.rb +2 -2
- data/spec/extensions/pg_array_ops_spec.rb +105 -0
- data/spec/extensions/pg_array_spec.rb +196 -0
- data/spec/extensions/pg_auto_parameterize_spec.rb +64 -0
- data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
- data/spec/extensions/pg_hstore_spec.rb +195 -0
- data/spec/extensions/pg_statement_cache_spec.rb +209 -0
- data/spec/extensions/prepared_statements_spec.rb +4 -0
- data/spec/extensions/pretty_table_spec.rb +6 -0
- data/spec/extensions/query_literals_spec.rb +168 -0
- data/spec/extensions/schema_caching_spec.rb +41 -0
- data/spec/extensions/schema_dumper_spec.rb +231 -11
- data/spec/extensions/schema_spec.rb +14 -2
- data/spec/extensions/select_remove_spec.rb +38 -0
- data/spec/extensions/sharding_spec.rb +6 -6
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +2 -1
- data/spec/extensions/sql_expr_spec.rb +28 -19
- data/spec/extensions/static_cache_spec.rb +145 -0
- data/spec/extensions/touch_spec.rb +1 -1
- data/spec/extensions/typecast_on_load_spec.rb +9 -1
- data/spec/integration/associations_test.rb +6 -6
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +89 -26
- data/spec/integration/migrator_test.rb +2 -3
- data/spec/integration/model_test.rb +3 -3
- data/spec/integration/plugin_test.rb +85 -22
- data/spec/integration/prepared_statement_test.rb +28 -8
- data/spec/integration/schema_test.rb +78 -7
- data/spec/integration/spec_helper.rb +1 -0
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +4 -6
- data/spec/integration/type_test.rb +2 -2
- data/spec/model/associations_spec.rb +94 -8
- data/spec/model/base_spec.rb +4 -4
- data/spec/model/hooks_spec.rb +2 -2
- data/spec/model/model_spec.rb +19 -7
- data/spec/model/record_spec.rb +135 -58
- data/spec/model/spec_helper.rb +1 -0
- metadata +35 -7
|
@@ -229,13 +229,19 @@ module Sequel
|
|
|
229
229
|
end
|
|
230
230
|
end
|
|
231
231
|
unless cps
|
|
232
|
-
cps = log_yield("
|
|
232
|
+
cps = log_yield("PREPARE #{name}: #{sql}"){conn.prepare(sql)}
|
|
233
233
|
conn.prepared_statements[name] = [cps, sql]
|
|
234
234
|
end
|
|
235
|
+
log_sql = "EXECUTE #{name}"
|
|
236
|
+
if ps.log_sql
|
|
237
|
+
log_sql << " ("
|
|
238
|
+
log_sql << sql
|
|
239
|
+
log_sql << ")"
|
|
240
|
+
end
|
|
235
241
|
if block
|
|
236
|
-
log_yield(
|
|
242
|
+
log_yield(log_sql, args){cps.execute(ps_args, &block)}
|
|
237
243
|
else
|
|
238
|
-
log_yield(
|
|
244
|
+
log_yield(log_sql, args){cps.execute!(ps_args){|r|}}
|
|
239
245
|
case type
|
|
240
246
|
when :insert
|
|
241
247
|
conn.last_insert_row_id
|
|
@@ -136,10 +136,10 @@ module Sequel
|
|
|
136
136
|
Database::DatasetClass = self
|
|
137
137
|
|
|
138
138
|
# Set the columns and yield the hashes to the block.
|
|
139
|
-
def fetch_rows(sql
|
|
139
|
+
def fetch_rows(sql)
|
|
140
140
|
execute(sql) do |res|
|
|
141
141
|
@columns = res.fields
|
|
142
|
-
res.each
|
|
142
|
+
res.each{|h| yield h}
|
|
143
143
|
end
|
|
144
144
|
self
|
|
145
145
|
end
|
|
@@ -36,11 +36,6 @@ module Sequel
|
|
|
36
36
|
include Sequel::MySQL::DatasetMethods
|
|
37
37
|
APOS = Dataset::APOS
|
|
38
38
|
|
|
39
|
-
# Use execute_insert to execute the replace_sql.
|
|
40
|
-
def replace(*args)
|
|
41
|
-
execute_insert(replace_sql(*args))
|
|
42
|
-
end
|
|
43
|
-
|
|
44
39
|
private
|
|
45
40
|
|
|
46
41
|
# Use Swift's escape method for quoting.
|
|
@@ -85,6 +85,16 @@ module Sequel
|
|
|
85
85
|
def log_connection_execute(conn, sql)
|
|
86
86
|
conn.execute(sql)
|
|
87
87
|
end
|
|
88
|
+
|
|
89
|
+
# Remove all other options except for ones specifically handled, as
|
|
90
|
+
# otherwise swift passes them to dbic++ which passes them to PostgreSQL
|
|
91
|
+
# which can raise an error.
|
|
92
|
+
def server_opts(o)
|
|
93
|
+
o = super
|
|
94
|
+
so = {}
|
|
95
|
+
[:db, :user, :password, :host, :port].each{|s| so[s] = o[s] if o.has_key?(s)}
|
|
96
|
+
so
|
|
97
|
+
end
|
|
88
98
|
|
|
89
99
|
# Extend the adapter with the Swift PostgreSQL AdapterMethods.
|
|
90
100
|
def setup_connection(conn)
|
|
@@ -66,6 +66,8 @@ module Sequel
|
|
|
66
66
|
SQL::JoinUsingClause.new(v(o.using), o.join_type, v(o.table), v(o.table_alias))
|
|
67
67
|
when SQL::JoinClause
|
|
68
68
|
SQL::JoinClause.new(o.join_type, v(o.table), v(o.table_alias))
|
|
69
|
+
when SQL::Wrapper
|
|
70
|
+
SQL::Wrapper.new(v(o.value))
|
|
69
71
|
else
|
|
70
72
|
o
|
|
71
73
|
end
|
|
@@ -172,6 +174,8 @@ module Sequel
|
|
|
172
174
|
def v(o)
|
|
173
175
|
if o.is_a?(SQL::ComplexExpression) && UNBIND_OPS.include?(o.op)
|
|
174
176
|
l, r = o.args
|
|
177
|
+
l = l.value if l.is_a?(Sequel::SQL::Wrapper)
|
|
178
|
+
r = r.value if r.is_a?(Sequel::SQL::Wrapper)
|
|
175
179
|
if UNBIND_KEY_CLASSES.any?{|c| l.is_a?(c)} && UNBIND_VALUE_CLASSES.any?{|c| r.is_a?(c)} && !r.is_a?(LiteralString)
|
|
176
180
|
key = bind_key(l)
|
|
177
181
|
if (old = binds[key]) && old != r
|
|
@@ -57,6 +57,14 @@ class Sequel::ConnectionPool
|
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
extend ClassMethods
|
|
60
|
+
|
|
61
|
+
# The after_connect proc used for this pool. This is called with each new
|
|
62
|
+
# connection made, and is usually used to set custom per-connection settings.
|
|
63
|
+
attr_accessor :after_connect
|
|
64
|
+
|
|
65
|
+
# The disconnect_proc used for the pool. This is called with each connection
|
|
66
|
+
# that is disconnected, usually to clean up related resources.
|
|
67
|
+
attr_accessor :disconnection_proc
|
|
60
68
|
|
|
61
69
|
# Instantiates a connection pool with the given options. The block is called
|
|
62
70
|
# with a single symbol (specifying the server/shard to use) every time a new
|
|
@@ -26,6 +26,11 @@ class Sequel::ShardedSingleConnectionPool < Sequel::ConnectionPool
|
|
|
26
26
|
def add_servers(servers)
|
|
27
27
|
servers.each{|s| @servers[s] = s}
|
|
28
28
|
end
|
|
29
|
+
|
|
30
|
+
# Yield all of the currently established connections
|
|
31
|
+
def all_connections
|
|
32
|
+
@conns.values.each{|c| yield c}
|
|
33
|
+
end
|
|
29
34
|
|
|
30
35
|
# The connection for the given server.
|
|
31
36
|
def conn(server=:default)
|
|
@@ -45,6 +45,23 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
|
|
|
45
45
|
@allocated[server]
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
+
# Yield all of the available connections, and the ones currently allocated to
|
|
49
|
+
# this thread. This will not yield connections currently allocated to other
|
|
50
|
+
# threads, as it is not safe to operate on them. This holds the mutex while
|
|
51
|
+
# it is yielding all of the connections, which means that until
|
|
52
|
+
# the method's block returns, the pool is locked.
|
|
53
|
+
def all_connections
|
|
54
|
+
t = Thread.current
|
|
55
|
+
sync do
|
|
56
|
+
@allocated.values.each do |threads|
|
|
57
|
+
threads.each do |thread, conn|
|
|
58
|
+
yield conn if t == thread
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
@available_connections.values.each{|v| v.each{|c| yield c}}
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
48
65
|
# An array of connections opened but not currently used, for the given
|
|
49
66
|
# server. Nonexistent servers will return nil. Treat this as read only, do
|
|
50
67
|
# not modify the resulting object.
|
|
@@ -8,6 +8,11 @@ class Sequel::SingleConnectionPool < Sequel::ConnectionPool
|
|
|
8
8
|
@conn ? 1 : 0
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
# Yield the connection if one has been made.
|
|
12
|
+
def all_connections
|
|
13
|
+
yield @conn if @conn
|
|
14
|
+
end
|
|
15
|
+
|
|
11
16
|
# Disconnect the connection from the database.
|
|
12
17
|
def disconnect(opts=nil, &block)
|
|
13
18
|
return unless @conn
|
|
@@ -36,6 +36,20 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
|
|
|
36
36
|
@allocated.length + @available_connections.length
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
# Yield all of the available connections, and the one currently allocated to
|
|
40
|
+
# this thread. This will not yield connections currently allocated to other
|
|
41
|
+
# threads, as it is not safe to operate on them. This holds the mutex while
|
|
42
|
+
# it is yielding all of the available connections, which means that until
|
|
43
|
+
# the method's block returns, the pool is locked.
|
|
44
|
+
def all_connections
|
|
45
|
+
hold do |c|
|
|
46
|
+
sync do
|
|
47
|
+
yield c
|
|
48
|
+
@available_connections.each{|c| yield c}
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
39
53
|
# Removes all connections currently available, optionally
|
|
40
54
|
# yielding each connection to the given block. This method has the effect of
|
|
41
55
|
# disconnecting from the database, assuming that no connections are currently
|
data/lib/sequel/core.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
warn 'Sequel support for ruby <1.8.7 is deprecated and will be removed in 3.35.0' if RUBY_VERSION < '1.8.7'
|
|
1
2
|
%w'bigdecimal date thread time uri'.each{|f| require f}
|
|
2
3
|
|
|
3
4
|
# Top level module for Sequel
|
|
@@ -17,8 +18,10 @@
|
|
|
17
18
|
#
|
|
18
19
|
# Sequel.sqlite('blog.db'){|db| puts db[:users].count}
|
|
19
20
|
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
21
|
+
# Sequel currently adds methods to the Array, Hash, String and Symbol classes by
|
|
22
|
+
# default. You can either require 'sequel/no_core_ext' or set the
|
|
23
|
+
# +SEQUEL_NO_CORE_EXTENSIONS+ constant or environment variable before requiring
|
|
24
|
+
# sequel to have # Sequel not add methods to those classes.
|
|
22
25
|
#
|
|
23
26
|
# For a more expanded introduction, see the {README}[link:files/README_rdoc.html].
|
|
24
27
|
# For a quicker introduction, see the {cheat sheet}[link:files/doc/cheat_sheet_rdoc.html].
|
|
@@ -140,6 +143,24 @@ module Sequel
|
|
|
140
143
|
def self.connect(*args, &block)
|
|
141
144
|
Database.connect(*args, &block)
|
|
142
145
|
end
|
|
146
|
+
|
|
147
|
+
if !defined?(::SEQUEL_NO_CORE_EXTENSIONS) && !ENV.has_key?('SEQUEL_NO_CORE_EXTENSIONS')
|
|
148
|
+
# Whether the core extensions are enabled. The core extensions are enabled by
|
|
149
|
+
# default for backwards compatibility, but can be disabled using the SEQUEL_NO_CORE_EXTENSIONS
|
|
150
|
+
# constant or environment variable.
|
|
151
|
+
def self.core_extensions?
|
|
152
|
+
# We override this method to return true inside the core_extensions.rb file,
|
|
153
|
+
# but we also set it here because that file is not loaded until most of Sequel
|
|
154
|
+
# is finished loading, and parts of Sequel check whether the core extensions
|
|
155
|
+
# are loaded.
|
|
156
|
+
true
|
|
157
|
+
end
|
|
158
|
+
else
|
|
159
|
+
def self.core_extensions?
|
|
160
|
+
false
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
143
164
|
|
|
144
165
|
# Convert the +exception+ to the given class. The given class should be
|
|
145
166
|
# <tt>Sequel::Error</tt> or a subclass. Returns an instance of +klass+ with
|
|
@@ -356,7 +377,7 @@ module Sequel
|
|
|
356
377
|
private_class_method :adapter_method, :def_adapter_method
|
|
357
378
|
|
|
358
379
|
require(%w"metaprogramming sql connection_pool exceptions dataset database timezones ast_transformer version")
|
|
359
|
-
|
|
380
|
+
extension(:core_extensions) if Sequel.core_extensions?
|
|
360
381
|
|
|
361
382
|
# Add the database adapter class methods to Sequel via metaprogramming
|
|
362
383
|
def_adapter_method(*Database::ADAPTERS)
|
|
@@ -46,6 +46,7 @@ module Sequel
|
|
|
46
46
|
when String
|
|
47
47
|
if match = /\A(jdbc|do):/o.match(conn_string)
|
|
48
48
|
c = adapter_class(match[1].to_sym)
|
|
49
|
+
opts = opts.merge(:orig_opts=>opts.dup)
|
|
49
50
|
opts = {:uri=>conn_string}.merge(opts)
|
|
50
51
|
else
|
|
51
52
|
uri = URI.parse(conn_string)
|
|
@@ -55,11 +56,14 @@ module Sequel
|
|
|
55
56
|
uri_options = c.send(:uri_to_options, uri)
|
|
56
57
|
uri.query.split('&').collect{|s| s.split('=')}.each{|k,v| uri_options[k.to_sym] = v if k && !k.empty?} unless uri.query.to_s.strip.empty?
|
|
57
58
|
uri_options.to_a.each{|k,v| uri_options[k] = URI.unescape(v) if v.is_a?(String)}
|
|
59
|
+
opts = opts.merge(:orig_opts=>opts.dup)
|
|
60
|
+
opts[:uri] = conn_string
|
|
58
61
|
opts = uri_options.merge(opts)
|
|
59
62
|
opts[:adapter] = scheme
|
|
60
63
|
end
|
|
61
64
|
when Hash
|
|
62
65
|
opts = conn_string.merge(opts)
|
|
66
|
+
opts = opts.merge(:orig_opts=>opts.dup)
|
|
63
67
|
c = adapter_class(opts[:adapter_class] || opts[:adapter] || opts['adapter'])
|
|
64
68
|
else
|
|
65
69
|
raise Error, "Sequel::Database.connect takes either a Hash or a String, given: #{conn_string.inspect}"
|
|
@@ -209,20 +213,26 @@ module Sequel
|
|
|
209
213
|
@single_threaded
|
|
210
214
|
end
|
|
211
215
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
216
|
+
if !defined?(RUBY_ENGINE) || RUBY_ENGINE == 'ruby'
|
|
217
|
+
# Acquires a database connection, yielding it to the passed block. This is
|
|
218
|
+
# useful if you want to make sure the same connection is used for all
|
|
219
|
+
# database queries in the block. It is also useful if you want to gain
|
|
220
|
+
# direct access to the underlying connection object if you need to do
|
|
221
|
+
# something Sequel does not natively support.
|
|
222
|
+
#
|
|
223
|
+
# If a server option is given, acquires a connection for that specific
|
|
224
|
+
# server, instead of the :default server.
|
|
225
|
+
#
|
|
226
|
+
# DB.synchronize do |conn|
|
|
227
|
+
# ...
|
|
228
|
+
# end
|
|
229
|
+
def synchronize(server=nil)
|
|
230
|
+
@pool.hold(server || :default){|conn| yield conn}
|
|
231
|
+
end
|
|
232
|
+
else
|
|
233
|
+
def synchronize(server=nil, &block)
|
|
234
|
+
@pool.hold(server || :default, &block)
|
|
235
|
+
end
|
|
226
236
|
end
|
|
227
237
|
|
|
228
238
|
# Attempts to acquire a database connection. Returns true if successful.
|
|
@@ -88,6 +88,7 @@ module Sequel
|
|
|
88
88
|
# end
|
|
89
89
|
def extend_datasets(mod=nil, &block)
|
|
90
90
|
raise(Error, "must provide either mod or block, not both") if mod && block
|
|
91
|
+
reset_schema_utility_dataset
|
|
91
92
|
mod = Module.new(&block) if block
|
|
92
93
|
if @dataset_modules.empty?
|
|
93
94
|
@dataset_modules = [mod]
|
data/lib/sequel/database/misc.rb
CHANGED
|
@@ -121,10 +121,14 @@ module Sequel
|
|
|
121
121
|
end
|
|
122
122
|
|
|
123
123
|
# Returns a string representation of the database object including the
|
|
124
|
-
# class name and
|
|
125
|
-
# cannot be constructed).
|
|
124
|
+
# class name and connection URI and options used when connecting (if any).
|
|
126
125
|
def inspect
|
|
127
|
-
|
|
126
|
+
a = []
|
|
127
|
+
a << uri.inspect if uri
|
|
128
|
+
if (oo = opts[:orig_opts]) && !oo.empty?
|
|
129
|
+
a << oo.inspect
|
|
130
|
+
end
|
|
131
|
+
"#<#{self.class}: #{a.join(' ')}>"
|
|
128
132
|
end
|
|
129
133
|
|
|
130
134
|
# Proxy the literal call to the dataset.
|
|
@@ -148,6 +152,12 @@ module Sequel
|
|
|
148
152
|
false
|
|
149
153
|
end
|
|
150
154
|
|
|
155
|
+
# Whether the database supports DROP TABLE IF EXISTS syntax,
|
|
156
|
+
# default is the same as #supports_create_table_if_not_exists?.
|
|
157
|
+
def supports_drop_table_if_exists?
|
|
158
|
+
supports_create_table_if_not_exists?
|
|
159
|
+
end
|
|
160
|
+
|
|
151
161
|
# Whether the database and adapter support prepared transactions
|
|
152
162
|
# (two-phase commit), false by default.
|
|
153
163
|
def supports_prepared_transactions?
|
|
@@ -197,29 +207,10 @@ module Sequel
|
|
|
197
207
|
end
|
|
198
208
|
end
|
|
199
209
|
|
|
200
|
-
# Returns the URI
|
|
201
|
-
#
|
|
202
|
-
# This method can raise an error if the database used options
|
|
203
|
-
# instead of a connection string, and will not include uri
|
|
204
|
-
# parameters.
|
|
205
|
-
#
|
|
206
|
-
# Sequel.connect('postgres://localhost/db?user=billg').url
|
|
207
|
-
# # => "postgres://billg@localhost/db"
|
|
210
|
+
# Returns the URI use to connect to the database. If a URI
|
|
211
|
+
# was not used when connecting, returns nil.
|
|
208
212
|
def uri
|
|
209
|
-
uri
|
|
210
|
-
adapter_scheme.to_s,
|
|
211
|
-
nil,
|
|
212
|
-
@opts[:host],
|
|
213
|
-
@opts[:port],
|
|
214
|
-
nil,
|
|
215
|
-
"/#{@opts[:database]}",
|
|
216
|
-
nil,
|
|
217
|
-
nil,
|
|
218
|
-
nil
|
|
219
|
-
)
|
|
220
|
-
uri.user = @opts[:user]
|
|
221
|
-
uri.password = @opts[:password] if uri.user
|
|
222
|
-
uri.to_s
|
|
213
|
+
opts[:uri]
|
|
223
214
|
end
|
|
224
215
|
|
|
225
216
|
# Explicit alias of uri for easier subclassing.
|
|
@@ -81,6 +81,24 @@ module Sequel
|
|
|
81
81
|
execute_dui(sql, opts, &block)
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
+
# Returns an array of hashes containing foreign key information from the
|
|
85
|
+
# table. Each hash will contain at least the following fields:
|
|
86
|
+
#
|
|
87
|
+
# :columns :: An array of columns in the given table
|
|
88
|
+
# :table :: The table referenced by the columns
|
|
89
|
+
# :key :: An array of columns referenced (in the table specified by :table),
|
|
90
|
+
# but can be nil on certain adapters if the primary key is referenced.
|
|
91
|
+
#
|
|
92
|
+
# The hash may also contain entries for:
|
|
93
|
+
#
|
|
94
|
+
# :deferrable :: Whether the constraint is deferrable
|
|
95
|
+
# :name :: The name of the constraint
|
|
96
|
+
# :on_delete :: The action to take ON DELETE
|
|
97
|
+
# :on_update :: The action to take ON UPDATE
|
|
98
|
+
def foreign_key_list(table, opts={})
|
|
99
|
+
raise NotImplemented, "#foreign_key_list should be overridden by adapters"
|
|
100
|
+
end
|
|
101
|
+
|
|
84
102
|
# Returns a single value from the database, e.g.:
|
|
85
103
|
#
|
|
86
104
|
# DB.get(1) # SELECT 1
|
|
@@ -286,11 +304,11 @@ module Sequel
|
|
|
286
304
|
if supports_savepoints?
|
|
287
305
|
unless @transactions[conn]
|
|
288
306
|
@transactions[conn] = {:savepoint_level=>0}
|
|
289
|
-
@transactions[conn][:prepare] = opts[:prepare] if supports_prepared_transactions?
|
|
307
|
+
@transactions[conn][:prepare] = opts[:prepare] if opts[:prepare] && supports_prepared_transactions?
|
|
290
308
|
end
|
|
291
309
|
else
|
|
292
310
|
@transactions[conn] = {}
|
|
293
|
-
@transactions[conn][:prepare] = opts[:prepare] if supports_prepared_transactions?
|
|
311
|
+
@transactions[conn][:prepare] = opts[:prepare] if opts[:prepare] && supports_prepared_transactions?
|
|
294
312
|
end
|
|
295
313
|
end
|
|
296
314
|
|
|
@@ -92,9 +92,9 @@ module Sequel
|
|
|
92
92
|
# or not allowing NULL values (if false). If unspecified, will default
|
|
93
93
|
# to whatever the database default is.
|
|
94
94
|
# :on_delete :: Specify the behavior of this column when being deleted
|
|
95
|
-
# (:restrict, cascade, :set_null, :set_default, :no_action).
|
|
95
|
+
# (:restrict, :cascade, :set_null, :set_default, :no_action).
|
|
96
96
|
# :on_update :: Specify the behavior of this column when being updated
|
|
97
|
-
# (:restrict, cascade, :set_null, :set_default, :no_action).
|
|
97
|
+
# (:restrict, :cascade, :set_null, :set_default, :no_action).
|
|
98
98
|
# :primary_key :: Make the column as a single primary key column. This should only
|
|
99
99
|
# be used if you have a single, nonautoincrementing primary key column.
|
|
100
100
|
# :size :: The size of the column, generally used with string
|
|
@@ -6,15 +6,10 @@ module Sequel
|
|
|
6
6
|
# ---------------------
|
|
7
7
|
|
|
8
8
|
AUTOINCREMENT = 'AUTOINCREMENT'.freeze
|
|
9
|
-
CASCADE = 'CASCADE'.freeze
|
|
10
9
|
COMMA_SEPARATOR = ', '.freeze
|
|
11
|
-
NO_ACTION = 'NO ACTION'.freeze
|
|
12
10
|
NOT_NULL = ' NOT NULL'.freeze
|
|
13
11
|
NULL = ' NULL'.freeze
|
|
14
12
|
PRIMARY_KEY = ' PRIMARY KEY'.freeze
|
|
15
|
-
RESTRICT = 'RESTRICT'.freeze
|
|
16
|
-
SET_DEFAULT = 'SET DEFAULT'.freeze
|
|
17
|
-
SET_NULL = 'SET NULL'.freeze
|
|
18
13
|
TEMPORARY = 'TEMPORARY '.freeze
|
|
19
14
|
UNDERSCORE = '_'.freeze
|
|
20
15
|
UNIQUE = ' UNIQUE'.freeze
|
|
@@ -23,6 +18,9 @@ module Sequel
|
|
|
23
18
|
# The order of column modifiers to use when defining a column.
|
|
24
19
|
COLUMN_DEFINITION_ORDER = [:collate, :default, :null, :unique, :primary_key, :auto_increment, :references]
|
|
25
20
|
|
|
21
|
+
# The default options for join table columns.
|
|
22
|
+
DEFAULT_JOIN_TABLE_COLUMN_OPTIONS = {:null=>false}
|
|
23
|
+
|
|
26
24
|
# Adds a column to the specified table. This method expects a column name,
|
|
27
25
|
# a datatype and optionally a hash with additional constraints and options:
|
|
28
26
|
#
|
|
@@ -76,6 +74,54 @@ module Sequel
|
|
|
76
74
|
nil
|
|
77
75
|
end
|
|
78
76
|
|
|
77
|
+
# Create a join table using a hash of foreign keys to referenced
|
|
78
|
+
# table names. Example:
|
|
79
|
+
#
|
|
80
|
+
# create_join_table(:cat_id=>:cats, :dog_id=>:dogs)
|
|
81
|
+
# # CREATE TABLE cats_dogs (
|
|
82
|
+
# # cat_id integer NOT NULL REFERENCES cats,
|
|
83
|
+
# # dog_id integer NOT NULL REFERENCES dogs,
|
|
84
|
+
# # PRIMARY KEY (cat_id, dog_id)
|
|
85
|
+
# # )
|
|
86
|
+
# # CREATE INDEX cats_dogs_dog_id_cat_id_index ON cats_dogs(dog_id, cat_id)
|
|
87
|
+
#
|
|
88
|
+
# The primary key and index are used so that almost all operations
|
|
89
|
+
# on the table can benefit from one of the two indexes, and the primary
|
|
90
|
+
# key ensures that entries in the table are unique, which is the typical
|
|
91
|
+
# desire for a join table.
|
|
92
|
+
#
|
|
93
|
+
# You can provide column options by making the values in the hash
|
|
94
|
+
# be option hashes, so long as the option hashes have a :table
|
|
95
|
+
# entry giving the table referenced:
|
|
96
|
+
#
|
|
97
|
+
# create_join_table(:cat_id=>{:table=>:cats, :type=>Bignum}, :dog_id=>:dogs)
|
|
98
|
+
#
|
|
99
|
+
# You can provide a second argument which is a table options hash:
|
|
100
|
+
#
|
|
101
|
+
# create_join_table({:cat_id=>:cats, :dog_id=>:dogs}, :temp=>true)
|
|
102
|
+
#
|
|
103
|
+
# Some table options are handled specially:
|
|
104
|
+
#
|
|
105
|
+
# :index_options :: The options to pass to the index
|
|
106
|
+
# :name :: The name of the table to create
|
|
107
|
+
# :no_index :: Set to true not to create the second index.
|
|
108
|
+
# :no_primary_key :: Set to true to not create the primary key.
|
|
109
|
+
def create_join_table(hash, options={})
|
|
110
|
+
keys = hash.keys.sort_by{|k| k.to_s}
|
|
111
|
+
create_table(join_table_name(hash, options), options) do
|
|
112
|
+
keys.each do |key|
|
|
113
|
+
v = hash[key]
|
|
114
|
+
unless v.is_a?(Hash)
|
|
115
|
+
v = {:table=>v}
|
|
116
|
+
end
|
|
117
|
+
v = DEFAULT_JOIN_TABLE_COLUMN_OPTIONS.merge(v)
|
|
118
|
+
foreign_key(key, v)
|
|
119
|
+
end
|
|
120
|
+
primary_key(keys) unless options[:no_primary_key]
|
|
121
|
+
index(keys.reverse, options[:index_options] || {}) unless options[:no_index]
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
79
125
|
# Creates a table with the columns given in the provided block:
|
|
80
126
|
#
|
|
81
127
|
# DB.create_table :posts do
|
|
@@ -102,18 +148,18 @@ module Sequel
|
|
|
102
148
|
# Forcibly create a table, attempting to drop it if it already exists, then creating it.
|
|
103
149
|
#
|
|
104
150
|
# DB.create_table!(:a){Integer :a}
|
|
105
|
-
# # SELECT
|
|
151
|
+
# # SELECT NULL FROM a LIMIT 1 -- check existence
|
|
106
152
|
# # DROP TABLE a -- drop table if already exists
|
|
107
153
|
# # CREATE TABLE a (a integer)
|
|
108
154
|
def create_table!(name, options={}, &block)
|
|
109
|
-
drop_table
|
|
155
|
+
drop_table?(name)
|
|
110
156
|
create_table(name, options, &block)
|
|
111
157
|
end
|
|
112
158
|
|
|
113
159
|
# Creates the table unless the table already exists.
|
|
114
160
|
#
|
|
115
161
|
# DB.create_table?(:a){Integer :a}
|
|
116
|
-
# # SELECT
|
|
162
|
+
# # SELECT NULL FROM a LIMIT 1 -- check existence
|
|
117
163
|
# # CREATE TABLE a (a integer) -- if it doesn't already exist
|
|
118
164
|
def create_table?(name, options={}, &block)
|
|
119
165
|
if supports_create_table_if_not_exists?
|
|
@@ -161,10 +207,19 @@ module Sequel
|
|
|
161
207
|
def drop_index(table, columns, options={})
|
|
162
208
|
alter_table(table){drop_index(columns, options)}
|
|
163
209
|
end
|
|
210
|
+
|
|
211
|
+
# Drop the join table that would have been created with the
|
|
212
|
+
# same arguments to create_join_table:
|
|
213
|
+
#
|
|
214
|
+
# drop_join_table(:cat_id=>:cats, :dog_id=>:dogs)
|
|
215
|
+
# # DROP TABLE cats_dogs
|
|
216
|
+
def drop_join_table(hash, options={})
|
|
217
|
+
drop_table(join_table_name(hash, options), options)
|
|
218
|
+
end
|
|
164
219
|
|
|
165
220
|
# Drops one or more tables corresponding to the given names:
|
|
166
221
|
#
|
|
167
|
-
# DB.drop_table(:posts)
|
|
222
|
+
# DB.drop_table(:posts) # DROP TABLE posts
|
|
168
223
|
# DB.drop_table(:posts, :comments)
|
|
169
224
|
# DB.drop_table(:posts, :comments, :cascade=>true)
|
|
170
225
|
def drop_table(*names)
|
|
@@ -176,6 +231,26 @@ module Sequel
|
|
|
176
231
|
nil
|
|
177
232
|
end
|
|
178
233
|
|
|
234
|
+
# Drops the table if it already exists. If it doesn't exist,
|
|
235
|
+
# does nothing.
|
|
236
|
+
#
|
|
237
|
+
# DB.drop_table?(:a)
|
|
238
|
+
# # SELECT NULL FROM a LIMIT 1 -- check existence
|
|
239
|
+
# # DROP TABLE a -- if it already exists
|
|
240
|
+
def drop_table?(*names)
|
|
241
|
+
options = names.last.is_a?(Hash) ? names.pop : {}
|
|
242
|
+
if supports_drop_table_if_exists?
|
|
243
|
+
options = options.merge(:if_exists=>true)
|
|
244
|
+
names.each do |name|
|
|
245
|
+
drop_table(name, options)
|
|
246
|
+
end
|
|
247
|
+
else
|
|
248
|
+
names.each do |name|
|
|
249
|
+
drop_table(name, options) if table_exists?(name)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
179
254
|
# Drops one or more views corresponding to the given names:
|
|
180
255
|
#
|
|
181
256
|
# DB.drop_view(:cheap_items)
|
|
@@ -343,7 +418,7 @@ module Sequel
|
|
|
343
418
|
sql = " REFERENCES #{quote_schema_table(column[:table])}"
|
|
344
419
|
sql << "(#{Array(column[:key]).map{|x| quote_identifier(x)}.join(COMMA_SEPARATOR)})" if column[:key]
|
|
345
420
|
sql << " ON DELETE #{on_delete_clause(column[:on_delete])}" if column[:on_delete]
|
|
346
|
-
sql << " ON UPDATE #{
|
|
421
|
+
sql << " ON UPDATE #{on_update_clause(column[:on_update])}" if column[:on_update]
|
|
347
422
|
sql << " DEFERRABLE INITIALLY DEFERRED" if column[:deferrable]
|
|
348
423
|
sql
|
|
349
424
|
end
|
|
@@ -408,7 +483,7 @@ module Sequel
|
|
|
408
483
|
|
|
409
484
|
# SQL DDL statement to drop the table with the given name.
|
|
410
485
|
def drop_table_sql(name, options)
|
|
411
|
-
"DROP TABLE #{quote_schema_table(name)}#{' CASCADE' if options[:cascade]}"
|
|
486
|
+
"DROP TABLE#{' IF EXISTS' if options[:if_exists]} #{quote_schema_table(name)}#{' CASCADE' if options[:cascade]}"
|
|
412
487
|
end
|
|
413
488
|
|
|
414
489
|
# SQL DDL statement to drop a view with the given name.
|
|
@@ -440,6 +515,32 @@ module Sequel
|
|
|
440
515
|
indexes.map{|i| index_definition_sql(table_name, i)}
|
|
441
516
|
end
|
|
442
517
|
|
|
518
|
+
# Extract the join table name from the arguments given to create_join_table.
|
|
519
|
+
# Also does argument validation for the create_join_table method.
|
|
520
|
+
def join_table_name(hash, options)
|
|
521
|
+
entries = hash.values
|
|
522
|
+
raise Error, "must have 2 entries in hash given to (create|drop)_join_table" unless entries.length == 2
|
|
523
|
+
if options[:name]
|
|
524
|
+
options[:name]
|
|
525
|
+
else
|
|
526
|
+
table_names = entries.map{|e| join_table_name_extract(e)}
|
|
527
|
+
table_names.map{|t| t.to_s}.sort.join('_')
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
# Extract an individual join table name, which should either be a string
|
|
532
|
+
# or symbol, or a hash containing one of those as the value for :table.
|
|
533
|
+
def join_table_name_extract(entry)
|
|
534
|
+
case entry
|
|
535
|
+
when Symbol, String
|
|
536
|
+
entry
|
|
537
|
+
when Hash
|
|
538
|
+
join_table_name_extract(entry[:table])
|
|
539
|
+
else
|
|
540
|
+
raise Error, "can't extract table name from #{entry.inspect}"
|
|
541
|
+
end
|
|
542
|
+
end
|
|
543
|
+
|
|
443
544
|
# SQL DDL ON DELETE fragment to use, based on the given action.
|
|
444
545
|
# The following actions are recognized:
|
|
445
546
|
#
|
|
@@ -450,19 +551,15 @@ module Sequel
|
|
|
450
551
|
# but do not allow deferring the integrity check.
|
|
451
552
|
# * :set_default - Set columns referencing this row to their default value.
|
|
452
553
|
# * :set_null - Set columns referencing this row to NULL.
|
|
554
|
+
#
|
|
555
|
+
# Any other object given is just converted to a string, with "_" converted to " " and upcased.
|
|
453
556
|
def on_delete_clause(action)
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
SET_NULL
|
|
461
|
-
when :set_default
|
|
462
|
-
SET_DEFAULT
|
|
463
|
-
else
|
|
464
|
-
NO_ACTION
|
|
465
|
-
end
|
|
557
|
+
action.to_s.gsub("_", " ").upcase
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
# Alias of #on_delete_clause, since the two usually behave the same.
|
|
561
|
+
def on_update_clause(action)
|
|
562
|
+
on_delete_clause(action)
|
|
466
563
|
end
|
|
467
564
|
|
|
468
565
|
# Proxy the quote_schema_table method to the dataset
|