zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

commit 9dbf6f3dd25c0119fc8a249d09790819cb5ce9e0
parent 4b2e4a280fedb6eb64731e794549f48337aa2fb9
Author: srfsh <dev@srf.sh>
Date:   Tue, 23 Aug 2022 11:55:24 +0300

Zenflows{Test,}.VF.SpatialThing: add paging support and small improvements

Diffstat:
Msrc/zenflows/vf/spatial_thing/domain.ex | 50++++++++++++++++++++++++++------------------------
Msrc/zenflows/vf/spatial_thing/resolv.ex | 14+++++++++-----
Msrc/zenflows/vf/spatial_thing/type.ex | 26+++++++++++++++++++++-----
Mtest/vf/spatial_thing/domain.test.exs | 55++++++++++++++++++++++++++++++++-----------------------
Mtest/vf/spatial_thing/type.test.exs | 138+++++++++++++++++++++++++++++++++----------------------------------------------
5 files changed, 145 insertions(+), 138 deletions(-)

diff --git a/src/zenflows/vf/spatial_thing/domain.ex b/src/zenflows/vf/spatial_thing/domain.ex @@ -21,35 +21,48 @@ defmodule Zenflows.VF.SpatialThing.Domain do alias Ecto.Multi alias Zenflows.DB.Repo +alias Zenflows.GQL.Paging alias Zenflows.VF.SpatialThing @typep repo() :: Ecto.Repo.t() @typep chgset() :: Ecto.Changeset.t() -@typep changes() :: Ecto.Multi.changes() @typep id() :: Zenflows.DB.Schema.id() @typep params() :: Zenflows.DB.Schema.params() -@spec by_id(repo(), id()) :: SpatialThing.t() | nil -def by_id(repo \\ Repo, id) do - repo.get(SpatialThing, id) +@spec one(repo(), id() | map() | Keyword.t()) + :: {:ok, SpatialThing.t()} | {:error, String.t()} +def one(repo \\ Repo, _) +def one(repo, id) when is_binary(id), do: one(repo, id: id) +def one(repo, clauses) do + case repo.get_by(SpatialThing, clauses) do + nil -> {:error, "not found"} + found -> {:ok, found} + end +end + +@spec all(Paging.params()) :: Paging.result(SpatialThing.t()) +def all(params) do + Paging.page(SpatialThing, params) end @spec create(params()) :: {:ok, SpatialThing.t()} | {:error, chgset()} def create(params) do Multi.new() - |> Multi.insert(:spt_thg, SpatialThing.chgset(params)) + |> Multi.insert(:insert, SpatialThing.chgset(params)) |> Repo.transaction() |> case do - {:ok, %{spt_thg: st}} -> {:ok, st} + {:ok, %{insert: st}} -> {:ok, st} {:error, _, cset, _} -> {:error, cset} end end -@spec update(id(), params()) :: {:ok, SpatialThing.t()} | {:error, chgset()} +@spec update(id(), params()) + :: {:ok, SpatialThing.t()} | {:error, String.t() | chgset()} def update(id, params) do Multi.new() - |> Multi.run(:get, multi_get(id)) - |> Multi.update(:update, &SpatialThing.chgset(&1.get, params)) + |> Multi.put(:id, id) + |> Multi.run(:one, &one/2) + |> Multi.update(:update, &SpatialThing.chgset(&1.one, params)) |> Repo.transaction() |> case do {:ok, %{update: st}} -> {:ok, st} @@ -57,27 +70,16 @@ def update(id, params) do end end -@spec delete(id()) :: {:ok, SpatialThing.t()} | {:error, chgset()} +@spec delete(id()) :: {:ok, SpatialThing.t()} | {:error, String.t() | chgset()} def delete(id) do Multi.new() - |> Multi.run(:get, multi_get(id)) - |> Multi.delete(:delete, &(&1.get)) + |> Multi.put(:id, id) + |> Multi.run(:one, &one/2) + |> Multi.delete(:delete, & &1.one) |> Repo.transaction() |> case do {:ok, %{delete: st}} -> {:ok, st} {:error, _, msg_or_cset, _} -> {:error, msg_or_cset} end end - -# Returns a SpatialThing in ok-err tuple from given ID. Used inside -# Ecto.Multi.run/5 to get a record in transaction. -@spec multi_get(id()) :: (repo(), changes() -> {:ok, SpatialThing.t()} | {:error, String.t()}) -defp multi_get(id) do - fn repo, _ -> - case by_id(repo, id) do - nil -> {:error, "not found"} - st -> {:ok, st} - end - end -end end diff --git a/src/zenflows/vf/spatial_thing/resolv.ex b/src/zenflows/vf/spatial_thing/resolv.ex @@ -21,23 +21,27 @@ defmodule Zenflows.VF.SpatialThing.Resolv do alias Zenflows.VF.SpatialThing.Domain -def spatial_thing(%{id: id}, _info) do - {:ok, Domain.by_id(id)} +def spatial_thing(params, _) do + Domain.one(params) end -def create_spatial_thing(%{spatial_thing: params}, _info) do +def spatial_things(params, _) do + Domain.all(params) +end + +def create_spatial_thing(%{spatial_thing: params}, _) do with {:ok, spt_thg} <- Domain.create(params) do {:ok, %{spatial_thing: spt_thg}} end end -def update_spatial_thing(%{spatial_thing: %{id: id} = params}, _info) do +def update_spatial_thing(%{spatial_thing: %{id: id} = params}, _) do with {:ok, spt_thg} <- Domain.update(id, params) do {:ok, %{spatial_thing: spt_thg}} end end -def delete_spatial_thing(%{id: id}, _info) do +def delete_spatial_thing(%{id: id}, _) do with {:ok, _} <- Domain.delete(id) do {:ok, true} end diff --git a/src/zenflows/vf/spatial_thing/type.ex b/src/zenflows/vf/spatial_thing/type.ex @@ -58,10 +58,6 @@ object :spatial_thing do field :note, :string end -object :spatial_thing_response do - field :spatial_thing, non_null(:spatial_thing) -end - input_object :spatial_thing_create_params do @desc @name field :name, non_null(:string) @@ -104,13 +100,33 @@ input_object :spatial_thing_update_params do field :note, :string end +object :spatial_thing_response do + field :spatial_thing, non_null(:spatial_thing) +end + +object :spatial_thing_edge do + field :cursor, non_null(:id) + field :node, non_null(:spatial_thing) +end + +object :spatial_thing_connection do + field :page_info, non_null(:page_info) + field :edges, non_null(list_of(non_null(:spatial_thing_edge))) +end + object :query_spatial_thing do field :spatial_thing, :spatial_thing do arg :id, non_null(:id) resolve &Resolv.spatial_thing/2 end - #spatialThings(start: ID, limit: Int): [SpatialThing!] + field :spatial_things, :spatial_thing_connection do + arg :first, :integer + arg :after, :id + arg :last, :integer + arg :before, :id + resolve &Resolv.spatial_things/2 + end end object :mutation_spatial_thing do diff --git a/test/vf/spatial_thing/domain.test.exs b/test/vf/spatial_thing/domain.test.exs @@ -24,42 +24,46 @@ alias Zenflows.VF.{SpatialThing, SpatialThing.Domain} setup do %{ params: %{ - name: Factory.uniq("name"), - mappable_address: Factory.uniq("address"), + name: Factory.str("name"), + mappable_address: Factory.str("address"), lat: Factory.float(), long: Factory.float(), alt: Factory.float(), - note: Factory.uniq("note"), + note: Factory.str("note"), }, - spatial_thing: Factory.insert!(:spatial_thing), + inserted: Factory.insert!(:spatial_thing), } end -test "by_id/1 returns a SpatialThing", %{spatial_thing: spt_thg} do - assert %SpatialThing{} = Domain.by_id(spt_thg.id) +describe "one/1" do + test "with good id: finds the SpatialThing", %{inserted: %{id: id}} do + assert {:ok, %SpatialThing{}} = Domain.one(id) + end + + test "with bad id: doesn't find the SpatialThing" do + assert {:error, "not found"} = Domain.one(Factory.id()) + end end describe "create/1" do - test "creates a SpatialThing with valid params", %{params: params} do - assert {:ok, %SpatialThing{} = spt_thg} = Domain.create(params) - - assert spt_thg.name == params.name - assert spt_thg.mappable_address == params.mappable_address - assert spt_thg.lat == params.lat - assert spt_thg.long == params.long - assert spt_thg.alt == params.alt - assert spt_thg.note == params.note + test "with good params: creates a SpatialThing", %{params: params} do + assert {:ok, %SpatialThing{} = new} = Domain.create(params) + assert new.name == params.name + assert new.mappable_address == params.mappable_address + assert new.lat == params.lat + assert new.long == params.long + assert new.alt == params.alt + assert new.note == params.note end - test "doesn't create a SpatialThing with invalid params" do + test "with bad params: doesn't create a SpatialThing" do assert {:error, %Changeset{}} = Domain.create(%{}) end end describe "update/2" do - test "updates a SpatialThing with valid params", %{params: params, spatial_thing: old} do + test "with good params: updates the SpatialThing", %{params: params, inserted: old} do assert {:ok, %SpatialThing{} = new} = Domain.update(old.id, params) - assert new.name == params.name assert new.mappable_address == params.mappable_address assert new.lat == params.lat @@ -68,9 +72,8 @@ describe "update/2" do assert new.note == params.note end - test "doesn't update a SpatialThing", %{spatial_thing: old} do + test "with bad params: doesn't update the SpatialThing", %{inserted: old} do assert {:ok, %SpatialThing{} = new} = Domain.update(old.id, %{}) - assert new.name == old.name assert new.mappable_address == old.mappable_address assert new.lat == old.lat @@ -80,8 +83,14 @@ describe "update/2" do end end -test "delete/1 deletes a SpatialThing", %{spatial_thing: %{id: id}} do - assert {:ok, %SpatialThing{id: ^id}} = Domain.delete(id) - assert Domain.by_id(id) == nil +describe "delete/1" do + test "with good id: deletes the SpatialThing", %{inserted: %{id: id}} do + assert {:ok, %SpatialThing{id: ^id}} = Domain.delete(id) + assert {:error, "not found"} = Domain.one(id) + end + + test "with bad id: doesn't delete the SpatialThing" do + assert {:error, "not found"} = Domain.delete(Factory.id()) + end end end diff --git a/test/vf/spatial_thing/type.test.exs b/test/vf/spatial_thing/type.test.exs @@ -21,113 +21,89 @@ use ZenflowsTest.Help.AbsinCase, async: true setup do %{ params: %{ - name: Factory.uniq("name"), - mappable_address: Factory.uniq("address"), - lat: Factory.float(), - long: Factory.float(), - alt: Factory.float(), - note: Factory.uniq("note"), + "name" => Factory.str("name"), + "mappableAddress" => Factory.str("address"), + "lat" => Factory.float(), + "long" => Factory.float(), + "alt" => Factory.float(), + "note" => Factory.str("note"), }, - spatial_thing: Factory.insert!(:spatial_thing), + inserted: Factory.insert!(:spatial_thing), } end +@frag """ +fragment spatialThing on SpatialThing { + id + name + mappableAddress + lat + long + alt + note +} +""" + describe "Query" do - test "spatialThing()", %{spatial_thing: spt_thg} do + test "spatialThing", %{inserted: new} do assert %{data: %{"spatialThing" => data}} = - query!(""" - spatialThing(id: "#{spt_thg.id}") { - id - name - mappableAddress - lat - long - alt - note + run!(""" + #{@frag} + query ($id: ID!) { + spatialThing(id: $id) {...spatialThing} } - """) + """, vars: %{"id" => new.id}) - assert data["id"] == spt_thg.id - assert data["name"] == spt_thg.name - assert data["mappableAddress"] == spt_thg.mappable_address - assert data["lat"] == spt_thg.lat - assert data["long"] == spt_thg.long - assert data["alt"] == spt_thg.alt - assert data["note"] == spt_thg.note + assert data["id"] == new.id + assert data["name"] == new.name + assert data["mappableAddress"] == new.mappable_address + assert data["lat"] == new.lat + assert data["long"] == new.long + assert data["alt"] == new.alt + assert data["note"] == new.note end end describe "Mutation" do - test "createSpatialThing()", %{params: params} do + test "createSpatialThing", %{params: params} do assert %{data: %{"createSpatialThing" => %{"spatialThing" => data}}} = - mutation!(""" - createSpatialThing(spatialThing: { - name: "#{params.name}" - mappableAddress: "#{params.mappable_address}" - lat: #{params.lat} - long: #{params.long} - alt: #{params.alt} - note: "#{params.note}" - }) { - spatialThing { - id - name - mappableAddress - lat - long - alt - note + run!(""" + #{@frag} + mutation ($spatialThing: SpatialThingCreateParams!) { + createSpatialThing(spatialThing: $spatialThing) { + spatialThing {...spatialThing} } } - """) + """, vars: %{"spatialThing" => params}) assert {:ok, _} = Zenflows.DB.ID.cast(data["id"]) - assert data["name"] == params.name - assert data["mappableAddress"] == params.mappable_address - assert data["lat"] == params.lat - assert data["long"] == params.long - assert data["alt"] == params.alt - assert data["note"] == params.note + data = Map.delete(data, "id") + assert data == params end - test "updateSpatialThing()", %{params: params, spatial_thing: spt_thg} do + test "updateSpatialThing", %{params: params, inserted: old} do assert %{data: %{"updateSpatialThing" => %{"spatialThing" => data}}} = - mutation!(""" - updateSpatialThing(spatialThing: { - id: "#{spt_thg.id}" - name: "#{params.name}" - mappableAddress: "#{params.mappable_address}" - lat: #{params.lat} - long: #{params.long} - alt: #{params.alt} - note: "#{params.note}" - }) { - spatialThing { - id - name - mappableAddress - lat - long - alt - note + run!(""" + #{@frag} + mutation ($spatialThing: SpatialThingUpdateParams!) { + updateSpatialThing(spatialThing: $spatialThing) { + spatialThing {...spatialThing} } } - """) + """, vars: %{"spatialThing" => Map.put(params, "id", old.id)}) - assert data["id"] == spt_thg.id - assert data["name"] == params.name - assert data["mappableAddress"] == params.mappable_address - assert data["lat"] == params.lat - assert data["long"] == params.long - assert data["alt"] == params.alt - assert data["note"] == params.note + assert data["id"] == old.id + data = Map.delete(data, "id") + assert data == params end - test "deleteSpatialThing()", %{spatial_thing: %{id: id}} do + test "deleteSpatialThing", %{inserted: %{id: id}} do assert %{data: %{"deleteSpatialThing" => true}} = - mutation!(""" - deleteSpatialThing(id: "#{id}") - """) + run!(""" + mutation ($id: ID!) { + deleteSpatialThing(id: $id) + } + """, vars: %{"id" => id}) end end end