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

A way to cast the result of a array to Set and object to Map #1914

Closed
kanongil opened this issue Jun 19, 2019 · 4 comments
Closed

A way to cast the result of a array to Set and object to Map #1914

kanongil opened this issue Jun 19, 2019 · 4 comments
Assignees
Labels
feature New functionality or improvement
Milestone

Comments

@kanongil
Copy link
Contributor

kanongil commented Jun 19, 2019

Describe the problem you are trying to fix (provide as much context as possible)

I have a configuration file, where an array is included containing unique elements.

JSON:

{
  "list": [1, 2 ,3]
}

Schema:

const schema = Joi.object().keys({
    list: Joi.array().items(Joi.number()).unique()
})

Once this has been validated with joi, I want to convert this array into a Set for fast O(1) complexity lookups.

Which API (or modification of the current API) do you suggest to solve that problem ?

While I can do the casting manually in a post-processing stage, I think an any.cast() option, which converts the rule value post-validation, could provide a great deal of value. Not only for this case, but others as well (eg. object to Map conversion). There is already precedent for such an output modifier with the any.raw() rule.

A simple and powerful way to do this, would be to just pass a method:

any.cast(fn)
Outputs the value returned from calling fn(value) instead of the casted or raw value.

const schema = Joi.object().keys({
    list: Joi.array().items(Joi.number()).unique().cast((v) => new Set(v))
})

The downside, is that it requires handling errors in the casting function, and that it might be abused to apply other stateful changes to the output. Eg. Joi.any().optional().cast(() => new Date()) to create a rule that adds the current date to an object. If that is the implementation, any.transform() might actually be a better name for it.

Are you ready to work on a pull request if your suggestion is accepted ?

Yes

@kanongil
Copy link
Contributor Author

Some further thoughts: The any.transform() method could take an object with pre and post functions. The pre would apply at conversion time, which could eg. be used to allow a Joi.boolean() to handle any truthy value.

Joi.boolean().transform({ pre: Boolean });

@hueniverse
Copy link
Contributor

My main concerns are that people will expect async support and that this basically breaks the ability to describe a schema. I assume your main use case is to apply transformation for parts of an input inside a larger validation. Otherwise, you can just call whatever you want on the result of the validation function.

@kanongil
Copy link
Contributor Author

People already expect async support from Joi, so I don't really see how this changes things. Anyway, this is somewhat redundant if we address your second "describe" concern, which I hadn't thought about. In that case, I would go back to cast(), drop the function argument, and explicitly specify the intended output. Eg:

const schema = Joi.object().keys({
    list: Joi.array().items(Joi.number()).unique().cast('set')
});

This will require Joi to implement logic for any such cast, probably beginning with Set for arrays, and Map for objects. How does that sound?

And yes, this is really about multiple such casts. I made a setify() method in one of my project that iteratively walks an object and converts any arrays to sets.

@Marsup
Copy link
Collaborator

Marsup commented Jun 19, 2019

OTOH do we really want to describe casts ? Should it mean something for the data being validated ? That seems like internal stuff. I'd wonder how should a cast fail though.

@hueniverse hueniverse changed the title A way to cast the result of a rule A way to cast the result of a array to Set and object to Map Jun 22, 2019
@hueniverse hueniverse self-assigned this Jun 22, 2019
@hueniverse hueniverse added this to the 16.0.0 milestone Jun 22, 2019
@hueniverse hueniverse added the v16 label Aug 11, 2019
@hueniverse hueniverse added feature New functionality or improvement and removed request labels Sep 19, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Mar 17, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature New functionality or improvement
Projects
None yet
Development

No branches or pull requests

3 participants