sequel 4.42.1 → 4.43.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.
- checksums.yaml +4 -4
- data/CHANGELOG +35 -1
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/doc/release_notes/4.43.0.txt +87 -0
- data/doc/sql.rdoc +26 -27
- data/doc/testing.rdoc +2 -0
- data/doc/validations.rdoc +1 -1
- data/lib/sequel/adapters/ado.rb +5 -0
- data/lib/sequel/adapters/cubrid.rb +5 -0
- data/lib/sequel/adapters/ibmdb.rb +5 -0
- data/lib/sequel/adapters/jdbc.rb +6 -0
- data/lib/sequel/adapters/jdbc/derby.rb +5 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +9 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +1 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +5 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +5 -0
- data/lib/sequel/adapters/mock.rb +12 -9
- data/lib/sequel/adapters/mysql.rb +6 -0
- data/lib/sequel/adapters/mysql2.rb +7 -2
- data/lib/sequel/adapters/oracle.rb +5 -0
- data/lib/sequel/adapters/shared/db2.rb +7 -1
- data/lib/sequel/adapters/shared/mssql.rb +5 -0
- data/lib/sequel/adapters/shared/mysql.rb +8 -1
- data/lib/sequel/adapters/shared/oracle.rb +20 -12
- data/lib/sequel/adapters/shared/postgres.rb +11 -2
- data/lib/sequel/adapters/shared/sqlanywhere.rb +6 -0
- data/lib/sequel/adapters/shared/sqlite.rb +29 -0
- data/lib/sequel/adapters/sqlanywhere.rb +5 -0
- data/lib/sequel/adapters/sqlite.rb +13 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +5 -0
- data/lib/sequel/connection_pool/single.rb +15 -6
- data/lib/sequel/database/dataset.rb +3 -0
- data/lib/sequel/database/misc.rb +22 -1
- data/lib/sequel/database/query.rb +2 -4
- data/lib/sequel/dataset/actions.rb +0 -1
- data/lib/sequel/dataset/misc.rb +2 -4
- data/lib/sequel/dataset/query.rb +23 -6
- data/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
- data/lib/sequel/extensions/_model_pg_row.rb +47 -0
- data/lib/sequel/extensions/looser_typecasting.rb +2 -0
- data/lib/sequel/extensions/migration.rb +12 -1
- data/lib/sequel/extensions/pg_array.rb +6 -0
- data/lib/sequel/extensions/pg_enum.rb +2 -1
- data/lib/sequel/extensions/pg_range.rb +6 -0
- data/lib/sequel/extensions/pg_row.rb +8 -0
- data/lib/sequel/model/associations.rb +3 -1
- data/lib/sequel/model/base.rb +14 -3
- data/lib/sequel/plugins/constraint_validations.rb +1 -8
- data/lib/sequel/plugins/instance_filters.rb +1 -1
- data/lib/sequel/plugins/pg_row.rb +1 -40
- data/lib/sequel/plugins/prepared_statements.rb +51 -20
- data/lib/sequel/plugins/prepared_statements_associations.rb +22 -4
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +9 -1
- data/lib/sequel/plugins/sharding.rb +5 -0
- data/lib/sequel/plugins/update_primary_key.rb +1 -1
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/spec_helper.rb +4 -0
- data/spec/core/connection_pool_spec.rb +10 -0
- data/spec/core/database_spec.rb +29 -0
- data/spec/extensions/blacklist_security_spec.rb +4 -4
- data/spec/extensions/defaults_setter_spec.rb +1 -1
- data/spec/extensions/force_encoding_spec.rb +3 -2
- data/spec/extensions/identifier_mangling_spec.rb +7 -0
- data/spec/extensions/instance_filters_spec.rb +1 -0
- data/spec/extensions/migration_spec.rb +19 -0
- data/spec/extensions/pg_array_spec.rb +5 -0
- data/spec/extensions/pg_range_spec.rb +5 -0
- data/spec/extensions/pg_row_spec.rb +9 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +45 -1
- data/spec/extensions/prepared_statements_spec.rb +138 -41
- data/spec/extensions/prepared_statements_with_pk_spec.rb +7 -0
- data/spec/extensions/serialization_spec.rb +6 -6
- data/spec/extensions/single_table_inheritance_spec.rb +3 -3
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/integration/associations_test.rb +2 -2
- data/spec/integration/dataset_test.rb +0 -4
- data/spec/integration/eager_loader_test.rb +5 -5
- data/spec/integration/plugin_test.rb +8 -6
- data/spec/integration/schema_test.rb +2 -2
- data/spec/integration/spec_helper.rb +10 -0
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +5 -5
- data/spec/model/associations_spec.rb +13 -6
- data/spec/model/base_spec.rb +1 -1
- data/spec/model/hooks_spec.rb +4 -4
- data/spec/model/model_spec.rb +2 -2
- data/spec/model/record_spec.rb +17 -18
- metadata +6 -2
@@ -56,49 +56,10 @@ module Sequel
|
|
56
56
|
# loaded, load the custom database extensions, and automatically register the
|
57
57
|
# row type if the model has a dataset.
|
58
58
|
def self.configure(model)
|
59
|
-
model.db.extension(:pg_row)
|
60
|
-
model.db.extend(DatabaseMethods)
|
59
|
+
model.db.extension(:pg_row, :_model_pg_row)
|
61
60
|
model.register_row_type if model.instance_variable_get(:@dataset)
|
62
61
|
end
|
63
62
|
|
64
|
-
module DatabaseMethods
|
65
|
-
ESCAPE_RE = /("|\\)/.freeze
|
66
|
-
ESCAPE_REPLACEMENT = '\\\\\1'.freeze
|
67
|
-
COMMA = ','
|
68
|
-
|
69
|
-
# Handle Sequel::Model instances in bound variables.
|
70
|
-
def bound_variable_arg(arg, conn)
|
71
|
-
case arg
|
72
|
-
when Sequel::Model
|
73
|
-
"(#{arg.values.values_at(*arg.columns).map{|v| bound_variable_array(v)}.join(COMMA)})"
|
74
|
-
else
|
75
|
-
super
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# If a Sequel::Model instance is given, return it as-is
|
80
|
-
# instead of attempting to convert it.
|
81
|
-
def row_type(db_type, v)
|
82
|
-
if v.is_a?(Sequel::Model)
|
83
|
-
v
|
84
|
-
else
|
85
|
-
super
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
private
|
90
|
-
|
91
|
-
# Handle Sequel::Model instances in bound variable arrays.
|
92
|
-
def bound_variable_array(arg)
|
93
|
-
case arg
|
94
|
-
when Sequel::Model
|
95
|
-
"\"(#{arg.values.values_at(*arg.columns).map{|v| bound_variable_array(v)}.join(COMMA).gsub(ESCAPE_RE, ESCAPE_REPLACEMENT)})\""
|
96
|
-
else
|
97
|
-
super
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
63
|
module ClassMethods
|
103
64
|
# Register the model's row type with the database.
|
104
65
|
def register_row_type
|
@@ -1,22 +1,11 @@
|
|
1
1
|
# frozen-string-literal: true
|
2
2
|
|
3
3
|
module Sequel
|
4
|
-
class Model
|
5
|
-
module InstanceMethods
|
6
|
-
# Whether prepared statements should be used for the given type of query
|
7
|
-
# (:insert, :insert_select, :refresh, :update, or :delete). True by default,
|
8
|
-
# can be overridden in other plugins to disallow prepared statements for
|
9
|
-
# specific types of queries.
|
10
|
-
def use_prepared_statements_for?(type)
|
11
|
-
true
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
4
|
module Plugins
|
17
5
|
# The prepared_statements plugin modifies the model to use prepared statements for
|
18
|
-
# instance level
|
19
|
-
# primary key
|
6
|
+
# instance level saves (inserts and updates). It also will use prepared statements for
|
7
|
+
# deletes, refreshes, and class level lookups by primary key, if it thinks that using
|
8
|
+
# a prepared statement will be faster in such cases.
|
20
9
|
#
|
21
10
|
# Note that this plugin is unsafe in some circumstances, as it can allow up to
|
22
11
|
# 2^N prepared statements to be created for each type of insert and update query, where
|
@@ -132,7 +121,7 @@ module Sequel
|
|
132
121
|
|
133
122
|
# Use a prepared statement to query the database for the row matching the given primary key.
|
134
123
|
def primary_key_lookup(pk)
|
135
|
-
return super
|
124
|
+
return super unless use_prepared_statements_for_pk_lookup?
|
136
125
|
prepared_lookup.call(primary_key_hash(pk))
|
137
126
|
end
|
138
127
|
|
@@ -148,6 +137,12 @@ module Sequel
|
|
148
137
|
ps = yield
|
149
138
|
Sequel.synchronize{h[subtype] = ps}
|
150
139
|
end
|
140
|
+
|
141
|
+
# Whether to use prepared statements for lookups by primary key. True if the default
|
142
|
+
# primary key lookup isn't optimized.
|
143
|
+
def use_prepared_statements_for_pk_lookup?
|
144
|
+
!@fast_pk_lookup_sql && !dataset.joined_dataset?
|
145
|
+
end
|
151
146
|
end
|
152
147
|
|
153
148
|
module InstanceMethods
|
@@ -156,7 +151,7 @@ module Sequel
|
|
156
151
|
# Use a prepared statement to delete the row.
|
157
152
|
def _delete_without_checking
|
158
153
|
if use_prepared_statements_for?(:delete)
|
159
|
-
model.send(:prepared_delete).call(pk_hash)
|
154
|
+
_set_prepared_statement_server(model.send(:prepared_delete)).call(pk_hash)
|
160
155
|
else
|
161
156
|
super
|
162
157
|
end
|
@@ -165,7 +160,7 @@ module Sequel
|
|
165
160
|
# Use a prepared statement to insert the values into the model's dataset.
|
166
161
|
def _insert_raw(ds)
|
167
162
|
if use_prepared_statements_for?(:insert)
|
168
|
-
model.send(:prepared_insert, @values.keys).call(@values)
|
163
|
+
_set_prepared_statement_server(model.send(:prepared_insert, @values.keys)).call(@values)
|
169
164
|
else
|
170
165
|
super
|
171
166
|
end
|
@@ -176,7 +171,7 @@ module Sequel
|
|
176
171
|
def _insert_select_raw(ds)
|
177
172
|
if use_prepared_statements_for?(:insert_select)
|
178
173
|
if ps = model.send(:prepared_insert_select, @values.keys)
|
179
|
-
ps.call(@values)
|
174
|
+
_set_prepared_statement_server(ps).call(@values)
|
180
175
|
end
|
181
176
|
else
|
182
177
|
super
|
@@ -186,7 +181,7 @@ module Sequel
|
|
186
181
|
# Use a prepared statement to refresh this model's column values.
|
187
182
|
def _refresh_get(ds)
|
188
183
|
if use_prepared_statements_for?(:refresh)
|
189
|
-
model.send(:prepared_refresh).call(pk_hash)
|
184
|
+
_set_prepared_statement_server(model.send(:prepared_refresh)).call(pk_hash)
|
190
185
|
else
|
191
186
|
super
|
192
187
|
end
|
@@ -195,11 +190,47 @@ module Sequel
|
|
195
190
|
# Use a prepared statement to update this model's columns in the database.
|
196
191
|
def _update_without_checking(columns)
|
197
192
|
if use_prepared_statements_for?(:update)
|
198
|
-
model.send(:prepared_update, columns.keys).call(Hash[columns].merge!(pk_hash))
|
193
|
+
_set_prepared_statement_server(model.send(:prepared_update, columns.keys)).call(Hash[columns].merge!(pk_hash))
|
199
194
|
else
|
200
195
|
super
|
201
196
|
end
|
202
197
|
end
|
198
|
+
|
199
|
+
# If a server is set for the instance, return a prepared statement that will use that server.
|
200
|
+
def _set_prepared_statement_server(ps)
|
201
|
+
if @server
|
202
|
+
ps.server(@server)
|
203
|
+
else
|
204
|
+
ps
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Whether prepared statements should be used for the given type of query
|
209
|
+
# (:insert, :insert_select, :refresh, :update, or :delete). True by default,
|
210
|
+
# can be overridden in other plugins to disallow prepared statements for
|
211
|
+
# specific types of queries.
|
212
|
+
def use_prepared_statements_for?(type)
|
213
|
+
if defined?(super)
|
214
|
+
result = super
|
215
|
+
return result unless result.nil?
|
216
|
+
end
|
217
|
+
|
218
|
+
case type
|
219
|
+
when :insert, :insert_select, :update
|
220
|
+
true
|
221
|
+
when :delete
|
222
|
+
return true unless model.fast_instance_delete_sql
|
223
|
+
|
224
|
+
# Using deletes for prepared statements appears faster on Oracle and DB2,
|
225
|
+
# but not for most other database types if optimized SQL is used.
|
226
|
+
db_type = model.db.database_type
|
227
|
+
db_type == :oracle || db_type == :db2
|
228
|
+
when :refresh
|
229
|
+
!model.fast_pk_lookup_sql
|
230
|
+
else
|
231
|
+
raise Error, "unsupported type used: #{type.inspect}"
|
232
|
+
end
|
233
|
+
end
|
203
234
|
end
|
204
235
|
end
|
205
236
|
end
|
@@ -8,6 +8,10 @@ module Sequel
|
|
8
8
|
# statements for associations where it will not work, assuming you load the
|
9
9
|
# plugin before defining the associations.
|
10
10
|
#
|
11
|
+
# Note that in most cases, this plugin will probably make things slower,
|
12
|
+
# so you should only use it if you really want to use prepared statements
|
13
|
+
# to load associations.
|
14
|
+
#
|
11
15
|
# Usage:
|
12
16
|
#
|
13
17
|
# # Make all model subclasses more safe when using prepared statements (called before loading subclasses)
|
@@ -27,6 +31,12 @@ module Sequel
|
|
27
31
|
module InstanceMethods
|
28
32
|
private
|
29
33
|
|
34
|
+
# Mark that associated objects should use the same server.
|
35
|
+
def _associated_objects_use_same_server?
|
36
|
+
return super if defined?(super)
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
30
40
|
# Return a bound variable hash that maps the keys in +ks+ (qualified by the +table+)
|
31
41
|
# to the values of the results of sending the methods in +vs+.
|
32
42
|
def association_bound_variable_hash(table, ks, vs)
|
@@ -36,6 +46,8 @@ module Sequel
|
|
36
46
|
# Given an association reflection, return a bound variable hash for the given
|
37
47
|
# association for this instance's values.
|
38
48
|
def association_bound_variables(opts)
|
49
|
+
return if opts[:instance_specific]
|
50
|
+
|
39
51
|
case opts[:type]
|
40
52
|
when :many_to_one
|
41
53
|
association_bound_variable_hash(opts.associated_class.table_name, opts.primary_keys, opts[:keys])
|
@@ -53,7 +65,7 @@ module Sequel
|
|
53
65
|
# instance. Return false if such a prepared statement cannot be created.
|
54
66
|
def association_prepared_statement(opts, assoc_bv)
|
55
67
|
return unless model.cache_associations
|
56
|
-
opts.send(:cached_fetch, :prepared_statement) do
|
68
|
+
ps = opts.send(:cached_fetch, :prepared_statement) do
|
57
69
|
unless opts[:instance_specific]
|
58
70
|
ds, bv = _associated_dataset(opts, {}).unbind
|
59
71
|
|
@@ -80,12 +92,18 @@ module Sequel
|
|
80
92
|
ds.clone(:log_sql=>true).prepare(opts.returns_array? ? :select : :first, :"smpsap_#{NEXT.call}")
|
81
93
|
end
|
82
94
|
end
|
95
|
+
|
96
|
+
if ps && @server && _associated_objects_use_same_server?
|
97
|
+
ps = ps.server(@server)
|
98
|
+
end
|
99
|
+
|
100
|
+
ps
|
83
101
|
end
|
84
102
|
|
85
103
|
# Use a prepared statement if possible to load the associated object,
|
86
104
|
# unless a dynamic callback is given.
|
87
105
|
def _load_associated_object(opts, dynamic_opts)
|
88
|
-
if !dynamic_opts[:callback] && (bv = association_bound_variables(opts)) && (ps
|
106
|
+
if !dynamic_opts[:callback] && (bv = association_bound_variables(opts)) && (ps = association_prepared_statement(opts, bv))
|
89
107
|
ps.call(bv)
|
90
108
|
else
|
91
109
|
super
|
@@ -95,7 +113,7 @@ module Sequel
|
|
95
113
|
# Use a prepared statement if possible to load the associated object,
|
96
114
|
# unless the associated model uses caching.
|
97
115
|
def _load_associated_object_via_primary_key(opts)
|
98
|
-
if !opts.associated_class.respond_to?(:cache_get_pk) && (bv = association_bound_variables(opts)) && (ps
|
116
|
+
if !opts.associated_class.respond_to?(:cache_get_pk) && (bv = association_bound_variables(opts)) && (ps = association_prepared_statement(opts, bv))
|
99
117
|
ps.call(bv)
|
100
118
|
else
|
101
119
|
super
|
@@ -105,7 +123,7 @@ module Sequel
|
|
105
123
|
# Use a prepared statement if possible to load the associated objects,
|
106
124
|
# unless a dynamic callback is given.
|
107
125
|
def _load_associated_object_array(opts, dynamic_opts)
|
108
|
-
if !dynamic_opts[:callback] && (bv = association_bound_variables(opts)) && (ps
|
126
|
+
if !dynamic_opts[:callback] && (bv = association_bound_variables(opts)) && (ps = association_prepared_statement(opts, bv))
|
109
127
|
ps.call(bv)
|
110
128
|
else
|
111
129
|
super
|
@@ -14,6 +14,10 @@ module Sequel
|
|
14
14
|
# service attack by allocating an arbitrary number of prepared statements. You have been
|
15
15
|
# warned.
|
16
16
|
#
|
17
|
+
# Note that in most cases, this plugin will probably make things slower,
|
18
|
+
# so you should only use it if you really want to use prepared statements
|
19
|
+
# for Dataset#with_pk.
|
20
|
+
#
|
17
21
|
# Usage:
|
18
22
|
#
|
19
23
|
# # Make all model subclasses use prepared statements for Dataset#with_pk (called before loading subclasses)
|
@@ -51,7 +55,11 @@ module Sequel
|
|
51
55
|
rescue UnbindDuplicate
|
52
56
|
super
|
53
57
|
else
|
54
|
-
model.send(:prepared_lookup_dataset, ds)
|
58
|
+
ps = model.send(:prepared_lookup_dataset, ds)
|
59
|
+
if server = @opts[:server]
|
60
|
+
ps = ps.server(server)
|
61
|
+
end
|
62
|
+
ps.call(bv)
|
55
63
|
end
|
56
64
|
end
|
57
65
|
end
|
@@ -83,6 +83,11 @@ module Sequel
|
|
83
83
|
nil
|
84
84
|
end
|
85
85
|
|
86
|
+
# Mark that associated objects should use the same server.
|
87
|
+
def _associated_objects_use_same_server?
|
88
|
+
true
|
89
|
+
end
|
90
|
+
|
86
91
|
# Ensure that the join table for many_to_many associations uses the correct shard.
|
87
92
|
def _join_table_dataset(opts)
|
88
93
|
use_server(super)
|
data/lib/sequel/version.rb
CHANGED
@@ -5,10 +5,10 @@ module Sequel
|
|
5
5
|
MAJOR = 4
|
6
6
|
# The minor version of Sequel. Bumped for every non-patch level
|
7
7
|
# release, generally around once a month.
|
8
|
-
MINOR =
|
8
|
+
MINOR = 43
|
9
9
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
10
10
|
# releases that fix regressions from previous versions.
|
11
|
-
TINY =
|
11
|
+
TINY = 0
|
12
12
|
|
13
13
|
# The version of Sequel you are using, as a string (e.g. "2.11.0")
|
14
14
|
VERSION = [MAJOR, MINOR, TINY].join('.').freeze
|
@@ -20,6 +20,10 @@ Sequel.split_symbols = false if ENV['SEQUEL_NO_SPLIT_SYMBOLS']
|
|
20
20
|
Sequel::Database.extension :duplicate_column_handler if ENV['SEQUEL_DUPLICATE_COLUMN_HANDLER']
|
21
21
|
Sequel::Database.extension :columns_introspection if ENV['SEQUEL_COLUMNS_INTROSPECTION']
|
22
22
|
Sequel::Model.cache_associations = false if ENV['SEQUEL_NO_CACHE_ASSOCIATIONS']
|
23
|
+
if ENV['SEQUEL_MODEL_PREPARED_STATEMENTS']
|
24
|
+
Sequel::Model.plugin :prepared_statements
|
25
|
+
Sequel::Model.plugin :prepared_statements_associations
|
26
|
+
end
|
23
27
|
Sequel.cache_anonymous_models = false
|
24
28
|
|
25
29
|
class Sequel::Database
|
@@ -905,6 +905,16 @@ describe "A single threaded pool with multiple servers" do
|
|
905
905
|
end
|
906
906
|
|
907
907
|
AllConnectionPoolClassesSpecs = shared_description do
|
908
|
+
it "should work correctly after being frozen" do
|
909
|
+
o = Object.new
|
910
|
+
db = mock_db.call{o}
|
911
|
+
cp = @class.new(db, {})
|
912
|
+
db.instance_variable_set(:@pool, cp)
|
913
|
+
db.freeze
|
914
|
+
cp.frozen?.must_equal true
|
915
|
+
db.synchronize{|c| c.must_be_same_as o}
|
916
|
+
end
|
917
|
+
|
908
918
|
it "should have pool correctly handle disconnect errors not raised as DatabaseDisconnectError" do
|
909
919
|
db = mock_db.call{Object.new}
|
910
920
|
def db.dec; @dec ||= Class.new(StandardError) end
|
data/spec/core/database_spec.rb
CHANGED
@@ -109,6 +109,28 @@ describe "A new Database" do
|
|
109
109
|
end if RUBY_VERSION >= '1.9.3'
|
110
110
|
end
|
111
111
|
|
112
|
+
describe "Database#freeze" do
|
113
|
+
before do
|
114
|
+
@db = Sequel.mock.freeze
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should freeze internal structures" do
|
118
|
+
@db.instance_exec do
|
119
|
+
frozen?.must_equal true
|
120
|
+
opts.frozen?.must_equal true
|
121
|
+
pool.frozen?.must_equal true
|
122
|
+
loggers.frozen?.must_equal true
|
123
|
+
@dataset_class.frozen?.must_equal true
|
124
|
+
@dataset_modules.frozen?.must_equal true
|
125
|
+
@schema_type_classes.frozen?.must_equal true
|
126
|
+
from(:a).frozen?.must_equal true
|
127
|
+
metadata_dataset.frozen?.must_equal true
|
128
|
+
end
|
129
|
+
|
130
|
+
proc{@db.extend_datasets{}}.must_raise RuntimeError, TypeError
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
112
134
|
describe "Database#disconnect" do
|
113
135
|
it "should call pool.disconnect" do
|
114
136
|
d = Sequel::Database.new
|
@@ -2390,6 +2412,13 @@ describe "Database extensions" do
|
|
2390
2412
|
@db.extension(:foo).a.must_equal 1
|
2391
2413
|
end
|
2392
2414
|
|
2415
|
+
it "should not call the block multiple times if extension loaded more than once" do
|
2416
|
+
@db.opts[:foo] = []
|
2417
|
+
Sequel::Database.register_extension(:foo){|db| db.opts[:foo] << 1}
|
2418
|
+
@db.extension(:foo).opts[:foo].must_equal [1]
|
2419
|
+
@db.extension(:foo).opts[:foo].must_equal [1]
|
2420
|
+
end
|
2421
|
+
|
2393
2422
|
it "should be able to register an extension with a block and have Database#extension call the block" do
|
2394
2423
|
Sequel::Database.register_extension(:foo){|db| db.opts[:foo] = 1}
|
2395
2424
|
@db.extension(:foo).opts[:foo].must_equal 1
|
@@ -31,9 +31,9 @@ describe Sequel::Model, "#(set|update)_except" do
|
|
31
31
|
|
32
32
|
it "#update_except should not update given attributes" do
|
33
33
|
@o1.update_except({:x => 1, :y => 2, :z=>3, :id=>4}, [:y, :z])
|
34
|
-
DB.sqls.must_equal ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE
|
34
|
+
DB.sqls.must_equal ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE id = 10"]
|
35
35
|
@c.new.update_except({:x => 1, :y => 2, :z=>3, :id=>4}, :y, :z)
|
36
|
-
DB.sqls.must_equal ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE
|
36
|
+
DB.sqls.must_equal ["INSERT INTO items (x) VALUES (1)", "SELECT * FROM items WHERE id = 10"]
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -68,7 +68,7 @@ describe Sequel::Model, ".restricted_columns " do
|
|
68
68
|
i = @c.new
|
69
69
|
i.update(:x => 7, :z => 9)
|
70
70
|
i.values.must_equal(:x => 7)
|
71
|
-
DB.sqls.must_equal ["INSERT INTO blahblah (x) VALUES (7)", "SELECT * FROM blahblah WHERE
|
71
|
+
DB.sqls.must_equal ["INSERT INTO blahblah (x) VALUES (7)", "SELECT * FROM blahblah WHERE id = 10"]
|
72
72
|
end
|
73
73
|
|
74
74
|
it "should have allowed take precedence over restricted" do
|
@@ -83,6 +83,6 @@ describe Sequel::Model, ".restricted_columns " do
|
|
83
83
|
i = @c.new
|
84
84
|
i.update(:y => 7, :z => 9)
|
85
85
|
i.values.must_equal(:y => 7)
|
86
|
-
DB.sqls.must_equal ["INSERT INTO blahblah (y) VALUES (7)", "SELECT * FROM blahblah WHERE
|
86
|
+
DB.sqls.must_equal ["INSERT INTO blahblah (y) VALUES (7)", "SELECT * FROM blahblah WHERE id = 10"]
|
87
87
|
end
|
88
88
|
end
|
@@ -57,7 +57,7 @@ describe "Sequel::Plugins::DefaultsSetter" do
|
|
57
57
|
o = c.new
|
58
58
|
o.a = o.a
|
59
59
|
o.save
|
60
|
-
@db.sqls.must_equal ["INSERT INTO foo (a) VALUES (CURRENT_TIMESTAMP)", "SELECT * FROM foo WHERE
|
60
|
+
@db.sqls.must_equal ["INSERT INTO foo (a) VALUES (CURRENT_TIMESTAMP)", "SELECT * FROM foo WHERE id = 1"]
|
61
61
|
end
|
62
62
|
|
63
63
|
it "should not override a given value" do
|
@@ -2,8 +2,7 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
2
|
if RUBY_VERSION >= '1.9.0'
|
3
3
|
describe "force_encoding plugin" do
|
4
4
|
before do
|
5
|
-
@c = Class.new(Sequel::Model)
|
6
|
-
end
|
5
|
+
@c = Class.new(Sequel::Model)
|
7
6
|
@c.columns :id, :x
|
8
7
|
@c.plugin :force_encoding, 'UTF-8'
|
9
8
|
@e1 = Encoding.find('UTF-8')
|
@@ -90,6 +89,7 @@ describe "force_encoding plugin" do
|
|
90
89
|
{:id=>1, :x=>s}
|
91
90
|
end
|
92
91
|
end
|
92
|
+
@c.instance_variable_set(:@fast_pk_lookup_sql, nil)
|
93
93
|
o.save
|
94
94
|
o.x.must_equal 'blah'
|
95
95
|
o.x.encoding.must_equal @e1
|
@@ -104,6 +104,7 @@ describe "force_encoding plugin" do
|
|
104
104
|
{:id=>1, :x=>s}
|
105
105
|
end
|
106
106
|
end
|
107
|
+
@c.instance_variable_set(:@fast_pk_lookup_sql, nil)
|
107
108
|
o.refresh
|
108
109
|
o.x.must_equal 'blah'
|
109
110
|
o.x.encoding.must_equal @e1
|