sequel 5.79.0 → 5.80.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 154517820668c8c59f141797157a9945ae3afaeb482e997619e68e9bebc5c70a
4
- data.tar.gz: c7991308e696d0f931f46cf38c301986c9094a44bca94a1d6749a0b798cb1d9c
3
+ metadata.gz: ddf0e8e9009f39ca7f6dffca8aef10ef4fbdf22a8c5002def5ecea4042f38763
4
+ data.tar.gz: b9f3cb97273dd9885e8002a64e17bddd0a6db2f932d1c68ce97844e2ac843096
5
5
  SHA512:
6
- metadata.gz: 7efb6286d8eded4c0064199f7335e9cd2b0575942fd52040b29c52e26498d1531168435d86ca6e42474512ac21c1b151db85dd4db0fa5ff6b3f90dad73568a3b
7
- data.tar.gz: 7ef17f79333fdabe90485b105fdc24925c8c75f41dc78f83f5400ebc39b0ac2b3709881624086526559132c8346c1dc8f07b9384a39bb838d1132bf4a7040ec1
6
+ metadata.gz: 7387d403f32cb492abe6fad35d6a87a4ac274fc3602aee0f8afba38d9feb30578ee774de2b168a88d86ab740a41fa2a62333f695c0d2fa507fde775943917daa
7
+ data.tar.gz: 11b1c1e9daf92153585f158358ee85078b83decfca8bcf4569fa90e59335dfd123a0d8fddf8f6e58e166801029de23937279dc3aa746d0d3878a34dac90ce636
data/CHANGELOG CHANGED
@@ -1,3 +1,11 @@
1
+ === 5.80.0 (2024-05-01)
2
+
3
+ * Support Dataset#skip_locked on MariaDB 10.6+ (simi) (#2150)
4
+
5
+ * Avoid allocating datasets in cases where the returned dataset would be the same as the receiver (jeremyevans)
6
+
7
+ * Add provenance dataset extension, which includes comments in queries showing how and where the dataset was built (jeremyevans)
8
+
1
9
  === 5.79.0 (2024-04-01)
2
10
 
