MishkaBlog.PostBlogger (Mishka Blog v0.0.1)

Copy Markdown View Source

Manages the many-to-many relationship between blog posts and bloggers with full version control.

This resource serves as the join table that associates bloggers with blog posts, enabling multi-author content and proper attribution. Each record represents an authorship assignment, indicating that a blogger is an author or co-author of a blog post.

The resource implements upsert functionality through the assign action, preventing duplicate authorship assignments while allowing efficient bulk updates. The unique constraint on post_id and blogger_id pairs ensures that each blogger can only be assigned to a post once, maintaining data integrity.

Post authorship history is tracked through PaperTrail integration, recording when authors are added or removed from posts. This provides a complete audit trail for content attribution changes, essential for editorial workflows and copyright management.

Access to this resource is controlled through policies that allow manipulation either through the BlogPost resource's blogger relationships or by users with administrative privileges. This ensures that authorship can only be modified by authorized actors.

Optional role field provides metadata about the author's contribution (e.g., 'primary author', 'co-author', 'contributor', 'editor').

Summary

Functions

Apply the full GuardedStruct pipeline (sanitize → validate → derive → main_validator) to attrs and return either {:ok, transformed_attrs} or {:error, errors}. Wire this into an Ash.Resource.Change to plug guardedstruct rules into Ash's changeset pipeline.

O(1) lookup of a field's compile-time metadata by name. Returns nil for unknown fields.

Compile-time-baked MapSet of every field name owned by the guardedstruct block. Used by GuardedStruct.AshResource.Change to decide, in O(1), whether a key in changeset.atomics belongs to the pipeline.

Validates that the keys in the provided input are valid for at least one action on the resource.

Same as input/1, except restricts the keys to values accepted by the action provided.

Types

t()

@type t() :: %MishkaBlog.PostBlogger{
  __lateral_join_source__: term(),
  __meta__: term(),
  __metadata__: term(),
  __order__: term(),
  aggregates: term(),
  blogger: term(),
  blogger_id: term(),
  calculations: term(),
  created_at: term(),
  post: term(),
  post_id: term(),
  post_in_any_state: term(),
  role: term()
}

Functions

__guarded_change__(attrs, error? \\ false)

Apply the full GuardedStruct pipeline (sanitize → validate → derive → main_validator) to attrs and return either {:ok, transformed_attrs} or {:error, errors}. Wire this into an Ash.Resource.Change to plug guardedstruct rules into Ash's changeset pipeline.

The function is named __guarded_change__ because it does more than validate — it can also transform values (trim, downcase, slugify, auto-fill, etc.) before they reach the data layer.

__guarded_field_meta__(name)

O(1) lookup of a field's compile-time metadata by name. Returns nil for unknown fields.

__guarded_field_name_set__()

Compile-time-baked MapSet of every field name owned by the guardedstruct block. Used by GuardedStruct.AshResource.Change to decide, in O(1), whether a key in changeset.atomics belongs to the pipeline.

default_short_name()

input(opts)

@spec input(values :: map() | Keyword.t()) :: map() | no_return()

Validates that the keys in the provided input are valid for at least one action on the resource.

Raises a KeyError error at compile time if not. This exists because generally a struct should only ever be created by Ash as a result of a successful action. You should not be creating records manually in code, e.g %MyResource{value: 1, value: 2}. Generally that is fine, but often with embedded resources it is nice to be able to validate the keys that are being provided, e.g

Resource
|> Ash.Changeset.for_create(:create, %{embedded: EmbeddedResource.input(foo: 1, bar: 2)})
|> Ash.create()

input(opts, action)

@spec input(values :: map() | Keyword.t(), action :: atom()) :: map() | no_return()

Same as input/1, except restricts the keys to values accepted by the action provided.

primary_key_matches?(left, right)