adding some tests, working on relationship stateful changes

This commit is contained in:
Zach Daniel 2019-12-20 00:30:27 -05:00
parent fc259c9012
commit 4e2e013f96
No known key found for this signature in database
GPG key ID: A57053A671EE649E
6 changed files with 154 additions and 52 deletions

View file

@ -90,7 +90,7 @@ defmodule Ash.Api.Interface do
end end
:error -> :error ->
{:error, "no such resource"} {:error, "no such resource #{resource}"}
end end
end end
@ -114,7 +114,7 @@ defmodule Ash.Api.Interface do
end end
:error -> :error ->
{:error, "no such resource"} {:error, "no such resource #{resource}"}
end end
end end
@ -136,7 +136,7 @@ defmodule Ash.Api.Interface do
end end
:error -> :error ->
{:error, "no such resource"} {:error, "no such resource #{resource}"}
end end
end end
@ -158,7 +158,7 @@ defmodule Ash.Api.Interface do
end end
:error -> :error ->
{:error, "no such resource"} {:error, "no such resource #{resource}"}
end end
end end

View file

@ -84,7 +84,7 @@ defmodule Ash.DataLayer.Ets do
|> Enum.reduce({:ok, []}, fn query, {:ok, records} -> |> Enum.reduce({:ok, []}, fn query, {:ok, records} ->
case do_run_query(resource, query, limit + offset) do case do_run_query(resource, query, limit + offset) do
{:ok, results} -> {:ok, records ++ results} {:ok, results} -> {:ok, records ++ results}
{:error, error} -> {:eror, error} {:error, error} -> {:error, error}
end end
end) end)
@ -109,7 +109,7 @@ defmodule Ash.DataLayer.Ets do
{:ok, match_spec} <- filter_to_matchspec(resource, filter), {:ok, match_spec} <- filter_to_matchspec(resource, filter),
{:ok, table} <- wrap_or_create_table(resource), {:ok, table} <- wrap_or_create_table(resource),
{:ok, results} <- match_limit(table, match_spec, limit) do {:ok, results} <- match_limit(table, match_spec, limit) do
{:ok, results} {:ok, Enum.map(results, &elem(&1, 1))}
else else
%{errors: errors} -> %{errors: errors} ->
{:error, errors} {:error, errors}

View file

@ -45,10 +45,7 @@ defmodule Ash.Filter.Merge do
# end # end
defp do_merge(left, right) do defp do_merge(left, right) do
# There is no way this can reasonably fail And.prebuilt_new(left, right)
{:ok, predicate} = And.prebuilt_new(left, right)
predicate
end end
## Equals + In filters ## Equals + In filters

View file

