Skip to content

Commit ada8cd1

Browse files
committed
Add create menu item mutation
1 parent 84deb65 commit ada8cd1

File tree

7 files changed

+149
-39
lines changed

7 files changed

+149
-39
lines changed

graphiql-workspace.json

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,21 @@
11
{
22
"key": "graphiql",
3-
"lastId": 2,
4-
"tabIds": [
5-
"tab1",
6-
"tab2"
7-
],
3+
"lastId": 3,
4+
"tabIds": ["tab1", "tab2", "tab3"],
85
"closedTabs": [],
96
"defaultUrl": "http://localhost:4000/playground",
107
"defaultWebsocketUrl": "",
118
"defaultQuery": "",
129
"defaultVariables": "",
1310
"defaultProxy": false,
1411
"defaultHeaders": [],
15-
"usedUrls": [
16-
"http://localhost:4000/playground"
17-
],
12+
"usedUrls": ["http://localhost:4000/playground"],
1813
"recentHeaders": [],
1914
"maxTabHistory": 20,
2015
"maxUrlHistory": 20,
2116
"maxHistory": 20,
2217
"savedQueries": [],
23-
"activeId": "tab2",
18+
"activeId": "tab3",
2419
"tabs": [
2520
{
2621
"id": "tab1",
@@ -31,13 +26,21 @@
3126
"headers": [],
3227
"collapsed": false,
3328
"maxHistory": 20,
34-
"history": [],
29+
"history": [
30+
{
31+
"query": "query Search($term: String!) {\n search(matching: $term) {\n ...MenuItemFields\n ...CategoryFields\n }\n}\n\nfragment MenuItemFields on MenuItem {\n name\n price\n description\n}\n\nfragment CategoryFields on Category {\n name\n items {\n ...MenuItemFields\n }\n}",
32+
"variables": {
33+
"term": "s"
34+
}
35+
}
36+
],
3537
"graphiql:query": "query Search($term: String!) {\n search(matching: $term) {\n ...MenuItemFields\n ...CategoryFields\n }\n}\n\nfragment MenuItemFields on MenuItem {\n name\n price\n description\n}\n\nfragment CategoryFields on Category {\n name\n items {\n ...MenuItemFields\n }\n}",
3638
"graphiql:variables": "{\n \"term\": \"s\"\n}",
37-
"graphiql:operationName": "Search",
38-
"graphiql:editorFlex": 1,
39+
"graphiql:docExplorerWidth": 350,
3940
"graphiql:variableEditorHeight": 200,
40-
"graphiql:docExplorerWidth": 350
41+
"graphiql:editorFlex": 1,
42+
"graphiql:operationName": "Search",
43+
"graphiql:queries": "{\"queries\":[{\"query\":\"query Search($term: String!) {\\n search(matching: $term) {\\n ...MenuItemFields\\n ...CategoryFields\\n }\\n}\\n\\nfragment MenuItemFields on MenuItem {\\n name\\n price\\n description\\n}\\n\\nfragment CategoryFields on Category {\\n name\\n items {\\n ...MenuItemFields\\n }\\n}\",\"variables\":\"{\\n \\\"term\\\": \\\"s\\\"\\n}\",\"operationName\":\"Search\"}]}"
4144
},
4245
{
4346
"id": "tab2",
@@ -65,6 +68,35 @@
6568
"graphiql:editorFlex": 1,
6669
"graphiql:variableEditorHeight": 200,
6770
"graphiql:docExplorerWidth": 350
71+
},
72+
{
73+
"id": "tab3",
74+
"name": "Add menu item",
75+
"url": "http://localhost:4000/playground",
76+
"websocketUrl": "",
77+
"proxy": false,
78+
"headers": [],
79+
"collapsed": false,
80+
"maxHistory": 20,
81+
"history": [
82+
{
83+
"query": "mutation ($menuItem: MenuItemInput!) {\n createMenuItem(input: $menuItem) {\n name\n description\n price\n }\n }",
84+
"variables": {
85+
"menuItem": {
86+
"name": "French Dip",
87+
"description": "Roast beef, caramelized onions, horseradish, ...",
88+
"price": "5.75",
89+
"categoryId": 1
90+
}
91+
}
92+
}
93+
],
94+
"graphiql:query": "mutation ($menuItem: MenuItemInput!) {\n createMenuItem(input: $menuItem) {\n name\n description\n price\n }\n }",
95+
"graphiql:variables": "{\n \"menuItem\": {\n \"name\": \"French Dip\",\n \"description\": \"Roast beef, caramelized onions, horseradish, ...\",\n \"price\": \"5.75\",\n \"categoryId\": 1\n }\n}",
96+
"graphiql:queries": "{\"queries\":[{\"query\":\"mutation ($menuItem: MenuItemInput!) {\\n createMenuItem(input: $menuItem) {\\n name\\n description\\n price\\n }\\n }\",\"variables\":\"{\\n \\\"menuItem\\\": {\\n \\\"name\\\": \\\"French Dip\\\",\\n \\\"description\\\": \\\"Roast beef, caramelized onions, horseradish, ...\\\",\\n \\\"price\\\": \\\"5.75\\\",\\n \\\"categoryId\\\": 1\\n }\\n}\"},{\"query\":\"mutation ($menuItem: MenuItemInput!) {\\n createMenuItem(input: $menuItem) {\\n name\\n description\\n price\\n }\\n }\",\"variables\":\"{\\n \\\"menuItem\\\": {\\n \\\"name\\\": \\\"French Dip\\\",\\n \\\"description\\\": \\\"Roast beef, caramelized onions, horseradish, ...\\\",\\n \\\"price\\\": \\\"5.75\\\",\\n \\\"categoryId\\\": \\\"1\\\"\\n }\\n}\"},{\"query\":\"mutation ($menuItem: MenuItemInput!) {\\n createMenuItem(input: $menuItem) {\\n name\\n description\\n price\\n }\\n }\",\"variables\":\"{\\n \\\"menuItem\\\": {\\n \\\"name\\\": \\\"French Dip\\\",\\n \\\"description\\\": \\\"Roast beef, caramelized onions, horseradish, ...\\\",\\n \\\"price\\\": \\\"5.75\\\",\\n \\\"categoryId\\\": 1\\n }\\n}\"}]}",
97+
"graphiql:editorFlex": 1,
98+
"graphiql:variableEditorHeight": 200,
99+
"graphiql:docExplorerWidth": 350
68100
}
69101
]
70-
}
102+
}

