sequel 5.78.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 +4 -4
- data/CHANGELOG +16 -0
- data/README.rdoc +5 -3
- data/doc/dataset_basics.rdoc +1 -1
- data/doc/opening_databases.rdoc +2 -0
- data/doc/querying.rdoc +6 -1
- data/doc/release_notes/5.79.0.txt +28 -0
- data/doc/release_notes/5.80.0.txt +40 -0
- data/lib/sequel/adapters/shared/mysql.rb +2 -2
- data/lib/sequel/adapters/shared/postgres.rb +1 -1
- data/lib/sequel/database/schema_methods.rb +2 -2
- data/lib/sequel/dataset/dataset_module.rb +1 -1
- data/lib/sequel/dataset/graph.rb +1 -0
- data/lib/sequel/dataset/query.rb +58 -9
- data/lib/sequel/extensions/caller_logging.rb +2 -1
- data/lib/sequel/extensions/provenance.rb +108 -0
- data/lib/sequel/model/base.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ddf0e8e9009f39ca7f6dffca8aef10ef4fbdf22a8c5002def5ecea4042f38763
|
4
|
+
data.tar.gz: b9f3cb97273dd9885e8002a64e17bddd0a6db2f932d1c68ce97844e2ac843096
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7387d403f32cb492abe6fad35d6a87a4ac274fc3602aee0f8afba38d9feb30578ee774de2b168a88d86ab740a41fa2a62333f695c0d2fa507fde775943917daa
|
7
|
+
data.tar.gz: 11b1c1e9daf92153585f158358ee85078b83decfca8bcf4569fa90e59335dfd123a0d8fddf8f6e58e166801029de23937279dc3aa746d0d3878a34dac90ce636
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,19 @@
|
|
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
|
+
|
9
|
+
=== 5.79.0 (2024-04-01)
|
10
|
+
|
11
|
+
* Support create_or_replace_view with :materialized option on PostgreSQL (nashby) (#2144)
|
12
|
+
|
13
|
+
* Support :unlogged_tables_default Database option on Postgres for making created tables unlogged by default (jeremyevans) (#2134)
|
14
|
+
|
15
|
+
* Add Dataset#select_prepend for prepending to the current selected columns (jeremyevans) (#2139)
|
16
|
+
|
1
17
|
=== 5.78.0 (2024-03-01)
|
2
18
|
|
3
19
|
* Support SQLite 3.45+ jsonb functions in the sqlite_json_ops extension (jeremyevans) (#2133)
|
data/README.rdoc
CHANGED
@@ -22,10 +22,10 @@ RDoc Documentation :: https://sequel.jeremyevans.net/rdoc
|
|
22
22
|
Source Code :: https://github.com/jeremyevans/sequel
|
23
23
|
Bug tracking (GitHub Issues) :: https://github.com/jeremyevans/sequel/issues
|
24
24
|
Discussion Forum (GitHub Discussions) :: https://github.com/jeremyevans/sequel/discussions
|
25
|
-
|
25
|
+
Archived Discussion Forum (sequel-talk Google Group) :: https://www.mail-archive.com/sequel-talk@googlegroups.com/
|
26
26
|
|
27
27
|
If you have questions about how to use Sequel, please ask on
|
28
|
-
GitHub Discussions
|
28
|
+
GitHub Discussions.
|
29
29
|
Only use the the bug tracker to report
|
30
30
|
bugs in Sequel, not to ask for help on using Sequel.
|
31
31
|
|
@@ -368,10 +368,12 @@ Like +order+, +select+ overrides an existing selection:
|
|
368
368
|
posts.select(:stamp).select(:name)
|
369
369
|
# SELECT name FROM posts
|
370
370
|
|
371
|
-
As you might expect, there
|
371
|
+
As you might expect, there are +order_append+ and +order_prepend+ equivalents for +select+ called +select_append+ and +select_prepend+:
|
372
372
|
|
373
373
|
posts.select(:stamp).select_append(:name)
|
374
374
|
# SELECT stamp, name FROM posts
|
375
|
+
posts.select(:stamp).select_prepend(:name)
|
376
|
+
# SELECT name, stamp FROM posts
|
375
377
|
|
376
378
|
=== Deleting Records
|
377
379
|
|
data/doc/dataset_basics.rdoc
CHANGED
@@ -65,7 +65,7 @@ Most Dataset methods that users will use can be broken down into two types:
|
|
65
65
|
|
66
66
|
Most dataset methods fall into this category, which can be further broken down by the clause they affect:
|
67
67
|
|
68
|
-
SELECT:: select, select_all, select_append, select_group, select_more
|
68
|
+
SELECT:: select, select_all, select_append, select_group, select_more, select_prepend
|
69
69
|
FROM:: from, from_self
|
70
70
|
JOIN:: join, left_join, right_join, full_join, natural_join, natural_left_join, natural_right_join, natural_full_join, cross_join, inner_join, left_outer_join, right_outer_join, full_outer_join, join_table
|
71
71
|
WHERE:: where, filter, exclude, or, grep, invert, unfiltered
|
data/doc/opening_databases.rdoc
CHANGED
@@ -346,6 +346,8 @@ The following additional options are supported:
|
|
346
346
|
separated by commas (for use via a URL: <tt>postgres:///?search_path=schema1,schema2</tt>), or it
|
347
347
|
can be an array of strings (for use via an option:
|
348
348
|
<tt>Sequel.postgres(search_path: ['schema1', 'schema2'])</tt>).
|
349
|
+
:unlogged_tables_default :: Set to true to use UNLOGGED by default for created tables, for potentially better performance
|
350
|
+
when data integrity is not important.
|
349
351
|
:use_iso_date_format :: This can be set to false to not force the ISO date format. Sequel forces
|
350
352
|
it by default to allow for an optimization.
|
351
353
|
|
data/doc/querying.rdoc
CHANGED
@@ -624,11 +624,16 @@ Like +order+, +select+ replaces the existing selected columns:
|
|
624
624
|
Artist.select(:id).select(:name)
|
625
625
|
# SELECT name FROM artists
|
626
626
|
|
627
|
-
To
|
627
|
+
To append to the existing selected columns, use +select_append+:
|
628
628
|
|
629
629
|
Artist.select(:id).select_append(:name)
|
630
630
|
# SELECT id, name FROM artists
|
631
631
|
|
632
|
+
To prepend to the existing selected columns, use +select_prepend+:
|
633
|
+
|
634
|
+
Artist.select(:id).select_prepend(:name)
|
635
|
+
# SELECT name, id FROM artists
|
636
|
+
|
632
637
|
To remove specifically selected columns, and default back to all
|
633
638
|
columns, use +select_all+:
|
634
639
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* Dataset#select_prepend has been added for prepending to the
|
4
|
+
currently selected columns:
|
5
|
+
|
6
|
+
DB[:table].select_prepend(:column)
|
7
|
+
# SELECT column, table.*
|
8
|
+
|
9
|
+
As not all databases support "SELECT column, *", select_prepend
|
10
|
+
qualifies wildcard selections to all tables referenced in the
|
11
|
+
query.
|
12
|
+
|
13
|
+
The only reason to use select_prepend is if you want the hashes
|
14
|
+
returned by Sequel to be in a specific order. Otherwise, it is
|
15
|
+
better to use select_append.
|
16
|
+
|
17
|
+
* On PostgreSQL, Sequel now supports an :unlogged_tables_default
|
18
|
+
Database option, which will default created tables to be UNLOGGED.
|
19
|
+
This can be useful to speedup testing in some cases, but it should
|
20
|
+
never be used in cases where data integrity is important.
|
21
|
+
|
22
|
+
= Other Improvements
|
23
|
+
|
24
|
+
* On PostgreSQL, Database#create_or_replace_view now supports the
|
25
|
+
:materialized option. This allows for dropping an existing
|
26
|
+
materialized view and creating a new one with the same name
|
27
|
+
(PostgreSQL does not have native support for replacing materialized
|
28
|
+
views).
|
@@ -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+
|
929
|
+
# MySQL 8+ and MariaDB 10.6+ support SKIP LOCKED.
|
930
930
|
def supports_skip_locked?
|
931
|
-
|
931
|
+
db.server_version >= (db.mariadb? ? 100600 : 80000)
|
932
932
|
end
|
933
933
|
|
934
934
|
# Check the database setting for whether fractional timestamps
|
@@ -1425,7 +1425,7 @@ module Sequel
|
|
1425
1425
|
elsif options[:foreign]
|
1426
1426
|
raise(Error, "can't provide both :foreign and :unlogged to create_table") if options[:unlogged]
|
1427
1427
|
'FOREIGN '
|
1428
|
-
elsif options[:
|
1428
|
+
elsif options.fetch(:unlogged){typecast_value_boolean(@opts[:unlogged_tables_default])}
|
1429
1429
|
'UNLOGGED '
|
1430
1430
|
end
|
1431
1431
|
|
@@ -252,10 +252,10 @@ module Sequel
|
|
252
252
|
# For databases where replacing a view is not natively supported, support
|
253
253
|
# is emulated by dropping a view with the same name before creating the view.
|
254
254
|
def create_or_replace_view(name, source, options = OPTS)
|
255
|
-
if supports_create_or_replace_view?
|
255
|
+
if supports_create_or_replace_view? && !options[:materialized]
|
256
256
|
options = options.merge(:replace=>true)
|
257
257
|
else
|
258
|
-
swallow_database_error{drop_view(name)}
|
258
|
+
swallow_database_error{drop_view(name, options)}
|
259
259
|
end
|
260
260
|
|
261
261
|
create_view(name, source, options)
|
@@ -21,7 +21,7 @@ module Sequel
|
|
21
21
|
where exclude exclude_having having
|
22
22
|
distinct grep group group_and_count group_append
|
23
23
|
limit offset order order_append order_prepend reverse
|
24
|
-
select select_all select_append select_group server
|
24
|
+
select select_all select_append select_group select_prepend server
|
25
25
|
METHS
|
26
26
|
|
27
27
|
# Define a method in the module
|
data/lib/sequel/dataset/graph.rb
CHANGED
data/lib/sequel/dataset/query.rb
CHANGED
@@ -43,7 +43,7 @@ module Sequel
|
|
43
43
|
add_graph_aliases distinct except exclude exclude_having
|
44
44
|
filter for_update from from_self graph grep group group_and_count group_append group_by having intersect invert
|
45
45
|
limit lock_style naked offset or order order_append order_by order_more order_prepend qualify
|
46
|
-
reverse reverse_order select select_all select_append select_group select_more server
|
46
|
+
reverse reverse_order select select_all select_append select_group select_more select_prepend server
|
47
47
|
set_graph_aliases unfiltered ungraphed ungrouped union
|
48
48
|
unlimited unordered where with with_recursive with_sql
|
49
49
|
METHS
|
@@ -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)
|
@@ -944,14 +951,8 @@ module Sequel
|
|
944
951
|
# DB[:items].select(:a).select_append(:b) # SELECT a, b FROM items
|
945
952
|
# DB[:items].select_append(:b) # SELECT *, b FROM items
|
946
953
|
def select_append(*columns, &block)
|
947
|
-
|
948
|
-
|
949
|
-
unless supports_select_all_and_column?
|
950
|
-
return select_all(*(Array(@opts[:from]) + Array(@opts[:join]))).select_append(*columns, &block)
|
951
|
-
end
|
952
|
-
cur_sel = [WILDCARD]
|
953
|
-
end
|
954
|
-
select(*(cur_sel + columns), &block)
|
954
|
+
virtual_row_columns(columns, block)
|
955
|
+
select(*(_current_select(true) + columns))
|
955
956
|
end
|
956
957
|
|
957
958
|
# Set both the select and group clauses with the given +columns+.
|
@@ -973,6 +974,18 @@ module Sequel
|
|
973
974
|
select_append(*columns, &block)
|
974
975
|
end
|
975
976
|
|
977
|
+
# Returns a copy of the dataset with the given columns added
|
978
|
+
# to the existing selected columns. If no columns are currently selected,
|
979
|
+
# it will select the columns given in addition to *.
|
980
|
+
#
|
981
|
+
# DB[:items].select(:a).select(:b) # SELECT b FROM items
|
982
|
+
# DB[:items].select(:a).select_prepend(:b) # SELECT b, a FROM items
|
983
|
+
# DB[:items].select_prepend(:b) # SELECT b, * FROM items
|
984
|
+
def select_prepend(*columns, &block)
|
985
|
+
virtual_row_columns(columns, block)
|
986
|
+
select(*(columns + _current_select(false)))
|
987
|
+
end
|
988
|
+
|
976
989
|
# Set the server for this dataset to use. Used to pick a specific database
|
977
990
|
# shard to run a query against, or to override the default (where SELECT uses
|
978
991
|
# :read_only database and all other queries use the :default database). This
|
@@ -999,6 +1012,7 @@ module Sequel
|
|
999
1012
|
|
1000
1013
|
# Specify that the check for limits/offsets when updating/deleting be skipped for the dataset.
|
1001
1014
|
def skip_limit_check
|
1015
|
+
return self if opts[:skip_limit_check]
|
1002
1016
|
cached_dataset(:_skip_limit_check_ds) do
|
1003
1017
|
clone(:skip_limit_check=>true)
|
1004
1018
|
end
|
@@ -1006,6 +1020,7 @@ module Sequel
|
|
1006
1020
|
|
1007
1021
|
# Skip locked rows when returning results from this dataset.
|
1008
1022
|
def skip_locked
|
1023
|
+
return self if opts[:skip_locked]
|
1009
1024
|
cached_dataset(:_skip_locked_ds) do
|
1010
1025
|
raise(Error, 'This dataset does not support skipping locked rows') unless supports_skip_locked?
|
1011
1026
|
clone(:skip_locked=>true)
|
@@ -1017,6 +1032,7 @@ module Sequel
|
|
1017
1032
|
# DB[:items].group(:a).having(a: 1).where(:b).unfiltered
|
1018
1033
|
# # SELECT * FROM items GROUP BY a
|
1019
1034
|
def unfiltered
|
1035
|
+
return self unless opts[:where] || opts[:having]
|
1020
1036
|
cached_dataset(:_unfiltered_ds){clone(:where => nil, :having => nil)}
|
1021
1037
|
end
|
1022
1038
|
|
@@ -1025,6 +1041,7 @@ module Sequel
|
|
1025
1041
|
# DB[:items].group(:a).having(a: 1).where(:b).ungrouped
|
1026
1042
|
# # SELECT * FROM items WHERE b
|
1027
1043
|
def ungrouped
|
1044
|
+
return self unless opts[:group] || opts[:having]
|
1028
1045
|
cached_dataset(:_ungrouped_ds){clone(:group => nil, :having => nil)}
|
1029
1046
|
end
|
1030
1047
|
|
@@ -1052,6 +1069,7 @@ module Sequel
|
|
1052
1069
|
#
|
1053
1070
|
# DB[:items].limit(10, 20).unlimited # SELECT * FROM items
|
1054
1071
|
def unlimited
|
1072
|
+
return self unless opts[:limit] || opts[:offset]
|
1055
1073
|
cached_dataset(:_unlimited_ds){clone(:limit=>nil, :offset=>nil)}
|
1056
1074
|
end
|
1057
1075
|
|
@@ -1059,6 +1077,7 @@ module Sequel
|
|
1059
1077
|
#
|
1060
1078
|
# DB[:items].order(:a).unordered # SELECT * FROM items
|
1061
1079
|
def unordered
|
1080
|
+
return self unless opts[:order]
|
1062
1081
|
cached_dataset(:_unordered_ds){clone(:order=>nil)}
|
1063
1082
|
end
|
1064
1083
|
|
@@ -1353,6 +1372,36 @@ module Sequel
|
|
1353
1372
|
end
|
1354
1373
|
# :nocov:
|
1355
1374
|
|
1375
|
+
# A frozen array for the currently selected columns.
|
1376
|
+
def _current_select(allow_plain_wildcard)
|
1377
|
+
cur_sel = @opts[:select]
|
1378
|
+
|
1379
|
+
if !cur_sel || cur_sel.empty?
|
1380
|
+
cur_sel = if allow_plain_wildcard && supports_select_all_and_column?
|
1381
|
+
[WILDCARD].freeze
|
1382
|
+
else
|
1383
|
+
_current_select_column_all
|
1384
|
+
end
|
1385
|
+
elsif !allow_plain_wildcard && cur_sel.include?(WILDCARD)
|
1386
|
+
cur_sel = cur_sel.dup
|
1387
|
+
index = cur_sel.index(WILDCARD)
|
1388
|
+
cur_sel.delete(WILDCARD)
|
1389
|
+
_current_select_column_all.each_with_index do |ca, i|
|
1390
|
+
cur_sel.insert(index+i, ca)
|
1391
|
+
end
|
1392
|
+
cur_sel.freeze
|
1393
|
+
end
|
1394
|
+
|
1395
|
+
cur_sel
|
1396
|
+
end
|
1397
|
+
|
1398
|
+
# An array of SQL::ColumnAll objects for all FROM and JOIN tables. Used for select_append
|
1399
|
+
# and select_prepend.
|
1400
|
+
def _current_select_column_all
|
1401
|
+
tables = Array(@opts[:from]) + Array(@opts[:join])
|
1402
|
+
tables.map{|t| i, a = split_alias(t); a || i}.map!{|t| SQL::ColumnAll.new(t)}.freeze
|
1403
|
+
end
|
1404
|
+
|
1356
1405
|
# If invert is true, invert the condition.
|
1357
1406
|
def _invert_filter(cond, invert)
|
1358
1407
|
if invert
|
@@ -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?(
|
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
|
data/lib/sequel/model/base.rb
CHANGED
@@ -17,7 +17,7 @@ module Sequel
|
|
17
17
|
# natural_join, natural_left_join, natural_right_join, offset, order, order_append, order_by,
|
18
18
|
# order_more, order_prepend, paged_each, qualify, reverse, reverse_order, right_join,
|
19
19
|
# right_outer_join, select, select_all, select_append, select_group, select_hash,
|
20
|
-
# select_hash_groups, select_map, select_more, select_order_map, server,
|
20
|
+
# select_hash_groups, select_map, select_more, select_order_map, select_prepend, server,
|
21
21
|
# single_record, single_record!, single_value, single_value!, sum, to_hash, to_hash_groups,
|
22
22
|
# truncate, unfiltered, ungraphed, ungrouped, union, unlimited, unordered, where, where_all,
|
23
23
|
# where_each, where_single_value, with, with_recursive, with_sql
|
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 = 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.
|
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-
|
11
|
+
date: 2024-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bigdecimal
|
@@ -225,7 +225,9 @@ extra_rdoc_files:
|
|
225
225
|
- doc/release_notes/5.76.0.txt
|
226
226
|
- doc/release_notes/5.77.0.txt
|
227
227
|
- doc/release_notes/5.78.0.txt
|
228
|
+
- doc/release_notes/5.79.0.txt
|
228
229
|
- doc/release_notes/5.8.0.txt
|
230
|
+
- doc/release_notes/5.80.0.txt
|
229
231
|
- doc/release_notes/5.9.0.txt
|
230
232
|
files:
|
231
233
|
- CHANGELOG
|
@@ -331,7 +333,9 @@ files:
|
|
331
333
|
- doc/release_notes/5.76.0.txt
|
332
334
|
- doc/release_notes/5.77.0.txt
|
333
335
|
- doc/release_notes/5.78.0.txt
|
336
|
+
- doc/release_notes/5.79.0.txt
|
334
337
|
- doc/release_notes/5.8.0.txt
|
338
|
+
- doc/release_notes/5.80.0.txt
|
335
339
|
- doc/release_notes/5.9.0.txt
|
336
340
|
- doc/schema_modification.rdoc
|
337
341
|
- doc/security.rdoc
|
@@ -494,6 +498,7 @@ files:
|
|
494
498
|
- lib/sequel/extensions/pg_static_cache_updater.rb
|
495
499
|
- lib/sequel/extensions/pg_timestamptz.rb
|
496
500
|
- lib/sequel/extensions/pretty_table.rb
|
501
|
+
- lib/sequel/extensions/provenance.rb
|
497
502
|
- lib/sequel/extensions/query.rb
|
498
503
|
- lib/sequel/extensions/round_timestamps.rb
|
499
504
|
- lib/sequel/extensions/run_transaction_hooks.rb
|
@@ -664,7 +669,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
664
669
|
- !ruby/object:Gem::Version
|
665
670
|
version: '0'
|
666
671
|
requirements: []
|
667
|
-
rubygems_version: 3.5.
|
672
|
+
rubygems_version: 3.5.9
|
668
673
|
signing_key:
|
669
674
|
specification_version: 4
|
670
675
|
summary: The Database Toolkit for Ruby
|