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

Need a constructor type to omit optional attributes and support nil for defaults #32

Closed
Kukunin opened this issue Mar 4, 2017 · 4 comments

Comments

@Kukunin
Copy link
Contributor

Kukunin commented Mar 4, 2017

I use dry-struct to build my domain entities and value objects.

Some entities has a lot of optional fields, that I don't want to specify.
I can use constructor_type :schema, but it allows to 'forget' required key.
I can use strit_with_defaults and .default(nil) to all my optional fields, but Types::Strict::String.optional.default(nil) is too much as for me.

Moreover, strict_with_defaultsdoesn't accept nil value for attributes with default value.

I use default attributes defined in Entity because: a) they are often business rules b) it gives encapsulation. Application still may send nil value for that attribute, the most obvious example is FactoryGirl who builds the object. And it's still desirable for Entity to set default value.

Currently, no constructor type fits this needs.

P.S. Does it make sense to consider .optional attribute as one which has .default(nil)?

@solnic
Copy link
Member

solnic commented Mar 7, 2017

Some entities has a lot of optional fields, that I don't want to specify.
I can use constructor_type :schema, but it allows to 'forget' required key.
I can use strit_with_defaults and .default(nil) to all my optional fields, but Types::Strict::String.optional.default(nil) is too much as for me.

irb(main):023:0> s = Class.new(Dry::Struct) { attribute :foo, Dry::Types['string'].optional }
=> #<Class:0x007f9abf989cf0>
irb(main):024:0> s.new
=> #<#<Class:0x007f9abf989cf0> foo=nil>
irb(main):025:0> s.new(foo: nil)
=> #<#<Class:0x007f9abf989cf0> foo=nil>
irb(main):026:0> s.new(foo: "bar")
=> #<#<Class:0x007f9abf989cf0> foo="bar">

Is this what you need?

I use default attributes defined in Entity because: a) they are often business rules b) it gives encapsulation.

What's the source of data for your entities?

Moreover, strict_with_defaults doesn't accept nil value for attributes with default value.

We do not use nil as an indicator that a default value should be set. "optional" means "nil or something else", so Types::Strict::String.optional is just a shortcut for Types::Strict::Nil | Types::Strict::String, which means if you pass a nil, then nil will be set as the value.

I use default attributes defined in Entity because: a) they are often business rules b) it gives encapsulation. Application still may send nil value for that attribute, the most obvious example is FactoryGirl who builds the object. And it's still desirable for Entity to set default value.

FactoryGirl, or any test-related use cases, this is not really relevant. Testing needs tools dedicated to testing. We have rom-factory which can build structs and we can add support for setting all attributes to nil by default.

P.S. Does it make sense to consider .optional attribute as one which has .default(nil)?

No, as I mentioned above, optional means that nil is allowed to be passed as a value.

@tmertens
Copy link

@solnic I just ran into this same issue, where some models have 'optional' attributes that are not set immediately on creation. It would be preferable to just have optional attributes be optional in the input hash entirely rather than only optional in the sense that they can be passed with nil values.

@solnic
Copy link
Member

solnic commented Jun 13, 2017

We'll address this, related issue is dry-rb/dry-types#194

@flash-gordon
Copy link
Member

This was addressed, see #64

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants