AshCascadeArchival

Automatically sets archive_related from ash_archival for all fully-contained child relationships (has_many and has_one).

Installation

Add ash_cascade_archival to your list of dependencies in mix.exs:

def deps do
  [
    {:ash_cascade_archival, "~> 0.4.0"}
  ]
end

Usage

Simply add AshCascadeArchival to your resource's extensions:

defmodule MyApp.Post do
  use Ash.Resource,
    extensions: [AshCascadeArchival.Resource]

  attributes do
    uuid_primary_key :id
    attribute :title, :string
  end

  relationships do
    belongs_to :author, MyApp.Author

    has_many :comments, MyApp.Comment
    has_many :post_tags, MyApp.PostTag

    many_to_many :tags, MyApp.Tag, through: MyApp.PostTag
  end

  actions do
    defaults [:read, :destroy, create: :*, update: :*]
  end
end

For the example above, archive_related is automatically set to:

archive do
  archive_related [:comments, :post_tags]
end

Features

Automatic Archive Configuration

AshCascadeArchival automatically identifies fully-contained child relationships and adds them to archive_related. A relationship is considered fully-contained when:

Note: many_to_many relationships are excluded because archive_related would target the destination resource, not the through resource. Instead, define a has_many relationship to the through resource (e.g., has_many :post_tags, PostTag) to archive it.

Excluding Relationships

Use the except option to exclude specific relationships:

defmodule MyApp.Post do
  use Ash.Resource,
    extensions: [AshCascadeArchival.Resource]

  cascade_archive do
    except [:post_tags]
  end

  relationships do
    has_many :comments, MyApp.Comment
    has_many :post_tags, MyApp.PostTag
  end
end

Result:

archive do
  archive_related [:comments]  # post_tags excluded
end

Validation

AshCascadeArchival verifies that parent resources with AshArchival have proper reverse relationships. If a child has a belongs_to to an archival parent, the parent must have a corresponding fully-contained relationship back to the child.

Example error:

AshArchival requires has_many or has_one to pair with belongs_to.
Parent MyApp.Author must have one of the following:

has_many :posts, MyApp.Post
has_one :post, MyApp.Post

How It Works

  1. Transformer: Finds all fully-contained child relationships and sets archive_related
  2. Verifier: Ensures bidirectional relationships are properly configured for archival

Configuration

Logging

By default, AshCascadeArchival logs the configured archive_related relationships during compilation. You can disable this in your config:

# config/config.exs
config :ash_cascade_archival, :log, false

Default: true (logging enabled)

Conflict with Manual Configuration

You cannot use both cascade_archive and manually set archive_related. If you need to exclude specific relationships, use the except option in cascade_archive:

cascade_archive do
  except [:relationship_name]
end

License

MIT