@ -19,6 +19,8 @@ defmodule Ash.Type do
@builtins [ @builtins [
string: [ecto_type: :string, filters: [:equal, :in], sortable?: true], string: [ecto_type: :string, filters: [:equal, :in], sortable?: true],
integer: [ecto_type: :integer, filters: [:equal, :in], sortable?: true],
int: [ecto_type: :integer, filters: [:equal, :in], sortable?: true],
boolean: [ecto_type: :boolean, filters: [:equal], sortable?: true], boolean: [ecto_type: :boolean, filters: [:equal], sortable?: true],
uuid: [ecto_type: :binary_id, filters: [:equal, :in], sortable?: true], uuid: [ecto_type: :binary_id, filters: [:equal, :in], sortable?: true],
utc_datetime: [ecto_type: :utc_datetime, filters: [:equal, :in], sortable?: true] utc_datetime: [ecto_type: :utc_datetime, filters: [:equal, :in], sortable?: true]

View file

@ -45,36 +45,28 @@ defmodule Ash.Test.Actions.SideLoadTest do
end end
describe "side_loads" do describe "side_loads" do
# setup do setup do
# author = Api.create!(Author, attributes: %{name: "zerg"}) author = Api.create!(Author, attributes: %{name: "zerg"})
# post1 = post1 =
# Api.create!(Post, attributes: %{title: "post1"}, relationships: %{author: author.id}) Api.create!(Post, attributes: %{title: "post1"}, relationships: %{author: author.id})
# post2 = post2 =
# Api.create!(Post, attributes: %{title: "post2"}, relationships: %{author: author.id}) Api.create!(Post, attributes: %{title: "post2"}, relationships: %{author: author.id})
# %{post1: post1, post2: post2} %{post1: post1, post2: post2}
# end
test "mything" do
Api.read!(Author, filter: [or: [[name: "zach"], [posts: [id: Ecto.UUID.generate()]]]])
end end
# test "it allows sideloading related data", %{post1: post1, post2: post2} do test "it allows sideloading related data", %{post1: post1, post2: post2} do
# %{results: [author]} = %{results: [author]} =
# Api.read!(Author, side_load: [posts: [:author]], filter: [posts: [id: post1.id]]) Api.read!(Author, side_load: [posts: [:author]], filter: [posts: [id: post1.id]])
# Api.read!(Author, assert Enum.sort(Enum.map(author.posts, &Map.get(&1, :id))) ==
# filter: [name: "zach", posts: [id: post1.id, title: "foo", contents: "bar"]] Enum.sort([post1.id, post2.id])
# )
# assert Enum.sort(Enum.map(author.posts, &Map.get(&1, :id))) == for post <- author.posts do
# Enum.sort([post1.id, post2.id]) assert post.author.id == author.id
end
# for post <- author.posts do end
# assert post.author.id == author.id
# end
# end
end end
end end

View file

@ -1,6 +1,27 @@
defmodule Ash.Test.Filter.FilterTest do defmodule Ash.Test.Filter.FilterTest do
use ExUnit.Case, async: true use ExUnit.Case, async: true
defmodule Profile do
use Ash.Resource, name: "profiles", type: "profile"
use Ash.DataLayer.Ets, private?: true
actions do
read :default
create :default
update :default
end
attributes do
attribute :bio, :string
end
relationships do
belongs_to :user, Ash.Test.Filter.FilterTest.User,
source_field: :user_id,
destination_field: :id
end
end
defmodule User do defmodule User do
use Ash.Resource, name: "users", type: "user" use Ash.Resource, name: "users", type: "user"
use Ash.DataLayer.Ets, private?: true use Ash.DataLayer.Ets, private?: true
@ -8,6 +29,7 @@ defmodule Ash.Test.Filter.FilterTest do
actions do actions do
read :default read :default
create :default create :default
update :default
end end
attributes do attributes do
@ -17,6 +39,27 @@ defmodule Ash.Test.Filter.FilterTest do
relationships do relationships do
has_many :posts, Ash.Test.Filter.FilterTest.Post has_many :posts, Ash.Test.Filter.FilterTest.Post
has_one :profile, Profile,
destination_field: :user_id,
source_field: :id
end
end
defmodule PostLink do
use Ash.Resource, name: "post_links", type: "post_link", primary_key: false
use Ash.DataLayer.Ets, private?: true
actions do
read :default
create :default
update :default
end
relationships do
belongs_to :source_post, Ash.Test.Filter.FilterTest.Post, primary_key?: true
belongs_to :destination_post, Ash.Test.Filter.FilterTest.Post, primary_key?: true
end end
end end
@ -28,11 +71,14 @@ defmodule Ash.Test.Filter.FilterTest do
read :default read :default
create :default create :default
update :default
end end
attributes do attributes do
attribute :title, :string attribute :title, :string
attribute :contents, :string attribute :contents, :string
attribute :points, :integer
end end
relationships do relationships do
@ -43,33 +89,98 @@ defmodule Ash.Test.Filter.FilterTest do
belongs_to :author2, User, belongs_to :author2, User,
destination_field: :id, destination_field: :id,
source_field: :author2_id source_field: :author2_id
many_to_many :related_posts, __MODULE__,
through: PostLink,
source_field_on_join_table: :source_post_id,
destination_field_on_join_table: :destination_post_id
end end
end end
defmodule Api do defmodule Api do
use Ash.Api use Ash.Api
resources [Post, Author] resources [Post, User, Profile]
end end
test "it works" do describe "simple attribute filters" do
authorization_steps = [ setup do
authorize_if: [author1: [id: 1]], post1 = Api.create!(Post, attributes: %{title: "title1", contents: "contents1", points: 1})
forbid_if: [author1: [allow_second_author: false]], post2 = Api.create!(Post, attributes: %{title: "title2", contents: "contents2", points: 2})
authorize_if: [author2: [id: 1]]
]
Ash.Filter.SatSolver.solve(Post, authorization_steps) %{post1: post1, post2: post2}
end
# Api.read(Post, test "single filter field", %{post1: post1} do
# filter: [ assert %{results: [^post1]} =
# title: "foo", Api.read!(Post,
# title: "bar", filter: [
# contents: [in: ["bar", "baz"]], title: post1.title
# contents: [in: ["foo", "bar"]], ]
# author1: [id: 1], )
# author2: [name: "bob"] end
# ]
# ) test "multiple filter field matches", %{post1: post1} do
assert %{results: [^post1]} =
Api.read!(Post,
filter: [
title: post1.title,
contents: post1.contents
]
)
end
test "no field matches" do
assert %{results: []} =
Api.read!(Post,
filter: [
title: "no match"
]
)
end
test "no field matches single record, but each matches one record", %{
post1: post1,
post2: post2
} do
assert %{results: []} =
Api.read!(Post,
filter: [
title: post1.title,
contents: post2.contents
]
)
end
end
describe "relationship filters" do
setup do
post1 = Api.create!(Post, attributes: %{title: "title1", contents: "contents1", points: 1})
post2 = Api.create!(Post, attributes: %{title: "title2", contents: "contents2", points: 2})
# post3 =
# Api.create!(Post,
# attributes: %{title: "title3", contents: "contents3", points: 3},
# relationships: %{related_posts: [post1, post2]}
# )
profile1 = Api.create!(Profile, attributes: %{bio: "dope"})
user1 =
Api.create!(User,
attributes: %{name: "broseph"},
relationships: %{posts: [post1, post2], profile: profile1}
)
user2 = Api.create!(User, attributes: %{name: "broseph"}, relationships: %{posts: [post2]})
profile2 = Api.create!(Profile, attributes: %{bio: "dope2"}, relationships: %{user: user2})
%{post1: post1, post2: post2}
end
test "it works" do
assert true
end
end end
end end