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

Add parse type [Any] with JsonValue #9

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Add parse type [Any] with JsonValue #9

wants to merge 1 commit into from

Conversation

Honga1
Copy link
Contributor

@Honga1 Honga1 commented May 30, 2019

Currently I can not see where JsonValue implements the array type. I see that it has a case for it, without supporting it in the init or the If functions.

This merge adds these two components. It allows traversal of input [Any]'s elements, and checks/converts the sub types to the appropriate format if possible.

Traverses an [Any]'s elements.
Finds whether they all conform to JsonValue types.
@NunoAlexandre NunoAlexandre self-requested a review May 31, 2019 19:00
Repository owner deleted a comment from houndci-bot Jun 9, 2019
Copy link
Owner

@NunoAlexandre NunoAlexandre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Honga1, thank you for your time contributing to Stork!

I left a review explaining extensively what I don't see as a good addition to the library and, on other parts, what I don't find useful enough in the proposed changes and how we could make it more useful.

Please have a look and I hope to have a further discussion on this 👍

@@ -25,6 +25,12 @@ public enum JsonValue {
self = .string(value)
case let value as JSON:
self = .object(value)
case let value as [JsonValue]:
self = .array(value)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is useful. We want to build a JsonValue from some primitive/basic type. If you have already have a [JsonValue], JsonValue.init was already called directly by the user, so instead of having to do:

let asArray: [JsonValue] = [.string("hello"),  .string("world")]
let asJsonValue: JsonValue? = JsonValue.init(asArray)

It's simpler to just do:

let jsonValue = .array([.string("hello"),  .string("world")])

case let value as [Any]:
self = .array(value.map {
JsonValue.init(fromAny: $0)!
})
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is useful in theory, although I am not sure if ever useful in practice.

To parse an array of type T from a JSON object, we'd use json ..? "field" or json ..! "field". In such a case, the T is inferred and Stork knows how to build values of that type T as long as it complies to FromJson.

In this proposed case, we would start with a value whose type is unknown, and we want to check whether it is an array of Any type. If so, we'd return array([JsonValue]), which - in any normal case - is still not good enough for a user. Having array([JsonValue]), we'd still need to parse it to a final, useful type:

case let .array(xs):
  let ys: [MyType] = xs.compactMap { decodeValue($0) }
  return .array(ys)

But that could be achieved in a single step by doing:

// At a high-level
let ys = [MyType].from(jsonArray: jsonArray) // where jsonArray is [JSON]

// Or when parsing a field from an object
array: json ..! "field" 

return nil
}
}

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same goes about this one. This would only be useful to define that a type T: FromJson can be built from a JSON array.

For example, consider a simple ReadingList type:

struct ReadingList {
  let books: [Book]
}

This ifArray method would be useful like so:

public static func from(value: JsonValue) -> ReadingList? {
  return value.ifArray { array in
    ReadingList(books: array.compactMap { Book.from(value: $0)  })
  }
}

Now, note that this represents much more work than the following alternatives:

// At a high-level
let readingList = ReadingList(
  books: [Book].from(jsonArray: booksArray)
)

// Or when parsing a field from an object
readingList: ReadingList(books: try json ..! "books")

Alternatives

Despite these arguments, I do like the idea to support arrays as Stork does for all other json value types.

Alternative 1

A way of having them in a useful, more convenient way would be to add a convenient way of building an [T] from [JsonValue] so that the ifArray scenario becomes:

public static func from(value: JsonValue) -> ReadingList? {
  return value.ifArray { array in
    ReadingList(books: [Book].from(jsonArray: array))
  }
}

Or a way of inferring the type desired to be obtained from [JsonValue], so to have:

public static func from(value: JsonValue) -> ReadingList? {
  return value.ifArray { array in
    ReadingList(books: array.parsed())
  }
}

Or even better:

public static func from(value: JsonValue) -> ReadingList? {
  return ReadingList(books: value.parsedArray())
}

Alternative 2

Introduce a FromJsonArray<T> protocol, so that the final type can be immediately inferred and having Stork only requiring types that are built from JSON arrays to do:

extension ReadingList: FromJsonArray<Book>

Although it looks nice, it'd introduce incongruity to the simple Stork design of FromJson, as now the parsers would need to handle the FromJson and FromJsonArray<T> cases.

Conclusion

I am open for discussion. I like the idea of supporting fully arrays for a matter of consistency but I don't see the objective benefit of doing so.

If we introduce this feature, I'd prefer to neat pick the simpler solutions proposed in the Alternative 1.

@Honga1
Copy link
Contributor Author

Honga1 commented Jan 3, 2020

Hi @NunoAlexandre. I'm too far away from this now to be able to go over this in detail.

Happy if I close this one off due to inactivity?

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

Successfully merging this pull request may close these issues.

2 participants