3
11
  * Support create_or_replace_view with :materialized option on PostgreSQL (nashby) (#2144)
@@ -0,0 +1,40 @@
1
+ = New Features
2
+
3
+ * A provenance dataset extension has been added. This extension makes
4
+ SQL queries include a comment describing how the dataset was built.
5
+ This can make debugging complex cases significantly easier. Here's
6
+ a simple example:
7
+
8
+ DB.extension :provenance
9
+
10
+ DB[:table].
11
+ select(:a).
12
+ where{b > 10}.
13
+ order(:c).
14
+ limit(10)
15
+ # SQL:
16
+ # SELECT a FROM table WHERE (b > 10) ORDER BY c LIMIT 10 --
17
+ # -- Dataset Provenance
18
+ # -- Keys:[:from] Source:(eval at bin/sequel:257):2:in `<main>'
19
+ # -- Keys:[:select] Source:(eval at bin/sequel:257):3:in `<main>'
20
+ # -- Keys:[:where] Source:(eval at bin/sequel:257):4:in `<main>'
21
+ # -- Keys:[:order] Source:(eval at bin/sequel:257):5:in `<main>'
22
+ # -- Keys:[:limit] Source:(eval at bin/sequel:257):6:in `<main>'
23
+
24
+ With the above example, it's obvious how the dataset is created, but
25
+ but in real applications, where datasets can be built from multiple
26
+ files, seeing where each dataset clone was made can be helpful.
27
+
28
+ The source listed will skip locations in the Ruby standard library
29
+ as well as Sequel itself. Other locations can be skipped by
30
+ providing a Database :provenance_caller_ignore Regexp option:
31
+
32
+ DB.opts[:provenance_caller_ignore] = /\/gems\/library_name-/
33
+
34
+ = Other Improvements
35
+
36
+ * For dataset methods where Sequel can determine that the return
37
+ value would be equivalent to the receiver, Sequel now returns the
38
+ receiver. This reduces the number of dataset allocations.
39
+
40
+ * Sequel now supports Dataset#skip_locked on MariaDB 10.6+.
@@ -926,9 +926,9 @@ module Sequel
926
926
  (type == :insert && db.mariadb? && db.adapter_scheme != :jdbc) ? (db.server_version >= 100500) : false
927
927
  end
928
928
 
929
- # MySQL 8+ supports SKIP LOCKED.
929
+ # MySQL 8+ and MariaDB 10.6+ support SKIP LOCKED.
930
930
  def supports_skip_locked?
931
- !db.mariadb? && db.server_version >= 80000
931
+ db.server_version >= (db.mariadb? ? 100600 : 80000)
932
932
  end
933
933
 
934
934
  # Check the database setting for whether fractional timestamps
@@ -253,6 +253,7 @@ module Sequel
253
253
  # Remove the splitting of results into subhashes, and all metadata
254
254
  # related to the current graph (if any).
255
255
  def ungraphed
256
+ return self unless opts[:graph]
256
257
  clone(:graph=>nil)
257
258
  end
258
259
 
@@ -129,6 +129,7 @@ module Sequel
129
129
  def distinct(*args, &block)
130
130
  virtual_row_columns(args, block)
131
131
  if args.empty?
132
+ return self if opts[:distinct] == EMPTY_ARRAY
132
133
  cached_dataset(:_distinct_ds){clone(:distinct => EMPTY_ARRAY)}
133
134
  else
134
135
  raise(InvalidOperation, "DISTINCT ON not supported") unless supports_distinct_on?
@@ -230,6 +231,7 @@ module Sequel
230
231
  #
231
232
  # DB[:table].for_update # SELECT * FROM table FOR UPDATE
232
233
  def for_update
234
+ return self if opts[:lock] == :update
233
235
  cached_dataset(:_for_update_ds){lock_style(:update)}
234
236
  end
235
237
 
@@ -641,6 +643,7 @@ module Sequel
641
643
  # DB.from(:a, DB[:b].where(Sequel[:a][:c]=>Sequel[:b][:d]).lateral)
642
644
  # # SELECT * FROM a, LATERAL (SELECT * FROM b WHERE (a.c = b.d))
643
645
  def lateral
646
+ return self if opts[:lateral]
644
647
  cached_dataset(:_lateral_ds){clone(:lateral=>true)}
645
648
  end
646
649
 
@@ -744,6 +747,7 @@ module Sequel
744
747
  # ds.all # => [{2=>:id}]
745
748
  # ds.naked.all # => [{:id=>2}]
746
749
  def naked
750
+ return self unless opts[:row_proc]
747
751
  cached_dataset(:_naked_ds){with_row_proc(nil)}
748
752
  end
749
753
 
@@ -753,6 +757,7 @@ module Sequel
753
757
  # DB[:items].for_update.nowait
754
758
  # # SELECT * FROM items FOR UPDATE NOWAIT
755
759
  def nowait
760
+ return self if opts[:nowait]
756
761
  cached_dataset(:_nowait_ds) do
757
762
  raise(Error, 'This dataset does not support raises errors instead of waiting for locked rows') unless supports_nowait?
758
763
  clone(:nowait=>true)
@@ -878,6 +883,7 @@ module Sequel
878
883
  # end
879
884
  def returning(*values)
880
885
  if values.empty?
886
+ return self if opts[:returning] == EMPTY_ARRAY
881
887
  cached_dataset(:_returning_ds) do
882
888
  raise Error, "RETURNING is not supported on #{db.database_type}" unless supports_returning?(:insert)
883
889
  clone(:returning=>EMPTY_ARRAY)
@@ -930,6 +936,7 @@ module Sequel
930
936
  # DB[:items].select_all(:items, :foo) # SELECT items.*, foo.* FROM items
931
937
  def select_all(*tables)
932
938
  if tables.empty?
939
+ return self unless opts[:select]
933
940
  cached_dataset(:_select_all_ds){clone(:select => nil)}
934
941
  else
935
942
  select(*tables.map{|t| i, a = split_alias(t); a || i}.map!{|t| SQL::ColumnAll.new(t)}.freeze)
@@ -1005,6 +1012,7 @@ module Sequel
1005
1012
 
1006
1013
  # Specify that the check for limits/offsets when updating/deleting be skipped for the dataset.
1007
1014
  def skip_limit_check
1015
+ return self if opts[:skip_limit_check]
1008
1016
  cached_dataset(:_skip_limit_check_ds) do
1009
1017
  clone(:skip_limit_check=>true)
1010
1018
  end
@@ -1012,6 +1020,7 @@ module Sequel
1012
1020
 
1013
1021
  # Skip locked rows when returning results from this dataset.
1014
1022
  def skip_locked
1023
+ return self if opts[:skip_locked]
1015
1024
  cached_dataset(:_skip_locked_ds) do
1016
1025
  raise(Error, 'This dataset does not support skipping locked rows') unless supports_skip_locked?
1017
1026
  clone(:skip_locked=>true)
@@ -1023,6 +1032,7 @@ module Sequel
1023
1032
  # DB[:items].group(:a).having(a: 1).where(:b).unfiltered
1024
1033
  # # SELECT * FROM items GROUP BY a
1025
1034
  def unfiltered
1035
+ return self unless opts[:where] || opts[:having]
1026
1036
  cached_dataset(:_unfiltered_ds){clone(:where => nil, :having => nil)}
1027
1037
  end
1028
1038
 
@@ -1031,6 +1041,7 @@ module Sequel
1031
1041
  # DB[:items].group(:a).having(a: 1).where(:b).ungrouped
1032
1042
  # # SELECT * FROM items WHERE b
1033
1043
  def ungrouped
1044
+ return self unless opts[:group] || opts[:having]
1034
1045
  cached_dataset(:_ungrouped_ds){clone(:group => nil, :having => nil)}
1035
1046
  end
1036
1047
 
@@ -1058,6 +1069,7 @@ module Sequel
1058
1069
  #
1059
1070
  # DB[:items].limit(10, 20).unlimited # SELECT * FROM items
1060
1071
  def unlimited
1072
+ return self unless opts[:limit] || opts[:offset]
1061
1073
  cached_dataset(:_unlimited_ds){clone(:limit=>nil, :offset=>nil)}
1062
1074
  end
1063
1075
 
@@ -1065,6 +1077,7 @@ module Sequel
1065
1077
  #
1066
1078
  # DB[:items].order(:a).unordered # SELECT * FROM items
1067
1079
  def unordered
1080
+ return self unless opts[:order]
1068
1081
  cached_dataset(:_unordered_ds){clone(:order=>nil)}
1069
1082
  end
1070
1083
 
@@ -36,6 +36,7 @@ require 'rbconfig'
36
36
  module Sequel
37
37
  module CallerLogging
38
38
  SEQUEL_LIB_PATH = (File.expand_path('../../..', __FILE__) + '/').freeze
39
+ RUBY_STDLIB = RbConfig::CONFIG["rubylibdir"]
39
40
 
40
41
  # A regexp of caller lines to ignore, in addition to internal Sequel and Ruby code.
41
42
  attr_accessor :caller_logging_ignore
@@ -59,7 +60,7 @@ module Sequel
59
60
  ignore = caller_logging_ignore
60
61
  c = caller.find do |line|
61
62
  !(line.start_with?(SEQUEL_LIB_PATH) ||
62
- line.start_with?(RbConfig::CONFIG["rubylibdir"]) ||
63
+ line.start_with?(RUBY_STDLIB) ||
63
64
  (ignore && line =~ ignore))
64
65
  end
65
66
 
@@ -0,0 +1,108 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # The provenance dataset extension tracks the locations of all
4
+ # dataset clones that resulted in the current dataset, and includes
5
+ # the information as a comment in the dataset's SQL. This makes it
6
+ # possible to see how a query was built, which can aid debugging.
7
+ # Example:
8
+ #
9
+ # DB[:table].
10
+ # select(:a).
11
+ # where{b > 10}.
12
+ # order(:c).
13
+ # limit(10)
14
+ # # SQL:
15
+ # # SELECT a FROM table WHERE (b > 10) ORDER BY c LIMIT 10 --
16
+ # # -- Dataset Provenance
17
+ # # -- Keys:[:from] Source:(eval at bin/sequel:257):2:in `<main>'
18
+ # # -- Keys:[:select] Source:(eval at bin/sequel:257):3:in `<main>'
19
+ # # -- Keys:[:where] Source:(eval at bin/sequel:257):4:in `<main>'
20
+ # # -- Keys:[:order] Source:(eval at bin/sequel:257):5:in `<main>'
21
+ # # -- Keys:[:limit] Source:(eval at bin/sequel:257):6:in `<main>'
22
+ #
23
+ # With the above example, the source is fairly obvious and not helpful,
24
+ # but in real applications, where datasets can be built from multiple
25
+ # files, seeing where each dataset clone was made can be helpful.
26
+ #
27
+ # The Source listed will skip locations in the Ruby standard library
28
+ # as well as Sequel itself. Other locations can be skipped by
29
+ # providing a Database :provenance_caller_ignore Regexp option:
30
+ #
31
+ # DB.opts[:provenance_caller_ignore] = /\/gems\/library_name-/
32
+ #
33
+ # Related module: Sequel::Dataset::Provenance
34
+
35
+ #
36
+ module Sequel
37
+ class Dataset
38
+ module Provenance
39
+ SEQUEL_LIB_PATH = (File.expand_path('../../..', __FILE__) + '/').freeze
40
+ RUBY_STDLIB = RbConfig::CONFIG["rubylibdir"]
41
+
42
+ if TRUE_FREEZE
43
+ # Include provenance information when cloning datasets.
44
+ def clone(opts = nil || (return self))
45
+ super(provenance_opts(opts))
46
+ end
47
+ else
48
+ # :nocov:
49
+ def clone(opts = OPTS) # :nodoc:
50
+ super(provenance_opts(opts))
51
+ end
52
+ # :nocov:
53
+ end
54
+
55
+ %w'select insert update delete'.each do |type|
56
+ # Include the provenance information as a comment when preparing dataset SQL
57
+ define_method(:"#{type}_sql") do |*a|
58
+ sql = super(*a)
59
+
60
+ if provenance = @opts[:provenance]
61
+ comment = provenance.map do |hash|
62
+ " -- Keys:#{hash[:keys].inspect} Source:#{hash[:source]}".to_s.gsub(/\s+/, ' ')
63
+ end
64
+ comment << ""
65
+ comment.unshift " -- Dataset Provenance"
66
+ comment.unshift " -- "
67
+ comment = comment.join("\n")
68
+
69
+ if sql.frozen?
70
+ sql += comment
71
+ sql.freeze
72
+ elsif @opts[:append_sql] || @opts[:placeholder_literalizer]
73
+ sql << comment
74
+ else
75
+ sql += comment
76
+ end
77
+ end
78
+
79
+ sql
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ # Return a copy of opts with provenance information added.
86
+ def provenance_opts(opts)
87
+ provenance = {source: provenance_source, keys: opts.keys.freeze}.freeze
88
+ opts = opts.dup
89
+ opts[:provenance] = ((@opts[:provenance] || EMPTY_ARRAY).dup << provenance).freeze
90
+ opts
91
+ end
92
+
93
+ # Return the caller line for the provenance change. This skips
94
+ # Sequel itself and the standard library. Additional locations
95
+ # can be skipped using the :provenance_caller_ignore Dataset option.
96
+ def provenance_source
97
+ ignore = db.opts[:provenance_caller_ignore]
98
+ caller.find do |line|
99
+ !(line.start_with?(SEQUEL_LIB_PATH) ||
100
+ line.start_with?(RUBY_STDLIB) ||
101
+ (ignore && line =~ ignore))
102
+ end
103
+ end
104
+ end
105
+
106
+ register_extension(:provenance, Provenance)
107
+ end
108
+ end
@@ -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 = 79
9
+ MINOR = 80
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,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.79.0
4
+ version: 5.80.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-01 00:00:00.000000000 Z
11
+ date: 2024-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bigdecimal
@@ -227,6 +227,7 @@ extra_rdoc_files:
227
227
  - doc/release_notes/5.78.0.txt
228
228
  - doc/release_notes/5.79.0.txt
229
229
  - doc/release_notes/5.8.0.txt
230
+ - doc/release_notes/5.80.0.txt
230
231
  - doc/release_notes/5.9.0.txt
231
232
  files:
232
233
  - CHANGELOG
@@ -334,6 +335,7 @@ files:
334
335
  - doc/release_notes/5.78.0.txt
335
336
  - doc/release_notes/5.79.0.txt
336
337
  - doc/release_notes/5.8.0.txt
338
+ - doc/release_notes/5.80.0.txt
337
339
  - doc/release_notes/5.9.0.txt
338
340
  - doc/schema_modification.rdoc
339
341
  - doc/security.rdoc
@@ -496,6 +498,7 @@ files:
496
498
  - lib/sequel/extensions/pg_static_cache_updater.rb
497
499
  - lib/sequel/extensions/pg_timestamptz.rb
498
500
  - lib/sequel/extensions/pretty_table.rb
501
+ - lib/sequel/extensions/provenance.rb
499
502
  - lib/sequel/extensions/query.rb
500
503
  - lib/sequel/extensions/round_timestamps.rb
501
504
  - lib/sequel/extensions/run_transaction_hooks.rb
@@ -666,7 +669,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
666
669
  - !ruby/object:Gem::Version
667
670
  version: '0'
668
671
  requirements: []
669
- rubygems_version: 3.5.3
672
+ rubygems_version: 3.5.9
670
673
  signing_key:
671
674
  specification_version: 4
672
675
  summary: The Database Toolkit for Ruby