sequel 3.11.0 → 3.12.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 +70 -0
- data/Rakefile +1 -1
- data/doc/active_record.rdoc +896 -0
- data/doc/advanced_associations.rdoc +46 -31
- data/doc/association_basics.rdoc +14 -9
- data/doc/dataset_basics.rdoc +3 -3
- data/doc/migration.rdoc +1011 -0
- data/doc/model_hooks.rdoc +198 -0
- data/doc/querying.rdoc +811 -86
- data/doc/release_notes/3.12.0.txt +304 -0
- data/doc/sharding.rdoc +17 -0
- data/doc/sql.rdoc +537 -0
- data/doc/validations.rdoc +501 -0
- data/lib/sequel/adapters/jdbc.rb +19 -27
- data/lib/sequel/adapters/jdbc/postgresql.rb +0 -7
- data/lib/sequel/adapters/mysql.rb +5 -4
- data/lib/sequel/adapters/odbc.rb +3 -2
- data/lib/sequel/adapters/shared/mssql.rb +7 -6
- data/lib/sequel/adapters/shared/mysql.rb +2 -7
- data/lib/sequel/adapters/shared/postgres.rb +2 -8
- data/lib/sequel/adapters/shared/sqlite.rb +2 -5
- data/lib/sequel/adapters/sqlite.rb +4 -4
- data/lib/sequel/core.rb +0 -1
- data/lib/sequel/database.rb +2 -1060
- data/lib/sequel/database/connecting.rb +227 -0
- data/lib/sequel/database/dataset.rb +58 -0
- data/lib/sequel/database/dataset_defaults.rb +127 -0
- data/lib/sequel/database/logging.rb +62 -0
- data/lib/sequel/database/misc.rb +246 -0
- data/lib/sequel/database/query.rb +390 -0
- data/lib/sequel/database/schema_generator.rb +7 -3
- data/lib/sequel/database/schema_methods.rb +351 -7
- data/lib/sequel/dataset/actions.rb +9 -2
- data/lib/sequel/dataset/misc.rb +6 -2
- data/lib/sequel/dataset/mutation.rb +3 -11
- data/lib/sequel/dataset/query.rb +49 -6
- data/lib/sequel/exceptions.rb +3 -0
- data/lib/sequel/extensions/migration.rb +395 -113
- data/lib/sequel/extensions/schema_dumper.rb +21 -13
- data/lib/sequel/model.rb +27 -25
- data/lib/sequel/model/associations.rb +72 -34
- data/lib/sequel/model/base.rb +74 -18
- data/lib/sequel/model/errors.rb +8 -1
- data/lib/sequel/plugins/active_model.rb +8 -0
- data/lib/sequel/plugins/association_pks.rb +87 -0
- data/lib/sequel/plugins/association_proxies.rb +8 -0
- data/lib/sequel/plugins/boolean_readers.rb +12 -6
- data/lib/sequel/plugins/caching.rb +14 -7
- data/lib/sequel/plugins/class_table_inheritance.rb +15 -9
- data/lib/sequel/plugins/composition.rb +2 -1
- data/lib/sequel/plugins/force_encoding.rb +10 -7
- data/lib/sequel/plugins/hook_class_methods.rb +12 -11
- data/lib/sequel/plugins/identity_map.rb +9 -0
- data/lib/sequel/plugins/instance_hooks.rb +23 -13
- data/lib/sequel/plugins/lazy_attributes.rb +4 -1
- data/lib/sequel/plugins/many_through_many.rb +18 -4
- data/lib/sequel/plugins/nested_attributes.rb +1 -0
- data/lib/sequel/plugins/optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +9 -8
- data/lib/sequel/plugins/schema.rb +8 -0
- data/lib/sequel/plugins/serialization.rb +1 -3
- data/lib/sequel/plugins/sharding.rb +135 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +117 -25
- data/lib/sequel/plugins/skip_create_refresh.rb +35 -0
- data/lib/sequel/plugins/string_stripper.rb +26 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +8 -0
- data/lib/sequel/plugins/timestamps.rb +15 -2
- data/lib/sequel/plugins/touch.rb +13 -0
- data/lib/sequel/plugins/update_primary_key.rb +48 -0
- data/lib/sequel/plugins/validation_class_methods.rb +8 -0
- data/lib/sequel/plugins/validation_helpers.rb +1 -1
- data/lib/sequel/sql.rb +17 -20
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/postgres_spec.rb +5 -5
- data/spec/core/core_sql_spec.rb +17 -1
- data/spec/core/database_spec.rb +17 -5
- data/spec/core/dataset_spec.rb +31 -8
- data/spec/core/schema_generator_spec.rb +8 -1
- data/spec/core/schema_spec.rb +13 -0
- data/spec/extensions/association_pks_spec.rb +85 -0
- data/spec/extensions/hook_class_methods_spec.rb +9 -9
- data/spec/extensions/migration_spec.rb +339 -219
- data/spec/extensions/schema_dumper_spec.rb +28 -17
- data/spec/extensions/sharding_spec.rb +272 -0
- data/spec/extensions/single_table_inheritance_spec.rb +92 -4
- data/spec/extensions/skip_create_refresh_spec.rb +17 -0
- data/spec/extensions/string_stripper_spec.rb +23 -0
- data/spec/extensions/update_primary_key_spec.rb +65 -0
- data/spec/extensions/validation_class_methods_spec.rb +5 -5
- data/spec/files/bad_down_migration/001_create_alt_basic.rb +4 -0
- data/spec/files/bad_down_migration/002_create_alt_advanced.rb +4 -0
- data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +9 -0
- data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +9 -0
- data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +3 -0
- data/spec/files/bad_up_migration/001_create_alt_basic.rb +4 -0
- data/spec/files/bad_up_migration/002_create_alt_advanced.rb +3 -0
- data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +9 -0
- data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +9 -0
- data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +4 -0
- data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +9 -0
- data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +9 -0
- data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +4 -0
- data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +4 -0
- data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +9 -0
- data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +9 -0
- data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +4 -0
- data/spec/files/integer_migrations/001_create_sessions.rb +9 -0
- data/spec/files/integer_migrations/002_create_nodes.rb +9 -0
- data/spec/files/integer_migrations/003_3_create_users.rb +4 -0
- data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +9 -0
- data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +9 -0
- data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +9 -0
- data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +9 -0
- data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +4 -0
- data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +4 -0
- data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +4 -0
- data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +9 -0
- data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +4 -0
- data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +9 -0
- data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +9 -0
- data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +4 -0
- data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +9 -0
- data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +9 -0
- data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +4 -0
- data/spec/integration/eager_loader_test.rb +20 -20
- data/spec/integration/migrator_test.rb +187 -0
- data/spec/integration/plugin_test.rb +150 -0
- data/spec/integration/schema_test.rb +13 -2
- data/spec/model/associations_spec.rb +41 -14
- data/spec/model/base_spec.rb +69 -0
- data/spec/model/eager_loading_spec.rb +7 -3
- data/spec/model/record_spec.rb +79 -4
- data/spec/model/validations_spec.rb +21 -9
- metadata +66 -5
- data/doc/schema.rdoc +0 -36
- data/lib/sequel/database/schema_sql.rb +0 -320
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
module Sequel
|
|
2
|
+
class Database
|
|
3
|
+
# ---------------------
|
|
4
|
+
# :section: Methods relating to adapters, connecting, disconnecting, and sharding
|
|
5
|
+
# This methods involve the Database's connection pool.
|
|
6
|
+
# ---------------------
|
|
7
|
+
|
|
8
|
+
# Array of supported database adapters
|
|
9
|
+
ADAPTERS = %w'ado amalgalite db2 dbi do firebird informix jdbc mysql odbc openbase oracle postgres sqlite'.collect{|x| x.to_sym}
|
|
10
|
+
|
|
11
|
+
# Whether to use the single threaded connection pool by default
|
|
12
|
+
@@single_threaded = false
|
|
13
|
+
|
|
14
|
+
# The Database subclass for the given adapter scheme.
|
|
15
|
+
# Raises Sequel::AdapterNotFound if the adapter
|
|
16
|
+
# could not be loaded.
|
|
17
|
+
def self.adapter_class(scheme)
|
|
18
|
+
scheme = scheme.to_s.gsub('-', '_').to_sym
|
|
19
|
+
|
|
20
|
+
unless klass = ADAPTER_MAP[scheme]
|
|
21
|
+
# attempt to load the adapter file
|
|
22
|
+
begin
|
|
23
|
+
Sequel.tsk_require "sequel/adapters/#{scheme}"
|
|
24
|
+
rescue LoadError => e
|
|
25
|
+
raise Sequel.convert_exception_class(e, AdapterNotFound)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# make sure we actually loaded the adapter
|
|
29
|
+
unless klass = ADAPTER_MAP[scheme]
|
|
30
|
+
raise AdapterNotFound, "Could not load #{scheme} adapter"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
klass
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Returns the scheme for the Database class.
|
|
37
|
+
def self.adapter_scheme
|
|
38
|
+
@scheme
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Connects to a database. See Sequel.connect.
|
|
42
|
+
def self.connect(conn_string, opts = {})
|
|
43
|
+
case conn_string
|
|
44
|
+
when String
|
|
45
|
+
if match = /\A(jdbc|do):/o.match(conn_string)
|
|
46
|
+
c = adapter_class(match[1].to_sym)
|
|
47
|
+
opts = {:uri=>conn_string}.merge(opts)
|
|
48
|
+
else
|
|
49
|
+
uri = URI.parse(conn_string)
|
|
50
|
+
scheme = uri.scheme
|
|
51
|
+
scheme = :dbi if scheme =~ /\Adbi-/
|
|
52
|
+
c = adapter_class(scheme)
|
|
53
|
+
uri_options = c.send(:uri_to_options, uri)
|
|
54
|
+
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?
|
|
55
|
+
uri_options.entries.each{|k,v| uri_options[k] = URI.unescape(v) if v.is_a?(String)}
|
|
56
|
+
opts = uri_options.merge(opts)
|
|
57
|
+
end
|
|
58
|
+
when Hash
|
|
59
|
+
opts = conn_string.merge(opts)
|
|
60
|
+
c = adapter_class(opts[:adapter] || opts['adapter'])
|
|
61
|
+
else
|
|
62
|
+
raise Error, "Sequel::Database.connect takes either a Hash or a String, given: #{conn_string.inspect}"
|
|
63
|
+
end
|
|
64
|
+
# process opts a bit
|
|
65
|
+
opts = opts.inject({}) do |m, kv| k, v = *kv
|
|
66
|
+
k = :user if k.to_s == 'username'
|
|
67
|
+
m[k.to_sym] = v
|
|
68
|
+
m
|
|
69
|
+
end
|
|
70
|
+
begin
|
|
71
|
+
db = c.new(opts)
|
|
72
|
+
db.test_connection if opts[:test] && db.send(:typecast_value_boolean, opts[:test])
|
|
73
|
+
result = yield(db) if block_given?
|
|
74
|
+
ensure
|
|
75
|
+
if block_given?
|
|
76
|
+
db.disconnect if db
|
|
77
|
+
::Sequel::DATABASES.delete(db)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
block_given? ? result : db
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Sets the default single_threaded mode for new databases.
|
|
84
|
+
# See Sequel.single_threaded=.
|
|
85
|
+
def self.single_threaded=(value)
|
|
86
|
+
@@single_threaded = value
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Sets the adapter scheme for the Database class. Call this method in
|
|
90
|
+
# descendants of Database to allow connection using a URL. For example the
|
|
91
|
+
# following:
|
|
92
|
+
#
|
|
93
|
+
# class Sequel::MyDB::Database < Sequel::Database
|
|
94
|
+
# set_adapter_scheme :mydb
|
|
95
|
+
# ...
|
|
96
|
+
# end
|
|
97
|
+
#
|
|
98
|
+
# would allow connection using:
|
|
99
|
+
#
|
|
100
|
+
# Sequel.connect('mydb://user:password@dbserver/mydb')
|
|
101
|
+
def self.set_adapter_scheme(scheme) # :nodoc:
|
|
102
|
+
@scheme = scheme
|
|
103
|
+
ADAPTER_MAP[scheme.to_sym] = self
|
|
104
|
+
end
|
|
105
|
+
private_class_method :set_adapter_scheme
|
|
106
|
+
|
|
107
|
+
# The connection pool for this database
|
|
108
|
+
attr_reader :pool
|
|
109
|
+
|
|
110
|
+
# Dynamically add new servers or modify server options at runtime. Also adds new
|
|
111
|
+
# servers to the connection pool. Intended for use with master/slave or shard
|
|
112
|
+
# configurations where it is useful to add new server hosts at runtime.
|
|
113
|
+
#
|
|
114
|
+
# servers argument should be a hash with server name symbol keys and hash or
|
|
115
|
+
# proc values. If a servers key is already in use, it's value is overridden
|
|
116
|
+
# with the value provided.
|
|
117
|
+
#
|
|
118
|
+
# DB.add_servers(:f=>{:host=>"hash_host_f"})
|
|
119
|
+
def add_servers(servers)
|
|
120
|
+
@opts[:servers] = @opts[:servers] ? @opts[:servers].merge(servers) : servers
|
|
121
|
+
@pool.add_servers(servers.keys)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Connects to the database. This method should be overridden by descendants.
|
|
125
|
+
def connect(server)
|
|
126
|
+
raise NotImplemented, "#connect should be overridden by adapters"
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# The database type for this database object, the same as the adapter scheme
|
|
130
|
+
# by default. Should be overridden in adapters (especially shared adapters)
|
|
131
|
+
# to be the correct type, so that even if two separate Database objects are
|
|
132
|
+
# using different adapters you can tell that they are using the same database
|
|
133
|
+
# type. Even better, you can tell that two Database objects that are using
|
|
134
|
+
# the same adapter are connecting to different database types (think JDBC or
|
|
135
|
+
# DataObjects).
|
|
136
|
+
def database_type
|
|
137
|
+
self.class.adapter_scheme
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Disconnects all available connections from the connection pool. Any
|
|
141
|
+
# connections currently in use will not be disconnected. Options:
|
|
142
|
+
# * :servers - Should be a symbol specifing the server to disconnect from,
|
|
143
|
+
# or an array of symbols to specify multiple servers.
|
|
144
|
+
def disconnect(opts = {})
|
|
145
|
+
pool.disconnect(opts)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Yield a new database object for every server in the connection pool.
|
|
149
|
+
# Intended for use in sharded environments where there is a need to make schema
|
|
150
|
+
# modifications (DDL queries) on each shard.
|
|
151
|
+
#
|
|
152
|
+
# DB.each_server{|db| db.create_table(:users){primary_key :id; String :name}}
|
|
153
|
+
def each_server(&block)
|
|
154
|
+
servers.each{|s| self.class.connect(server_opts(s), &block)}
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Dynamically remove existing servers from the connection pool. Intended for
|
|
158
|
+
# use with master/slave or shard configurations where it is useful to remove
|
|
159
|
+
# existing server hosts at runtime.
|
|
160
|
+
#
|
|
161
|
+
# servers should be symbols or arrays of symbols. If a nonexistent server
|
|
162
|
+
# is specified, it is ignored. If no servers have been specified for
|
|
163
|
+
# this database, no changes are made. If you attempt to remove the :default server,
|
|
164
|
+
# an error will be raised.
|
|
165
|
+
#
|
|
166
|
+
# DB.remove_servers(:f1, :f2)
|
|
167
|
+
def remove_servers(*servers)
|
|
168
|
+
if @opts[:servers] && !@opts[:servers].empty?
|
|
169
|
+
servs = @opts[:servers].dup
|
|
170
|
+
servers.flatten!
|
|
171
|
+
servers.each{|s| servs.delete(s)}
|
|
172
|
+
@opts[:servers] = servs
|
|
173
|
+
@pool.remove_servers(servers)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# An array of servers/shards for this Database object.
|
|
178
|
+
def servers
|
|
179
|
+
pool.servers
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Returns true if the database is using a single-threaded connection pool.
|
|
183
|
+
def single_threaded?
|
|
184
|
+
@single_threaded
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Acquires a database connection, yielding it to the passed block.
|
|
188
|
+
def synchronize(server=nil, &block)
|
|
189
|
+
@pool.hold(server || :default, &block)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Attempts to acquire a database connection. Returns true if successful.
|
|
193
|
+
# Will probably raise an error if unsuccessful.
|
|
194
|
+
def test_connection(server=nil)
|
|
195
|
+
synchronize(server){|conn|}
|
|
196
|
+
true
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
private
|
|
200
|
+
|
|
201
|
+
# The default options for the connection pool.
|
|
202
|
+
def connection_pool_default_options
|
|
203
|
+
{}
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Return the options for the given server by merging the generic
|
|
207
|
+
# options for all server with the specific options for the given
|
|
208
|
+
# server specified in the :servers option.
|
|
209
|
+
def server_opts(server)
|
|
210
|
+
opts = if @opts[:servers] && server_options = @opts[:servers][server]
|
|
211
|
+
case server_options
|
|
212
|
+
when Hash
|
|
213
|
+
@opts.merge(server_options)
|
|
214
|
+
when Proc
|
|
215
|
+
@opts.merge(server_options.call(self))
|
|
216
|
+
else
|
|
217
|
+
raise Error, 'Server opts should be a hash or proc'
|
|
218
|
+
end
|
|
219
|
+
else
|
|
220
|
+
@opts.dup
|
|
221
|
+
end
|
|
222
|
+
opts.delete(:servers)
|
|
223
|
+
opts
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
end
|
|
227
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Sequel
|
|
2
|
+
class Database
|
|
3
|
+
# ---------------------
|
|
4
|
+
# :section: Methods that create datasets
|
|
5
|
+
# These methods all return instances of this database's dataset class.
|
|
6
|
+
# ---------------------
|
|
7
|
+
|
|
8
|
+
# Returns a dataset from the database. If the first argument is a string,
|
|
9
|
+
# the method acts as an alias for Database#fetch, returning a dataset for
|
|
10
|
+
# arbitrary SQL:
|
|
11
|
+
#
|
|
12
|
+
# DB['SELECT * FROM items WHERE name = ?', my_name].all
|
|
13
|
+
#
|
|
14
|
+
# Otherwise, acts as an alias for Database#from, setting the primary
|
|
15
|
+
# table for the dataset:
|
|
16
|
+
#
|
|
17
|
+
# DB[:items].sql #=> "SELECT * FROM items"
|
|
18
|
+
def [](*args)
|
|
19
|
+
(String === args.first) ? fetch(*args) : from(*args)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns a blank dataset for this database
|
|
23
|
+
def dataset
|
|
24
|
+
ds = Sequel::Dataset.new(self)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Fetches records for an arbitrary SQL statement. If a block is given,
|
|
28
|
+
# it is used to iterate over the records:
|
|
29
|
+
#
|
|
30
|
+
# DB.fetch('SELECT * FROM items'){|r| p r}
|
|
31
|
+
#
|
|
32
|
+
# The method returns a dataset instance:
|
|
33
|
+
#
|
|
34
|
+
# DB.fetch('SELECT * FROM items').all
|
|
35
|
+
#
|
|
36
|
+
# Fetch can also perform parameterized queries for protection against SQL
|
|
37
|
+
# injection:
|
|
38
|
+
#
|
|
39
|
+
# DB.fetch('SELECT * FROM items WHERE name = ?', my_name).all
|
|
40
|
+
def fetch(sql, *args, &block)
|
|
41
|
+
ds = dataset.with_sql(sql, *args)
|
|
42
|
+
ds.each(&block) if block
|
|
43
|
+
ds
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Returns a new dataset with the from method invoked. If a block is given,
|
|
47
|
+
# it is used as a filter on the dataset.
|
|
48
|
+
def from(*args, &block)
|
|
49
|
+
ds = dataset.from(*args)
|
|
50
|
+
block ? ds.filter(&block) : ds
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns a new dataset with the select method invoked.
|
|
54
|
+
def select(*args, &block)
|
|
55
|
+
dataset.select(*args, &block)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
module Sequel
|
|
2
|
+
class Database
|
|
3
|
+
# ---------------------
|
|
4
|
+
# :section: Methods that set defaults for created datasets
|
|
5
|
+
# This methods change the default behavior of this database's datasets.
|
|
6
|
+
# ---------------------
|
|
7
|
+
|
|
8
|
+
# The identifier input method to use by default
|
|
9
|
+
@@identifier_input_method = nil
|
|
10
|
+
|
|
11
|
+
# The identifier output method to use by default
|
|
12
|
+
@@identifier_output_method = nil
|
|
13
|
+
|
|
14
|
+
# Whether to quote identifiers (columns and tables) by default
|
|
15
|
+
@@quote_identifiers = nil
|
|
16
|
+
|
|
17
|
+
# The method to call on identifiers going into the database
|
|
18
|
+
def self.identifier_input_method
|
|
19
|
+
@@identifier_input_method
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Set the method to call on identifiers going into the database
|
|
23
|
+
# See Sequel.identifier_input_method=.
|
|
24
|
+
def self.identifier_input_method=(v)
|
|
25
|
+
@@identifier_input_method = v || ""
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# The method to call on identifiers coming from the database
|
|
29
|
+
def self.identifier_output_method
|
|
30
|
+
@@identifier_output_method
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Set the method to call on identifiers coming from the database
|
|
34
|
+
# See Sequel.identifier_output_method=.
|
|
35
|
+
def self.identifier_output_method=(v)
|
|
36
|
+
@@identifier_output_method = v || ""
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Sets the default quote_identifiers mode for new databases.
|
|
40
|
+
# See Sequel.quote_identifiers=.
|
|
41
|
+
def self.quote_identifiers=(value)
|
|
42
|
+
@@quote_identifiers = value
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# The default schema to use, generally should be nil.
|
|
46
|
+
attr_accessor :default_schema
|
|
47
|
+
|
|
48
|
+
# The method to call on identifiers going into the database
|
|
49
|
+
def identifier_input_method
|
|
50
|
+
case @identifier_input_method
|
|
51
|
+
when nil
|
|
52
|
+
@identifier_input_method = @opts.fetch(:identifier_input_method, (@@identifier_input_method.nil? ? identifier_input_method_default : @@identifier_input_method))
|
|
53
|
+
@identifier_input_method == "" ? nil : @identifier_input_method
|
|
54
|
+
when ""
|
|
55
|
+
nil
|
|
56
|
+
else
|
|
57
|
+
@identifier_input_method
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Set the method to call on identifiers going into the database
|
|
62
|
+
def identifier_input_method=(v)
|
|
63
|
+
reset_schema_utility_dataset
|
|
64
|
+
@identifier_input_method = v || ""
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# The method to call on identifiers coming from the database
|
|
68
|
+
def identifier_output_method
|
|
69
|
+
case @identifier_output_method
|
|
70
|
+
when nil
|
|
71
|
+
@identifier_output_method = @opts.fetch(:identifier_output_method, (@@identifier_output_method.nil? ? identifier_output_method_default : @@identifier_output_method))
|
|
72
|
+
@identifier_output_method == "" ? nil : @identifier_output_method
|
|
73
|
+
when ""
|
|
74
|
+
nil
|
|
75
|
+
else
|
|
76
|
+
@identifier_output_method
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Set the method to call on identifiers coming from the database
|
|
81
|
+
def identifier_output_method=(v)
|
|
82
|
+
reset_schema_utility_dataset
|
|
83
|
+
@identifier_output_method = v || ""
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Whether to quote identifiers (columns and tables) for this database
|
|
87
|
+
def quote_identifiers=(v)
|
|
88
|
+
reset_schema_utility_dataset
|
|
89
|
+
@quote_identifiers = v
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Returns true if the database quotes identifiers.
|
|
93
|
+
def quote_identifiers?
|
|
94
|
+
return @quote_identifiers unless @quote_identifiers.nil?
|
|
95
|
+
@quote_identifiers = @opts.fetch(:quote_identifiers, (@@quote_identifiers.nil? ? quote_identifiers_default : @@quote_identifiers))
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
# The default value for default_schema.
|
|
101
|
+
def default_schema_default
|
|
102
|
+
nil
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# The method to apply to identifiers going into the database by default.
|
|
106
|
+
# Should be overridden in subclasses for databases that fold unquoted
|
|
107
|
+
# identifiers to lower case instead of uppercase, such as
|
|
108
|
+
# MySQL, PostgreSQL, and SQLite.
|
|
109
|
+
def identifier_input_method_default
|
|
110
|
+
:upcase
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# The method to apply to identifiers coming the database by default.
|
|
114
|
+
# Should be overridden in subclasses for databases that fold unquoted
|
|
115
|
+
# identifiers to lower case instead of uppercase, such as
|
|
116
|
+
# MySQL, PostgreSQL, and SQLite.
|
|
117
|
+
def identifier_output_method_default
|
|
118
|
+
:downcase
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Whether to quote identifiers by default for this database, true
|
|
122
|
+
# by default.
|
|
123
|
+
def quote_identifiers_default
|
|
124
|
+
true
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Sequel
|
|
2
|
+
class Database
|
|
3
|
+
# ---------------------
|
|
4
|
+
# :section: Methods relating to logging
|
|
5
|
+
# This methods affect relating to the logging of executed SQL.
|
|
6
|
+
# ---------------------
|
|
7
|
+
|
|
8
|
+
# Numeric specifying the duration beyond which queries are logged at warn
|
|
9
|
+
# level instead of info level.
|
|
10
|
+
attr_accessor :log_warn_duration
|
|
11
|
+
|
|
12
|
+
# Array of SQL loggers to use for this database
|
|
13
|
+
attr_accessor :loggers
|
|
14
|
+
|
|
15
|
+
# Log a message at level info to all loggers.
|
|
16
|
+
def log_info(message, args=nil)
|
|
17
|
+
log_each(:info, args ? "#{message}; #{args.inspect}" : message)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Yield to the block, logging any errors at error level to all loggers,
|
|
21
|
+
# and all other queries with the duration at warn or info level.
|
|
22
|
+
def log_yield(sql, args=nil)
|
|
23
|
+
return yield if @loggers.empty?
|
|
24
|
+
sql = "#{sql}; #{args.inspect}" if args
|
|
25
|
+
start = Time.now
|
|
26
|
+
begin
|
|
27
|
+
yield
|
|
28
|
+
rescue => e
|
|
29
|
+
log_each(:error, "#{e.class}: #{e.message.strip}: #{sql}")
|
|
30
|
+
raise
|
|
31
|
+
ensure
|
|
32
|
+
log_duration(Time.now - start, sql) unless e
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Remove any existing loggers and just use the given logger.
|
|
37
|
+
def logger=(logger)
|
|
38
|
+
@loggers = Array(logger)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
# Log the given SQL and then execute it on the connection, used by
|
|
44
|
+
# the transaction code.
|
|
45
|
+
def log_connection_execute(conn, sql)
|
|
46
|
+
log_yield(sql){conn.send(connection_execute_method, sql)}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Log message with message prefixed by duration at info level, or
|
|
50
|
+
# warn level if duration is greater than log_warn_duration.
|
|
51
|
+
def log_duration(duration, message)
|
|
52
|
+
log_each((lwd = log_warn_duration and duration >= lwd) ? :warn : :info, "(#{sprintf('%0.6fs', duration)}) #{message}")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Log message at level (which should be :error, :warn, or :info)
|
|
56
|
+
# to all loggers.
|
|
57
|
+
def log_each(level, message)
|
|
58
|
+
@loggers.each{|logger| logger.send(level, message)}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
end
|