Composing schemas
Warning
This feature is experimental until dry-schema reaches 2.0.0
You can compose schemas using the following standard logic operators:
s1 & s2
- both schemas must passs1 | s2
- both or one of the schemas must passs1 > s2
- ifs1
passes thens2
must be pass too, otherwise the entire statement passes
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"]}}