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

Feature request: either_of filter #147

Open
MOZGIII opened this issue Dec 12, 2019 · 3 comments
Open

Feature request: either_of filter #147

MOZGIII opened this issue Dec 12, 2019 · 3 comments

Comments

@MOZGIII
Copy link

MOZGIII commented Dec 12, 2019

I need an either_of filter. It should accept a hash of values where exactly one key of the listed if filled:

either_of do
  hash :a do
    string :f1
  end
  hash :b do
    string :f2
    string :f3
  end
  hash :c do
    string :f4
    string :f5
  end
end

Valid:

  • {"a": { "f1": "qwe" }}
  • {"b": { "f2": "qwe", "f3": "wqe" }}
  • {"c": { "f4": "asd", "f5": "asd }}

Error:

  • {}
  • {"a": { "f1": "qwe" }, "b": { "f2": "qwe", "f3": "wqe" }}
  • { "d": {} }
  • { "a": { "f1": "qwe" }, "d": "qwe" }

What do you think?

@eugeneius
Copy link
Collaborator

This seems like it would be a lot of work to implement, in order to satisfy a very specific use case.

It would be much easier, if a little uglier, to achieve this as a custom validation instead:

def validate
  unless (raw_inputs.keys & %w(a b c)).one?
    add_error(...)
  end
end

If you did still want to work on this feature, I think I'd prefer to see a combination of two options:

any_of { ... }, which uses the first filter that matches the input
strict: true, which tells a hash filter to treat unexpected inputs as an error

I'm interested in any_of because it could also be useful for arrays:

array :strings_and_numbers do
  any_of do
    string
    integer
  end
end

@MOZGIII
Copy link
Author

MOZGIII commented Dec 29, 2019

I ended up with the following:

hash :value do
  optional do
    hash :a do
      string :f1
    end
    hash :b do
      string :f2
      string :f3
    end
    hash :c do
      string :f4
      string :f5
    end
  end
end

And a validator:

add_error(...) unless value.count == 1

And an accessor:

discriminant, data = value.first

It does the trick

I model algebraic enum, so it doesn't make sense to allow specifying nov value directly (as that would not provide the discriminant, which is mandatory). Instead, to allow nil I'd do something like this:

optional do
  hash :value do
    optional do
      string :a
      integer :b
    end
  end
end

I'd still like to have an either_of, though a bit different now.

either_of :value do
  hash :a do
    string :f1
  end
  hash :b do
    string :f2
    string :f3
  end
  hash :c do
    string :f4
    string :f5
  end
end

Notice how there's :value specified now.

If should also be usable with arrays:

array :strings_and_numbers do
  either_of do
    string :a
    integer :b
  end
end
array :strings_and_numbers do
  optional do
    either_of do
      string :a
      integer :b
    end
  end
end

@MOZGIII
Copy link
Author

MOZGIII commented Dec 29, 2019

Seems like I'll be using these quite a lot, and I'm a bit tired of using custom validators.

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

2 participants