GraphQLSwift / Graphiti

The Swift GraphQL Schema framework for macOS and Linux
MIT License
531 stars 67 forks source link

add custom cursors #45

Closed JaapWijnen closed 4 years ago

JaapWijnen commented 4 years ago

This is an attempt to add custom cursors to the Graphiti framework. I wanted to encapsulate the current "default cursor" behavior by implementing a default cursor that is automatically used when Node conforms to Identifiable But couldn't fully get this working yet. I would like your initial thoughts though! Or if this is something you think is worth including in the framework.

Cheers!

paulofaria commented 4 years ago

I think an easier route would be to simply allow users to pass their own makeCursor function as a parameter to connection, like so:

@available(OSX 10.15, *)
func connect<Node>(
    to elements: [Node],
    arguments: PaginationArguments,
    makeCursor: @escaping (Node) -> String
) throws -> Connection<Node> where Node : Encodable {
    let edges = elements.map { element in
        Edge<Node>(node: element, cursor: makeCursor(element))
    }

    let cursorEdges = slicingCursor(edges: edges, arguments: arguments)
    let countEdges = try slicingCount(edges: cursorEdges, arguments: arguments)

    return Connection(
        edges: countEdges,
        pageInfo: PageInfo(
            hasPreviousPage: hasPreviousPage(edges: cursorEdges, arguments: arguments),
            hasNextPage: hasNextPage(edges: cursorEdges, arguments: arguments),
            startCursor: countEdges.first.map({ $0.cursor }),
            endCursor: countEdges.last.map({ $0.cursor })
        )
    )
}

Then call this function from the previous implementation of connection passing Connection<Node>.cursor as the makeCursor parameter. We would need to change the signature of Connection<Node>.cursor to make it receive a node instead, like so:

@available(OSX 10.15, *)
public extension Connection where Node : Identifiable, Node.ID : LosslessStringConvertible {
    ...

    static func cursor(_ node: Node) -> String? {
        node.id.description.base64Encoded()
    }
}

I think this is enough to solve the issue?

JaapWijnen commented 4 years ago

True! This leaves all the encoding and decoding to the user though. Thats why I went with this solution at first. But if you think that fits better I can change it to do that instead! :)

paulofaria commented 4 years ago

Yeah, I think that's more flexible!