AshVersioned.Relationships
Copy MarkdownAdds 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
endAshVersioned.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_idby 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, destinationDeclares 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.Projectbelongs_to_versioned :document, MyApp.Document do
destination_attribute :document_id
allow_nil? false
end
Arguments
| Name | Type | Default | Docs |
|---|---|---|---|
name | atom | The name of the relationship | |
destination | module | The destination resource |
Options
| Name | Type | Default | Docs |
|---|---|---|---|
primary_key? | boolean | false | Whether the generated attribute is, or is part of, the primary key of a resource. |
allow_nil? | boolean | true | Whether 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? | boolean | Whether the generated attribute will be marked as writable. If not set, it will default to the relationship's writable? setting. | |
attribute_public? | boolean | Whether or not the generated attribute will be public. If not set, it will default to the relationship's public? setting. | |
attribute_always_select? | boolean | false | Whether or not the generated attribute will be always selected when reading from the database. |
define_attribute? | boolean | true | If 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_type | any | :uuid | The type of the generated created attribute. See Ash.Type for more. |
description | String.t | An optional description for the relationship | |
destination_attribute | atom | The destination's identity attribute. Defaults to :resource_id, but self-referential relationships to versioned resources resolve automatically. | |
source_attribute | atom | The field on this resource that should match the destination_attribute on the related resource. - Defaults to <name>_id | |
relationship_context | any | Context to be set on any queries or changesets generated for managing or querying this relationship. | |
public? | boolean | false | Whether or not the relationship will appear in public interfaces |
not_found_message | String.t | A message to show if there is a conflict with this relationship in the database on update or create, or when managing relationships. | |
writable? | boolean | true | Whether or not the relationship may be managed. |
read_action | atom | :__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_arguments | map | %{} | 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. |
domain | atom | The domain module to use when working with the related entity. | |
filterable? | boolean | true | If set to false, the relationship will not be usable in filters. |
sortable? | boolean | true | If set to false, the relationship will not be usable in sorts. |
sort | any | A sort statement to be applied when loading the relationship. | |
default_sort | any | A default sort statement to be applied when loading the relationship. | |
violation_message | String.t | A message to show if there is a conflict with this relationship in the database on destroy. | |
authorize_read_with | :error | :filter | If 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? | boolean | false | If 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 filterApplies 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
| Name | Type | Default | Docs |
|---|---|---|---|
filter | any | The 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, destinationDeclares 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_idhas_one_versioned :profile, MyApp.Profile do
source_attribute :resource_id
end
Arguments
| Name | Type | Default | Docs |
|---|---|---|---|
name | atom | The name of the relationship | |
destination | module | The destination resource |
Options
| Name | Type | Default | Docs |
|---|---|---|---|
manual | (any, any -> any) | module | A 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? | boolean | All 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. | |
through | atom | 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? | boolean | true | Marks the relationship as required. Has no effect on validations, but can inform extensions that there will always be a related entity. |
from_many? | boolean | false | Signal 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. |
offset | non_neg_integer | An offset to skip entries when loading the relationship. Implies from_many?: true. | |
description | String.t | An optional description for the relationship | |
destination_attribute | atom | The attribute on the related resource that should match the source_attribute configured on this resource. | |
validate_destination_attribute? | boolean | true | Whether or not to validate that the destination field exists on the destination resource |
source_attribute | atom | :id | The field on this resource that should match the destination_attribute on the related resource. |
relationship_context | any | Context to be set on any queries or changesets generated for managing or querying this relationship. | |
public? | boolean | false | Whether or not the relationship will appear in public interfaces |
not_found_message | String.t | A message to show if there is a conflict with this relationship in the database on update or create, or when managing relationships. | |
writable? | boolean | true | Whether or not the relationship may be managed. |
read_action | atom | :__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_arguments | map | %{} | 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. |
domain | atom | The domain module to use when working with the related entity. | |
filterable? | boolean | true | If set to false, the relationship will not be usable in filters. |
sortable? | boolean | true | If set to false, the relationship will not be usable in sorts. |
sort | any | A sort statement to be applied when loading the relationship. | |
default_sort | any | A default sort statement to be applied when loading the relationship. | |
could_be_related_at_creation? | boolean | false | Whether or not related values may exist for this relationship at creation. |
violation_message | String.t | A message to show if there is a conflict with this relationship in the database on destroy. | |
authorize_read_with | :error | :filter | If 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? | boolean | false | If 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 filterApplies 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
| Name | Type | Default | Docs |
|---|---|---|---|
filter | any | The 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, destinationDeclares 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.Taskhas_many_versioned :tasks, MyApp.Task do
source_attribute :resource_id
filter expr(archived == false)
end
Arguments
| Name | Type | Default | Docs |
|---|---|---|---|
name | atom | The name of the relationship | |
destination | module | The destination resource |
Options
| Name | Type | Default | Docs |
|---|---|---|---|
manual | (any, any -> any) | module | A 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? | boolean | All 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. | |
through | atom | 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. | |
limit | integer | An integer to limit entries from loaded relationship. | |
offset | non_neg_integer | An offset to skip entries when loading the relationship. | |
description | String.t | An optional description for the relationship | |
destination_attribute | atom | The attribute on the related resource that should match the source_attribute configured on this resource. | |
validate_destination_attribute? | boolean | true | Whether or not to validate that the destination field exists on the destination resource |
source_attribute | atom | :id | The field on this resource that should match the destination_attribute on the related resource. |
relationship_context | any | Context to be set on any queries or changesets generated for managing or querying this relationship. | |
public? | boolean | false | Whether or not the relationship will appear in public interfaces |
not_found_message | String.t | A message to show if there is a conflict with this relationship in the database on update or create, or when managing relationships. | |
writable? | boolean | true | Whether or not the relationship may be managed. |
read_action | atom | :__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_arguments | map | %{} | 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. |
domain | atom | The domain module to use when working with the related entity. | |
filterable? | boolean | true | If set to false, the relationship will not be usable in filters. |
sortable? | boolean | true | If set to false, the relationship will not be usable in sorts. |
sort | any | A sort statement to be applied when loading the relationship. | |
default_sort | any | A default sort statement to be applied when loading the relationship. | |
could_be_related_at_creation? | boolean | false | Whether or not related values may exist for this relationship at creation. |
violation_message | String.t | A message to show if there is a conflict with this relationship in the database on destroy. | |
authorize_read_with | :error | :filter | If 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? | boolean | false | If 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 filterApplies 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
| Name | Type | Default | Docs |
|---|---|---|---|
filter | any | The 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