diff --git a/lib/decentralised_book_index/metadata.ex b/lib/decentralised_book_index/metadata.ex index ce97016..6db42f0 100644 --- a/lib/decentralised_book_index/metadata.ex +++ b/lib/decentralised_book_index/metadata.ex @@ -3,21 +3,30 @@ defmodule DecentralisedBookIndex.Metadata do alias DecentralisedBookIndex.Metadata + json_api do + routes do + base_route "/author", Metadata.Author do + get :read + index :search + end + end + end + resources do resource DecentralisedBookIndex.Metadata.Book do define :create_book, action: :create, args: [ :title, - :isbn, :description, + :bids, :author_roles, {:optional, :book_editions_registry_id} ] define :add_book_to_related_editions_registry, action: :add_book_to_related_editions_registry, - args: [:title, :isbn, :description, :author_roles, :related_book_id] + args: [:title, :description, :bids, :author_roles, :related_book_id] define :list_books, action: :read define :get_book_by_id, args: [:id], action: :by_id @@ -70,14 +79,13 @@ defmodule DecentralisedBookIndex.Metadata do define :update_author_role, action: :update define :destroy_author_role, action: :destroy end - end - json_api do - routes do - base_route "/author", Metadata.Author do - get :read - index :search - end + resource DecentralisedBookIndex.Metadata.BookId do + define :create_book_id, action: :create, args: [:type, :bid, :order] + define :list_book_ids, action: :read + define :get_book_id_by_id, args: [:id], action: :by_id + define :update_book_id, action: :update + define :destroy_book_id, action: :destroy end end end diff --git a/lib/decentralised_book_index/metadata/book.ex b/lib/decentralised_book_index/metadata/book.ex index 990eea6..fa5d14f 100644 --- a/lib/decentralised_book_index/metadata/book.ex +++ b/lib/decentralised_book_index/metadata/book.ex @@ -17,7 +17,8 @@ defmodule DecentralisedBookIndex.Metadata.Book do create :create do primary? true - accept [:title, :isbn, :description, :book_editions_registry_id] + accept [:title, :description, :book_editions_registry_id] + argument :bids, {:array, :map} argument :author_roles, {:array, :map} change fn changeset, _ -> @@ -32,16 +33,18 @@ defmodule DecentralisedBookIndex.Metadata.Book do 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, :isbn, :description] + accept [:title, :description] argument :related_book_id, :uuid do allow_nil? false end + argument :bids, {:array, :map} argument :author_roles, {:array, :map} change fn changeset, context -> @@ -56,6 +59,7 @@ defmodule DecentralisedBookIndex.Metadata.Book do 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 @@ -99,11 +103,6 @@ defmodule DecentralisedBookIndex.Metadata.Book do public? true end - attribute :isbn, :string do - allow_nil? false - public? true - end - attribute :description, :string do allow_nil? false public? true @@ -119,5 +118,10 @@ defmodule DecentralisedBookIndex.Metadata.Book do sort order: :asc public? true end + + has_many :bids, Metadata.BookId do + sort order: :asc + public? true + end end end diff --git a/lib/decentralised_book_index/metadata/book_id.ex b/lib/decentralised_book_index/metadata/book_id.ex new file mode 100644 index 0000000..eceb02a --- /dev/null +++ b/lib/decentralised_book_index/metadata/book_id.ex @@ -0,0 +1,55 @@ +defmodule DecentralisedBookIndex.Metadata.BookId do + use Ash.Resource, + otp_app: :decentralised_book_index, + domain: DecentralisedBookIndex.Metadata, + data_layer: AshPostgres.DataLayer + + alias DecentralisedBookIndex.Metadata + + postgres do + table "book_ids" + repo DecentralisedBookIndex.Repo + end + + actions do + defaults [:read, :update, :destroy] + + create :create do + primary? true + accept [:type, :bid, :order] + end + + read :by_id do + argument :id, :uuid, allow_nil?: false + get? true + filter expr(id == ^arg(:id)) + end + end + + attributes do + uuid_primary_key :id + + attribute :type, :string do + allow_nil? false + public? true + end + + attribute :bid, :string do + allow_nil? false + public? true + end + + attribute :order, :integer do + allow_nil? false + public? true + end + + timestamps() + end + + relationships do + belongs_to :book, Metadata.Book do + allow_nil? true + end + end +end diff --git a/priv/repo/migrations/20250314080954_add_book_ids_and_book_relationship.exs b/priv/repo/migrations/20250314080954_add_book_ids_and_book_relationship.exs new file mode 100644 index 0000000..1385273 --- /dev/null +++ b/priv/repo/migrations/20250314080954_add_book_ids_and_book_relationship.exs @@ -0,0 +1,48 @@ +defmodule DecentralisedBookIndex.Repo.Migrations.AddBookIdsAndBookRelationship do + @moduledoc """ + Updates resources based on their most recent snapshots. + + This file was autogenerated with `mix ash_postgres.generate_migrations` + """ + + use Ecto.Migration + + def up do + alter table(:books) do + remove :isbn + end + + create table(:book_ids, primary_key: false) do + add :id, :uuid, null: false, default: fragment("gen_random_uuid()"), primary_key: true + add :type, :text, null: false + add :bid, :text, null: false + add :order, :bigint, null: false + + add :inserted_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + + add :updated_at, :utc_datetime_usec, + null: false, + default: fragment("(now() AT TIME ZONE 'utc')") + + add :book_id, + references(:books, + column: :id, + name: "book_ids_book_id_fkey", + type: :uuid, + prefix: "public" + ) + end + end + + def down do + drop constraint(:book_ids, "book_ids_book_id_fkey") + + drop table(:book_ids) + + alter table(:books) do + add :isbn, :text, null: false + end + end +end diff --git a/priv/resource_snapshots/repo/book_ids/20250314080955.json b/priv/resource_snapshots/repo/book_ids/20250314080955.json new file mode 100644 index 0000000..96c9647 --- /dev/null +++ b/priv/resource_snapshots/repo/book_ids/20250314080955.json @@ -0,0 +1,108 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "type", + "type": "text" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "bid", + "type": "text" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "order", + "type": "bigint" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "book_ids_book_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "books" + }, + "size": null, + "source": "book_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "A3DC9C31FED651813574444110B78088B636E27F25A22BADF8DACF121B3CD9CE", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.DecentralisedBookIndex.Repo", + "schema": null, + "table": "book_ids" +} \ No newline at end of file diff --git a/priv/resource_snapshots/repo/books/20250314080955.json b/priv/resource_snapshots/repo/books/20250314080955.json new file mode 100644 index 0000000..0f3949b --- /dev/null +++ b/priv/resource_snapshots/repo/books/20250314080955.json @@ -0,0 +1,98 @@ +{ + "attributes": [ + { + "allow_nil?": false, + "default": "fragment(\"gen_random_uuid()\")", + "generated?": false, + "primary_key?": true, + "references": null, + "size": null, + "source": "id", + "type": "uuid" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "title", + "type": "text" + }, + { + "allow_nil?": false, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "description", + "type": "text" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "inserted_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": false, + "default": "fragment(\"(now() AT TIME ZONE 'utc')\")", + "generated?": false, + "primary_key?": false, + "references": null, + "size": null, + "source": "updated_at", + "type": "utc_datetime_usec" + }, + { + "allow_nil?": true, + "default": "nil", + "generated?": false, + "primary_key?": false, + "references": { + "deferrable": false, + "destination_attribute": "id", + "destination_attribute_default": null, + "destination_attribute_generated": null, + "index?": false, + "match_type": null, + "match_with": null, + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "name": "books_book_editions_registry_id_fkey", + "on_delete": null, + "on_update": null, + "primary_key?": true, + "schema": "public", + "table": "book_editions_registries" + }, + "size": null, + "source": "book_editions_registry_id", + "type": "uuid" + } + ], + "base_filter": null, + "check_constraints": [], + "custom_indexes": [], + "custom_statements": [], + "has_create_action": true, + "hash": "223A162BB5B9834C390467F85FB3A7ADC00F5EA9A223CD1A796D280518459C84", + "identities": [], + "multitenancy": { + "attribute": null, + "global": null, + "strategy": null + }, + "repo": "Elixir.DecentralisedBookIndex.Repo", + "schema": null, + "table": "books" +} \ No newline at end of file