lib/plate_slate_web/resolvers/menu.ex

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
defmodule PlateSlateWeb.Resolvers.Menu do
22
alias PlateSlate.Menu
33

4+
def create_item(_, %{input: params}, _) do
5+
case Menu.create_item(params) do
6+
{:error, _} ->
7+
{:error, "Could not create menu item"}
8+
9+
{:ok, _} = success ->
10+
success
11+
end
12+
end
13+
414
def menu_items(_, args, _) do
515
{:ok, Menu.list_items(args)}
616
end

lib/plate_slate_web/schema.ex

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,22 @@ defmodule PlateSlateWeb.Schema do
1414
end
1515
end
1616

17+
mutation do
18+
import_fields(:menu_mutations)
19+
end
20+
21+
scalar :decimal do
22+
parse(fn
23+
%{value: value}, _ ->
24+
Decimal.parse(value)
25+
26+
_, _ ->
27+
:error
28+
end)
29+
30+
serialize(&to_string/1)
31+
end
32+
1733
scalar :date do
1834
parse(fn input ->
1935
with %Absinthe.Blueprint.Input.String{value: value} <- input,

lib/plate_slate_web/schema/menu_types.ex

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,28 @@ defmodule PlateSlateWeb.Schema.MenuTypes do
33

44
alias PlateSlateWeb.Resolvers
55

6+
object :menu_queries do
7+
field :menu_items, list_of(:menu_item) do
8+
arg(:filter, :menu_item_filter)
9+
arg(:order, type: :sort_order, default_value: :asc)
10+
resolve(&Resolvers.Menu.menu_items/3)
11+
end
12+
end
13+
14+
object :menu_mutations do
15+
field :create_menu_item, :menu_item do
16+
arg(:input, non_null(:menu_item_input))
17+
resolve(&Resolvers.Menu.create_item/3)
18+
end
19+
end
20+
21+
input_object :menu_item_input do
22+
field :name, non_null(:string)
23+
field :description, :string
24+
field :price, non_null(:decimal)
25+
field :category_id, non_null(:id)
26+
end
27+
628
object :category do
729
field(:name, :string)
830
field(:description, :string)
@@ -51,19 +73,11 @@ defmodule PlateSlateWeb.Schema.MenuTypes do
5173
field(:added_after, :date)
5274
end
5375

54-
object :menu_queries do
55-
field :menu_items, list_of(:menu_item) do
56-
arg(:filter, :menu_item_filter)
57-
arg(:order, type: :sort_order, default_value: :asc)
58-
resolve(&Resolvers.Menu.menu_items/3)
59-
end
60-
end
61-
6276
object :menu_item do
6377
field(:id, :id)
6478
field(:name, :string)
6579
field(:description, :string)
66-
field(:price, :float)
80+
field(:price, :decimal)
6781
field(:added_on, :date)
6882
end
6983
end
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
defmodule PlateSlateWeb.Schema.Mutation.CreateMenuTest do
2+
use PlateSlateWeb.ConnCase, async: true
3+
4+
alias PlateSlate.{Repo, Menu}
5+
import Ecto.Query
6+
7+
setup do
8+
PlateSlate.Seeds.run()
9+
10+
category_id =
11+
from(t in Menu.Category, where: t.name == "Sandwiches")
12+
|> Repo.one!()
13+
|> Map.fetch!(:id)
14+
|> to_string
15+
16+
{:ok, category_id: category_id}
17+
end
18+
19+
@query """
20+
mutation ($menuItem: MenuItemInput!) {
21+
createMenuItem(input: $menuItem) {
22+
name
23+
description
24+
price
25+
}
26+
}
27+
"""
28+
29+
test "createMenuItem field creates an item", %{category_id: category_id} do
30+
menu_item = %{
31+
"name" => "French Dip",
32+
"description" => "Roast beef, caramelized onions, horseradish, ...",
33+
"price" => "5.75",
34+
"categoryId" => category_id
35+
}
36+
37+
conn = build_conn()
38+
39+
conn =
40+
post conn, "/api",
41+
query: @query,
42+
variables: %{"menuItem" => menu_item}
43+
44+
assert json_response(conn, 200) == %{
45+
"data" => %{
46+
"createMenuItem" => %{
47+
"name" => menu_item["name"],
48+
"description" => menu_item["description"],
49+
"price" => menu_item["price"]
50+
}
51+
}
52+
}
53+
end
54+
end

test/plate_slate_web/schema/query/menu_items_test.exs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
# ---
2-
# Excerpted from "Craft GraphQL APIs in Elixir with Absinthe",
3-
# published by The Pragmatic Bookshelf.
4-
# Copyrights apply to this code. It may not be used to create training material,
5-
# courses, books, articles, and the like. Contact us if you are in doubt.
6-
# We make no guarantees that this code is fit for any purpose.
7-
# Visit http://www.pragmaticprogrammer.com/titles/wwgraphql for more book information.
8-
# ---
91
defmodule PlateSlateWeb.Schema.Query.MenuItemsTest do
102
use PlateSlateWeb.ConnCase, async: true
113

test/plate_slate_web/schema/query/search_test.exs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
# ---
2-
# Excerpted from "Craft GraphQL APIs in Elixir with Absinthe",
3-
# published by The Pragmatic Bookshelf.
4-
# Copyrights apply to this code. It may not be used to create training material,
5-
# courses, books, articles, and the like. Contact us if you are in doubt.
6-
# We make no guarantees that this code is fit for any purpose.
7-
# Visit http://www.pragmaticprogrammer.com/titles/wwgraphql for more book information.
8-
# ---
91
defmodule PlateSlateWeb.Schema.Query.SearchTest do
102
use PlateSlateWeb.ConnCase, async: true
113

0 commit comments

Comments
 (0)