AshVersioned.Relationships

Copy Markdown

Adds belongs_to_versioned, has_one_versioned, and has_many_versioned to the relationships section of any resource for relationships to AshVersioned.Resource resources.

use Ash.Resource,
  extensions: [AshVersioned.Relationships]

relationships do
  belongs_to_versioned :project, MyApp.Project
end

AshVersioned.Resource adds this extension automatically, so it only needs to be added on non-versioned resources.

Each is equivalent to the same Ash relationship that:

  • filters on the latest version of the destination (in loads, aggregates, exists, and data layer joins alike);
  • reads through the destination's __ash_versioned_read__ action by default, which includes archived records, so a relationship to an archived record still resolves; and
  • for belongs_to_versioned, joins on the destination's identity attribute (:resource_id by default) and never creates a foreign key.

A destination with a non-default identity name requires destination_attribute on belongs_to_versioned (except for self-referential relationships, which use the resource's own identity), which is checked once the resources are compiled.

When the source resource is versioned, has_one_versioned and has_many_versioned should set source_attribute to the source's identity attribute, since the destination's belongs_to_versioned holds the identity rather than the primary key.

relationships.belongs_to_versioned

belongs_to_versioned name, destination

Declares a belongs_to relationship to the latest version of a versioned resource, joined on the destination's identity attribute. No foreign key is created, as the identity attribute is not unique across versions.

Takes the same options as belongs_to, except validate_destination_attribute?.

Nested DSLs

Examples

belongs_to_versioned :project, MyApp.Project
belongs_to_versioned :document, MyApp.Document do
  destination_attribute :document_id
  allow_nil? false
end

Arguments

NameTypeDefaultDocs
nameatomThe name of the relationship
destinationmoduleThe destination resource

Options

NameTypeDefaultDocs
primary_key?booleanfalseWhether the generated attribute is, or is part of, the primary key of a resource.
allow_nil?booleantrueWhether this relationship must always be present, e.g: must be included on creation, and never removed (it may be modified). The generated attribute will not allow nil values.
attribute_writable?booleanWhether the generated attribute will be marked as writable. If not set, it will default to the relationship's writable? setting.
attribute_public?booleanWhether or not the generated attribute will be public. If not set, it will default to the relationship's public? setting.
attribute_always_select?booleanfalseWhether or not the generated attribute will be always selected when reading from the database.
define_attribute?booleantrueIf set to false an attribute is not created on the resource for this relationship, and one must be manually added in attributes, invalidating many other options.
attribute_typeany:uuidThe type of the generated created attribute. See Ash.Type for more.
descriptionString.tAn optional description for the relationship
destination_attributeatomThe destination's identity attribute. Defaults to :resource_id, but self-referential relationships to versioned resources resolve automatically.
source_attributeatomThe field on this resource that should match the destination_attribute on the related resource. - Defaults to <name>_id
relationship_contextanyContext to be set on any queries or changesets generated for managing or querying this relationship.
public?booleanfalseWhether or not the relationship will appear in public interfaces
not_found_messageString.tA message to show if there is a conflict with this relationship in the database on update or create, or when managing relationships.
writable?booleantrueWhether or not the relationship may be managed.
read_actionatom:__ash_versioned_read__The read action on the destination resource used when loading data and filtering. Defaults to :__ash_versioned_read__, generated on every versioned resource, which returns the latest version of each record whether or not it is archived.
read_action_argumentsmap%{}Arguments to pass to the configured read_action when loading data and filtering. Arguments provided explicitly when loading the relationship take precedence over these arguments.
domainatomThe domain module to use when working with the related entity.
filterable?booleantrueIf set to false, the relationship will not be usable in filters.
sortable?booleantrueIf set to false, the relationship will not be usable in sorts.
sortanyA sort statement to be applied when loading the relationship.
default_sortanyA default sort statement to be applied when loading the relationship.
violation_messageString.tA message to show if there is a conflict with this relationship in the database on destroy.
authorize_read_with:error | :filterIf set to :error, any authorization filter added to the relationship will result in an error if any record matches the filter in the database.
allow_forbidden_field?booleanfalseIf set to true, the relationship will be set to %Ash.ForbiddenField{} if its query produces a forbidden error.
temporal_keys{atom, atom}For relationships involving temporal resources, the {source, destination} period attributes (e.g. {:valid_at, :valid_at}). Use nil for a non-temporal side ({nil, :valid_at} / {:valid_at, nil}). When both are set, a range_overlaps(parent(source), destination) filter is added to the relationship, alongside its usual attribute join. See the temporal section of Ash.Resource.Dsl.

relationships.belongs_to_versioned.filter

filter filter

Applies a filter. Can use ^arg/1, ^context/1 and ^actor/1 templates. Multiple filters are combined with and.

Examples

filter expr(first_name == "fred")
filter expr(last_name == "weasley" and magician == true)

Arguments

NameTypeDefaultDocs
filteranyThe filter to apply. Can use ^arg/1, ^context/1 and ^actor/1 templates. Multiple filters are combined with and.

Introspection

Target: Ash.Resource.Dsl.Filter

Introspection

Target: Ash.Resource.Relationships.BelongsTo

relationships.has_one_versioned

has_one_versioned name, destination

Declares a has_one relationship to the latest version of a versioned resource.

Takes the same options as has_one.

Nested DSLs

Examples

has_one_versioned :customer, MyApp.Customer, destination_attribute: :resource_id
has_one_versioned :profile, MyApp.Profile do
  source_attribute :resource_id
end

Arguments

NameTypeDefaultDocs
nameatomThe name of the relationship
destinationmoduleThe destination resource

Options

NameTypeDefaultDocs
manual(any, any -> any) | moduleA module that implements Ash.Resource.ManualRelationship. Also accepts a 2 argument function that takes the source records and the context. Setting this will automatically set no_attributes? to true.
no_attributes?booleanAll existing entities are considered related, i.e this relationship is not based on any fields, and source_attribute and destination_attribute are ignored. See the See the relationships guide for more.
throughatom | list(atom)A list of relationship names to traverse. The result will be the first record reachable by following the relationships in order.
allow_nil?booleantrueMarks the relationship as required. Has no effect on validations, but can inform extensions that there will always be a related entity.
from_many?booleanfalseSignal that this relationship is actually a has_many where the first record is given via the sort. This will allow data layers to properly deduplicate when necessary.
offsetnon_neg_integerAn offset to skip entries when loading the relationship. Implies from_many?: true.
descriptionString.tAn optional description for the relationship
destination_attributeatomThe attribute on the related resource that should match the source_attribute configured on this resource.
validate_destination_attribute?booleantrueWhether or not to validate that the destination field exists on the destination resource
source_attributeatom:idThe field on this resource that should match the destination_attribute on the related resource.
relationship_contextanyContext to be set on any queries or changesets generated for managing or querying this relationship.
public?booleanfalseWhether or not the relationship will appear in public interfaces
not_found_messageString.tA message to show if there is a conflict with this relationship in the database on update or create, or when managing relationships.
writable?booleantrueWhether or not the relationship may be managed.
read_actionatom:__ash_versioned_read__The read action on the destination resource used when loading data and filtering. Defaults to :__ash_versioned_read__, generated on every versioned resource, which returns the latest version of each record whether or not it is archived.
read_action_argumentsmap%{}Arguments to pass to the configured read_action when loading data and filtering. Arguments provided explicitly when loading the relationship take precedence over these arguments.
domainatomThe domain module to use when working with the related entity.
filterable?booleantrueIf set to false, the relationship will not be usable in filters.
sortable?booleantrueIf set to false, the relationship will not be usable in sorts.
sortanyA sort statement to be applied when loading the relationship.
default_sortanyA default sort statement to be applied when loading the relationship.
could_be_related_at_creation?booleanfalseWhether or not related values may exist for this relationship at creation.
violation_messageString.tA message to show if there is a conflict with this relationship in the database on destroy.
authorize_read_with:error | :filterIf set to :error, any authorization filter added to the relationship will result in an error if any record matches the filter in the database.
allow_forbidden_field?booleanfalseIf set to true, the relationship will be set to %Ash.ForbiddenField{} if its query produces a forbidden error.
temporal_keys{atom, atom}For relationships involving temporal resources, the {source, destination} period attributes (e.g. {:valid_at, :valid_at}). Use nil for a non-temporal side ({nil, :valid_at} / {:valid_at, nil}). When both are set, a range_overlaps(parent(source), destination) filter is added to the relationship, alongside its usual attribute join. See the temporal section of Ash.Resource.Dsl.

relationships.has_one_versioned.filter

filter filter

Applies a filter. Can use ^arg/1, ^context/1 and ^actor/1 templates. Multiple filters are combined with and.

Examples

filter expr(first_name == "fred")
filter expr(last_name == "weasley" and magician == true)

Arguments

NameTypeDefaultDocs
filteranyThe filter to apply. Can use ^arg/1, ^context/1 and ^actor/1 templates. Multiple filters are combined with and.

Introspection

Target: Ash.Resource.Dsl.Filter

Introspection

Target: Ash.Resource.Relationships.HasOne

relationships.has_many_versioned

has_many_versioned name, destination

Declares a has_many relationship to the latest versions of a versioned resource.

Takes the same options as has_many.

Nested DSLs

Examples

has_many_versioned :tasks, MyApp.Task
has_many_versioned :tasks, MyApp.Task do
  source_attribute :resource_id
  filter expr(archived == false)
end

Arguments

NameTypeDefaultDocs
nameatomThe name of the relationship
destinationmoduleThe destination resource

Options

NameTypeDefaultDocs
manual(any, any -> any) | moduleA module that implements Ash.Resource.ManualRelationship. Also accepts a 2 argument function that takes the source records and the context. Setting this will automatically set no_attributes? to true.
no_attributes?booleanAll existing entities are considered related, i.e this relationship is not based on any fields, and source_attribute and destination_attribute are ignored. See the See the relationships guide for more.
throughatom | list(atom)A list of relationship names to traverse. The result will be all records reachable by following the relationships in order. For example, through: [:classrooms, :teachers] would load all teachers from all classrooms.
limitintegerAn integer to limit entries from loaded relationship.
offsetnon_neg_integerAn offset to skip entries when loading the relationship.
descriptionString.tAn optional description for the relationship
destination_attributeatomThe attribute on the related resource that should match the source_attribute configured on this resource.
validate_destination_attribute?booleantrueWhether or not to validate that the destination field exists on the destination resource
source_attributeatom:idThe field on this resource that should match the destination_attribute on the related resource.
relationship_contextanyContext to be set on any queries or changesets generated for managing or querying this relationship.
public?booleanfalseWhether or not the relationship will appear in public interfaces
not_found_messageString.tA message to show if there is a conflict with this relationship in the database on update or create, or when managing relationships.
writable?booleantrueWhether or not the relationship may be managed.
read_actionatom:__ash_versioned_read__The read action on the destination resource used when loading data and filtering. Defaults to :__ash_versioned_read__, generated on every versioned resource, which returns the latest version of each record whether or not it is archived.
read_action_argumentsmap%{}Arguments to pass to the configured read_action when loading data and filtering. Arguments provided explicitly when loading the relationship take precedence over these arguments.
domainatomThe domain module to use when working with the related entity.
filterable?booleantrueIf set to false, the relationship will not be usable in filters.
sortable?booleantrueIf set to false, the relationship will not be usable in sorts.
sortanyA sort statement to be applied when loading the relationship.
default_sortanyA default sort statement to be applied when loading the relationship.
could_be_related_at_creation?booleanfalseWhether or not related values may exist for this relationship at creation.
violation_messageString.tA message to show if there is a conflict with this relationship in the database on destroy.
authorize_read_with:error | :filterIf set to :error, any authorization filter added to the relationship will result in an error if any record matches the filter in the database.
allow_forbidden_field?booleanfalseIf set to true, the relationship will be set to %Ash.ForbiddenField{} if its query produces a forbidden error.
temporal_keys{atom, atom}For relationships involving temporal resources, the {source, destination} period attributes (e.g. {:valid_at, :valid_at}). Use nil for a non-temporal side ({nil, :valid_at} / {:valid_at, nil}). When both are set, a range_overlaps(parent(source), destination) filter is added to the relationship, alongside its usual attribute join. See the temporal section of Ash.Resource.Dsl.

relationships.has_many_versioned.filter

filter filter

Applies a filter. Can use ^arg/1, ^context/1 and ^actor/1 templates. Multiple filters are combined with and.

Examples

filter expr(first_name == "fred")
filter expr(last_name == "weasley" and magician == true)

Arguments

NameTypeDefaultDocs
filteranyThe filter to apply. Can use ^arg/1, ^context/1 and ^actor/1 templates. Multiple filters are combined with and.

Introspection

Target: Ash.Resource.Dsl.Filter

Introspection

Target: Ash.Resource.Relationships.HasMany