defmodule Linear.Queries do @moduledoc false alias Linear.{Client, Pagination} @viewer_query """ query LinearViewer { viewer { id name email displayName active admin } } """ @teams_query """ query LinearTeams { teams { nodes { id name key description } } } """ @issue_query """ query LinearIssue($id: String!) { issue(id: $id) { id identifier title description priority url branchName state { id name } assignee { id name email } labels { nodes { id name color } } project { id name } team { id name key } createdAt updatedAt } } """ @issues_query """ query LinearIssues($filter: IssueFilter, $first: Int!, $after: String, $includeArchived: Boolean) { issues(filter: $filter, first: $first, after: $after, includeArchived: $includeArchived) { nodes { id identifier title description priority url branchName state { id name } assignee { id name email } labels { nodes { id name color } } project { id name } team { id name key } createdAt updatedAt } pageInfo { hasNextPage endCursor } } } """ @workflow_states_query """ query LinearWorkflowStates($filter: WorkflowStateFilter) { workflowStates(filter: $filter) { nodes { id name color type position team { id name key } } } } """ @projects_query """ query LinearProjects($first: Int!, $after: String, $includeArchived: Boolean) { projects(first: $first, after: $after, includeArchived: $includeArchived) { nodes { id name description state url teams { nodes { id name key } } createdAt updatedAt } pageInfo { hasNextPage endCursor } } } """ @spec viewer(Client.t(), keyword()) :: {:ok, map()} | {:error, term()} def viewer(client, opts \\ []) do case Client.query(client, @viewer_query, opts) do {:ok, %{"viewer" => viewer}} -> {:ok, viewer} error -> error end end @spec list_teams(Client.t(), keyword()) :: {:ok, [map()]} | {:error, term()} def list_teams(client, opts \\ []) do case Client.query(client, @teams_query, opts) do {:ok, %{"teams" => %{"nodes" => nodes}}} -> {:ok, nodes} error -> error end end @spec get_issue(Client.t(), String.t(), keyword()) :: {:ok, map()} | {:error, term()} def get_issue(client, issue_id, opts \\ []) do case Client.query(client, @issue_query, Keyword.merge(opts, variables: %{"id" => issue_id})) do {:ok, %{"issue" => issue}} -> {:ok, issue} error -> error end end @spec list_issues(Client.t(), keyword()) :: {:ok, [map()]} | {:error, term()} def list_issues(client, opts \\ []) do first = Keyword.get(opts, :first, 50) include_archived = Keyword.get(opts, :include_archived, false) filter = build_issue_filter(opts) query_opts = Keyword.take(opts, [:request_fn]) Pagination.paginate(fn after_cursor -> variables = %{"filter" => filter, "first" => first, "includeArchived" => include_archived} |> put_cursor(after_cursor) case Client.query(client, @issues_query, Keyword.merge(query_opts, variables: variables)) do {:ok, %{"issues" => connection}} -> {:ok, connection} error -> error end end) end @spec list_workflow_states(Client.t(), keyword()) :: {:ok, [map()]} | {:error, term()} def list_workflow_states(client, opts \\ []) do filter = case Keyword.get(opts, :team_id) do nil -> nil id -> %{"team" => %{"id" => %{"eq" => id}}} end variables = if filter, do: %{"filter" => filter}, else: %{} query_opts = Keyword.take(opts, [:request_fn]) case Client.query(client, @workflow_states_query, Keyword.merge(query_opts, variables: variables)) do {:ok, %{"workflowStates" => %{"nodes" => nodes}}} -> {:ok, nodes} error -> error end end @spec list_projects(Client.t(), keyword()) :: {:ok, [map()]} | {:error, term()} def list_projects(client, opts \\ []) do first = Keyword.get(opts, :first, 50) include_archived = Keyword.get(opts, :include_archived, false) query_opts = Keyword.take(opts, [:request_fn]) Pagination.paginate(fn after_cursor -> variables = %{"first" => first, "includeArchived" => include_archived} |> put_cursor(after_cursor) case Client.query(client, @projects_query, Keyword.merge(query_opts, variables: variables)) do {:ok, %{"projects" => connection}} -> {:ok, connection} error -> error end end) end defp build_issue_filter(opts) do %{} |> maybe_filter(:team_id, opts, fn id -> %{"team" => %{"id" => %{"eq" => id}}} end) |> maybe_filter(:project_id, opts, fn id -> %{"project" => %{"id" => %{"eq" => id}}} end) |> maybe_filter(:state_names, opts, fn names -> %{"state" => %{"name" => %{"in" => names}}} end) |> maybe_filter(:assignee_id, opts, fn id -> %{"assignee" => %{"id" => %{"eq" => id}}} end) |> then(fn f -> if f == %{}, do: nil, else: f end) end defp maybe_filter(filter, key, opts, build_fn) do case Keyword.get(opts, key) do nil -> filter [] -> filter value -> Map.merge(filter, build_fn.(value)) end end defp put_cursor(variables, nil), do: variables defp put_cursor(variables, cursor), do: Map.put(variables, "after", cursor) end