dry-schema

v1.14
  1. Introduction
  2. Basics
    1. Built-in predicates
    2. Macros
    3. Type specs
    4. Working with schemas
  3. Optional keys and values
  4. Nested data
  5. Reusing schemas
  6. Params
  7. JSON
  8. Error messages
  9. Advanced
    1. Composing schemas
    2. Custom predicates
    3. Custom types
    4. Filtering
    5. Key maps
    6. Predicate logic
    7. Processor steps
    8. Rule AST
    9. Unexpected keys
  10. Extensions
    1. Hints
    2. Info
    3. JSON Schema
    4. Monads

TOC

  1. Using &
  2. Using |
  3. Using >

Composing schemas

^WARNING
This feature is experimental until dry-schema reaches 2.0.0
^

You can compose schemas using the following standard logic operators:

^INFO
Currently ^ (xor) is not supported because it's not yet clear how to generate errors messages in this case
^

Using &

When you compose schemas using &, the right side will be applied only when left side passed first:

Role = Dry::Schema.JSON do
  required(:id).filled(:string)
end

Expirable = Dry::Schema.JSON do
  required(:expires_on).value(:date)
end

User = Dry::Schema.JSON do
  required(:name).filled(:string)
  required(:role).hash(Role & Expirable)
end

puts User.(name: "Jane", role: { id: "admin", expires_on: "2020-05-01" }).errors.to_h.inspect
# {}

puts User.(name: "Jane", role: { id: "", expires_on: "2020-05-01" }).errors.to_h.inspect
# {role: {id: ["must be filled"]}}

puts User.(name: "Jane", role: { id: "admin", expires_on: "oops" }).errors.to_h.inspect
# {role: {expires_on: ["must be a date"]}}

Using |

When you use |, both schemas will be applied and the error messages will be nested under special :or key:

RoleID = Dry::Schema.JSON do
  required(:id).filled(:string)
end

RoleTitle = Dry::Schema.JSON do
  required(:title).filled(:string)
end

User = Dry::Schema.JSON do
  required(:name).filled(:string)
  required(:role).hash(RoleID | RoleTitle)
end

puts User.(name: "Jane", role: {id: "admin"}).errors.to_h.inspect
# {}

puts User.(name: "Jane", role: {title: "Admin"}).errors.to_h.inspect

puts User.(name: "Jane", role: { id: ""}).errors.to_h.inspect
# {:role=>{:or=>[{:id=>["must be filled"]}, {:title=>["is missing"]}]}}

puts User.(name: "Jane", role: { title: ""}).errors.to_h.inspect
# {:role=>{:or=>[{:id=>["is missing"]}, {:title=>["must be filled"]}]}}

Using >

When you compose schemas using >, the right side will be applied only if the left side passed:

RoleID = Dry::Schema.JSON do
  required(:id).filled(:string)
end

RoleTitle = Dry::Schema.JSON do
  required(:title).filled(:string)
end

User = Dry::Schema.JSON do
  required(:name).filled(:string)
  required(:role).hash(RoleID > RoleTitle)
end

puts User.(name: "Jane", role: {id: "admin", title: "Admin"}).errors.to_h.inspect
# {}

puts User.(name: "Jane", role: { id: ""}).errors.to_h.inspect
# {}

puts User.(name: "Jane", role: {title: "Admin"}).errors.to_h.inspect
# {}

puts User.(name: "Jane", role: { id: "admin", title: ""}).errors.to_h.inspect
# {:role=>{:title=>["must be filled"]}}