sequel 5.71.0 → 5.72.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17fbd14a63974634d39c289194210ea773d5e2017ad24ac3f6a5c89cc6eb481d
4
- data.tar.gz: 390a9c664bf0a7710bb341ef8699e53b0ed2ea4d4fd2c221f7e140393d52047e
3
+ metadata.gz: 9e135f19f0f4fb1b78f2c3d0c542ca3db937fa6e1e4960d11120e36a0f6ca314
4
+ data.tar.gz: f1550faa63cfda46f2fc2c4142e009e19357ce961f8e63542874cabdefbaf597
5
5
  SHA512:
6
- metadata.gz: 0af7a0afdad27b270d69eb8248e734408c0c132d209c111f03957a14d1fc2ef44fc4a6da66eaa4986dadf1565f428a140dc9b807bb0215117b015b69057445a1
7
- data.tar.gz: a2aade8559d69fe43306b6834069e976f57809170e1a9102501e4031d899dd046119de95f485712024e68aa5b077cf63cccc74b7a77b244e821a2c42b87a09a3
6
+ metadata.gz: '093c3ca50f23e97bc3a10b1b0b2a4dea3f79e9cc85bff92801676709fad00e36dd8a84156a5179758bf091fe9e1486d65fc3de300a2b8038f181f36d16481918'
7
+ data.tar.gz: db0f0c8c81e1fa33b80dbc2e45d477997392965c5aca8a32fc92125843cff4b49045d3d83bd182c9b8bdf980336e1dc97c47a1a32e186e6ef01e5b7d98bbd0a5
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ === 5.72.0 (2023-09-01)
2
+
3
+ * Sort caches before marshalling when using schema_caching, index_caching, static_cache_cache, and pg_auto_constraint_validations (jeremyevans)
4
+
5
+ * Change the defaults_setter plugin do a deep-copy of database default hash/array values and delegates (jeremyevans) (#2069)
6
+
7
+ * Add pg_auto_parameterize_in_array extension, for converting IN/NOT IN to = ANY or != ALL for more types (jeremyevans)
8
+
9
+ * Fix literalization of infinite and NaN float values in PostgreSQL array bound variables (jeremyevans)
10
+
1
11
  === 5.71.0 (2023-08-01)
2
12
 
3
13
  * Support ILIKE ANY on PostgreSQL by not forcing the use of ESCAPE for ILIKE (gilesbowkett) (#2066)
data/README.rdoc CHANGED
@@ -825,7 +825,7 @@ You can dynamically customize eager loads for both +eager+ and +eager_graph+ whi
825
825
 
826
826
  === Joining with Associations
827
827
 
828
- You can use the +association_join+ method to add a join to the model's dataset based on the assocation:
828
+ You can use the +association_join+ method to add a join to the model's dataset based on the association:
829
829
 
830
830
  Post.association_join(:author)
831
831
  # SELECT * FROM posts
@@ -48,7 +48,7 @@ If you want to change mass assignment so it ignores attempts to access restricte
48
48
  Since mass assignment by default allows modification of all column values except for primary key columns, it can be a security risk in some cases.
49
49
  If you are dealing with untrusted input, you are generally going to want to restrict what should be updated.
50
50
 
51
- Sequel has <tt>Model#set_fields</tt> and <tt>Model#update_fields</tt> methods, which are designed to be used with untrused input.
51
+ Sequel has <tt>Model#set_fields</tt> and <tt>Model#update_fields</tt> methods, which are designed to be used with untrusted input.
52
52
  These methods take two arguments, the untrusted hash as the first argument, and a trusted array of field names as the second argument:
53
53
 
54
54
  post.set_fields({title: 'T', body: 'B'}, [:title, :body])
@@ -0,0 +1,33 @@
1
+ = New Features
2
+
3
+ * A pg_auto_parameterize_in_array extension has been added, which
4
+ handles conversion of IN/NOT IN to = ANY or != ALL for more types.
5
+ The pg_auto_parameterize extension only handles integer types by
6
+ default, because other types require the pg_array extension. This
7
+ new extension adds handling for Float, BigDecimal, Date, Time,
8
+ DateTime, Sequel::SQLTime, and Sequel::SQL::Blob types. It can
9
+ also handle String types if the :treat_string_list_as_text_array
10
+ Database option is present, using the text type for that. Handling
11
+ String values as text is not the default because that may cause
12
+ issues for some queries.
13
+
14
+ = Other Improvements
15
+
16
+ * The defaults_setter plugin now does a deep copy of database
17
+ default values that are hash/array or delegates to hash/array.
18
+ This fixes cases where the database default values are mutated.
19
+
20
+ * Sequel now correctly handles infinite and NaN float values used
21
+ inside PostgreSQL array bound variables.
22
+
23
+ * The data in the cache files used by the schema_caching and
24
+ index_caching extensions and static_cache_cache and
25
+ pg_auto_constraint_validations plugins are now sorted before the
26
+ cache file is saved, increasing consistency between runs.
27
+
28
+ * bigdecimal has been added as a dependency. bigdecimal is currently
29
+ a default gem in Ruby from 1.9 to 3.2, but it will move to a
30
+ bundled gem in Ruby 3.4, and there will be warnings in Ruby 3.3
31
+ for cases that will break in Ruby 3.4. Adding bigdecimal as a
32
+ dependency should avoid warnings when using bundler in Ruby 3.3,
33
+ and should avoid errors in Ruby 3.4.
data/doc/testing.rdoc CHANGED
@@ -176,7 +176,7 @@ SEQUEL_MODEL_PREPARED_STATEMENTS :: Use the prepared_statements plugin when runn
176
176
  SEQUEL_MODEL_THROW_FAILURES :: Use the throw_failures plugin when running the specs
177
177
  SEQUEL_NO_CACHE_ASSOCIATIONS :: Don't cache association metadata when running the specs
178
178
  SEQUEL_NO_PENDING :: Don't skip any specs, try running all specs (note, can cause lockups for some adapters)
179
- SEQUEL_PG_AUTO_PARAMETERIZE :: Use the pg_auto_parameterize extension when running the postgres specs
179
+ SEQUEL_PG_AUTO_PARAMETERIZE :: Use the pg_auto_parameterize extension when running the postgres specs. Value can be +in_array+ to test the pg_auto_parameterize_in_array extension, and +in_array_string+ to test the pg_auto_parameterize_in_array extension with the +:treat_in_string_list_as_text_array+ Database option set.
180
180
  SEQUEL_PG_TIMESTAMPTZ :: Use the pg_timestamptz extension when running the postgres specs
181
181
  SEQUEL_PRIMARY_KEY_LOOKUP_CHECK_VALUES :: Use the primary_key_lookup_check_values extension when running the adapter or integration specs
182
182
  SEQUEL_QUERY_PER_ASSOCIATION_DB_0_URL :: Run query-per-association integration tests with multiple databases (all 4 must be set to run)
@@ -56,7 +56,11 @@ module Sequel
56
56
 
57
57
  # Dump the index cache to the filename given in Marshal format.
58
58
  def dump_index_cache(file)
59
- File.open(file, 'wb'){|f| f.write(Marshal.dump(@indexes))}
59
+ indexes = {}
60
+ @indexes.sort.each do |k, v|
61
+ indexes[k] = v
62
+ end
63
+ File.open(file, 'wb'){|f| f.write(Marshal.dump(indexes))}
60
64
  nil
61
65
  end
62
66
 
@@ -233,6 +233,14 @@ module Sequel
233
233
  a
234
234
  when String
235
235
  bound_variable_array_string(a)
236
+ when Float
237
+ if a.infinite?
238
+ a > 0 ? '"Infinity"' : '"-Infinity"'
239
+ elsif a.nan?
240
+ '"NaN"'
241
+ else
242
+ literal(a)
243
+ end
236
244
  else
237
245
  if (s = bound_variable_arg(a, nil)).is_a?(String)
238
246
  bound_variable_array_string(s)
@@ -0,0 +1,110 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # The pg_auto_parameterize_in_array extension builds on the pg_auto_parameterize
4
+ # extension, adding support for handling additional types when converting from
5
+ # IN to = ANY and NOT IN to != ALL:
6
+ #
7
+ # DB[:table].where(column: [1.0, 2.0, ...])
8
+ # # Without extension: column IN ($1::numeric, $2:numeric, ...) # bound variables: 1.0, 2.0, ...
9
+ # # With extension: column = ANY($1::numeric[]) # bound variables: [1.0, 2.0, ...]
10
+ #
11
+ # This prevents the use of an unbounded number of bound variables based on the
12
+ # size of the array, as well as using different SQL for different array sizes.
13
+ #
14
+ # The following types are supported when doing the conversions, with the database
15
+ # type used:
16
+ #
17
+ # Float :: if any are infinite or NaN, double precision, otherwise numeric
18
+ # BigDecimal :: numeric
19
+ # Date :: date
20
+ # Time :: timestamp (or timestamptz if pg_timestamptz extension is used)
21
+ # DateTime :: timestamp (or timestamptz if pg_timestamptz extension is used)
22
+ # Sequel::SQLTime :: time
23
+ # Sequel::SQL::Blob :: bytea
24
+ #
25
+ # String values are also supported using the +text+ type, but only if the
26
+ # +:treat_string_list_as_text_array+ Database option is used. This is because
27
+ # treating strings as text can break programs, since the type for
28
+ # literal strings in PostgreSQL is +unknown+, not +text+.
29
+ #
30
+ # The conversion is only done for single dimensional arrays that have more
31
+ # than two elements, where all elements are of the same class (other than
32
+ # nil values).
33
+ #
34
+ # Related module: Sequel::Postgres::AutoParameterizeInArray
35
+
36
+ module Sequel
37
+ module Postgres
38
+ # Enable automatically parameterizing queries.
39
+ module AutoParameterizeInArray
40
+ # Transform column IN (...) expressions into column = ANY($)
41
+ # and column NOT IN (...) expressions into column != ALL($)
42
+ # using an array bound variable for the ANY/ALL argument,
43
+ # if all values inside the predicate are of the same type and
44
+ # the type is handled by the extension.
45
+ # This is the same optimization PostgreSQL performs internally,
46
+ # but this reduces the number of bound variables.
47
+ def complex_expression_sql_append(sql, op, args)
48
+ case op
49
+ when :IN, :"NOT IN"
50
+ l, r = args
51
+ if auto_param?(sql) && (type = _bound_variable_type_for_array(r))
52
+ if op == :IN
53
+ op = :"="
54
+ func = :ANY
55
+ else
56
+ op = :!=
57
+ func = :ALL
58
+ end
59
+ args = [l, Sequel.function(func, Sequel.pg_array(r, type))]
60
+ end
61
+ end
62
+
63
+ super
64
+ end
65
+
66
+ private
67
+
68
+ # The bound variable type string to use for the bound variable array.
69
+ # Returns nil if a bound variable should not be used for the array.
70
+ def _bound_variable_type_for_array(r)
71
+ return unless Array === r && r.size > 1
72
+ classes = r.map(&:class)
73
+ classes.uniq!
74
+ classes.delete(NilClass)
75
+ return unless classes.size == 1
76
+
77
+ klass = classes[0]
78
+ if klass == Integer
79
+ # This branch is not taken on Ruby <2.4, because of the Fixnum/Bignum split.
80
+ # However, that causes no problems as pg_auto_parameterize handles integer
81
+ # arrays natively (though the SQL used is different)
82
+ "int8"
83
+ elsif klass == String
84
+ "text" if db.typecast_value(:boolean, db.opts[:treat_string_list_as_text_array])
85
+ elsif klass == BigDecimal
86
+ "numeric"
87
+ elsif klass == Date
88
+ "date"
89
+ elsif klass == Time
90
+ @db.cast_type_literal(Time)
91
+ elsif klass == Float
92
+ # PostgreSQL treats literal floats as numeric, not double precision
93
+ # But older versions of PostgreSQL don't handle Infinity/NaN in numeric
94
+ r.all?{|v| v.nil? || v.finite?} ? "numeric" : "double precision"
95
+ elsif klass == Sequel::SQLTime
96
+ "time"
97
+ elsif klass == DateTime
98
+ @db.cast_type_literal(DateTime)
99
+ elsif klass == Sequel::SQL::Blob
100
+ "bytea"
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ Database.register_extension(:pg_auto_parameterize_in_array) do |db|
107
+ db.extension(:pg_array, :pg_auto_parameterize)
108
+ db.extend_datasets(Postgres::AutoParameterizeInArray)
109
+ end
110
+ end
@@ -52,7 +52,7 @@ module Sequel
52
52
  # Dump the cached schema to the filename given in Marshal format.
53
53
  def dump_schema_cache(file)
54
54
  sch = {}
55
- @schemas.each do |k,v|
55
+ @schemas.sort.each do |k,v|
56
56
  sch[k] = v.map do |c, h|
57
57
  h = Hash[h]
58
58
  h.delete(:callable_default)
@@ -1,5 +1,7 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ require 'delegate'
4
+
3
5
  module Sequel
4
6
  module Plugins
5
7
  # The defaults_setter plugin makes the column getter methods return the default
@@ -106,6 +108,20 @@ module Sequel
106
108
  lambda{Date.today}
107
109
  when Sequel::CURRENT_TIMESTAMP
108
110
  lambda{dataset.current_datetime}
111
+ when Hash, Array
112
+ v = Marshal.dump(v).freeze
113
+ lambda{Marshal.load(v)}
114
+ when Delegator
115
+ # DelegateClass returns an anonymous case, which cannot be marshalled, so marshal the
116
+ # underlying object and create a new instance of the class with the unmarshalled object.
117
+ klass = v.class
118
+ case o = v.__getobj__
119
+ when Hash, Array
120
+ v = Marshal.dump(o).freeze
121
+ lambda{klass.new(Marshal.load(v))}
122
+ else
123
+ v
124
+ end
109
125
  else
110
126
  v
111
127
  end
@@ -133,7 +133,11 @@ module Sequel
133
133
  # Dump the in-memory cached metadata to the cache file.
134
134
  def dump_pg_auto_constraint_validations_cache
135
135
  raise Error, "No pg_auto_constraint_validations setup" unless file = @pg_auto_constraint_validations_cache_file
136
- File.open(file, 'wb'){|f| f.write(Marshal.dump(@pg_auto_constraint_validations_cache))}
136
+ pg_auto_constraint_validations_cache = {}
137
+ @pg_auto_constraint_validations_cache.sort.each do |k, v|
138
+ pg_auto_constraint_validations_cache[k] = v
139
+ end
140
+ File.open(file, 'wb'){|f| f.write(Marshal.dump(pg_auto_constraint_validations_cache))}
137
141
  nil
138
142
  end
139
143
 
@@ -26,7 +26,11 @@ module Sequel
26
26
  module ClassMethods
27
27
  # Dump the in-memory cached rows to the cache file.
28
28
  def dump_static_cache_cache
29
- File.open(@static_cache_cache_file, 'wb'){|f| f.write(Marshal.dump(@static_cache_cache))}
29
+ static_cache_cache = {}
30
+ @static_cache_cache.sort.each do |k, v|
31
+ static_cache_cache[k] = v
32
+ end
33
+ File.open(@static_cache_cache_file, 'wb'){|f| f.write(Marshal.dump(static_cache_cache))}
30
34
  nil
31
35
  end
32
36
 
@@ -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 = 71
9
+ MINOR = 72
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,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.71.0
4
+ version: 5.72.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: 2023-08-01 00:00:00.000000000 Z
11
+ date: 2023-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bigdecimal
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: minitest
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -204,6 +218,7 @@ extra_rdoc_files:
204
218
  - doc/release_notes/5.7.0.txt
205
219
  - doc/release_notes/5.70.0.txt
206
220
  - doc/release_notes/5.71.0.txt
221
+ - doc/release_notes/5.72.0.txt
207
222
  - doc/release_notes/5.8.0.txt
208
223
  - doc/release_notes/5.9.0.txt
209
224
  files:
@@ -303,6 +318,7 @@ files:
303
318
  - doc/release_notes/5.7.0.txt
304
319
  - doc/release_notes/5.70.0.txt
305
320
  - doc/release_notes/5.71.0.txt
321
+ - doc/release_notes/5.72.0.txt
306
322
  - doc/release_notes/5.8.0.txt
307
323
  - doc/release_notes/5.9.0.txt
308
324
  - doc/schema_modification.rdoc
@@ -445,6 +461,7 @@ files:
445
461
  - lib/sequel/extensions/pg_array.rb
446
462
  - lib/sequel/extensions/pg_array_ops.rb
447
463
  - lib/sequel/extensions/pg_auto_parameterize.rb
464
+ - lib/sequel/extensions/pg_auto_parameterize_in_array.rb
448
465
  - lib/sequel/extensions/pg_enum.rb
449
466
  - lib/sequel/extensions/pg_extended_date_support.rb
450
467
  - lib/sequel/extensions/pg_extended_integer_support.rb