dry-rb / dry-schema

Coercion and validation for data structures
https://dry-rb.org/gems/dry-schema
MIT License
415 stars 108 forks source link

Coercing empty strings to nil in dry-schema params #475

Closed luisbelloch closed 7 months ago

luisbelloch commented 7 months ago

I was looking at the documentation about Handling empty strings and it states the following:

Your schema will automatically coerce empty strings to nil, provided that you allow a value to be nil:

However, this example gives me a different result:

Contract = Dry::Schema.Params do
  optional(:foo).maybe(:str?)
end

irb(main):005:0> Contract.call({foo:nil})
=> #<Dry::Schema::Result{:foo=>nil} errors={} path=[]>
irb(main):006:0> Contract.call({foo:""})
=> #<Dry::Schema::Result{:foo=>""} errors={} path=[]>

I was wondering if that behavior is correct or not, I would have expect second example to return nil instead.

I've found similar issues in #227 and also different fix in #229 and #397.

Thanks!

luisbelloch commented 7 months ago

The workaround, in case anyone is interested:

require "dry/types"
require "dry/schema"

module Types
  include Dry.Types()

  FilledOrNilString = Types::String.constructor { |s| s.to_s.empty? ? nil : s }
end

Contract = Dry::Schema.Params do
  optional(:foo).maybe(Types::FilledOrNilString)
end
luisbelloch commented 7 months ago

ok, I've spot the error, my bad. It should be :string, not :str?.

Contract = Dry::Schema.Params do
-  optional(:foo).maybe(:str?)
+  optional(:foo).maybe(:string)
end
solnic commented 7 months ago

I'm sorry you hit this gotcha :/ We should finally deprecate this behavior as in 2.0.0 type specs will be mandatory.