sequel 5.91.0 → 5.93.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/lib/sequel/adapters/oracle.rb +16 -0
- data/lib/sequel/adapters/shared/postgres.rb +100 -3
- data/lib/sequel/database/dataset_defaults.rb +1 -1
- data/lib/sequel/dataset/prepared_statements.rb +68 -24
- data/lib/sequel/dataset/query.rb +1 -1
- data/lib/sequel/dataset/sql.rb +13 -8
- data/lib/sequel/extensions/migration.rb +4 -0
- data/lib/sequel/extensions/pg_auto_parameterize.rb +5 -0
- data/lib/sequel/model/base.rb +29 -2
- data/lib/sequel/plugins/instance_filters.rb +4 -1
- data/lib/sequel/plugins/paged_operations.rb +5 -2
- data/lib/sequel/sql.rb +7 -5
- data/lib/sequel/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd35e8223b7f6d450cf4c1efeaad152236b4a1e360299aa46b03841bb45996c6
|
4
|
+
data.tar.gz: '096a62cc241cf6f48d0c2b3e0799402f21aa24a1196a332e022ef53ebaaeea85'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b66c7e30dfb69468ad41bfe64de4e0442ad62590ea735b2e4bb591c46b949794a7a453c21532999c89296694f0136d9353041ec56fc470ab2ba0483f0534d61
|
7
|
+
data.tar.gz: 978dcd457829ff39f1ae9769dc574049cf29d07a2dbc8e307aa806a7b1954cd72432257de37d9e5236269b5746f615f8d0f7feb4979e9b86b619f582344afc29
|
@@ -353,6 +353,20 @@ module Sequel
|
|
353
353
|
i = prepared_args.length
|
354
354
|
LiteralString.new(":#{i}")
|
355
355
|
end
|
356
|
+
|
357
|
+
# Avoid infinite recursion on Oracle <12 for datasets with limits
|
358
|
+
# (which are implemented via subqueries). If the given dataset's
|
359
|
+
# prepared args are the same object as current dataset's, call the
|
360
|
+
# standard Sequel::Dataset#subselect_sql_append method, instead
|
361
|
+
# of calling super (which will call prepared_sql and result in
|
362
|
+
# infinite recursion).
|
363
|
+
def subselect_sql_append(sql, ds)
|
364
|
+
if !supports_fetch_next_rows? && ds.opts[:prepared_args].equal?(@opts[:prepared_args])
|
365
|
+
orig_subselect_sql_append(sql, ds)
|
366
|
+
else
|
367
|
+
super
|
368
|
+
end
|
369
|
+
end
|
356
370
|
end
|
357
371
|
|
358
372
|
BindArgumentMethods = prepared_statements_module(:bind, ArgumentMapper)
|
@@ -383,6 +397,8 @@ module Sequel
|
|
383
397
|
|
384
398
|
private
|
385
399
|
|
400
|
+
alias orig_subselect_sql_append subselect_sql_append
|
401
|
+
|
386
402
|
def literal_other_append(sql, v)
|
387
403
|
case v
|
388
404
|
when OraDate
|
@@ -101,7 +101,7 @@ module Sequel
|
|
101
101
|
|
102
102
|
def self.mock_adapter_setup(db)
|
103
103
|
db.instance_exec do
|
104
|
-
@server_version =
|
104
|
+
@server_version = 170000
|
105
105
|
initialize_postgres_adapter
|
106
106
|
extend(MockAdapterDatabaseMethods)
|
107
107
|
end
|
@@ -1888,9 +1888,48 @@ module Sequel
|
|
1888
1888
|
super
|
1889
1889
|
end
|
1890
1890
|
|
1891
|
-
# Return the results of an EXPLAIN query
|
1891
|
+
# Return the results of an EXPLAIN query. Boolean options:
|
1892
|
+
#
|
1893
|
+
# :analyze :: Use the ANALYZE option.
|
1894
|
+
# :buffers :: Use the BUFFERS option.
|
1895
|
+
# :costs :: Use the COSTS option.
|
1896
|
+
# :generic_plan :: Use the GENERIC_PLAN option.
|
1897
|
+
# :memory :: Use the MEMORY option.
|
1898
|
+
# :settings :: Use the SETTINGS option.
|
1899
|
+
# :summary :: Use the SUMMARY option.
|
1900
|
+
# :timing :: Use the TIMING option.
|
1901
|
+
# :verbose :: Use the VERBOSE option.
|
1902
|
+
# :wal :: Use the WAL option.
|
1903
|
+
#
|
1904
|
+
# Non boolean options:
|
1905
|
+
#
|
1906
|
+
# :format :: Use the FORMAT option to change the format of the
|
1907
|
+
# returned value. Values can be :text, :xml, :json,
|
1908
|
+
# or :yaml.
|
1909
|
+
# :serialize :: Use the SERIALIZE option to get timing on
|
1910
|
+
# serialization. Values can be :none, :text, or
|
1911
|
+
# :binary.
|
1912
|
+
#
|
1913
|
+
# See the PostgreSQL EXPLAIN documentation for an explanation of
|
1914
|
+
# what each option does.
|
1915
|
+
#
|
1916
|
+
# In most cases, the return value is a single string. However,
|
1917
|
+
# using the <tt>format: :json</tt> option can result in the return
|
1918
|
+
# value being an array containing a hash.
|
1892
1919
|
def explain(opts=OPTS)
|
1893
|
-
|
1920
|
+
rows = clone(:append_sql=>explain_sql_string_origin(opts)).map(:'QUERY PLAN')
|
1921
|
+
|
1922
|
+
if rows.length == 1
|
1923
|
+
rows[0]
|
1924
|
+
elsif rows.all?{|row| String === row}
|
1925
|
+
rows.join("\r\n")
|
1926
|
+
# :nocov:
|
1927
|
+
else
|
1928
|
+
# This branch is unreachable in tests, but it seems better to just return
|
1929
|
+
# all rows than throw in error if this case actually happens.
|
1930
|
+
rows
|
1931
|
+
# :nocov:
|
1932
|
+
end
|
1894
1933
|
end
|
1895
1934
|
|
1896
1935
|
# Return a cloned dataset which will use FOR SHARE to lock returned rows.
|
@@ -2417,7 +2456,65 @@ module Sequel
|
|
2417
2456
|
c ||= true
|
2418
2457
|
end
|
2419
2458
|
end
|
2459
|
+
|
2460
|
+
EXPLAIN_BOOLEAN_OPTIONS = {}
|
2461
|
+
%w[analyze verbose costs settings generic_plan buffers wal timing summary memory].each do |str|
|
2462
|
+
EXPLAIN_BOOLEAN_OPTIONS[str.to_sym] = str.upcase.freeze
|
2463
|
+
end
|
2464
|
+
EXPLAIN_BOOLEAN_OPTIONS.freeze
|
2465
|
+
|
2466
|
+
EXPLAIN_NONBOOLEAN_OPTIONS = {
|
2467
|
+
:serialize => {:none=>"SERIALIZE NONE", :text=>"SERIALIZE TEXT", :binary=>"SERIALIZE BINARY"}.freeze,
|
2468
|
+
:format => {:text=>"FORMAT TEXT", :xml=>"FORMAT XML", :json=>"FORMAT JSON", :yaml=>"FORMAT YAML"}.freeze
|
2469
|
+
}.freeze
|
2420
2470
|
|
2471
|
+
# A mutable string used as the prefix when explaining a query.
|
2472
|
+
def explain_sql_string_origin(opts)
|
2473
|
+
origin = String.new
|
2474
|
+
origin << 'EXPLAIN '
|
2475
|
+
|
2476
|
+
# :nocov:
|
2477
|
+
if server_version < 90000
|
2478
|
+
if opts[:analyze]
|
2479
|
+
origin << 'ANALYZE '
|
2480
|
+
end
|
2481
|
+
|
2482
|
+
return origin
|
2483
|
+
end
|
2484
|
+
# :nocov:
|
2485
|
+
|
2486
|
+
comma = nil
|
2487
|
+
paren = "("
|
2488
|
+
|
2489
|
+
add_opt = lambda do |str, value|
|
2490
|
+
origin << paren if paren
|
2491
|
+
origin << comma if comma
|
2492
|
+
origin << str
|
2493
|
+
origin << " FALSE" unless value
|
2494
|
+
comma ||= ', '
|
2495
|
+
paren &&= nil
|
2496
|
+
end
|
2497
|
+
|
2498
|
+
EXPLAIN_BOOLEAN_OPTIONS.each do |key, str|
|
2499
|
+
unless (value = opts[key]).nil?
|
2500
|
+
add_opt.call(str, value)
|
2501
|
+
end
|
2502
|
+
end
|
2503
|
+
|
2504
|
+
EXPLAIN_NONBOOLEAN_OPTIONS.each do |key, e_opts|
|
2505
|
+
if value = opts[key]
|
2506
|
+
if str = e_opts[value]
|
2507
|
+
add_opt.call(str, true)
|
2508
|
+
else
|
2509
|
+
raise Sequel::Error, "unrecognized value for Dataset#explain #{key.inspect} option: #{value.inspect}"
|
2510
|
+
end
|
2511
|
+
end
|
2512
|
+
end
|
2513
|
+
|
2514
|
+
origin << ') ' unless paren
|
2515
|
+
origin
|
2516
|
+
end
|
2517
|
+
|
2421
2518
|
# Add ON CONFLICT clause if it should be used
|
2422
2519
|
def insert_conflict_sql(sql)
|
2423
2520
|
if opts = @opts[:insert_conflict]
|
@@ -61,7 +61,7 @@ module Sequel
|
|
61
61
|
# # SELECT id, name FROM table WHERE active ORDER BY id
|
62
62
|
def extend_datasets(mod=nil, &block)
|
63
63
|
raise(Error, "must provide either mod or block, not both") if mod && block
|
64
|
-
mod = Sequel.set_temp_name(Dataset::DatasetModule.new(&block)){"Sequel::Dataset::_DatasetModule(#{block.source_location.join(':')})"} if block
|
64
|
+
mod = Sequel.set_temp_name(Dataset::DatasetModule.new(&block)){"Sequel::Dataset::_DatasetModule(#{block.source_location[0,2].join(':')})"} if block
|
65
65
|
if @dataset_modules.empty?
|
66
66
|
@dataset_modules = [mod]
|
67
67
|
@dataset_class = Sequel.set_temp_name(Class.new(@dataset_class)){"Sequel::Dataset::_Subclass"}
|
@@ -91,8 +91,14 @@ module Sequel
|
|
91
91
|
@opts[:log_sql]
|
92
92
|
end
|
93
93
|
|
94
|
-
# The type of
|
95
|
-
#
|
94
|
+
# The type of SQL to generate for the prepared statement. Generally
|
95
|
+
# the same as #prepared_type, but can be different.
|
96
|
+
def prepared_sql_type
|
97
|
+
@opts[:prepared_sql_type] || prepared_type
|
98
|
+
end
|
99
|
+
|
100
|
+
# The type of prepared statement, which controls how the prepared statement
|
101
|
+
# handles results from the database.
|
96
102
|
def prepared_type
|
97
103
|
@opts[:prepared_type]
|
98
104
|
end
|
@@ -141,7 +147,7 @@ module Sequel
|
|
141
147
|
# Returns the SQL for the prepared statement, depending on
|
142
148
|
# the type of the statement and the prepared_modify_values.
|
143
149
|
def prepared_sql
|
144
|
-
case
|
150
|
+
case prepared_sql_type
|
145
151
|
when :select, :all, :each
|
146
152
|
# Most common scenario, so listed first.
|
147
153
|
select_sql
|
@@ -182,34 +188,30 @@ module Sequel
|
|
182
188
|
|
183
189
|
# Run the method based on the type of prepared statement.
|
184
190
|
def run(&block)
|
185
|
-
case prepared_type
|
191
|
+
case type = prepared_type
|
186
192
|
when :select, :all
|
187
|
-
|
193
|
+
with_sql_all(prepared_sql, &block)
|
188
194
|
when :each
|
189
|
-
|
190
|
-
when :insert_select
|
191
|
-
|
192
|
-
when :first
|
193
|
-
first
|
195
|
+
with_sql_each(prepared_sql, &block)
|
196
|
+
when :insert_select, :first
|
197
|
+
with_sql_first(prepared_sql)
|
194
198
|
when :insert, :update, :delete
|
195
199
|
if opts[:returning] && supports_returning?(prepared_type)
|
196
200
|
returning_fetch_rows(prepared_sql)
|
197
|
-
elsif
|
198
|
-
|
201
|
+
elsif type == :delete
|
202
|
+
with_sql_delete(prepared_sql)
|
199
203
|
else
|
200
|
-
public_send(
|
204
|
+
force_prepared_sql.public_send(type, *prepared_modify_values)
|
201
205
|
end
|
202
|
-
when :insert_pk
|
203
|
-
|
206
|
+
when :insert_pk, :single_value
|
207
|
+
with_sql_single_value(prepared_sql)
|
204
208
|
when Array
|
205
209
|
# :nocov:
|
206
|
-
case
|
210
|
+
case type[0]
|
207
211
|
# :nocov:
|
208
212
|
when :map, :as_hash, :to_hash, :to_hash_groups
|
209
|
-
public_send(*
|
213
|
+
force_prepared_sql.public_send(*type, &block)
|
210
214
|
end
|
211
|
-
when :single_value
|
212
|
-
single_value
|
213
215
|
else
|
214
216
|
raise Error, "unsupported prepared statement type used: #{prepared_type.inspect}"
|
215
217
|
end
|
@@ -217,6 +219,16 @@ module Sequel
|
|
217
219
|
|
218
220
|
private
|
219
221
|
|
222
|
+
# If the prepared_sql_type does not match the prepared statement, return a clone that
|
223
|
+
# with the prepared SQL, to ensure the prepared_sql_type is respected.
|
224
|
+
def force_prepared_sql
|
225
|
+
if prepared_sql_type != prepared_type
|
226
|
+
with_sql(prepared_sql)
|
227
|
+
else
|
228
|
+
self
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
220
232
|
# Returns the value of the prepared_args hash for the given key.
|
221
233
|
def prepared_arg(k)
|
222
234
|
@opts[:bind_vars][k]
|
@@ -294,11 +306,12 @@ module Sequel
|
|
294
306
|
prepared_sql, frags = Sequel::Dataset::PlaceholderLiteralizer::Recorder.new.send(:prepared_sql_and_frags, self, prepared_args) do |pl, ds|
|
295
307
|
ds = ds.clone(:recorder=>pl)
|
296
308
|
|
297
|
-
|
309
|
+
sql_type = prepared_sql_type || type
|
310
|
+
case sql_type
|
298
311
|
when :first, :single_value
|
299
312
|
ds.limit(1)
|
300
313
|
when :update, :insert, :insert_select, :delete
|
301
|
-
ds.with_sql(:"#{
|
314
|
+
ds.with_sql(:"#{sql_type}_sql", *values)
|
302
315
|
when :insert_pk
|
303
316
|
ds.with_sql(:insert_sql, *values)
|
304
317
|
else
|
@@ -344,13 +357,23 @@ module Sequel
|
|
344
357
|
clone(:bind_vars=>bind_vars)
|
345
358
|
end
|
346
359
|
|
347
|
-
# For the given type
|
348
|
-
#
|
349
|
-
#
|
360
|
+
# For the given type, run the sql with the bind variables specified in the hash.
|
361
|
+
# +values+ is a hash passed to insert or update (if one of those types is used),
|
362
|
+
# which may contain placeholders.
|
363
|
+
#
|
364
|
+
# The following types are supported:
|
365
|
+
#
|
366
|
+
# * :select, :all, :each, :first, :single_value, :insert, :insert_select, :insert_pk, :update, :delete
|
367
|
+
# * Array where first element is :map, :as_hash, :to_hash, :to_hash_groups (remaining elements
|
368
|
+
# are passed to the related method)
|
350
369
|
#
|
351
370
|
# DB[:table].where(id: :$id).call(:first, id: 1)
|
352
371
|
# # SELECT * FROM table WHERE id = ? LIMIT 1 -- (1)
|
353
372
|
# # => {:id=>1}
|
373
|
+
#
|
374
|
+
# DB[:table].where(id: :$id).call(:update, {c: 1, id: 2}, col: :$c)
|
375
|
+
# # UPDATE table WHERE id = ? SET col = ? -- (2, 1)
|
376
|
+
# # => 1
|
354
377
|
def call(type, bind_variables=OPTS, *values, &block)
|
355
378
|
to_prepared_statement(type, values, :extend=>bound_variable_modules).call(bind_variables, &block)
|
356
379
|
end
|
@@ -371,6 +394,14 @@ module Sequel
|
|
371
394
|
# # => {:id=>1, :name=>'Blah'}
|
372
395
|
#
|
373
396
|
# DB.call(:select_by_name, name: 'Blah') # Same thing
|
397
|
+
#
|
398
|
+
# +values+ given are passed to +insert+ or +update+ if they are used:
|
399
|
+
#
|
400
|
+
# ps = DB[:table].where(id: :$i).prepare(:update, :update_name, name: :$n)
|
401
|
+
#
|
402
|
+
# ps.call(i: 1, n: 'Blah')
|
403
|
+
# # UPDATE table WHERE id = ? SET name = ? -- (1, 'Blah')
|
404
|
+
# # => 1
|
374
405
|
def prepare(type, name, *values)
|
375
406
|
ps = to_prepared_statement(type, values, :name=>name, :extend=>prepared_statement_modules, :no_delayed_evaluations=>true)
|
376
407
|
|
@@ -387,6 +418,19 @@ module Sequel
|
|
387
418
|
ps
|
388
419
|
end
|
389
420
|
|
421
|
+
# Set the type of SQL to use for prepared statements based on this
|
422
|
+
# dataset. Prepared statements default to using the same SQL type
|
423
|
+
# as the type that is passed to #prepare/#call, but there are cases
|
424
|
+
# where it is helpful to use a different SQL type.
|
425
|
+
#
|
426
|
+
# Available types are: :select, :first, :single_value, :update,
|
427
|
+
# :delete, :insert, :insert_select, :insert_pk
|
428
|
+
#
|
429
|
+
# Other types are treated as :select.
|
430
|
+
def prepare_sql_type(type)
|
431
|
+
clone(:prepared_sql_type => type)
|
432
|
+
end
|
433
|
+
|
390
434
|
protected
|
391
435
|
|
392
436
|
# Return a cloned copy of the current dataset extended with
|
data/lib/sequel/dataset/query.rb
CHANGED
@@ -1240,7 +1240,7 @@ module Sequel
|
|
1240
1240
|
def with_extend(*mods, &block)
|
1241
1241
|
c = Sequel.set_temp_name(Class.new(self.class)){"Sequel::Dataset::_Subclass"}
|
1242
1242
|
c.include(*mods) unless mods.empty?
|
1243
|
-
c.include(Sequel.set_temp_name(DatasetModule.new(&block)){"Sequel::Dataset::_DatasetModule(#{block.source_location.join(':')})"}) if block
|
1243
|
+
c.include(Sequel.set_temp_name(DatasetModule.new(&block)){"Sequel::Dataset::_DatasetModule(#{block.source_location[0,2].join(':')})"}) if block
|
1244
1244
|
o = c.freeze.allocate
|
1245
1245
|
o.instance_variable_set(:@db, @db)
|
1246
1246
|
o.instance_variable_set(:@opts, @opts)
|
data/lib/sequel/dataset/sql.rb
CHANGED
@@ -685,10 +685,10 @@ module Sequel
|
|
685
685
|
# being quoted, returns name as a string. If identifiers are being quoted
|
686
686
|
# quote the name with quoted_identifier.
|
687
687
|
def quote_identifier_append(sql, name)
|
688
|
+
name = name.value if name.is_a?(SQL::Identifier)
|
688
689
|
if name.is_a?(LiteralString)
|
689
690
|
sql << name
|
690
691
|
else
|
691
|
-
name = name.value if name.is_a?(SQL::Identifier)
|
692
692
|
name = input_identifier(name)
|
693
693
|
if quote_identifiers?
|
694
694
|
quoted_identifier_append(sql, name)
|
@@ -700,11 +700,14 @@ module Sequel
|
|
700
700
|
|
701
701
|
# Append literalization of identifier or unqualified identifier to SQL string.
|
702
702
|
def quote_schema_table_append(sql, table)
|
703
|
-
|
704
|
-
|
705
|
-
|
703
|
+
qualifiers = split_qualifiers(table)
|
704
|
+
table = qualifiers.pop
|
705
|
+
|
706
|
+
qualifiers.each do |q|
|
707
|
+
quote_identifier_append(sql, q)
|
706
708
|
sql << '.'
|
707
709
|
end
|
710
|
+
|
708
711
|
quote_identifier_append(sql, table)
|
709
712
|
end
|
710
713
|
|
@@ -1430,10 +1433,6 @@ module Sequel
|
|
1430
1433
|
# calls +sql_literal+ if object responds to it, otherwise raises an error.
|
1431
1434
|
# If a database specific type is allowed, this should be overriden in a subclass.
|
1432
1435
|
def literal_other_append(sql, v)
|
1433
|
-
# We can't be sure if v will always literalize to the same SQL, so
|
1434
|
-
# don't cache SQL for a dataset that uses this.
|
1435
|
-
disable_sql_caching!
|
1436
|
-
|
1437
1436
|
if v.respond_to?(:sql_literal_append)
|
1438
1437
|
v.sql_literal_append(self, sql)
|
1439
1438
|
elsif v.respond_to?(:sql_literal)
|
@@ -1441,6 +1440,12 @@ module Sequel
|
|
1441
1440
|
else
|
1442
1441
|
raise Error, "can't express #{v.inspect} as a SQL literal"
|
1443
1442
|
end
|
1443
|
+
|
1444
|
+
if !v.respond_to?(:sql_literal_allow_caching?) || !v.sql_literal_allow_caching?(self)
|
1445
|
+
# We can't be sure if v will always literalize to the same SQL, so
|
1446
|
+
# don't cache SQL for a dataset that uses this.
|
1447
|
+
disable_sql_caching!
|
1448
|
+
end
|
1444
1449
|
end
|
1445
1450
|
|
1446
1451
|
# SQL fragment for Sequel::SQLTime, containing just the time part
|
@@ -287,6 +287,10 @@ module Sequel
|
|
287
287
|
def set_column_allow_null(name, allow_null=true)
|
288
288
|
@actions << [:set_column_allow_null, name, !allow_null]
|
289
289
|
end
|
290
|
+
|
291
|
+
def set_column_not_null(name)
|
292
|
+
@actions << [:set_column_allow_null, name]
|
293
|
+
end
|
290
294
|
end
|
291
295
|
|
292
296
|
# The preferred method for writing Sequel migrations, using a DSL:
|
@@ -463,6 +463,11 @@ module Sequel
|
|
463
463
|
@opts[:no_auto_parameterize] ? super : QueryString.new
|
464
464
|
end
|
465
465
|
|
466
|
+
# A mutable string used as the prefix when explaining a query.
|
467
|
+
def explain_sql_string_origin(opts)
|
468
|
+
@opts[:no_auto_parameterize] ? super : (QueryString.new << super)
|
469
|
+
end
|
470
|
+
|
466
471
|
# If subquery uses with_sql with a method name symbol, get the dataset
|
467
472
|
# with_sql was called on, and use that as the subquery, recording the
|
468
473
|
# arguments to with_sql that will be used to calculate the sql.
|
data/lib/sequel/model/base.rb
CHANGED
@@ -533,10 +533,28 @@ module Sequel
|
|
533
533
|
end
|
534
534
|
end
|
535
535
|
|
536
|
+
# Return a qualified identifier or array of qualified identifiers for
|
537
|
+
# the model's primary key. Uses the given qualifier if provided, or
|
538
|
+
# the table_name otherwise. If the model does not have a primary key,
|
539
|
+
# raises an +Error+.
|
540
|
+
#
|
541
|
+
# Artist.order(Artist.qualified_primary_key)
|
542
|
+
# # SELECT * FROM artists ORDER BY artists.id
|
543
|
+
def qualified_primary_key(qualifier=table_name)
|
544
|
+
case key = @primary_key
|
545
|
+
when Symbol
|
546
|
+
SQL::QualifiedIdentifier.new(qualifier, key)
|
547
|
+
when Array
|
548
|
+
key.map{|k| SQL::QualifiedIdentifier.new(qualifier, k)}
|
549
|
+
else
|
550
|
+
raise(Error, "#{self} does not have a primary key")
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
536
554
|
# Return a hash where the keys are qualified column references. Uses the given
|
537
555
|
# qualifier if provided, or the table_name otherwise. This is useful if you
|
538
556
|
# plan to join other tables to this table and you want the column references
|
539
|
-
# to be qualified.
|
557
|
+
# to be qualified. If the model does not have a primary key, raises an +Error+.
|
540
558
|
#
|
541
559
|
# Artist.where(Artist.qualified_primary_key_hash(1))
|
542
560
|
# # SELECT * FROM artists WHERE (artists.id = 1)
|
@@ -2260,7 +2278,7 @@ END
|
|
2260
2278
|
# Return the dataset ordered by the model's primary key. This should not
|
2261
2279
|
# be used if the model does not have a primary key.
|
2262
2280
|
def _force_primary_key_order
|
2263
|
-
cached_dataset(:_pk_order_ds){order(*
|
2281
|
+
cached_dataset(:_pk_order_ds){order(*unambiguous_primary_key)}
|
2264
2282
|
end
|
2265
2283
|
|
2266
2284
|
# If the dataset is not already ordered, and the model has a primary key,
|
@@ -2288,6 +2306,15 @@ END
|
|
2288
2306
|
end
|
2289
2307
|
end
|
2290
2308
|
|
2309
|
+
# The primary key for the dataset's model, qualified if the dataset is joined.
|
2310
|
+
def unambiguous_primary_key
|
2311
|
+
if joined_dataset?
|
2312
|
+
model.qualified_primary_key
|
2313
|
+
else
|
2314
|
+
model.primary_key
|
2315
|
+
end
|
2316
|
+
end
|
2317
|
+
|
2291
2318
|
def non_sql_option?(key)
|
2292
2319
|
super || key == :model
|
2293
2320
|
end
|
@@ -102,7 +102,10 @@ module Sequel
|
|
102
102
|
|
103
103
|
# Apply the instance filters to the given dataset
|
104
104
|
def apply_instance_filters(ds)
|
105
|
-
instance_filters.inject(ds)
|
105
|
+
instance_filters.inject(ds) do |ds1, i|
|
106
|
+
block = i[1]
|
107
|
+
ds1.where(*i[0], &block)
|
108
|
+
end
|
106
109
|
end
|
107
110
|
|
108
111
|
# Clear the instance filters.
|
@@ -157,13 +157,16 @@ module Sequel
|
|
157
157
|
raise Error, "the paged_operations plugin is not supported on DB2 when using emulated offsets, set the :offset_strategy Database option to 'limit_offset' or 'offset_fetch'"
|
158
158
|
end
|
159
159
|
|
160
|
-
case pk =
|
160
|
+
case pk = unambiguous_primary_key
|
161
161
|
when Symbol
|
162
162
|
Sequel.identifier(pk)
|
163
163
|
when Array
|
164
164
|
raise Error, "cannot use #{meth} on a model with a composite primary key"
|
165
|
-
|
165
|
+
when nil
|
166
166
|
raise Error, "cannot use #{meth} on a model without a primary key"
|
167
|
+
else
|
168
|
+
# Likely SQL::QualifiedIdentifier, if the dataset is joined.
|
169
|
+
pk
|
167
170
|
end
|
168
171
|
end
|
169
172
|
|
data/lib/sequel/sql.rb
CHANGED
@@ -1733,12 +1733,11 @@ module Sequel
|
|
1733
1733
|
|
1734
1734
|
# Automatically convert SQL::Identifiers to strings
|
1735
1735
|
def convert_identifier(identifier)
|
1736
|
-
|
1737
|
-
|
1738
|
-
identifier.
|
1739
|
-
else
|
1740
|
-
identifier
|
1736
|
+
if identifier.is_a?(SQL::Identifier)
|
1737
|
+
identifier = identifier.value
|
1738
|
+
identifier = identifier.to_s unless identifier.is_a?(LiteralString)
|
1741
1739
|
end
|
1740
|
+
identifier
|
1742
1741
|
end
|
1743
1742
|
end
|
1744
1743
|
|
@@ -2053,6 +2052,9 @@ module Sequel
|
|
2053
2052
|
end
|
2054
2053
|
end
|
2055
2054
|
|
2055
|
+
SQL::Constants::OLD = SQL::Identifier.new(LiteralString.new("OLD").freeze)
|
2056
|
+
SQL::Constants::NEW = SQL::Identifier.new(LiteralString.new("NEW").freeze)
|
2057
|
+
|
2056
2058
|
include SQL::Constants
|
2057
2059
|
extend SQL::Builders
|
2058
2060
|
extend SQL::OperatorBuilders
|
data/lib/sequel/version.rb
CHANGED
@@ -6,7 +6,7 @@ module Sequel
|
|
6
6
|
|
7
7
|
# The minor version of Sequel. Bumped for every non-patch level
|
8
8
|
# release, generally around once a month.
|
9
|
-
MINOR =
|
9
|
+
MINOR = 93
|
10
10
|
|
11
11
|
# The tiny version of Sequel. Usually 0, only bumped for bugfix
|
12
12
|
# releases that fix regressions from previous versions.
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.93.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: bigdecimal
|
@@ -448,7 +448,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
448
448
|
- !ruby/object:Gem::Version
|
449
449
|
version: '0'
|
450
450
|
requirements: []
|
451
|
-
rubygems_version: 3.6.
|
451
|
+
rubygems_version: 3.6.7
|
452
452
|
specification_version: 4
|
453
453
|
summary: The Database Toolkit for Ruby
|
454
454
|
test_files: []
|