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:
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