dry-rb / dry-schema

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

Composed schema incorrectly handle nested schemas #306

Open rickychilcott opened 4 years ago

rickychilcott commented 4 years ago

Describe the bug

It appears when using an ored schema in an array, schemas nested below that will not pass validation when they should.

To Reproduce

require "dry/validation"

ScaleOptionsSchema = Dry::Schema.Params do
  required(:value)
  required(:text).filled(:string)
end

ScaleSchema = Dry::Schema.Params do
  required(:type).filled(eql?: "scale")
  required(:id).filled(:string)
  required(:options)
    .value(:array, min_size?: 1)
    .each(:hash, ScaleOptionsSchema)
end

QuestionSchema = Dry::Schema.Params do
  required(:type).filled(eql?: "question")
  required(:id).filled(:string)
  required(:text).filled(:string)
end

Schema = Dry::Schema.Params do
  required(:definitions)
    .value(:array, min_size?: 1)
    .each(:hash, ScaleSchema | QuestionSchema)
end

valid_hash = {
  "definitions" => [
    {
      "type" => "scale",
      "id" => "1",
      "options" => [
        {
          "text" => "No",
          "value" => 1,
        },
        {
          "text" => "Yes",
          "value" => 2,
        },
      ],
    },
    {
      "id" => "2",
      "type" => "question",
      "text" => "hello",
    },
  ],
}

validator = Schema.call(valid_hash)
puts validator.success?
puts validator.errors.to_h.inspect # contains errors

Expected behavior

Expected no errors to be be found by the validator. This may not work until 2.0 based on the experimental nature of composing schemas (https://dry-rb.org/gems/dry-schema/1.5/advanced/composing-schemas/).

Your environment

tadeusz-niemiec commented 4 years ago

I tried to resolve this and I figured out that this fails ONLY when the keys are provided as strings, similarly as mentioned here - https://github.com/dry-rb/dry-schema/issues/296

I'll try to propose a solution for this, in a meantime you can work around this by changing your hash keys to symbols.

solnic commented 1 year ago

Unfortunately when composed schemas are passed as an argument, it's not working, but this should work:

Schema = Dry::Schema.Params do
  required(:definitions).filled(:array).each(:hash) { ScaleSchema | QuestionSchema }
end
joaovitoras commented 1 year ago

@solnic this example did not return an error, but it also did not bring values in the result

# ...

Schema = Dry::Schema.Params do
  required(:definitions).filled(:array).each(:hash) { ScaleSchema | QuestionSchema }
end

validator = Schema.call(valid_hash)
validator.to_h
=> {:definitions=>[{}, {}]}