defmodule DecentralisedBookIndex.Metadata.Book do use Ash.Resource, otp_app: :decentralised_book_index, domain: DecentralisedBookIndex.Metadata, data_layer: AshPostgres.DataLayer require Ash.Query alias DecentralisedBookIndex.Metadata postgres do table "books" repo DecentralisedBookIndex.Repo end actions do defaults [:read, :update, :destroy] create :create do primary? true accept [:title, :description, :format, :language, :page_count, :published, :publisher_id, :book_editions_registry_id] argument :bids, {:array, :map} argument :author_roles, {:array, :map} 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 change manage_relationship(:bids, type: :direct_control, order_is_key: :order) change manage_relationship(:author_roles, type: :direct_control, order_is_key: :order) end create :add_book_to_related_editions_registry do accept [:title, :description, :format, :language, :page_count, :published, :publisher_id] argument :related_book_id, :uuid do allow_nil? false end argument :bids, {:array, :map} argument :author_roles, {:array, :map} 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 change manage_relationship(:bids, type: :direct_control, order_is_key: :order) change manage_relationship(:author_roles, type: :direct_control, order_is_key: :order) end read :by_id do argument :id, :uuid, allow_nil?: false get? true filter expr(id == ^arg(:id)) end read :by_bid do argument :type, :string, allow_nil?: false argument :bid, :string, allow_nil?: false get? true filter expr(exists(bids, type == ^arg(:type) and bid == ^arg(:bid))) 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 read :get_author_books do argument :author, :struct, allow_nil?: false prepare fn query, context -> author = query.arguments.author {:ok, author_ids} = Metadata.get_author_ids(author) Metadata.Book |> Ash.Query.filter(expr(exists(author_roles, author_id in ^author_ids))) end end end attributes do uuid_primary_key :id attribute :title, :string do allow_nil? false public? true end attribute :description, :string do allow_nil? false public? true end attribute :published, :date do allow_nil? false public? true end attribute :language, :string do allow_nil? false public? true end attribute :format, :string do allow_nil? false public? true end attribute :page_count, :integer do allow_nil? false public? true end timestamps() end relationships do belongs_to :book_editions_registry, Metadata.BookEditionsRegistry belongs_to :publisher, Metadata.Publisher has_many :author_roles, Metadata.AuthorRole do sort order: :asc public? true end has_many :bids, Metadata.BookId do sort order: :asc public? true end end end