ash_graphql/test/relationship_pagination_test.exs
Davide Briani 18d4e1b010
test: add tests on paginated relationships (#177)
Add tests to verify that relationships can be queried on the results of
GraphQL queries and mutations.

Querying paginated relationships on the result of deletions doesn't
correctly work yet.
Indeed, Ash currently queries relationships using a lateral join but
after the resource deletion has happened, so it looks like nothing is
related.

Signed-off-by: Davide Briani <davide@briani.dev>
2024-06-11 09:49:05 -04:00

530 lines
14 KiB
Elixir

defmodule AshGraphql.RelationshipPaginationTest do
use ExUnit.Case, async: false
require Ash.Query
setup do
on_exit(fn ->
AshGraphql.TestHelpers.stop_ets()
end)
end
test "works with :relay strategy" do
movie =
AshGraphql.Test.Movie
|> Ash.Changeset.for_create(:create, title: "Foo")
|> Ash.create!()
for i <- 1..5 do
AshGraphql.Test.Actor
|> Ash.Changeset.for_create(:create, name: "Actor #{i}")
|> Ash.Changeset.manage_relationship(:movies, movie, type: :append)
|> Ash.create!()
end
document =
"""
query Movies($first: Int, $after: String) {
getMovies {
actors(first: $first, after: $after, sort: [{field: NAME}]) {
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
count
edges {
cursor
node {
name
}
}
}
}
}
"""
resp = Absinthe.run(document, AshGraphql.Test.Schema, variables: %{"first" => 1})
assert {:ok, result} = resp
refute Map.has_key?(result, :errors)
assert %{
data: %{
"getMovies" => [
%{
"actors" => %{
"count" => 5,
"edges" => [%{"cursor" => cursor, "node" => %{"name" => "Actor 1"}}],
"pageInfo" => %{
"hasPreviousPage" => false,
"hasNextPage" => true
}
}
}
]
}
} = result
resp =
Absinthe.run(document, AshGraphql.Test.Schema,
variables: %{"first" => 4, "after" => cursor}
)
assert {:ok, result} = resp
refute Map.has_key?(result, :errors)
assert %{
data: %{
"getMovies" => [
%{
"actors" => %{
"edges" => edges,
"pageInfo" => %{
"hasPreviousPage" => true,
"hasNextPage" => false
}
}
}
]
}
} = result
assert length(edges) == 4
assert [%{"node" => %{"name" => "Actor 2"}} | _] = edges
end
test "works with :offset strategy" do
movie =
AshGraphql.Test.Movie
|> Ash.Changeset.for_create(:create, title: "Foo")
|> Ash.create!()
for i <- 1..5 do
AshGraphql.Test.Review
|> Ash.Changeset.for_create(:create, text: "Review #{i}")
|> Ash.Changeset.manage_relationship(:movie, movie, type: :append)
|> Ash.create!()
end
document =
"""
query Movies($limit: Int, $offset: Int) {
getMovies {
reviews(limit: $limit, offset: $offset, sort: [{field: TEXT}]) {
results {
text
}
count
hasNextPage
}
}
}
"""
resp = Absinthe.run(document, AshGraphql.Test.Schema, variables: %{"limit" => 1})
assert {:ok, result} = resp
refute Map.has_key?(result, :errors)
assert %{
data: %{
"getMovies" => [
%{
"reviews" => %{
"count" => 5,
"results" => [%{"text" => "Review 1"}],
"hasNextPage" => true
}
}
]
}
} = result
resp =
Absinthe.run(document, AshGraphql.Test.Schema, variables: %{"limit" => 4, "offset" => 1})
assert {:ok, result} = resp
refute Map.has_key?(result, :errors)
assert %{
data: %{
"getMovies" => [
%{
"reviews" => %{
"results" => results,
"hasNextPage" => false
}
}
]
}
} = result
assert length(results) == 4
assert [%{"text" => "Review 2"} | _] = results
end
test "works with :keyset strategy" do
movie =
AshGraphql.Test.Movie
|> Ash.Changeset.for_create(:create, title: "Foo")
|> Ash.create!()
for i <- 1..5 do
AshGraphql.Test.Award
|> Ash.Changeset.for_create(:create, name: "Award #{i}")
|> Ash.Changeset.manage_relationship(:movie, movie, type: :append)
|> Ash.create!()
end
document =
"""
query Movies($first: Int, $after: String) {
getMovies {
awards(first: $first, after: $after, sort: [{field: NAME}]) {
results {
name
}
count
endKeyset
}
}
}
"""
resp = Absinthe.run(document, AshGraphql.Test.Schema, variables: %{"first" => 1})
assert {:ok, result} = resp
refute Map.has_key?(result, :errors)
assert %{
data: %{
"getMovies" => [
%{
"awards" => %{
"count" => 5,
"results" => [%{"name" => "Award 1"}],
"endKeyset" => cursor
}
}
]
}
} = result
resp =
Absinthe.run(document, AshGraphql.Test.Schema,
variables: %{"first" => 4, "after" => cursor}
)
assert {:ok, result} = resp
refute Map.has_key?(result, :errors)
assert %{data: %{"getMovies" => [%{"awards" => %{"results" => results}}]}} = result
assert length(results) == 4
assert [%{"name" => "Award 2"} | _] = results
end
describe "works when nested" do
test "on return values for queries" do
movie =
AshGraphql.Test.Movie
|> Ash.Changeset.for_create(:create, title: "Movie")
|> Ash.create!()
agents =
for i <- 1..4 do
AshGraphql.Test.Agent
|> Ash.Changeset.for_create(:create, name: "Agent #{i}")
|> Ash.create!()
end
for i <- 1..5 do
AshGraphql.Test.Actor
|> Ash.Changeset.for_create(:create, name: "Actor #{i}")
|> Ash.Changeset.manage_relationship(:movies, movie, type: :append)
|> Ash.Changeset.manage_relationship(:agents, agents, type: :append)
|> Ash.create!()
end
document =
"""
query Movies($first: Int, $after: String) {
getMovies(sort: [{field: TITLE}]) {
actors(first: 1, sort: [{field: NAME}]) {
count
edges {
cursor
node {
name
agents(first: $first, after: $after, sort: [{field: NAME}]) {
count
edges {
cursor
node {
name
}
}
}
}
}
}
}
}
"""
resp = Absinthe.run(document, AshGraphql.Test.Schema, variables: %{"first" => 1})
assert {:ok, result} = resp
refute Map.has_key?(result, :errors)
assert %{
data: %{
"getMovies" => [
%{
"actors" => %{
"count" => 5,
"edges" => [
%{
"node" => %{
"name" => "Actor 1",
"agents" => %{
"count" => 4,
"edges" => [
%{
"cursor" => cursor,
"node" => %{
"name" => "Agent 1"
}
}
]
}
}
}
]
}
}
]
}
} = result
resp =
Absinthe.run(document, AshGraphql.Test.Schema,
variables: %{"first" => 3, "after" => cursor}
)
assert {:ok, result} = resp
refute Map.has_key?(result, :errors)
assert %{
data: %{
"getMovies" => [
%{
"actors" => %{
"count" => 5,
"edges" => [
%{
"node" => %{
"name" => "Actor 1",
"agents" => %{
"count" => 4,
"edges" => edges
}
}
}
]
}
}
]
}
} = result
assert length(edges) == 3
assert [%{"node" => %{"name" => "Agent 2"}} | _] = edges
end
test "on return values for create mutations" do
actor1 = Ash.create!(AshGraphql.Test.Actor, %{name: "Actor 1"})
actor2 = Ash.create!(AshGraphql.Test.Actor, %{name: "Actor 2"})
document =
"""
mutation CreateMovie($input: CreateMovieInput!, $first: Int, $after: String) {
createMovie(input: $input) {
result {
title
actors(first: $first, after: $after, sort: [{field: NAME}]) {
count
edges {
cursor
node {
name
}
}
}
}
}
}
"""
variables = %{
"input" => %{"title" => "Movie 1", "actorIds" => [actor2.id, actor1.id]},
"first" => 1
}
resp = Absinthe.run(document, AshGraphql.Test.Schema, variables: variables)
assert {:ok, result} = resp
refute Map.has_key?(result, :errors)
assert %{
data: %{
"createMovie" => %{
"result" => %{
"title" => "Movie 1",
"actors" => %{
"count" => 2,
"edges" => [
%{
"cursor" => cursor,
"node" => %{
"name" => "Actor 1"
}
}
]
}
}
}
}
} = result
variables = %{
"input" => %{"title" => "Movie 2", "actorIds" => [actor2.id, actor1.id]},
"first" => 2,
"after" => cursor
}
resp = Absinthe.run(document, AshGraphql.Test.Schema, variables: variables)
assert {:ok, result} = resp
refute Map.has_key?(result, :errors)
assert %{
data: %{
"createMovie" => %{
"result" => %{
"title" => "Movie 2",
"actors" => %{
"count" => 2,
"edges" => [
%{
"node" => %{
"name" => "Actor 2"
}
}
]
}
}
}
}
} = result
end
test "on return values for update mutations" do
movie =
AshGraphql.Test.Movie
|> Ash.Changeset.for_create(:create, title: "Title")
|> Ash.create!()
for i <- 1..5 do
AshGraphql.Test.Actor
|> Ash.Changeset.for_create(:create, name: "Actor #{i}")
|> Ash.Changeset.manage_relationship(:movies, movie, type: :append)
|> Ash.create!()
end
document =
"""
mutation UpdateMovie($id: ID!, $input: UpdateMovieInput!, $first: Int, $after: String) {
updateMovie(id: $id, input: $input) {
result {
title
actors(first: $first, after: $after, sort: [{field: NAME}]) {
count
edges {
cursor
node {
name
}
}
}
}
}
}
"""
variables = %{"id" => movie.id, "input" => %{"title" => "Updated Title 1"}, "first" => 1}
resp = Absinthe.run(document, AshGraphql.Test.Schema, variables: variables)
assert {:ok, result} = resp
refute Map.has_key?(result, :errors)
assert %{
data: %{
"updateMovie" => %{
"result" => %{
"title" => "Updated Title 1",
"actors" => %{
"count" => 5,
"edges" => [
%{
"cursor" => cursor,
"node" => %{
"name" => "Actor 1"
}
}
]
}
}
}
}
} = result
variables = %{
"id" => movie.id,
"input" => %{"title" => "Updated Title 2"},
"first" => 3,
"after" => cursor
}
resp = Absinthe.run(document, AshGraphql.Test.Schema, variables: variables)
assert {:ok, result} = resp
refute Map.has_key?(result, :errors)
assert %{
data: %{
"updateMovie" => %{
"result" => %{
"title" => "Updated Title 2",
"actors" => %{
"count" => 5,
"edges" => [
%{
"node" => %{
"name" => "Actor 2"
}
},
%{
"node" => %{
"name" => "Actor 3"
}
},
%{
"node" => %{
"name" => "Actor 4"
}
}
]
}
}
}
}
} = result
end
end
end