-
Notifications
You must be signed in to change notification settings - Fork 731
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
Defining a CustomScalarType which is [String:Any] #3369
Comments
Hi @solidcell - can you share the code you've got so far for your custom scalar? I agree moving to 1.0 is a large migration; have you read the 1.0 migration guide that lays out everything that you may need to change during the migration? |
Yea I've already read the migration guide. The easiest way I've found to get a first pass which compiles, and sort of works is to not use a public struct JSON: CustomScalarType, SelectionSetEntityValue {
public init(_fieldData: AnyHashable?) {
guard let _fieldData else {
fatalError()
}
self.value = _fieldData
}
public init(_jsonValue value: JSONValue) throws {
self.value = value
}
public init(anyHashable: JSONValue) {
self.value = anyHashable
}
public var _fieldData: AnyHashable {
value
}
public var _jsonValue: JSONValue {
value
}
public var _asAnyHashable: AnyHashable {
value
}
public subscript<T>(_ key: String) -> T? {
guard let dict = value as? [String : Any],
let casted = dict[key] as? T
else { fatalError() }
return casted
}
public func compactMap<T>(
_ transform: ((key: String, value: Any)) throws -> T?
) rethrows -> [T] {
guard let dict = value as? [String : Any]
else { fatalError() }
return try dict.compactMap(transform)
}
public func compactMapValues<T>(
_ transform: (Any) throws -> T?
) rethrows -> [String : T] {
guard let dict = value as? [String : Any]
else { fatalError() }
return try dict.compactMapValues(transform)
}
public var values: Dictionary<String, Any>.Values {
guard let dict = value as? [String : Any]
else { fatalError() }
return dict.values
}
public var description: String {
guard let dict = value as? [String : Any]
else { fatalError() }
return dict.description
}
private let value: JSONValue
} I haven't refactored this up yet since I don't like the direction this solution is going. It's enabled me to get the app compiling and running again, but there are a few issues I've noticed so far:
I would much prefer to be able to simply work with the underlying Doing this, for instance: public typealias JSON = [String : Any]
extension JSON: CustomScalarType {} Is giving me:
I'm just starting to dive deeper, but something tells me I'm fighting against the current. The types and protocols in Apollo 1.x are a lot to take in, so I'm just trying to wrap my head around it. For instance, the first error: |
I'm not sure why you need to be defining conformance to
Can you show me how you ideally want to be able to access the custom scalar value? I'm not sure there is any way around having to cast the type out of the subscript when using the value type of Custom scalars are for your code to define and the type safety you get from that is entirely up to what your custom type provides. If you want that type to be generated for you then it needs to be fully defined in the schema so codegen can work with it. |
@solidcell - have you managed to make any progress on this or is it still an issue? I'm wondering if the other issue we've worked on been able to help you with this one too? |
What if you change your scalar type to |
@solidcell below is a sample project I put together that uses a custom scalar named CustomScalar-AnyHashable-SampleProject.zip I'm going to close this issue with supplying the working sample project but if this doesn't suit your needs let me know in another comment on this issue and I'll pick it up again. |
Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo iOS usage and allow us to serve you better. |
I independently wrote almost exactly this snippet today to test Contentful's GraphQL API. public struct JSONScalar: Hashable, CustomScalarType {
public let values: [String: AnyHashable]
public init(_jsonValue value: JSONValue) throws {
guard let object = value as? [String: AnyHashable] else {
throw JSONDecodingError.couldNotConvert(value: value, to: [String: AnyHashable].self)
}
self.values = object
}
public var _jsonValue: JSONValue {
self.values as JSONValue
}
} While developing stuff around this I also encountered the same issue that @solidcell mentioned (" |
We have this section in the Custom Scalars documentation that talks about |
@calvincestari Thanks for the example.
Maybe I'm misunderstanding this, but that's not quite true. It's still a wrapper around public typealias Date = Foundation.Date
extension Foundation.Date: CustomScalarType {
// .... Your code improves the implementation I had going, but unfortunately since it's still really just wrapping a
So I'm still having to delegate to the underlying Also, since I'm getting back a if let nestedJSON = model.everything?.first?.custom?["lastKey"] as? JSON {
// BUG! After updating Apollo and the implementation of JSON, we'll never actually go in here anymore, since the value for "lastKey" is not actuallly `[String: String]` anymore, but a wrapper around it.
// So now I need to always be careful if I mean `JSON` or `[String: AnyHashable]` and I need to carefully comb my current codebase for changes to make like this.
} An example of one of many changes I've needed to make in our codebase to account for this: Original (Apollo 0.x): if let a = json["key"] as? JSON { //... Now required modification (Apollo 1.x): if let a = json.wrapped["key"] as? [String : AnyHashable] { //... Unfortunately I've already run into new bugs that cropped up for this reason. Unfortunately our API uses this |
OK, I understand better what you're getting at now. Let me see what I can get working here.. |
Question
I'm migrating from 0.51.2 to 1.10.0 and I'm having a tough time converting a custom scalar to the new system.
We used to have a simple
public typealias JSON = [String: Any]
which was all we needed. However, now that doesn't suffice since we get errors thatJSON
needs to conform toSelectionSetEntityValue
andOutputTypeConvertible
.This migration is quite the beast, so even if I get this JSON scalar related code to compile, I'm not so confident with how it should behave with errors and casting and such. Any help would be very much appreciated.
The text was updated successfully, but these errors were encountered: