sequel 4.42.1 → 4.43.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|