thoughtbot/Argo

[Question] Array decoding

robertodias180 opened this issue · 4 comments

I was wondering if it possible to ignore the elements in the array that the decode fails?

Good question. By default, we perform an all-or-nothing operation when decoding an array. However, you can write your own decode function that removes failures instead. We actually export a catDecoded function for just this purpose. Usage might look something like this:

let decodedUsers: [User] = catDecoded(j <|| "users")

In a decode operation you'd do something like:

  <*> pure(catDecoded(j <|| "users"))

nope that's wrong. It's more complicated than that:

let jsonObjects: [Decoded<JSON>] = j <|| "users" // this will always succeed as long as the key is there and it contains an array of elements
let decodedUsers: [Decoded<User>] = jsonObjects.map(User.decode) // This performs the decode operation
let users: [User] = catDecoded(decodedUsers) // This removes the failures and unwraps the successes

jesus christ I'm sorry, I apparently need more coffee.

You want something like this:

func decodeArray<T: Decodable>(_ json: JSON) -> Decoded<[T]> where T.DecodedType == T {
  switch json {
    case let .array(a): return pure(catDecoded(a.map(T.decode)))
    default: return .typeMismatch(expected: "Array", actual: value)
  }
}

You'd use it with flatMap inside a decoder like so:

  <*> (j <| "users") >>- decodeArray

you might need more or less parens there, I can never remember.

@gfontenot thanks man, that worked like a charm 😄