Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix info extension for maybe macro #471

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions lib/dry/schema/extensions/info/schema_compiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def visit_and(node, opts = EMPTY_HASH)
# @api private
def visit_implication(node, opts = EMPTY_HASH)
node.each do |el|
visit(el, opts.merge(required: false))
visit(el, opts.merge(required: false, nullable: false))
end
end

Expand All @@ -83,7 +83,14 @@ def visit_each(node, opts = EMPTY_HASH)
# @api private
def visit_key(node, opts = EMPTY_HASH)
name, rest = node
visit(rest, opts.merge(key: name, required: true))
visit(rest, opts.merge(key: name, required: true, nullable: false))
end

# @api private
def visit_not(_node, opts = EMPTY_HASH)
key = opts[:key]

keys[key][:nullable] = true
end
Comment on lines +90 to 94
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't have time for a deeper look but this analysis seems very shallow. You cannot deduce a key is nullable from merely using not, this is too general. Of course, the tests pass but it's only because there are too few of them. I think you ought to analyze in visit_predicate, this is the place where you can detect if it was the maybe macro.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, will do that 💯


# @api private
Expand All @@ -93,7 +100,10 @@ def visit_predicate(node, opts = EMPTY_HASH)
key = opts[:key]

if name.equal?(:key?)
keys[rest[0][1]] = {required: opts.fetch(:required, true)}
required = opts.fetch(:required, true)
nullable = opts.fetch(:nullable, false)

keys[rest[0][1]] = {required: required, nullable: nullable}
else
type = PREDICATE_TO_TYPE[name]
assign_type(key, type) if type
Expand Down
24 changes: 19 additions & 5 deletions spec/extensions/info/schema_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
subject(:schema) do
Dry::Schema.JSON do
required(:email).filled(:string)
optional(:age).filled(:integer)
optional(:age).maybe(:integer)

required(:roles).array(:hash) do
required(:name).filled(:string)
Expand All @@ -17,9 +17,9 @@

optional(:address).hash do
required(:street).filled(:string)
required(:zipcode).filled(:string)
optional(:zipcode).filled(:string)
required(:city).filled(:string)
optional(:phone).filled(:string)
optional(:phone).maybe(:string)
end
end
end
Expand All @@ -28,46 +28,56 @@
{
keys: {
email: {
nullable: false,
required: true,
type: "string"
},
age: {
nullable: true,
required: false,
type: "integer"
},
roles: {
nullable: false,
required: true,
type: "array",
member: {
keys: {
name: {
nullable: false,
required: true,
type: "string"
},
desc: {
nullable: false,
required: false,
type: "string"
}
}
}
},
address: {
nullable: false,
required: false,
type: "hash",
keys: {
street: {
nullable: false,
required: true,
type: "string"
},
zipcode: {
required: true,
nullable: false,
required: false,
type: "string"
},
city: {
nullable: false,
required: true,
type: "string"
},
phone: {
nullable: true,
required: false,
type: "string"
}
Expand Down Expand Up @@ -95,20 +105,24 @@
{
keys: {
opt1: {
nullable: false,
required: true,
type: "array"
},
opt2: {
nullable: false,
required: true,
type: "array",
member: "string"
},
opt3: {
nullable: false,
required: true,
type: "array",
member: "integer"
},
opt4: {
nullable: false,
required: true,
type: "array",
member: "bool"
Expand Down Expand Up @@ -136,7 +150,7 @@
}.each do |type_spec, type_name|
it "infers '#{type_name}' from '#{type_spec}'" do
expect(Dry::Schema.define { required(:key).value(type_spec) }.info).to eql(
keys: {key: {required: true, type: type_name}}
keys: {key: {nullable: false, required: true, type: type_name}}
)
end
end
Expand Down