-
Notifications
You must be signed in to change notification settings - Fork 108
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
add filter and withFilter alias on DecodeResult #133
Conversation
Would it be possible to have a slightly more generalised test in CodecSpecification for this? Otherwise it looks good to me, but I'd prefer to have a test that deals with both positive and negative cases. |
Hey @chrislewis, I am not really sure what you intend the behaviour to be, but as it is defined, there are a few subtle problems - primarily you will lose any error message or context if you hit the guard (because it is going to call monoid zero - so it error will be empty string and empty history). And, I am a bit hesitant to introduce a gotcha like that. As an alternative, I would be happier with a validate combinator on DecodeResult and/or DecodeJson, something like:
Also, open to other suggestions, but I would really prefer it if at least the cursor history is maintained - the ability to provide a sensible error is also useful. |
Hi @markhibberd - I actually like that much better! Still new to the code but I'm guessing preserving the history in |
@markhibberd in your proposed sketch def validate(f: A => Boolean, error: String) =
flatMap { a =>
if (f(a)) this
else DecodeResult(-\/(error -> (history getOrElse CursorHistory(Nil))))
} If the predicate fails, the result is the provided error string and the cursor history, which will be empty if there was no history. If that's what you had in mind then def filter(f: A => Boolean) =
validate(f, "Predicate filtered value") Obviously that's a less useful message, but it least it's sane. Have I misunderstood anything? |
@chrislewis The cursor argument was intentional, because dropping the history means you lose the connection of what failed (you will know why, but not necessarily what field). I passed it explicitly to solve that problem, however it would be possible for the success case of DecodeResult to maintain the cursor state in the success case as well - basically |
Ah, I see. So if it were to be implemented without changing the structure of def validate(f: A => Boolean, c: HCursor, error: String) =
flatMap { a =>
if (f(a)) this
else DecodeResult(-\/(error -> c.history))
} And def validate(f: A => Boolean, error: String) =
flatMap { a =>
if (f(a)) this
else DecodeResult(history, -\/(error))
} And |
@chrislewis Yep, that all sounds right. |
Awesome, that's the better path then. |
Original motivation was wanting a slightly more humane way of filtering json that parsed successfully, yet may not represent a valid value. For example, if a string value is used to represent case objects and we need to make sure this value maps to one of them, pattern guards are convenient means to do so.