Skip to content

Commit

Permalink
Change the defaults_setter plugin do a deep-copy of database default …
Browse files Browse the repository at this point in the history
…hash/array values and delegates (Fixes #2069)
  • Loading branch information
jeremyevans committed Aug 10, 2023
1 parent f5723e7 commit ddb185e
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
=== master

* Change the defaults_setter plugin do a deep-copy of database default hash/array values and delegates (jeremyevans) (#2069)

* Add pg_auto_parameterize_in_array extension, for converting IN/NOT IN to = ANY or != ALL for more types (jeremyevans)

* Fix literalization of infinite and NaN float values in PostgreSQL array bound variables (jeremyevans)
Expand Down
16 changes: 16 additions & 0 deletions lib/sequel/plugins/defaults_setter.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen-string-literal: true

require 'delegate'

module Sequel
module Plugins
# The defaults_setter plugin makes the column getter methods return the default
Expand Down Expand Up @@ -106,6 +108,20 @@ def convert_default_value(v)
lambda{Date.today}
when Sequel::CURRENT_TIMESTAMP
lambda{dataset.current_datetime}
when Hash, Array
v = Marshal.dump(v).freeze
lambda{Marshal.load(v)}
when Delegator
# DelegateClass returns an anonymous case, which cannot be marshalled, so marshal the
# underlying object and create a new instance of the class with the unmarshalled object.
klass = v.class
case o = v.__getobj__
when Hash, Array
v = Marshal.dump(o).freeze
lambda{klass.new(Marshal.load(v))}
else
v
end
else
v
end
Expand Down
42 changes: 42 additions & 0 deletions spec/extensions/defaults_setter_spec.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require_relative "spec_helper"

require 'delegate'

describe "Sequel::Plugins::DefaultsSetter" do
before do
@db = db = Sequel.mock
Expand Down Expand Up @@ -46,6 +48,46 @@ def db.schema(*) [] end
(t - Time.now).must_be :<, 1
end

it "should not reuse the same default hash for multiple objects" do
h = {}
c = @pr.call(h)
c.new.a.must_equal(h)
c.new.a.wont_be_same_as c.new.a
c.default_values[:a].must_be_kind_of Proc
end

it "should not reuse the same default array for multiple objects" do
h = []
c = @pr.call(h)
c.new.a.must_equal(h)
c.new.a.wont_be_same_as c.new.a
c.default_values[:a].must_be_kind_of Proc
end

it "should not reuse the same default hash delegate for multiple objects" do
h = DelegateClass(Hash).new({})
c = @pr.call(h)
c.new.a.must_equal(h)
c.new.a.wont_be_same_as c.new.a
c.default_values[:a].must_be_kind_of Proc
end

it "should not reuse the same default array delegate for multiple objects" do
h = DelegateClass(Array).new([])
c = @pr.call(h)
c.new.a.must_equal(h)
c.new.a.wont_be_same_as c.new.a
c.default_values[:a].must_be_kind_of Proc
end

it "should use other object delegates as-is" do
h = DelegateClass(Integer).new(1)
c = @pr.call(h)
c.new.a.must_equal(h)
c.new.a.object_id.must_equal c.new.a.object_id
c.default_values[:a].object_id.must_equal h.object_id
end

it "should handle :callable_default values in schema in preference to :ruby_default" do
@db.define_singleton_method(:schema) do |*|
[[:id, {:primary_key=>true}],
Expand Down

0 comments on commit ddb185e

Please sign in to comment.