Skip to content

Instantly share code, notes, and snippets.

@sjchmiela
Last active April 17, 2017 09:34
Show Gist options
  • Save sjchmiela/319208e1a450ead062c8c644ba5b84e5 to your computer and use it in GitHub Desktop.
Save sjchmiela/319208e1a450ead062c8c644ba5b84e5 to your computer and use it in GitHub Desktop.
defmodule Sheetly.Schema do
@moduledoc """
GraphQL schema
"""
use Absinthe.Schema
use Absinthe.Relay.Schema
import_types Sheetly.Schema.Types
alias Sheetly.{
ProjectMembershipResolver,
AuthenticationResolver,
ContractResolver,
ProjectResolver,
ViewerResolver,
ClientResolver,
UserResolver,
Viewer,
}
query do
field :viewer, type: :viewer do
resolve &ViewerResolver.find/2
end
node field do
resolve fn
%{type: :contract} = query, info -> ContractResolver.find(query, info)
%{type: :project} = query, info -> ProjectResolver.find(query, info)
%{type: :client} = query, info -> ClientResolver.find(query, info)
%{type: :user} = query, info -> UserResolver.find(query, info)
%{type: :viewer}, _ -> {:ok, %Viewer{}}
_, _ -> {:error, "Unknown node ID supplied."}
end
end
end
mutation do
@desc "A mutation to create access token from email and password"
payload field :create_token do
input do
field :email, non_null(:string)
field :password, non_null(:string)
end
output do
field :token, :string
end
resolve &AuthenticationResolver.create_token/2
end
@desc "A mutation to register a new user in our system"
payload field :register_user do
input do
field :first_name, non_null(:string)
field :last_name, non_null(:string)
field :email, non_null(:string)
field :password, non_null(:string)
field :password_confirmation, non_null(:string)
end
output do
field :token, :string
end
resolve &AuthenticationResolver.register_user/2
end
@desc "A mutation to create new client"
payload field :create_client do
input do
field :name, non_null(:string)
end
output do
field :client, :client
field :viewer, type: :viewer do
resolve &ViewerResolver.find/2
end
end
resolve &ClientResolver.create/2
end
@desc "A mutation to create a new project"
payload field :create_project do
input do
field :name, non_null(:string)
field :client_id, non_null(:id)
end
output do
field :project, :project
field :viewer, type: :viewer do
resolve &ViewerResolver.find/2
end
end
resolve parsing_node_ids(&ProjectResolver.create/2, client_id: :client)
end
@desc "A mutation to update given client"
payload field :update_client do
input do
field :id, non_null(:id)
field :name, non_null(:string)
end
output do
field :client, :client
field :viewer, type: :viewer do
resolve &ViewerResolver.find/2
end
end
resolve parsing_node_ids(&ClientResolver.update/2, id: :client)
end
@desc "A mutation to update given project"
payload field :update_project do
input do
field :id, non_null(:id)
field :name, non_null(:string)
field :client_id, non_null(:id)
end
output do
field :project, :project
field :viewer, type: :viewer do
resolve &ViewerResolver.find/2
end
end
resolve parsing_node_ids(
&ProjectResolver.update/2,
id: :project,
client_id: :client
)
end
@desc "A mutation to update given user"
payload field :update_user do
input do
field :id, non_null(:id)
field :email, non_null(:string)
field :is_employee, non_null(:boolean)
field :is_admin, non_null(:boolean)
field :is_accountant, non_null(:boolean)
field :password, :string
field :password_confirmation, :string
field :first_name, non_null(:string)
field :last_name, non_null(:string)
field :client_id, :id
end
output do
field :user, :user
field :viewer, type: :viewer do
resolve &ViewerResolver.find/2
end
end
resolve parsing_node_ids(
&UserResolver.update/2,
id: :user,
client_id: :client
)
end
@desc "A mutation to add users to given client"
payload field :add_users_to_client do
input do
field :id, non_null(:id)
field :user_ids, list_of(:id)
end
output do
field :client, :client
field :viewer, type: :viewer do
resolve &ViewerResolver.find/2
end
end
resolve(
parsing_lists_of_node_ids(
parsing_node_ids(
&ClientResolver.add_users/2,
id: :client
),
user_ids: :user
)
)
end
@desc "A mutation to add user to given project"
payload field :add_user_to_project do
input do
field :project_id, non_null(:id)
field :user_id, non_null(:id)
field :from, non_null(:date)
field :to, non_null(:date)
field :client_hourly_rate, non_null(:float)
field :role, non_null(:string)
end
output do
field :project, :project
field :user, :user
field :viewer, type: :viewer do
resolve &ViewerResolver.find/2
end
end
resolve parsing_node_ids(
&ProjectMembershipResolver.add_user_to_project/2,
project_id: :project,
user_id: :user
)
end
@desc "A mutation to create a contract for given user"
payload field :create_contract do
input do
field :user_id, non_null(:id)
field :from, non_null(:date)
field :to, non_null(:date)
field :hourly_rate, non_null(:float)
end
output do
field :user, :user
field :contract, :contract
field :viewer, type: :viewer do
resolve &ViewerResolver.find/2
end
end
resolve parsing_node_ids(
&ContractResolver.create/2,
user_id: :user
)
end
@desc "A mutation to update a contract"
payload field :update_contract do
input do
field :id, non_null(:id)
field :user_id, non_null(:id)
field :from, non_null(:date)
field :to, non_null(:date)
field :hourly_rate, non_null(:float)
end
output do
field :user, :user
field :contract, :contract
field :viewer, type: :viewer do
resolve &ViewerResolver.find/2
end
end
resolve parsing_node_ids(
&ContractResolver.update/2,
id: :contract,
user_id: :user
)
end
end
def parsing_lists_of_node_ids(resolver, id_keys) do
fn args, info ->
args = Enum.reduce(id_keys, args, &reduce_lists_of_node_ids/2)
resolver.(args, info)
end
end
def reduce_lists_of_node_ids({key, type}, args) do
with {:ok, global_ids} <- Map.fetch(args, key),
{:ok, internal_ids} <- translate_list_of_node_ids(global_ids, type) do
Map.put(args, key, internal_ids)
else
{:error, %{bad_type: bad_type}} ->
{:error, "Invalid node type found for argument `#{key}`;\
should be #{type}, was #{bad_type}"}
{:error, msg} ->
raise ArgumentError, msg
{:success, args} -> args
_ -> args
end
end
def translate_list_of_node_ids(list, type), do: translate_list_of_node_ids(list, type, [])
def translate_list_of_node_ids([], _, acc), do: {:ok, :lists.reverse(acc)}
def translate_list_of_node_ids([head | tail], type, acc) do
case Absinthe.Relay.Node.from_global_id(head, Sheetly.Schema) do
{:ok, %{type: ^type, id: id}} ->
translate_list_of_node_ids(tail, type, [id | acc])
{:ok, %{type: bad_type}} ->
{:error, %{bad_type: bad_type}}
{:error, reason} -> {:error, reason}
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment