mirror of
https://github.com/ash-project/ash_graphql.git
synced 2024-09-20 13:24:14 +12:00
f0836f18b6
metadata on read actions is merged with the rest of the fields on the query, so must have a name unique from the attributes/calculations/aggregates. The system will warn you if there is metadata on the underlying action that is being ignored, and will tell you how to fix it.
576 lines
14 KiB
Elixir
576 lines
14 KiB
Elixir
defmodule AshGraphql.ReadTest do
|
|
use ExUnit.Case, async: false
|
|
|
|
require Ash.Query
|
|
|
|
setup do
|
|
on_exit(fn ->
|
|
AshGraphql.TestHelpers.stop_ets()
|
|
end)
|
|
end
|
|
|
|
test "float fields works correctly" do
|
|
AshGraphql.Test.Post
|
|
|> Ash.Changeset.for_create(:create, text: "foo", published: true, score: 9.8)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
AshGraphql.Test.Post
|
|
|> Ash.Changeset.for_create(:create, text: "bar", published: true, score: 9.85)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
resp =
|
|
"""
|
|
query PostScore($score: Float) {
|
|
postScore(score: $score) {
|
|
text
|
|
}
|
|
}
|
|
"""
|
|
|> Absinthe.run(AshGraphql.Test.Schema,
|
|
variables: %{
|
|
"score" => 9.8
|
|
}
|
|
)
|
|
|
|
assert {:ok, result} = resp
|
|
|
|
refute Map.has_key?(result, :errors)
|
|
assert %{data: %{"postScore" => [%{"text" => "foo"}]}} = result
|
|
end
|
|
|
|
test "metadata fields are rendered" do
|
|
AshGraphql.Test.User
|
|
|> Ash.Changeset.for_create(:create,
|
|
name: "My Name"
|
|
)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
resp =
|
|
"""
|
|
query CurrentUserWithMetadata {
|
|
currentUserWithMetadata {
|
|
bar
|
|
}
|
|
}
|
|
"""
|
|
|> Absinthe.run(AshGraphql.Test.Schema)
|
|
|
|
assert {:ok, result} = resp
|
|
|
|
refute Map.has_key?(result, :errors)
|
|
assert %{data: %{"currentUserWithMetadata" => %{"bar" => "bar"}}} = result
|
|
end
|
|
|
|
test "a read with arguments works" do
|
|
AshGraphql.Test.Post
|
|
|> Ash.Changeset.for_create(:create, text: "foo", published: true)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
AshGraphql.Test.Post
|
|
|> Ash.Changeset.for_create(:create, text: "bar", published: false)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
resp =
|
|
"""
|
|
query PostLibrary($published: Boolean) {
|
|
postLibrary(published: $published) {
|
|
text
|
|
}
|
|
}
|
|
"""
|
|
|> Absinthe.run(AshGraphql.Test.Schema,
|
|
variables: %{
|
|
"published" => true
|
|
}
|
|
)
|
|
|
|
assert {:ok, result} = resp
|
|
|
|
refute Map.has_key?(result, :errors)
|
|
assert %{data: %{"postLibrary" => [%{"text" => "foo"}]}} = result
|
|
end
|
|
|
|
test "a read with custom set types works" do
|
|
AshGraphql.Test.Post
|
|
|> Ash.Changeset.for_create(:create, text: "foo", integer_as_string_in_api: 1, published: true)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
resp =
|
|
"""
|
|
query PostLibrary {
|
|
postLibrary {
|
|
text
|
|
integerAsStringInApi
|
|
}
|
|
}
|
|
"""
|
|
|> Absinthe.run(AshGraphql.Test.Schema)
|
|
|
|
assert {:ok, result} = resp
|
|
|
|
refute Map.has_key?(result, :errors)
|
|
assert %{data: %{"postLibrary" => [%{"integerAsStringInApi" => "1"}]}} = result
|
|
end
|
|
|
|
test "reading relationships works, without selecting the id field" do
|
|
post =
|
|
AshGraphql.Test.Post
|
|
|> Ash.Changeset.for_create(:create, text: "foo", published: true)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
AshGraphql.Test.Comment
|
|
|> Ash.Changeset.for_create(:create, %{text: "stuff"})
|
|
|> Ash.Changeset.force_change_attribute(:post_id, post.id)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
resp =
|
|
"""
|
|
query PostLibrary($published: Boolean) {
|
|
postLibrary(published: $published) {
|
|
text
|
|
comments{
|
|
text
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
|> Absinthe.run(AshGraphql.Test.Schema,
|
|
variables: %{
|
|
"published" => true
|
|
}
|
|
)
|
|
|
|
assert {:ok, result} = resp
|
|
|
|
refute Map.has_key?(result, :errors)
|
|
|
|
assert %{data: %{"postLibrary" => [%{"text" => "foo", "comments" => [%{"text" => "stuff"}]}]}} =
|
|
result
|
|
end
|
|
|
|
test "the same relationship can be fetched with different parameters" do
|
|
post =
|
|
AshGraphql.Test.Post
|
|
|> Ash.Changeset.for_create(:create, text: "foo", published: true)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
for _ <- 0..1 do
|
|
AshGraphql.Test.Comment
|
|
|> Ash.Changeset.for_create(:create, %{text: "stuff"})
|
|
|> Ash.Changeset.force_change_attribute(:post_id, post.id)
|
|
|> AshGraphql.Test.Api.create!()
|
|
end
|
|
|
|
resp =
|
|
"""
|
|
query PostLibrary($published: Boolean) {
|
|
postLibrary(published: $published) {
|
|
text
|
|
foo: comments(limit: 1){
|
|
text
|
|
}
|
|
bar: comments(limit: 2){
|
|
text
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
|> Absinthe.run(AshGraphql.Test.Schema,
|
|
variables: %{
|
|
"published" => true
|
|
}
|
|
)
|
|
|
|
assert {:ok, result} = resp
|
|
|
|
refute Map.has_key?(result, :errors)
|
|
|
|
assert %{
|
|
data: %{
|
|
"postLibrary" => [
|
|
%{
|
|
"text" => "foo",
|
|
"foo" => [%{"text" => "stuff"}],
|
|
"bar" => [%{"text" => "stuff"}, %{"text" => "stuff"}]
|
|
}
|
|
]
|
|
}
|
|
} = result
|
|
end
|
|
|
|
test "complexity is calculated for relationships" do
|
|
query = """
|
|
query PostLibrary {
|
|
paginatedPosts(limit: 2) {
|
|
results{
|
|
text
|
|
comments(limit: 2){
|
|
text
|
|
post {
|
|
comments(limit: 2) {
|
|
text
|
|
post {
|
|
text
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
|
|
query
|
|
|> Absinthe.run(AshGraphql.Test.Schema,
|
|
analyze_complexity: true,
|
|
max_complexity: 36
|
|
)
|
|
|
|
resp =
|
|
query
|
|
|> Absinthe.run(AshGraphql.Test.Schema,
|
|
analyze_complexity: true,
|
|
max_complexity: 35
|
|
)
|
|
|
|
assert {:ok, %{errors: errors}} = resp
|
|
|
|
assert errors |> Enum.map(& &1.message) |> Enum.sort() == [
|
|
"Field paginatedPosts is too complex: complexity is 36 and maximum is 35",
|
|
"Operation PostLibrary is too complex: complexity is 36 and maximum is 35"
|
|
]
|
|
end
|
|
|
|
test "a read with a loaded field works" do
|
|
AshGraphql.Test.Post
|
|
|> Ash.Changeset.for_create(:create, text: "bar", published: true)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
resp =
|
|
"""
|
|
query PostLibrary($published: Boolean) {
|
|
postLibrary(published: $published) {
|
|
text
|
|
staticCalculation
|
|
}
|
|
}
|
|
"""
|
|
|> Absinthe.run(AshGraphql.Test.Schema,
|
|
variables: %{
|
|
"published" => true
|
|
}
|
|
)
|
|
|
|
assert {:ok, result} = resp
|
|
|
|
refute Map.has_key?(result, :errors)
|
|
|
|
assert %{data: %{"postLibrary" => [%{"text" => "bar", "staticCalculation" => "static"}]}} =
|
|
result
|
|
end
|
|
|
|
test "the same calculation can be loaded twice with different arguments via aliases" do
|
|
AshGraphql.Test.Post
|
|
|> Ash.Changeset.for_create(:create, text: "bar", text1: "1", text2: "2", published: true)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
resp =
|
|
"""
|
|
query PostLibrary($published: Boolean) {
|
|
postLibrary(published: $published) {
|
|
foo: text1And2(separator: "foo")
|
|
bar: text1And2(separator: "bar")
|
|
}
|
|
}
|
|
"""
|
|
|> Absinthe.run(AshGraphql.Test.Schema)
|
|
|
|
assert {:ok, result} = resp
|
|
|
|
refute Map.has_key?(result, :errors)
|
|
|
|
assert %{data: %{"postLibrary" => [%{"foo" => "1foo2", "bar" => "1bar2"}]}} = result
|
|
end
|
|
|
|
test "the same calculation can be sorted on twice with different arguments via aliases" do
|
|
AshGraphql.Test.Post
|
|
|> Ash.Changeset.for_create(:create, text: "bar", text1: "1", text2: "2", published: true)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
AshGraphql.Test.Post
|
|
|> Ash.Changeset.for_create(:create, text: "bar", text1: "1", text2: "2", published: true)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
resp =
|
|
"""
|
|
query PostLibrary($published: Boolean) {
|
|
postLibrary(published: $published, sort: [{field: TEXT1_AND2, order: DESC, text1And2Input: {separator: "a"}}, {field: TEXT1_AND2, order: DESC, text1And2Input: {separator: "b"}}]) {
|
|
a: text1And2(separator: "a")
|
|
b: text1And2(separator: "b")
|
|
}
|
|
}
|
|
"""
|
|
|> Absinthe.run(AshGraphql.Test.Schema)
|
|
|
|
assert {:ok, result} = resp
|
|
|
|
refute Map.has_key?(result, :errors)
|
|
|
|
assert %{
|
|
data: %{
|
|
"postLibrary" => [%{"a" => "1a2", "b" => "1b2"}, %{"a" => "1a2", "b" => "1b2"}]
|
|
}
|
|
} = result
|
|
end
|
|
|
|
test "a read with a non-id primary key fills in the id field" do
|
|
record =
|
|
AshGraphql.Test.NonIdPrimaryKey
|
|
|> Ash.Changeset.for_create(:create, %{})
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
resp =
|
|
"""
|
|
query GetNonIdPrimaryKey($id: ID!) {
|
|
getNonIdPrimaryKey(id: $id) {
|
|
id
|
|
}
|
|
}
|
|
"""
|
|
|> Absinthe.run(AshGraphql.Test.Schema,
|
|
variables: %{
|
|
"id" => record.other
|
|
}
|
|
)
|
|
|
|
assert {:ok, result} = resp
|
|
|
|
refute Map.has_key?(result, :errors)
|
|
id = record.other
|
|
|
|
assert %{data: %{"getNonIdPrimaryKey" => %{"id" => ^id}}} = result
|
|
end
|
|
|
|
test "get requests against non-encoded primary key fields accept both fields and display both fields" do
|
|
record =
|
|
AshGraphql.Test.CompositePrimaryKeyNotEncoded
|
|
|> Ash.Changeset.for_create(:create, %{})
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
resp =
|
|
"""
|
|
query GetCompositePrimaryKeyNotEncoded($first: ID!, $second: ID!) {
|
|
getCompositePrimaryKeyNotEncoded(first: $first, second: $second) {
|
|
first
|
|
second
|
|
}
|
|
}
|
|
"""
|
|
|> Absinthe.run(AshGraphql.Test.Schema,
|
|
variables: %{
|
|
"first" => record.first,
|
|
"second" => record.second
|
|
}
|
|
)
|
|
|
|
assert {:ok, result} = resp
|
|
|
|
refute Map.has_key?(result, :errors)
|
|
first = record.first
|
|
second = record.second
|
|
|
|
assert %{
|
|
data: %{
|
|
"getCompositePrimaryKeyNotEncoded" => %{"first" => ^first, "second" => ^second}
|
|
}
|
|
} = result
|
|
end
|
|
|
|
test "a read with a composite primary key fills in the id field" do
|
|
record =
|
|
AshGraphql.Test.CompositePrimaryKey
|
|
|> Ash.Changeset.for_create(:create, %{})
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
resp =
|
|
"""
|
|
query GetCompositePrimaryKey($id: ID!) {
|
|
getCompositePrimaryKey(id: $id) {
|
|
id
|
|
}
|
|
}
|
|
"""
|
|
|> Absinthe.run(AshGraphql.Test.Schema,
|
|
variables: %{
|
|
"id" => AshGraphql.Resource.encode_primary_key(record)
|
|
}
|
|
)
|
|
|
|
assert {:ok, result} = resp
|
|
|
|
refute Map.has_key?(result, :errors)
|
|
id = AshGraphql.Resource.encode_primary_key(record)
|
|
|
|
assert %{data: %{"getCompositePrimaryKey" => %{"id" => ^id}}} = result
|
|
end
|
|
|
|
test "a read with custom types works" do
|
|
AshGraphql.Test.Post
|
|
|> Ash.Changeset.for_create(:create,
|
|
text: "bar",
|
|
published: true,
|
|
foo: %{foo: "foo", bar: "bar"}
|
|
)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
resp =
|
|
"""
|
|
query PostLibrary($published: Boolean) {
|
|
postLibrary(published: $published) {
|
|
text
|
|
staticCalculation
|
|
foo{
|
|
foo
|
|
bar
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
|> Absinthe.run(AshGraphql.Test.Schema,
|
|
variables: %{
|
|
"published" => true
|
|
}
|
|
)
|
|
|
|
assert {:ok, result} = resp
|
|
|
|
refute Map.has_key?(result, :errors)
|
|
|
|
assert %{
|
|
data: %{
|
|
"postLibrary" => [
|
|
%{
|
|
"text" => "bar",
|
|
"staticCalculation" => "static",
|
|
"foo" => %{"foo" => "foo", "bar" => "bar"}
|
|
}
|
|
]
|
|
}
|
|
} = result
|
|
end
|
|
|
|
test "a read without an argument works" do
|
|
user =
|
|
AshGraphql.Test.User
|
|
|> Ash.Changeset.for_create(:create,
|
|
name: "My Name"
|
|
)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
doc = """
|
|
query CurrentUser {
|
|
currentUser {
|
|
name
|
|
}
|
|
}
|
|
"""
|
|
|
|
assert {:ok,
|
|
%{
|
|
data: %{
|
|
"currentUser" => %{
|
|
"name" => "My Name"
|
|
}
|
|
}
|
|
}} == Absinthe.run(doc, AshGraphql.Test.Schema, context: %{actor: user})
|
|
end
|
|
|
|
test "a multitenant object can be read if tenant is set" do
|
|
tenant = "Some Tenant"
|
|
|
|
tag =
|
|
AshGraphql.Test.MultitenantTag
|
|
|> Ash.Changeset.for_create(
|
|
:create,
|
|
[name: "My Tag1"],
|
|
tenant: tenant
|
|
)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
doc = """
|
|
query MultitenantTag($id: ID!) {
|
|
getMultitenantTag(id: $id) {
|
|
name
|
|
}
|
|
}
|
|
"""
|
|
|
|
assert {:ok,
|
|
%{
|
|
data: %{
|
|
"getMultitenantTag" => %{
|
|
"name" => "My Tag1"
|
|
}
|
|
}
|
|
}} ==
|
|
Absinthe.run(doc, AshGraphql.Test.Schema,
|
|
context: %{tenant: tenant},
|
|
variables: %{"id" => tag.id}
|
|
)
|
|
end
|
|
|
|
test "a multitenant relation can be read if tenant is set" do
|
|
tenant = "Some Tenant"
|
|
|
|
tag =
|
|
AshGraphql.Test.MultitenantTag
|
|
|> Ash.Changeset.for_create(
|
|
:create,
|
|
[name: "My Tag"],
|
|
tenant: tenant
|
|
)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
post =
|
|
AshGraphql.Test.Post
|
|
|> Ash.Changeset.for_create(:create, text: "foo", published: true)
|
|
|> Ash.Changeset.manage_relationship(
|
|
:multitenant_tags,
|
|
[tag],
|
|
on_no_match: {:create, :create_action},
|
|
on_lookup: :relate
|
|
)
|
|
|> AshGraphql.Test.Api.create!()
|
|
|
|
doc = """
|
|
query MultitenantPostTag($id: ID!) {
|
|
getPost(id: $id) {
|
|
text
|
|
published
|
|
multitenantTags {
|
|
name
|
|
}
|
|
}
|
|
}
|
|
"""
|
|
|
|
assert {:ok,
|
|
%{
|
|
data: %{
|
|
"getPost" => %{
|
|
"published" => true,
|
|
"text" => "foo",
|
|
"multitenantTags" => [
|
|
%{
|
|
"name" => "My Tag"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}} ==
|
|
Absinthe.run(doc, AshGraphql.Test.Schema,
|
|
context: %{tenant: tenant},
|
|
variables: %{"id" => post.id}
|
|
)
|
|
end
|
|
end
|