defmodule GraphQL.Relay.Connection do @moduledoc """ You define a Connection for Relay when you want a paginated data source. For example, in a Todo application a User can have many Todos that you want to list and paginate through. A Connection is the perfect fit for this. For an example see https://github.com/graphql-elixir/graphql_relay/blob/44e6912a08468743f7dfa1343723914bbf6809e1/examples/todo/web/graphql/user.ex For the Connection type specification see: https://facebook.github.io/relay/graphql/connections.htm#sec-Connection-Types """ alias GraphQL.Type.Boolean alias GraphQL.Type.Int alias GraphQL.Type.NonNull alias GraphQL.Type.ObjectType def new(config) do node_type = config[:node_type] name = config[:name] || Map.get(node_type, :name) edge_fields = config[:edge_fields] || %{} connection_fields = config[:connection_fields] || %{} resolve_node = config[:resolve_node] resolve_cursor = config[:resolve_cursor] edge_type = %ObjectType{ name: "#{name}Edge", description: "An edge in a connection.", fields: Map.merge(GraphQL.Relay.resolve_maybe_thunk(edge_fields), %{ node: %{ type: node_type, description: "The item at the end of the edge", resolve: resolve_node }, cursor: %{ type: %NonNull{ofType: %GraphQL.Type.String{}}, description: "A cursor for use in pagination", resolve: resolve_cursor } }) } connection_type = %ObjectType{ name: "#{name}Connection", description: "A connection to a list of items.", fields: Map.merge(GraphQL.Relay.resolve_maybe_thunk(connection_fields), %{ edges: %{ type: %GraphQL.Type.List{ofType: edge_type}, description: "Information to aid in pagination." }, pageInfo: %{ type: %NonNull{ofType: page_info}, description: "Information to aid in pagination." }, }) } %{edge_type: edge_type, connection_type: connection_type} end def args(additional_args \\ %{}) do Map.merge(forward_args, backward_args) |> Map.merge(additional_args) end def forward_args do %{ "after": %{type: %GraphQL.Type.String{}}, first: %{type: %Int{}} } end def backward_args do %{ before: %{type: %GraphQL.Type.String{}}, last: %{type: %Int{}} } end def page_info do %ObjectType{ name: "PageInfo", description: "Information about pagination in a connection.", fields: %{ hasNextPage: %{ type: %NonNull{ofType: %Boolean{}}, description: "When paginating forwards, are there more items?" }, hasPreviousPage: %{ type: %NonNull{ofType: %Boolean{}}, description: "When paginating backwards, are there more items?" }, startCursor: %{ type: %GraphQL.Type.String{}, description: "When paginating backwards, the cursor to continue." }, endCursor: %{ type: %GraphQL.Type.String{}, description: "When paginating forwards, the cursor to continue." } } } end end