From 74f4e999575bc431c72d7ea6db9066c0b13272c2 Mon Sep 17 00:00:00 2001 From: KKlochko Date: Sat, 8 Mar 2025 22:06:12 +0200 Subject: [PATCH] Add actions to support books' editions. --- lib/decentralised_book_index/metadata.ex | 24 +++++++- lib/decentralised_book_index/metadata/book.ex | 59 ++++++++++++++++++- .../metadata/book_test.exs | 50 ++++++++++++++++ 3 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 test/decentralised_book_index/metadata/book_test.exs diff --git a/lib/decentralised_book_index/metadata.ex b/lib/decentralised_book_index/metadata.ex index 74bcfc7..5c1c6ff 100644 --- a/lib/decentralised_book_index/metadata.ex +++ b/lib/decentralised_book_index/metadata.ex @@ -3,7 +3,21 @@ defmodule DecentralisedBookIndex.Metadata do otp_app: :decentralised_book_index resources do - resource DecentralisedBookIndex.Metadata.Book + resource DecentralisedBookIndex.Metadata.Book do + define :create_book, + action: :create, + args: [:title, :isbn, :description, {:optional, :book_editions_registry_id}] + + define :add_book_to_related_editions_registry, + action: :add_book_to_related_editions_registry, + args: [:title, :isbn, :description, :related_book_id] + + define :list_books, action: :read + define :get_book_by_id, args: [:id], action: :by_id + define :get_book_alternative_editions, args: [:book], action: :get_alternative_editions + define :update_book, action: :update + define :destroy_book, action: :destroy + end resource DecentralisedBookIndex.Metadata.Author do define :create_author, @@ -31,6 +45,12 @@ defmodule DecentralisedBookIndex.Metadata do define :destroy_author_alias_registry, action: :destroy end - resource DecentralisedBookIndex.Metadata.BookEditionsRegistry + resource DecentralisedBookIndex.Metadata.BookEditionsRegistry do + define :create_book_editions_registry, action: :create + define :list_book_editions_registries, action: :read + define :get_book_editions_registry_by_id, args: [:id], action: :by_id + define :update_book_editions_registry, action: :update + define :destroy_book_editions_registry, action: :destroy + end end end diff --git a/lib/decentralised_book_index/metadata/book.ex b/lib/decentralised_book_index/metadata/book.ex index 068558d..8b970b5 100644 --- a/lib/decentralised_book_index/metadata/book.ex +++ b/lib/decentralised_book_index/metadata/book.ex @@ -4,13 +4,70 @@ defmodule DecentralisedBookIndex.Metadata.Book do domain: DecentralisedBookIndex.Metadata, data_layer: AshPostgres.DataLayer + require Ash.Query + postgres do table "books" repo DecentralisedBookIndex.Repo end actions do - defaults [:read] + defaults [:read, :update, :destroy] + + create :create do + primary? true + accept [:title, :isbn, :description, :book_editions_registry_id] + + change fn changeset, _ -> + registry_id = Ash.Changeset.get_attribute(changeset, :book_editions_registry_id) + + if registry_id == nil do + {:ok, registry} = DecentralisedBookIndex.Metadata.create_book_editions_registry() + + Ash.Changeset.force_change_attribute(changeset, :book_editions_registry_id, registry.id) + else + changeset + end + end + end + + create :add_book_to_related_editions_registry do + accept [:title, :isbn, :description] + + argument :related_book_id, :uuid do + allow_nil? false + end + + change fn changeset, context -> + related_book_id = changeset.arguments.related_book_id + + if related_book_id == nil do + Ash.Changeset.add_error(changeset, :related_book_id, "Related book is empty") + else + {:ok, related_book} = DecentralisedBookIndex.Metadata.get_book_by_id(related_book_id) + + Ash.Changeset.force_change_attribute(changeset, :book_editions_registry_id, related_book.book_editions_registry_id) + end + end + end + + read :by_id do + argument :id, :uuid, allow_nil?: false + get? true + filter expr(id == ^arg(:id)) + end + + read :get_alternative_editions do + argument :book, :struct, allow_nil?: false + + prepare fn query, context -> + book = query.arguments.book + + DecentralisedBookIndex.Metadata.Book + |> Ash.Query.filter(book_editions_registry_id == ^book.book_editions_registry_id + and id != ^book.id) + end + end end attributes do diff --git a/test/decentralised_book_index/metadata/book_test.exs b/test/decentralised_book_index/metadata/book_test.exs new file mode 100644 index 0000000..7f99ed2 --- /dev/null +++ b/test/decentralised_book_index/metadata/book_test.exs @@ -0,0 +1,50 @@ +defmodule DecentralisedBookIndex.Metadata.BookTest do + use DecentralisedBookIndex.DataCase, async: true + + alias DecentralisedBookIndex.Metadata + + describe "books and registries relationship" do + test "a new book get new registry by default" do + assert {:ok, book} = Metadata.create_book("Book", "1234567890", "An description") + assert book.book_editions_registry_id != nil + end + + test "a new book belongs to a registry if specified" do + assert {:ok, registry} = Metadata.create_book_editions_registry() + assert {:ok, book} = Metadata.create_book("Book", "1234567890", "An description", registry.id) + assert book.book_editions_registry_id == registry.id + end + + test "a new book to a registry via a related book record" do + {:ok, related_book} = Metadata.create_book("Book", "1234567890", "An description") + + assert {:ok, book} = + Metadata.add_book_to_related_editions_registry("Book2", "1234567891", "An description2", related_book.id) + + assert related_book.book_editions_registry_id == book.book_editions_registry_id + end + + test "a new book to a registry via a empty related book record" do + assert {:error, _} = + Metadata.add_book_to_related_editions_registry("Book2", "1234567891", "An description2", nil) + end + end + + describe "books alternatives names" do + test "new book has no alternatives names" do + {:ok, book} = Metadata.create_book("Book", "1234567890", "An description") + assert {:ok, alternatives_names} = Metadata.get_book_alternative_editions(book) + assert alternatives_names = [] + end + + test "book has related book so they has one alternative name" do + {:ok, related_book} = Metadata.create_book("Book", "1234567890", "An description") + + {:ok, book} = + Metadata.add_book_to_related_editions_registry("Book2", "1234567891", "An description2", related_book.id) + + assert {:ok, alternatives_names} = Metadata.get_book_alternative_editions(book) + assert alternatives_names = [related_book] + end + end +end