Ash Resource Fragment which is the foundation for TMF Place subtypes.
BasePlace is the foundation for the TMF Place cascade (TMF673–675) — Place is
an abstract TMF concept, and concrete subtype identity lives on the fragments
that compose with it:
Diffo.Provider.BaseGeographicAddress— TMF673 GeographicAddress fields (street_name, postcode, country, …)Diffo.Provider.BaseGeographicSite— TMF674 GeographicSite fields (site_type, site_code, projected :address ref)Diffo.Provider.BaseGeographicLocation— TMF675 GeographicLocation fields (accuracy) and tightened geometry validation
Each subtype fragment composes with BasePlace on a concrete leaf:
defmodule MyApp.SydneyExchange do
use Ash.Resource,
fragments: [
Diffo.Provider.BasePlace,
Diffo.Provider.BaseGeographicSite
],
domain: MyApp.Domain
# consumer-specific attributes here
endDiffo ships the three corresponding concrete leaves out of the box:
Diffo.Provider.GeographicAddress, Diffo.Provider.GeographicSite,
Diffo.Provider.GeographicLocation. Use them directly or as templates
for your own domain leaves.
Diffo.Provider.Place is also kept in core but is plumbing (abstract
reader for projection + PlaceRef-typed placeholder support), not a
TMF subtype recommendation. See its moduledoc for details.
Preferred consumer API
The Diffo.Provider domain exposes a type-atom dispatcher that handles
the subtype routing for you:
Diffo.Provider.create_place!(:GeographicSite, %{...})
Diffo.Provider.get_place_by_id!(id) # returns concrete subtype struct via projectionAttributes
id— string primary key (required, no default — set by domain).href— optional URI for the place.name— the place name.type— TMF@type. Defaults to:PlaceRef. One of:PlaceRef,:GeographicSite,:GeographicLocation,:GeographicAddress. Whenreferred_typeis present,typemust be:PlaceRef.referred_type— TMF@referredType. One of:GeographicSite,:GeographicLocation,:GeographicAddress. When present, indicates this is a reference to a place of that kind;typemust be:PlaceRef.location— optionalAshGeo.GeoJson(:point, WGS-84) for point-like Places. Values are%Geo.Point{coordinates: {lon, lat}, srid: 4326}.bounds— optionalAshGeo.GeoJson(:polygon, WGS-84) for region Places. Values are%Geo.Polygon{coordinates: [ring], srid: 4326}. Polygon is the wire form; axis-aligned-bounding-box is the conventional use today but not type-enforced. At most one oflocation/boundsmay be set on a record, and only whentype == :GeographicLocation(per TMF675).
Usage
defmodule MyApp.GeographicSite do
use Ash.Resource, fragments: [BasePlace], domain: MyApp.Domain
resource do
description "A Geographic Site"
plural_name :geographic_sites
end
jason do
pick [:id, :href, :name, :referred_type, :type]
compact true
rename referred_type: "@referredType", type: "@type"
end
outstanding do
expect [:id, :name, :referred_type, :type]
end
actions do
create :build do
accept [:id, :href, :name]
change set_attribute(:type, :GeographicSite)
end
end
endDomain-specific attributes
Add Ash attribute declarations directly to your derived resource for any fields beyond the
base set. Those attributes can only be set via actions you declare on the derived resource —
the base create action provided by BasePlace only accepts the base fields (id, href,
name, type, referred_type). Use your domain API to call the derived resource's action:
defmodule MyApp.DataCentre do
use Ash.Resource, fragments: [BasePlace], domain: MyApp.Domain
attributes do
attribute :tier, :integer, public?: true
attribute :power_capacity_kw, :integer, public?: true
end
actions do
create :build do
accept [:id, :href, :name, :tier, :power_capacity_kw]
change set_attribute(:type, :GeographicSite)
end
end
end
# Use the domain API — Provider.create_place!/1 does not know about :tier
MyApp.Domain.create_data_centre!(%{name: "M2", tier: 3, power_capacity_kw: 40_000})TMF type and referred_type
The type and referred_type attributes map to the TMF @type and @referredType JSON
fields via the jason layer. When referred_type is present, type must be :PlaceRef;
otherwise type must not be :PlaceRef.