Home > Enterprise >  Using Apollo Graphql Fragments as generic types in Swift
Using Apollo Graphql Fragments as generic types in Swift

Time:03-30

I am fairly new to the Swift programming language. I am trying to create a util function that takes a generic.

class Utils {
  static func formatArtists<T: ArtistDetails>(_ artists: [T]) -> String {
    return artists.map({ artist in
        return artist.name
    }).joined(separator: ", ")
  }
}

I get two errors for this piece of code

 Type 'T' constrained to non-protocol, non-class type 'ArtistDetails'
 Value of type 'T' has no member 'name'

I think I need to extend a protocol or something.

I want to be able to call the helper function like this.

Text(Utils.formatArtists(track.artists))
Text(Utils.formatArtists(mix.artists))

With both track and mix artists using the ArtistDetails fragment.

Artist Details gets generated by Apollo swift library

public struct ArtistDetails: GraphQLFragment {
  /// The raw GraphQL definition of this fragment.
  public static let fragmentDefinition: String =
    """
    fragment ArtistDetails on Artist {
      __typename
      id
      name
    }
    """

  public static let possibleTypes: [String] = ["Artist"]

  public static var selections: [GraphQLSelection] {
    return [
      GraphQLField("__typename", type: .nonNull(.scalar(String.self))),
      GraphQLField("id", type: .nonNull(.scalar(GraphQLID.self))),
      GraphQLField("name", type: .nonNull(.scalar(String.self))),
    ]
  }

  public private(set) var resultMap: ResultMap

  public init(unsafeResultMap: ResultMap) {
    self.resultMap = unsafeResultMap
  }

  public init(id: GraphQLID, name: String) {
    self.init(unsafeResultMap: ["__typename": "Artist", "id": id, "name": name])
  }

  public var __typename: String {
    get {
      return resultMap["__typename"]! as! String
    }
    set {
      resultMap.updateValue(newValue, forKey: "__typename")
    }
  }

  public var id: GraphQLID {
    get {
      return resultMap["id"]! as! GraphQLID
    }
    set {
      resultMap.updateValue(newValue, forKey: "id")
    }
  }

  public var name: String {
    get {
      return resultMap["name"]! as! String
    }
    set {
      resultMap.updateValue(newValue, forKey: "name")
    }
  }
}
protocol GraphQLFragment : GraphQLSelectionSet

Thanks

CodePudding user response:

In Swift you might prefer to write it like

extension Collection where Element == ArtistDetails {
    var formatted: String {
        map(\.name).joined(separator: ", ")
    }
}

Text(track.artists.formatted)

You can't write a generic like <T: ArtistDetails> because ArtistDetails is a struct so doesn't support subclassing, and isn't a protocol, so T can't be any type that implements the protocol or "is a" ArtistDetails. There's no need for a Utils class - if you ever need a namespace like that an enum (with no cases) would be preferred as a type that can't be instantiated.

  • Related