From 141dcb603b1d096dc9540d803e6605bf1f3e7fbe Mon Sep 17 00:00:00 2001 From: Matt Beanland Date: Mon, 27 Apr 2026 20:35:30 +0930 Subject: [PATCH] =?UTF-8?q?Instance=20DSL=20parties=20=E2=80=94=20multipli?= =?UTF-8?q?city,=20validation,=20and=20enforcement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `parties do` DSL to the Instance Extension, allowing resources to declare which party roles they accept, with optional min/max multiplicity constraints. Runtime enforcement is applied in `build_before` via `Party.validate_parties/1`, checking roles against declarations and rejecting builds that violate constraints. Renames Party Extension DSL sections from singular (`instance`/`party`) to plural (`instances`/`parties`) for consistency. Replaces `.license` sidecar files with `REUSE.toml`. Fixes ExDoc sidebar by removing a duplicate `docs:` key in mix.exs that shadowed the DSL extras config. Adds `Assignment.compare/2` so `Enum.sort/2` works in the Assigner. Updates all three livebooks to use the local path dep and cleans up stale commented-out version pins. Co-Authored-By: Claude Sonnet 4.6 --- .gitignore.license | 3 - .tool-versions.license | 3 - REUSE.toml | 12 + diffo.livemd | 58 ++++- .../DSL-Diffo.Provider.Instance.Extension.md | 65 ++++-- ...ffo.Provider.Instance.Extension.md.license | 3 - .../DSL-Diffo.Provider.Party.Extension.md | 32 +-- ...-Diffo.Provider.Party.Extension.md.license | 3 - .../use_diffo_provider_extension.livemd | 212 +++++++----------- documentation/how_to/use_diffo_type.livemd | 4 +- lib/diffo/changes/detail_event.ex | 7 +- lib/diffo/changes/detail_relationship.ex | 8 +- lib/diffo/helpers/util.ex | 28 +-- lib/diffo/helpers/uuid.ex | 5 +- lib/diffo/provider.ex | 4 +- .../provider/assigner/assignable_value.ex | 4 +- lib/diffo/provider/assigner/assigner.ex | 5 +- lib/diffo/provider/assigner/assignment.ex | 14 +- .../provider/components/base_instance.ex | 69 +++++- lib/diffo/provider/components/base_party.ex | 170 +++++++++++--- .../components/calculations/instance_href.ex | 7 +- .../calculations/specification_href.ex | 8 +- .../specification_instance_type.ex | 7 +- .../calculations/specification_version.ex | 7 +- .../provider/components/characteristic.ex | 17 +- lib/diffo/provider/components/entity.ex | 36 +-- lib/diffo/provider/components/entity_ref.ex | 17 +- lib/diffo/provider/components/event.ex | 17 +- .../components/external_identifier.ex | 17 +- lib/diffo/provider/components/feature.ex | 16 +- lib/diffo/provider/components/instance.ex | 4 +- .../provider/components/instance/extension.ex | 74 ++++-- .../instance/extension/action_helper.ex | 8 +- .../instance/extension/characteristic.ex | 7 +- .../components/instance/extension/feature.ex | 7 +- .../components/instance/extension/party.ex | 64 +++++- .../instance/extension/party_declaration.ex | 6 +- .../components/instance/extension/place.ex | 7 +- .../instance/extension/relationship.ex | 7 +- .../instance/extension/specification.ex | 6 +- .../provider/components/instance/util.ex | 120 ++-------- lib/diffo/provider/components/note.ex | 17 +- lib/diffo/provider/components/party.ex | 175 ++------------- .../provider/components/party/extension.ex | 23 +- .../components/party/extension/info.ex | 2 +- .../party/extension/instance_role.ex | 3 - .../components/party/extension/party_role.ex | 3 - lib/diffo/provider/components/party_ref.ex | 21 +- lib/diffo/provider/components/place.ex | 36 +-- lib/diffo/provider/components/place_ref.ex | 19 +- .../provider/components/process_status.ex | 17 +- lib/diffo/provider/components/relationship.ex | 4 +- .../provider/components/specification.ex | 4 +- lib/diffo/provider/outstanding.ex | 18 +- lib/diffo/provider/reference.ex | 24 +- lib/diffo/provider/service.ex | 8 +- lib/diffo/repo.ex | 8 +- lib/diffo/type/dynamic.ex | 34 ++- lib/diffo/type/outstanding/dynamic.ex | 32 --- lib/diffo/type/outstanding/primitive.ex | 35 --- lib/diffo/type/primitive.ex | 34 ++- lib/diffo/type/value.ex | 6 +- lib/diffo/unwrap.ex | 3 - lib/diffo/unwrap/any.ex | 2 + lib/diffo/unwrap/ash_ci_string.ex | 2 + lib/diffo/unwrap/ash_custom_expression.ex | 2 + lib/diffo/unwrap/ash_not_loaded.ex | 2 + lib/diffo/unwrap/ash_union.ex | 2 + lib/diffo/unwrap/list.ex | 2 + lib/diffo/validations/href_ends_with_id.ex | 7 +- lib/diffo/validations/is_related_different.ex | 7 +- lib/diffo/validations/is_uuid4_or_nil.ex | 7 +- logos/diffo.jpg.license | 3 - mix.exs | 12 +- mix.lock.license | 3 - test/instance_extension/assigner_test.exs | 9 +- .../characteristic_test.exs | 3 +- test/instance_extension/feature_test.exs | 3 +- test/instance_extension/party_test.exs | 129 +++++++++-- test/provider/entity_ref_test.exs | 54 ++--- test/provider/entity_test.exs | 80 +++---- test/provider/external_identifier_test.exs | 44 ++-- test/provider/instance_test.exs | 20 +- test/provider/instance_util_test.exs | 88 ++++++++ test/provider/note_test.exs | 40 ++-- test/provider/party_ref_test.exs | 46 ++-- test/provider/party_test.exs | 80 +++---- test/provider/place_ref_test.exs | 36 +-- test/provider/place_test.exs | 80 +++---- test/provider/reference_test.exs | 31 +++ test/support/nbn.ex | 12 +- test/support/parties.ex | 7 + test/support/resource/organisation.ex | 27 --- test/support/resource/organization.ex | 43 ++++ test/support/resource/person.ex | 20 +- test/support/resource/shelf.ex | 7 +- 96 files changed, 1283 insertions(+), 1321 deletions(-) delete mode 100644 .gitignore.license delete mode 100644 .tool-versions.license create mode 100644 REUSE.toml delete mode 100644 documentation/dsls/DSL-Diffo.Provider.Instance.Extension.md.license delete mode 100644 documentation/dsls/DSL-Diffo.Provider.Party.Extension.md.license delete mode 100644 lib/diffo/type/outstanding/dynamic.ex delete mode 100644 lib/diffo/type/outstanding/primitive.ex delete mode 100644 logos/diffo.jpg.license delete mode 100644 mix.lock.license create mode 100644 test/provider/instance_util_test.exs delete mode 100644 test/support/resource/organisation.ex create mode 100644 test/support/resource/organization.ex diff --git a/.gitignore.license b/.gitignore.license deleted file mode 100644 index 40c9cb0..0000000 --- a/.gitignore.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2025 diffo contributors - -SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/.tool-versions.license b/.tool-versions.license deleted file mode 100644 index 40c9cb0..0000000 --- a/.tool-versions.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2025 diffo contributors - -SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/REUSE.toml b/REUSE.toml new file mode 100644 index 0000000..bfc02fe --- /dev/null +++ b/REUSE.toml @@ -0,0 +1,12 @@ +version = 1 + +[[annotations]] +path = [ + ".gitignore", + ".tool-versions", + "mix.lock", + "logos/diffo.jpg", + "documentation/dsls/**", +] +SPDX-FileCopyrightText = "2025 diffo contributors " +SPDX-License-Identifier = "MIT" diff --git a/diffo.livemd b/diffo.livemd index 9fa9b38..8617475 100644 --- a/diffo.livemd +++ b/diffo.livemd @@ -1,4 +1,4 @@ - # Diffo.Provider.Instance.Extension -DSL Extension customising an Instance +DSL Extension customising an Instance. + +Provides compile-time declaration blocks for domain-specific Service and Resource kinds +built on `Diffo.Provider.BaseInstance`. All declarations are introspectable via +`Diffo.Provider.Instance.Extension.Info`. + +See the [DSL cheat sheet](DSL-Diffo.Provider.Instance.Extension.html) for the full DSL reference. +See `Diffo.Provider.BaseInstance` for full usage documentation. ## specification @@ -117,16 +124,10 @@ Adds a Characteristic -### Introspection - -Target: `Diffo.Provider.Instance.Characteristic` - -### Introspection -Target: `Diffo.Provider.Instance.Feature` @@ -176,9 +177,6 @@ Adds a Characteristic -### Introspection - -Target: `Diffo.Provider.Instance.Characteristic` @@ -188,13 +186,15 @@ List of Instance Party roles ### Nested DSLs * [party](#parties-party) + * [parties](#parties-parties) ### Examples ``` parties do - party :facilitated_by, MyApp.Rsp - party :overseen_by, MyApp.Person + party :provider, MyApp.Provider, calculate: :provider_calculation + parties :technician, MyApp.Technician, constraints: [min: 1, max: 3] + party :owner, MyApp.InfrastructureCo, reference: true end ``` @@ -208,7 +208,7 @@ party role, party_type ``` -Declares a party role on this Instance +Declares a singular party role on this Instance @@ -220,7 +220,46 @@ Declares a party role on this Instance |------|------|---------|------| | [`role`](#parties-party-role){: #parties-party-role .spark-required} | `atom` | | The role name, an atom | | [`party_type`](#parties-party-party_type){: #parties-party-party_type } | `any` | | The module of the Party kind. An atom module name such as a BaseParty-derived resource. | +### Options +| Name | Type | Default | Docs | +|------|------|---------|------| +| [`reference`](#parties-party-reference){: #parties-party-reference } | `boolean` | `false` | If true, no direct PartyRef edge is created; the party is reachable by graph traversal. | +| [`calculate`](#parties-party-calculate){: #parties-party-calculate } | `atom` | | Name of an Ash calculation on this resource that produces the party at build time. | + + + + + +### Introspection + +Target: `Diffo.Provider.Instance.Extension.PartyDeclaration` + +### parties.parties +```elixir +parties role, party_type +``` + + +Declares a plural party role on this Instance + + + + + +### Arguments + +| Name | Type | Default | Docs | +|------|------|---------|------| +| [`role`](#parties-parties-role){: #parties-parties-role .spark-required} | `atom` | | The role name, an atom | +| [`party_type`](#parties-parties-party_type){: #parties-parties-party_type } | `any` | | The module of the Party kind. An atom module name such as a BaseParty-derived resource. | +### Options + +| Name | Type | Default | Docs | +|------|------|---------|------| +| [`reference`](#parties-parties-reference){: #parties-parties-reference } | `boolean` | `false` | If true, no direct PartyRef edge is created; the party is reachable by graph traversal. | +| [`calculate`](#parties-parties-calculate){: #parties-parties-calculate } | `atom` | | Name of an Ash calculation on this resource that produces the party at build time. | +| [`constraints`](#parties-parties-constraints){: #parties-parties-constraints } | `keyword` | | Multiplicity constraints on the number of parties in this role, e.g. [min: 1, max: 3] | diff --git a/documentation/dsls/DSL-Diffo.Provider.Instance.Extension.md.license b/documentation/dsls/DSL-Diffo.Provider.Instance.Extension.md.license deleted file mode 100644 index 40c9cb0..0000000 --- a/documentation/dsls/DSL-Diffo.Provider.Instance.Extension.md.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2025 diffo contributors - -SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/documentation/dsls/DSL-Diffo.Provider.Party.Extension.md b/documentation/dsls/DSL-Diffo.Provider.Party.Extension.md index eb8d110..92e0d82 100644 --- a/documentation/dsls/DSL-Diffo.Provider.Party.Extension.md +++ b/documentation/dsls/DSL-Diffo.Provider.Party.Extension.md @@ -3,19 +3,25 @@ This file was generated by Spark. Do not edit it by hand. --> # Diffo.Provider.Party.Extension -DSL Extension customising a Party +DSL Extension customising a Party. +Provides compile-time declaration blocks for domain-specific Party kinds +built on `Diffo.Provider.BaseParty`. All declarations are introspectable via +`Diffo.Provider.Party.Extension.Info`. -## instance +See the [DSL cheat sheet](DSL-Diffo.Provider.Party.Extension.html) for the full DSL reference. + + +## instances Declares the roles this Party kind plays with respect to Instances ### Nested DSLs - * [role](#instance-role) + * [role](#instances-role) ### Examples ``` -instance do +instances do role :facilitates, MyApp.AccessService end @@ -24,7 +30,7 @@ end -### instance.role +### instances.role ```elixir role role, party_type ``` @@ -40,8 +46,8 @@ Declares a role this Party kind plays | Name | Type | Default | Docs | |------|------|---------|------| -| [`role`](#instance-role-role){: #instance-role-role .spark-required} | `atom` | | The role name, an atom | -| [`party_type`](#instance-role-party_type){: #instance-role-party_type } | `any` | | The module of the related resource | +| [`role`](#instances-role-role){: #instances-role-role .spark-required} | `atom` | | The role name, an atom | +| [`party_type`](#instances-role-party_type){: #instances-role-party_type } | `any` | | The module of the related resource | @@ -55,16 +61,16 @@ Target: `Diffo.Provider.Party.Extension.InstanceRole` -## party +## parties Declares the roles this Party kind plays with respect to other Parties ### Nested DSLs - * [role](#party-role) + * [role](#parties-role) ### Examples ``` -party do +parties do role :managed_by, MyApp.Person end @@ -73,7 +79,7 @@ end -### party.role +### parties.role ```elixir role role, party_type ``` @@ -89,8 +95,8 @@ Declares a role this Party kind plays with respect to other Parties | Name | Type | Default | Docs | |------|------|---------|------| -| [`role`](#party-role-role){: #party-role-role .spark-required} | `atom` | | The role name, an atom | -| [`party_type`](#party-role-party_type){: #party-role-party_type } | `any` | | The module of the related Party kind | +| [`role`](#parties-role-role){: #parties-role-role .spark-required} | `atom` | | The role name, an atom | +| [`party_type`](#parties-role-party_type){: #parties-role-party_type } | `any` | | The module of the related Party kind | diff --git a/documentation/dsls/DSL-Diffo.Provider.Party.Extension.md.license b/documentation/dsls/DSL-Diffo.Provider.Party.Extension.md.license deleted file mode 100644 index b381ebe..0000000 --- a/documentation/dsls/DSL-Diffo.Provider.Party.Extension.md.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2025 diffo contributors - -SPDX-License-Identifier: MIT diff --git a/documentation/how_to/use_diffo_provider_extension.livemd b/documentation/how_to/use_diffo_provider_extension.livemd index d6cfc03..974a475 100644 --- a/documentation/how_to/use_diffo_provider_extension.livemd +++ b/documentation/how_to/use_diffo_provider_extension.livemd @@ -4,14 +4,14 @@ SPDX-FileCopyrightText: 2025 diffo contributors -# Using the Diffo Provider Extension +# Using the Diffo Provider Instance Extension ```elixir Mix.install( [ - {:diffo, "~> 0.2.0"}, + {:diffo, path: "/Users/Beanlanda/git/diffo"} ], - config: [ + config: [ diffo: [ash_domains: [Diffo.Provider]] ], consolidate_protocols: false @@ -27,7 +27,7 @@ If you are not already familiar with Ash then please explore [Ash Get Started](h First ensure you've explored the Diffo Livebook for an introduction to Diffo: [![Run in Livebook](https://livebook.dev/badge/v1/blue.svg)](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fdiffo%2Ddev%2Fdiffo%2Fblob%2Fdev%2Fdiffo.livemd) -In this 'Diffo Provider Extension' livebook you will learn about: +In this 'Diffo Provider Instance Extension' livebook you will learn about: * TMF Services and Resources * Building your own Domain @@ -122,14 +122,12 @@ Partial resource assignment uses a relationship characteristic to indicate which ## Instance Extension -Diffo.Provider.Instance modelling a Service or Resource actually uses the Diffo.Provider.BaseInstance [Spark.Dsl.Fragment](https://hexdocs.pm/spark/Spark.Dsl.Fragment.html). There is no need to evaluate the Diffo.Provider.Instance below, it is already defined. +Diffo.Provider.Instance models either a Service or Resource. It actually uses the Diffo.Provider.BaseInstance [Spark.Dsl.Fragment](https://hexdocs.pm/spark/Spark.Dsl.Fragment.html). There is no need to evaluate the Diffo.Provider.Instance below, it is already defined. ```elixir defmodule Diffo.Provider.Instance do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Instance - Ash Resource for a TMF Service or Resource Instance + Ash Resource for a TMF Service or Resource Instance """ alias Diffo.Provider.BaseInstance @@ -144,7 +142,7 @@ defmodule Diffo.Provider.Instance do end ``` -Diffo also has an inbuilt Spark DSL extension [Diffo.Provider.Instance.Extension](https://hexdocs.pm/diffo/Diffo.Provider.Instance.Extension.html) which provides DSL and functions for use in building domain specific services and resources. +Diffo also has an inbuilt Spark DSL extension [Diffo.Provider.Instance.Extension](https://hexdocs.pm/diffo/Diffo.Provider.Instance.Extension.html) which provides DSL and functions for use in building and operating domain specific services and resources. Currently it has DSL to allow you to declare specification, features, characteristics, and party roles. It can be used for services or resources. Feature and Instance Characteristics can have payloads defined by [Ash.TypedStruct](https://hexdocs.pm/ash/Ash.TypedStruct.html). TypedStruct are DSL specified types which are effectively lightweight embedded resources. We've extended both [AshJason](https://hexdocs.pm/ash_jason/) and [AshOutstanding](https://hexdocs.pm/ash_outstanding/) to support Ash.TypedStruct. @@ -168,9 +166,7 @@ We will start by declaring the Cluster Resource. It is going to be a composite r ```elixir defmodule Diffo.Compute.Cluster do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Cluster - Cluster Resource Instance + Cluster Resource Instance """ alias Diffo.Provider.BaseInstance @@ -179,7 +175,7 @@ defmodule Diffo.Compute.Cluster do alias Diffo.Provider.Instance.ActionHelper alias Diffo.Compute alias Diffo.Compute.ClusterValue - alias Diffo.Compute.Organisation + alias Diffo.Compute.Tenant alias Diffo.Compute.Engineer use Ash.Resource, @@ -204,8 +200,8 @@ defmodule Diffo.Compute.Cluster do end parties do - party :operated_by, Organisation - party :managed_by, Engineer + party :operator, Tenant + party :manager, Engineer end actions do @@ -261,9 +257,7 @@ And of course we'll need a ClusterValue TypedStruct for the Cluster Resource's c ```elixir defmodule Diffo.Compute.ClusterValue do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - ClusterValue - AshTyped Struct for Cluster Characteristic Value + AshTyped Struct for Cluster Characteristic Value """ use Ash.TypedStruct, extensions: [AshJason.TypedStruct, AshOutstanding.TypedStruct] @@ -305,9 +299,7 @@ We'll now define a GPU Resource which uses the Diffo.Provider.Assigner functiona ```elixir defmodule Diffo.Compute.GPU do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - GPU - GPU Resource Instance + GPU Resource Instance """ alias Diffo.Provider.BaseInstance @@ -406,9 +398,7 @@ And we must define the GPUValue TypedStruct, used in the GPU's gpu characteristi ```elixir defmodule Diffo.Compute.GPUValue do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - GPUValue - AshTyped Struct for GPU Characteristic Value + AshTyped Struct for GPU Characteristic Value """ use Ash.TypedStruct, extensions: [AshJason.TypedStruct, AshOutstanding.TypedStruct] @@ -441,22 +431,20 @@ end ## Party Extension -`Diffo.Provider.BaseParty` is an Ash Resource Fragment for domain-specific Party kinds, mirroring `BaseInstance`. It provides common Party attributes — `id`, `name`, `kind` — and the `Diffo.Provider.Party.Extension` DSL, which lets a Party kind declare the roles it plays with respect to Instances and other Parties. +`Diffo.Provider.BaseParty` is an Ash Resource Fragment for domain-specific Party kinds, mirroring `BaseInstance`. It provides common Party attributes — `id`, `href`, `name`, `type`, `referred_type` — and the `Diffo.Provider.Party.Extension` DSL, which lets a Party kind declare the roles it plays with respect to Instances and other Parties. -`kind` is either `:individual` or `:organization`. The `id` defaults to a generated uuid but can be set by the domain to any meaningful string (such as an ABN or a data centre identifier). +`type` defaults to `:PartyRef` and can be set to `:Individual`, `:Organization`, or `:Entity`. Domain party kinds typically set `type` in their `build` action. The `id` defaults to a generated uuid but can be set to any meaningful string (such as an ABN or a data centre identifier). The `Diffo.Provider.Party.Extension` DSL cheat sheet is at [DSL-Diffo.Provider.Party.Extension](https://hexdocs.pm/diffo/DSL-Diffo.Provider.Party.Extension.html). ### Defining Party kinds -We'll add two Party kinds to our Compute domain — `Organisation` for the operating company, and `Engineer` for the individuals who manage resources. +We'll add two Party kinds to our Compute domain — `Tenant` for the operating company, and `Engineer` for the individuals who manage resources. ```elixir -defmodule Diffo.Compute.Organisation do +defmodule Diffo.Compute.Tenant do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Organisation - an Organisation in the Compute domain + Tenant in the Compute domain """ alias Diffo.Provider.BaseParty @@ -467,13 +455,20 @@ defmodule Diffo.Compute.Organisation do domain: Compute resource do - description "A Compute Organisation" - plural_name :organisations + description "A Compute Tenant" + plural_name :tenants + end + + actions do + create :build do + accept [:id, :name] + change set_attribute(:type, :Organization) + end end - instance do - role :operates, Diffo.Compute.Cluster - role :operates, Diffo.Compute.GPU + instances do + role :operator, Diffo.Compute.Cluster + role :operator, Diffo.Compute.GPU end end ``` @@ -481,9 +476,7 @@ end ```elixir defmodule Diffo.Compute.Engineer do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Engineer - an Engineer in the Compute domain + Engineer in the Compute domain """ alias Diffo.Provider.BaseParty @@ -498,12 +491,19 @@ defmodule Diffo.Compute.Engineer do plural_name :engineers end - instance do - role :manages, Diffo.Compute.Cluster + actions do + create :build do + accept [:id, :name] + change set_attribute(:type, :Individual) + end + end + + instances do + role :manager, Diffo.Compute.Cluster end - party do - role :employed_by, Diffo.Compute.Organisation + parties do + role :employer, Diffo.Compute.Tenant end end ``` @@ -515,8 +515,6 @@ With all resources defined we can now declare the `Diffo.Compute` domain, which ```elixir defmodule Diffo.Compute do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - Compute - example domain """ use Ash.Domain, @@ -526,7 +524,7 @@ defmodule Diffo.Compute do alias Diffo.Compute.GPU #alias Diffo.Compute.NPU alias Diffo.Compute.Cluster - alias Diffo.Compute.Organisation + alias Diffo.Compute.Tenant alias Diffo.Compute.Engineer resources do @@ -553,22 +551,22 @@ defmodule Diffo.Compute do define :relate_cluster, action: :relate end - resource Organisation do - define :create_organisation, action: :create - define :get_organisation_by_id, action: :read, get_by: :id - define :list_organisations, action: :list + resource Tenant do + define :create_tenant, action: :build + define :get_tenant_by_id, action: :read, get_by: :id + define :list_tenants, action: :read end resource Engineer do - define :create_engineer, action: :create + define :create_engineer, action: :build define :get_engineer_by_id, action: :read, get_by: :id - define :list_engineers, action: :list + define :list_engineers, action: :read end end end ``` -### Creating a Cluster +### Creating Party instances Clear any data from previous runs before starting (safe to re-evaluate): @@ -576,13 +574,30 @@ Clear any data from previous runs before starting (safe to re-evaluate): AshNeo4j.Neo4jHelper.delete_all() ``` -Now the domain is defined we can create our first Cluster instance. We'll use a helper module to set up the place and provider party ref: +Now the domain is defined we'll create our Tenant and Engineer first — we'll need them when building Cluster instances. The `id` for the Tenant is set to a meaningful string — the company's ABN. + +```elixir +alias Diffo.Compute +alias Diffo.Provider.Instance.Party + +{:ok, tenant} = Compute.create_tenant(%{ + id: "51824753556", + name: "Acme Compute Pty Ltd" +}) + +{:ok, engineer} = Compute.create_engineer(%{ + name: "Alice Zhang" +}) +``` + +### Creating a Cluster + +We'll use a helper module to set up the data centre place: ```elixir defmodule Diffo.Compute.Test do alias Diffo.Provider alias Diffo.Provider.Instance.Place - alias Diffo.Provider.Instance.Party def create_data_centre_place do dc = @@ -590,26 +605,18 @@ defmodule Diffo.Compute.Test do id: "NXTM2", name: :dataCentreId, href: "place/compute/NXTM2", - referredType: :GeographicSite - }) - - %Place{id: dc.id, role: :DataCentre} - end - - def create_provider_party do - provider = - Provider.create_party!(%{ - id: "Compute", - name: :organizationId, - referredType: :Organization + referred_type: :GeographicSite }) - %Party{id: provider.id, role: :Provider} + %Place{id: dc.id, role: :dataCentre} end end places = [Diffo.Compute.Test.create_data_centre_place()] -parties = [Diffo.Compute.Test.create_provider_party()] +parties = [ + %Party{id: tenant.id, role: :operator}, + %Party{id: engineer.id, role: :manager} +] cluster_1 = Diffo.Compute.build_cluster!(%{name: "cluster_1", places: places, parties: parties}) ``` @@ -622,8 +629,6 @@ Jason.encode!(cluster_1, pretty: true) |> IO.puts Now we'll create a couple of GPU instances: ```elixir -alias Diffo.Compute - gpu_1 = Compute.build_gpu!(%{name: "GPU 1"}) gpu_2 = Compute.build_gpu!(%{name: "GPU 2"}) ``` @@ -652,7 +657,6 @@ Now we can auto-assign GPU cores from each GPU to our cluster_1. We'll assign 3 ```elixir alias Diffo.Provider.Assignment -alias Diffo.Compute assignment = %{assignment: %Assignment{assignee_id: cluster_1.id, operation: :auto_assign}} gpu_1 = Compute.assign_gpu_core!(gpu_1, assignment) @@ -677,71 +681,9 @@ As an exercise, clone the GPU resource to create an NPU resource and assign some What happens when there are none left to assign? What happens when I request a specific assignment from an instance to which the partial resource is already assigned? -### Creating Party instances - -Now we can create an Organisation and an Engineer in the Compute domain. The `id` for the Organisation is set to a meaningful string — the company's ABN. - -```elixir -alias Diffo.Compute - -{:ok, org} = Compute.create_organisation(%{ - id: "51824753556", - name: "Acme Compute Pty Ltd", - kind: :organization -}) - -{:ok, engineer} = Compute.create_engineer(%{ - name: "Alice Zhang", - kind: :individual -}) -``` - -### Using Parties with a Cluster - -We can now build a Cluster and relate it to our Organisation and Engineer using the base provider party ref mechanism. - -```elixir -alias Diffo.Provider.Instance.Party - -parties = [ - %Party{id: org.id, role: :operated_by}, - %Party{id: engineer.id, role: :managed_by} -] - -cluster_2 = Compute.build_cluster!(%{ - name: "cluster_2", - places: [Diffo.Compute.Test.create_data_centre_place()], - parties: parties -}) - -Jason.encode!(cluster_2, pretty: true) |> IO.puts -``` - -### What the Party DSL declares - -The `instance do` and `party do` blocks are compile-time declarations — they document which roles a Party kind plays and make that information available via `Diffo.Provider.Party.Extension.Info`: - -```elixir -alias Diffo.Provider.Party.Extension.Info, as: PartyInfo - -PartyInfo.instance(Diffo.Compute.Organisation) -``` - -```elixir -PartyInfo.party(Diffo.Compute.Engineer) -``` - -These declarations also inform the Instance DSL's `parties do` block, which documents which party kinds an Instance resource expects: - -```elixir -alias Diffo.Provider.Instance.Extension.Info, as: InstanceInfo - -InstanceInfo.parties(Diffo.Compute.Cluster) -``` - ### What Next? -In this tutorial you've used Diffo's Provider Instance Extension to define a Compute domain with a composite Cluster resource comprised of assigned GPU cores, and the Provider Party Extension to define Organisation and Engineer party kinds that operate and manage those resources. +In this tutorial you've used Diffo's Provider Instance Extension to define a Compute domain with a composite Cluster resource comprised of assigned GPU cores, and the Provider Party Extension to define Tenant and Engineer party kinds that operate and manage those resources. The BaseParty fragment follows the same pattern as BaseInstance — domain-specific resources use it as a fragment and finish their actions with a domain-scoped reload to pick up extended fields. diff --git a/documentation/how_to/use_diffo_type.livemd b/documentation/how_to/use_diffo_type.livemd index e4df360..83f783e 100644 --- a/documentation/how_to/use_diffo_type.livemd +++ b/documentation/how_to/use_diffo_type.livemd @@ -9,7 +9,7 @@ SPDX-License-Identifier: MIT ```elixir Mix.install( [ - {:diffo, "~> 0.2.0"} + {:diffo, path: "/Users/Beanlanda/git/diffo"} ], consolidate_protocols: false ) @@ -289,4 +289,4 @@ Ash.Type.cast_input(Dynamic, valid, []) ## Further reading * [Diffo Livebook](../../diffo.livemd) — full tutorial including Neo4j setup and Provider resources -* [Using Diffo Provider Instance Extension](./use_diffo_provider_instance_extension.livemd) — defining custom resources with typed characteristics +* [Using Diffo Provider Instance Extension](./use_diffo_provider_extension.livemd) — defining custom resources with typed characteristics diff --git a/lib/diffo/changes/detail_event.ex b/lib/diffo/changes/detail_event.ex index b6c7911..7d24ffb 100644 --- a/lib/diffo/changes/detail_event.ex +++ b/lib/diffo/changes/detail_event.ex @@ -3,12 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Changes.DetailEvent do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - DetailEvent - Ash Resource Change for detailing an Event - - """ + @moduledoc false use Ash.Resource.Change def change(changeset, _opts, _context) do diff --git a/lib/diffo/changes/detail_relationship.ex b/lib/diffo/changes/detail_relationship.ex index 137ec97..6515b14 100644 --- a/lib/diffo/changes/detail_relationship.ex +++ b/lib/diffo/changes/detail_relationship.ex @@ -3,13 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Changes.DetailRelationship do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - - DetailRelationship - Ash Resource Change for populating relationship detail - - """ + @moduledoc false use Ash.Resource.Change def change(changeset, _opts, _context) do diff --git a/lib/diffo/helpers/util.ex b/lib/diffo/helpers/util.ex index 5c23eda..c75606c 100644 --- a/lib/diffo/helpers/util.ex +++ b/lib/diffo/helpers/util.ex @@ -4,11 +4,8 @@ defmodule Diffo.Util do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Util - utility methods + Utility methods """ - @doc """ Renames map key, unless old value is empty ## Examples @@ -98,25 +95,6 @@ defmodule Diffo.Util do end end - @spec compare(any(), any()) :: :eq | :gt | :lt - @doc """ - Compares two terms - ## Examples - iex> Diffo.Util.compare("a", "a") - :eq - iex> Diffo.Util.compare("b", "a") - :gt - iex> Diffo.Util.compare("a", "b") - :lt - """ - def compare(a, b) do - cond do - a < b -> :lt - a > b -> :gt - true -> :eq - end - end - @doc """ true if the datetime is close to (+/- 5 mins) from now ## Examples @@ -149,7 +127,6 @@ defmodule Diffo.Util do iex> Diffo.Util.past?(DateTime.utc_now() |> DateTime.shift(minute: -4)) false """ - def past?(datetime) do now = DateTime.utc_now() past = DateTime.shift(now, minute: -5) @@ -165,7 +142,6 @@ defmodule Diffo.Util do iex> Diffo.Util.future?(DateTime.utc_now() |> DateTime.shift(minute: 4)) false """ - def future?(datetime) do now = DateTime.utc_now() future = DateTime.shift(now, minute: 5) @@ -215,7 +191,6 @@ defmodule Diffo.Util do :past """ - def summarise(datetime) do cond do close_to_now?(datetime) -> :now @@ -235,7 +210,6 @@ defmodule Diffo.Util do "past,now,future" """ - def summarise_dates(payload) do Regex.replace(~r/\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}.\d{3}Z/, payload, fn iso8601 -> case DateTime.from_iso8601(iso8601) do diff --git a/lib/diffo/helpers/uuid.ex b/lib/diffo/helpers/uuid.ex index ed04e79..7229535 100644 --- a/lib/diffo/helpers/uuid.ex +++ b/lib/diffo/helpers/uuid.ex @@ -4,11 +4,8 @@ defmodule Diffo.Uuid do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Uuid - validate and/or create uuids + Validate and/or create Uuid """ - @doc """ Generates a uuid4 """ diff --git a/lib/diffo/provider.ex b/lib/diffo/provider.ex index 50c5b0a..18ea091 100644 --- a/lib/diffo/provider.ex +++ b/lib/diffo/provider.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Provider - API endpoint + Provider API endpoint """ use Ash.Domain, otp_app: :diffo diff --git a/lib/diffo/provider/assigner/assignable_value.ex b/lib/diffo/provider/assigner/assignable_value.ex index 51432a6..be36eb2 100644 --- a/lib/diffo/provider/assigner/assignable_value.ex +++ b/lib/diffo/provider/assigner/assignable_value.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.AssignableValue do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - AssignableValue - AshTyped Struct for Assignable Characteristic Value + Ash Typed Struct for Assignable Characteristic Value """ use Ash.TypedStruct, extensions: [AshJason.TypedStruct] diff --git a/lib/diffo/provider/assigner/assigner.ex b/lib/diffo/provider/assigner/assigner.ex index 1867cca..32b47e2 100644 --- a/lib/diffo/provider/assigner/assigner.ex +++ b/lib/diffo/provider/assigner/assigner.ex @@ -4,11 +4,8 @@ defmodule Diffo.Provider.Assigner do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Assigner - Helper to perform Assignment maintaining AssignableValue + Helper to perform Assignment maintaining AssignableValue """ - alias Diffo.Provider.AssignableValue alias Diffo.Type.Value diff --git a/lib/diffo/provider/assigner/assignment.ex b/lib/diffo/provider/assigner/assignment.ex index 8103b44..9f34ea0 100644 --- a/lib/diffo/provider/assigner/assignment.ex +++ b/lib/diffo/provider/assigner/assignment.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.Assignment do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Assignment - AshTyped Struct for Assignment + Ash Typed Struct for Assignment """ use Ash.TypedStruct, extensions: [AshJason.TypedStruct] @@ -31,12 +29,18 @@ defmodule Diffo.Provider.Assignment do constraints: [one_of: [nil, :assign, :unassign, :auto_assign]] end + def compare(%__MODULE__{id: a}, %__MODULE__{id: b}) do + cond do + a < b -> :lt + a > b -> :gt + true -> :eq + end + end + defimpl String.Chars do def to_string(struct) do inspect(struct) end end - def compare(%{id: id0}, %{id: id1}), - do: Diffo.Util.compare(id0, id1) end diff --git a/lib/diffo/provider/components/base_instance.ex b/lib/diffo/provider/components/base_instance.ex index 76d04dd..6fcb5cd 100644 --- a/lib/diffo/provider/components/base_instance.ex +++ b/lib/diffo/provider/components/base_instance.ex @@ -4,9 +4,74 @@ defmodule Diffo.Provider.BaseInstance do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference + Ash Resource Fragment which is a the point of extension for your TMF Service or Resource Instance - BaseInstance - Ash Resource Fragment of a TMF Service or Resource Instance + `BaseInstance` is the foundation for domain-specific Service and Resource kinds. + Include it as a fragment on an `Ash.Resource` to get common Instance attributes, + Neo4j graph wiring, state machine, and the `Diffo.Provider.Instance.Extension` DSL. + + ## Instance Extension DSL + + The `Diffo.Provider.Instance.Extension` DSL provides compile-time declaration blocks + for describing the shape of a domain-specific Service or Resource. + + `specification do` — declares the TMF Specification for this Instance kind. + + `features do` — declares the Features this Instance kind may have, each optionally + carrying a typed characteristic payload. + + `characteristics do` — declares the top-level Characteristics of this Instance kind, + each backed by an `Ash.TypedStruct`. + + `parties do` — declares the Party roles this Instance kind relates to. Role names are + domain-specific nouns describing what the party is to the instance. Two forms: + + parties do + party :provider, MyApp.Provider, calculate: :provider_calculation + parties :installer, MyApp.Installer + parties :technician, MyApp.Technician, constraints: [min: 1, max: 3] + party :owner, MyApp.InfrastructureCo, reference: true + end + + - `party` — singular (at most one party in this role) + - `parties` — plural (unbounded, or bounded with `constraints:`) + - `reference: true` — no direct `PartyRef` edge; party is reachable by graph traversal + - `calculate:` — names an Ash calculation on this resource that produces the party at build time + + All declarations are introspectable via `Diffo.Provider.Instance.Extension.Info`. + + ## Usage + + defmodule MyApp.Cluster do + use Ash.Resource, fragments: [BaseInstance], domain: MyApp.Domain + + resource do + description "A Cluster Resource Instance" + plural_name :clusters + end + + specification do + id "4bcfc4c9-e776-4878-a658-e8d81857bed7" + name "cluster" + type :resourceSpecification + end + + parties do + party :operator, MyApp.Organization + parties :installer, MyApp.Engineer + end + end + + ## Action pattern + + Domain-specific Instance resources should finish their `build` action with a reload via + their own domain's `get_xxx_by_id` to pick up extended fields: + + create :build do + change after_action(fn changeset, result, _context -> + ActionHelper.build_after(changeset, result, MyApp.Domain, :get_cluster_by_id) + end) + end """ use Spark.Dsl.Fragment, of: Ash.Resource, diff --git a/lib/diffo/provider/components/base_party.ex b/lib/diffo/provider/components/base_party.ex index f1f3c01..3498f19 100644 --- a/lib/diffo/provider/components/base_party.ex +++ b/lib/diffo/provider/components/base_party.ex @@ -4,42 +4,88 @@ defmodule Diffo.Provider.BaseParty do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference + Ash Resource Fragment which is a the point of extension for your TMF Party - BaseParty - Ash Resource Fragment of a TMF Party + `BaseParty` is the foundation for domain-specific Party kinds such as Organization or Person. + Include it as a fragment on an `Ash.Resource` to get common Party attributes, Neo4j graph + wiring, and the `Diffo.Provider.Party.Extension` DSL. - `BaseParty` is the foundation for domain-specific Party kinds such as RSP or Person. - It provides common Party attributes and the `Diffo.Provider.Party.Extension` DSL, which - allows a Party kind to declare the roles it plays with respect to Instances and other Parties. + `Diffo.Provider.Party` uses `BaseParty` directly as the out-of-the-box TMF Party resource. + Domain-specific resources extend it for richer domain identity. + + ## Attributes + + - `id` — string primary key, defaults to a generated uuid4. Can be set by the domain to any + meaningful string (e.g. an ABN or a data centre identifier). + - `href` — optional URI for the party. + - `name` — the party name. + - `type` — TMF `@type`. Defaults to `:PartyRef`. One of `:PartyRef`, `:Individual`, + `:Organization`, `:Entity`. When `referred_type` is present, `type` must be `:PartyRef`. + - `referred_type` — TMF `@referredType`. One of `:Individual`, `:Organization`, `:Entity`. + When present, indicates this is a reference to a party of that kind; `type` must be `:PartyRef`. + + ## Party Extension DSL + + The `Diffo.Provider.Party.Extension` DSL provides two compile-time declaration blocks. + Role names are domain-specific nouns from the party's perspective — timeless, camelCase + when multi-word. + + `instances do` — declares the roles this Party kind plays with respect to Instances: + + instances do + role :operator, MyApp.Cluster + role :dataCentre, MyApp.Facility + end + + `parties do` — declares the roles this Party kind plays with respect to other Parties: + + parties do + role :employer, MyApp.Organization + end + + Both blocks are introspectable via `Diffo.Provider.Party.Extension.Info`. ## Usage - defmodule MyApp.Organisation do + defmodule MyApp.RSP do use Ash.Resource, fragments: [BaseParty], domain: MyApp.Domain resource do - description "An Organisation" - plural_name :organisations + description "A Retail Service Provider" + plural_name :rsps end - instance do - role :facilitates, MyApp.AccessService + jason do + pick [:id, :name, :type] + compact true end - end - ## Action pattern + outstanding do + expect [:id, :name, :type] + end - Domain-specific Party resources should finish their `create` action with a reload via - their own domain's `get_xxx_by_id` to pick up extended fields: + actions do + create :build do + accept [:id, :href, :name] + change set_attribute(:referred_type, :Organization) + end + end - create :create do - accept [:name] - change after_action(fn _changeset, result, _context -> - MyApp.Domain.get_organisation_by_id(result.id) - end) + instances do + role :provider, MyApp.AccessService + end end - """ + ## TMF type and referred_type + + The `type` and `referred_type` attributes map to the TMF `@type` and `@referredType` JSON + fields via the jason layer. Use the `build` action to declare the TMF identity of your + domain party — this is also the contract for how the party appears in TMF serialisation + of `relatedParty` on instances. + + - `type: :Organization` — this party IS an Organization (direct). + - `referred_type: :Organization` — this is a PartyRef pointing to an Organization. + """ use Spark.Dsl.Fragment, of: Ash.Resource, otp_app: :diffo, @@ -53,19 +99,16 @@ defmodule Diffo.Provider.BaseParty do neo4j do relate [ - {:party_refs, :RELATES, :incoming, :PartyRef} + {:party_refs, :RELATES, :incoming, :PartyRef}, + {:external_identifiers, :OWNS, :outgoing, :ExternalIdentifier}, + {:notes, :AUTHORS, :outgoing, :Note} ] - label :Party - end - - jason do - pick [:id, :name, :kind] - compact true - end + guard [ + {:OWNS, :outgoing, :ExternalIdentifier} + ] - outstanding do - expect [:id, :name, :kind] + label :Party end attributes do @@ -78,17 +121,31 @@ defmodule Diffo.Provider.BaseParty do source :key end + attribute :href, :string do + description "the href of this party" + allow_nil? true + public? true + end + attribute :name, :string do description "the name of this party" allow_nil? true public? true end - attribute :kind, :atom do - description "the kind of this party, either individual or organization" + attribute :type, :atom do + description "the type of the party" allow_nil? false public? true - constraints one_of: [:individual, :organization] + default :PartyRef + constraints one_of: [:PartyRef, :Individual, :Organization, :Entity] + end + + attribute :referred_type, :atom do + description "the type of the party" + allow_nil? true + public? true + constraints one_of: [:Individual, :Organization, :Entity] end create_timestamp :created_at @@ -102,6 +159,18 @@ defmodule Diffo.Provider.BaseParty do destination_attribute :party_id public? true end + + has_many :external_identifiers, Diffo.Provider.ExternalIdentifier do + description "the external identifiers owned by this party" + destination_attribute :owner_id + public? true + end + + has_many :notes, Diffo.Provider.Note do + description "the notes authored by this party" + destination_attribute :note_id + public? true + end end actions do @@ -109,19 +178,30 @@ defmodule Diffo.Provider.BaseParty do create :create do description "creates a party of this kind" - accept [:id, :name, :kind] + accept [:id, :href, :name, :type, :referred_type] upsert? true end update :update do description "updates the party name" - accept [:name] + accept [:href, :name, :type, :referred_type] end read :list do description "lists all parties of this kind" end + read :find_by_id do + description "finds parties by id" + get? false + + argument :query, :ci_string do + description "Return only parties with id's including the given value." + end + + filter expr(contains(id, ^arg(:query))) + end + read :find_by_name do description "finds parties by name" get? false @@ -133,4 +213,24 @@ defmodule Diffo.Provider.BaseParty do filter expr(contains(name, ^arg(:query))) end end + + validations do + validate {Diffo.Validations.HrefEndsWithId, id: :id, href: :href} do + where [present(:id), present(:href)] + end + + validate attribute_equals(:type, :PartyRef) do + where present(:referred_type) + message "when referred_type is present, type must be PartyRef" + end + + validate attribute_does_not_equal(:type, :PartyRef) do + where absent(:referred_type) + message "when referred_type is absent, type must be not be PartyRef" + end + end + + preparations do + prepare build(sort: [id: :asc, name: :asc]) + end end diff --git a/lib/diffo/provider/components/calculations/instance_href.ex b/lib/diffo/provider/components/calculations/instance_href.ex index eccc37f..70c9aac 100644 --- a/lib/diffo/provider/components/calculations/instance_href.ex +++ b/lib/diffo/provider/components/calculations/instance_href.ex @@ -3,12 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Calculations.InstanceHref do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - InstanceHref - Ash Resource Calculation for generating instance href - - """ + @moduledoc false use Ash.Resource.Calculation @impl true diff --git a/lib/diffo/provider/components/calculations/specification_href.ex b/lib/diffo/provider/components/calculations/specification_href.ex index 8382a10..ae32b4d 100644 --- a/lib/diffo/provider/components/calculations/specification_href.ex +++ b/lib/diffo/provider/components/calculations/specification_href.ex @@ -5,13 +5,7 @@ defmodule Diffo.Provider.Calculations.SpecificationHref do use Ash.Resource.Calculation - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - SpecificationHref - Ash Resource Calculation for generating specification href - - """ - + @moduledoc false @impl true def load(_query, _opts, _context), do: [:type, :tmf_version, :id] diff --git a/lib/diffo/provider/components/calculations/specification_instance_type.ex b/lib/diffo/provider/components/calculations/specification_instance_type.ex index 64cdff6..b812bc0 100644 --- a/lib/diffo/provider/components/calculations/specification_instance_type.ex +++ b/lib/diffo/provider/components/calculations/specification_instance_type.ex @@ -3,12 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Calculations.SpecificationInstanceType do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - SpecificationInstanceType - Ash Resource Calculation for generating the instance type a specification specifies - - """ + @moduledoc false use Ash.Resource.Calculation @impl true diff --git a/lib/diffo/provider/components/calculations/specification_version.ex b/lib/diffo/provider/components/calculations/specification_version.ex index fad6aee..4bb90c2 100644 --- a/lib/diffo/provider/components/calculations/specification_version.ex +++ b/lib/diffo/provider/components/calculations/specification_version.ex @@ -3,12 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Calculations.SpecificationVersion do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - SpecificationVersion - Ash Resource Calculation for generating the version of a specification - - """ + @moduledoc false use Ash.Resource.Calculation @impl true diff --git a/lib/diffo/provider/components/characteristic.ex b/lib/diffo/provider/components/characteristic.ex index 3f46f9d..64f49dd 100644 --- a/lib/diffo/provider/components/characteristic.ex +++ b/lib/diffo/provider/components/characteristic.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.Characteristic do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Characteristic - Ash Resource for a TMF Characteristic + Ash Resource for a TMF Characteristic """ use Ash.Resource, otp_app: :diffo, @@ -204,19 +202,6 @@ defmodule Diffo.Provider.Characteristic do prepare build(sort: [name: :asc]) end - @doc """ - Compares two characteristic, by ascending name - ## Examples - iex> Diffo.Provider.Characteristic.compare(%{name: "a"}, %{name: "a"}) - :eq - iex> Diffo.Provider.Characteristic.compare(%{name: "b"}, %{name: "a"}) - :gt - iex> Diffo.Provider.Characteristic.compare(%{name: "a"}, %{name: "b"}) - :lt - - """ - def compare(%{name: name0}, %{name: name1}), do: Diffo.Util.compare(name0, name1) - defimpl Diffo.Unwrap do def unwrap(%{values: values}) when is_list(values), do: Diffo.Unwrap.unwrap(values) def unwrap(%{value: value}), do: Diffo.Unwrap.unwrap(value) diff --git a/lib/diffo/provider/components/entity.ex b/lib/diffo/provider/components/entity.ex index ce736cd..ab9a017 100644 --- a/lib/diffo/provider/components/entity.ex +++ b/lib/diffo/provider/components/entity.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.Entity do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Entity - Ash Resource for a TMF Entity + Ash Resource for a TMF Entity """ use Ash.Resource, otp_app: :diffo, @@ -26,13 +24,13 @@ defmodule Diffo.Provider.Entity do end jason do - pick [:id, :href, :name, :referredType, :type] + pick [:id, :href, :name, :referred_type, :type] compact true - rename referredType: "@referredType", type: "@type" + rename referred_type: "@referredType", type: "@type" end outstanding do - expect [:id, :href, :name, :referredType, :type] + expect [:id, :href, :name, :referred_type, :type] end actions do @@ -40,7 +38,7 @@ defmodule Diffo.Provider.Entity do create :create do description "creates a entity" - accept [:id, :href, :name, :type, :referredType] + accept [:id, :href, :name, :type, :referred_type] upsert? true end @@ -72,7 +70,7 @@ defmodule Diffo.Provider.Entity do update :update do description "updates the entity" - accept [:href, :name, :type, :referredType] + accept [:href, :name, :type, :referred_type] end end @@ -104,7 +102,7 @@ defmodule Diffo.Provider.Entity do default :EntityRef end - attribute :referredType, :atom do + attribute :referred_type, :atom do description "the type of the entity" allow_nil? true public? true @@ -129,13 +127,13 @@ defmodule Diffo.Provider.Entity do end validate attribute_equals(:type, :EntityRef) do - where present(:referredType) - message "when referredType is present, type must be EntityRef" + where present(:referred_type) + message "when referred_type is present, type must be EntityRef" end validate attribute_does_not_equal(:type, :EntityRef) do - where absent(:referredType) - message "when referredType is absent, type must be not be EntityRef" + where absent(:referred_type) + message "when referred_type is absent, type must be not be EntityRef" end end @@ -143,16 +141,4 @@ defmodule Diffo.Provider.Entity do prepare build(sort: [id: :asc]) end - @doc """ - Compares two entity, by ascending id - ## Examples - iex> Diffo.Provider.Entity.compare(%{id: "a"}, %{id: "a"}) - :eq - iex> Diffo.Provider.Entity.compare(%{id: "b"}, %{id: "a"}) - :gt - iex> Diffo.Provider.Entity.compare(%{id: "a"}, %{id: "b"}) - :lt - - """ - def compare(%{id: id0}, %{id: id1}), do: Diffo.Util.compare(id0, id1) end diff --git a/lib/diffo/provider/components/entity_ref.ex b/lib/diffo/provider/components/entity_ref.ex index f85cbc3..532b3c9 100644 --- a/lib/diffo/provider/components/entity_ref.ex +++ b/lib/diffo/provider/components/entity_ref.ex @@ -4,8 +4,6 @@ defmodule Diffo.Provider.EntityRef do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - EntityRef - Ash Resource for a TMF Entity Reference """ use Ash.Resource, @@ -34,7 +32,7 @@ defmodule Diffo.Provider.EntityRef do |> Diffo.Util.extract_suppress(:entity, :id, :id) |> Diffo.Util.extract_suppress(:entity, :href, :href) |> Diffo.Util.extract_suppress(:entity, :name, :name) - |> Diffo.Util.extract_suppress(:entity, :referredType, "@referredType") + |> Diffo.Util.extract_suppress(:entity, :referred_type, "@referredType") |> Diffo.Util.extract_suppress(:entity, :type, "@type") |> Diffo.Util.remove(:party) end @@ -124,17 +122,4 @@ defmodule Diffo.Provider.EntityRef do prepare build(load: [:entity], sort: [created_at: :desc]) end - @doc """ - Compares two entity ref, by ascending entity_id - ## Examples - iex> Diffo.Provider.EntityRef.compare(%{entity_id: "a"}, %{entity_id: "a"}) - :eq - iex> Diffo.Provider.EntityRef.compare(%{entity_id: "b"}, %{entity_id: "a"}) - :gt - iex> Diffo.Provider.EntityRef.compare(%{entity_id: "a"}, %{entity_id: "b"}) - :lt - - """ - def compare(%{entity_id: entity_id0}, %{entity_id: entity_id1}), - do: Diffo.Util.compare(entity_id0, entity_id1) end diff --git a/lib/diffo/provider/components/event.ex b/lib/diffo/provider/components/event.ex index 3173273..1ec9167 100644 --- a/lib/diffo/provider/components/event.ex +++ b/lib/diffo/provider/components/event.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.Event do @moduledoc """ - Diffo - TMF Service and Reource Management with a difference - - Event - Ash Resource for a TMF Event + Ash Resource for a TMF Event """ use Ash.Resource, otp_app: :diffo, @@ -156,17 +154,4 @@ defmodule Diffo.Provider.Event do ) end - @doc """ - Compares two event, by id - ## Examples - iex> Diffo.Provider.Event.compare(%{id: "a"}, %{id: "a"}) - :eq - iex> Diffo.Provider.Event.compare(%{id: "b"}, %{id: "a"}) - :gt - iex> Diffo.Provider.Event.compare(%{id: "a"}, %{id: "b"}) - :lt - - """ - def compare(%{id: id0}, %{id: id1}), - do: Diffo.Util.compare(id0, id1) end diff --git a/lib/diffo/provider/components/external_identifier.ex b/lib/diffo/provider/components/external_identifier.ex index 63f09b6..4bd7702 100644 --- a/lib/diffo/provider/components/external_identifier.ex +++ b/lib/diffo/provider/components/external_identifier.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.ExternalIdentifier do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - ExternalIdentifier - Ash Resource for a TMF ExternalIdentifier + Ash Resource for a TMF ExternalIdentifier """ use Ash.Resource, otp_app: :diffo, @@ -147,17 +145,4 @@ defmodule Diffo.Provider.ExternalIdentifier do prepare build(load: [:owner], sort: [created_at: :desc]) end - @doc """ - Compares two external identifier, by most recent insertion order - ## Examples - iex> Diffo.Provider.ExternalIdentifier.compare(%{created_at: "a"}, %{created_at: "a"}) - :eq - iex> Diffo.Provider.ExternalIdentifier.compare(%{created_at: "b"}, %{created_at: "a"}) - :gt - iex> Diffo.Provider.ExternalIdentifier.compare(%{created_at: "a"}, %{created_at: "b"}) - :lt - - """ - def compare(%{created_at: created_at0}, %{created_at: created_at1}), - do: Diffo.Util.compare(created_at0, created_at1) end diff --git a/lib/diffo/provider/components/feature.ex b/lib/diffo/provider/components/feature.ex index 3300781..505c72b 100644 --- a/lib/diffo/provider/components/feature.ex +++ b/lib/diffo/provider/components/feature.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.Feature do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Feature - Ash Resource for a TMF Feature + Ash Resource for a TMF Feature """ use Ash.Resource, otp_app: :diffo, @@ -138,16 +136,4 @@ defmodule Diffo.Provider.Feature do prepare build(load: [:characteristics], sort: [name: :asc]) end - @doc """ - Compares two feature, by ascending name - ## Examples - iex> Diffo.Provider.Feature.compare(%{name: "a"}, %{name: "a"}) - :eq - iex> Diffo.Provider.Feature.compare(%{name: "b"}, %{name: "a"}) - :gt - iex> Diffo.Provider.Feature.compare(%{name: "a"}, %{name: "b"}) - :lt - - """ - def compare(%{name: name0}, %{name: name1}), do: Diffo.Util.compare(name0, name1) end diff --git a/lib/diffo/provider/components/instance.ex b/lib/diffo/provider/components/instance.ex index a9d28ad..aab1d76 100644 --- a/lib/diffo/provider/components/instance.ex +++ b/lib/diffo/provider/components/instance.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.Instance do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Instance - Ash Resource for a TMF Service or Resource Instance + Ash Resource for a TMF Service or Resource Instance """ alias Diffo.Provider.BaseInstance diff --git a/lib/diffo/provider/components/instance/extension.ex b/lib/diffo/provider/components/instance/extension.ex index f353f9d..3956787 100644 --- a/lib/diffo/provider/components/instance/extension.ex +++ b/lib/diffo/provider/components/instance/extension.ex @@ -4,9 +4,15 @@ defmodule Diffo.Provider.Instance.Extension do @moduledoc """ - DSL Extension customising an Instance - """ + DSL Extension customising an Instance. + + Provides compile-time declaration blocks for domain-specific Service and Resource kinds + built on `Diffo.Provider.BaseInstance`. All declarations are introspectable via + `Diffo.Provider.Instance.Extension.Info`. + See the [DSL cheat sheet](DSL-Diffo.Provider.Instance.Extension.html) for the full DSL reference. + See `Diffo.Provider.BaseInstance` for full usage documentation. + """ @specification %Spark.Dsl.Section{ name: :specification, describe: "Defines the Instance Specification", @@ -152,26 +158,50 @@ defmodule Diffo.Provider.Instance.Extension do ] } + @party_schema [ + role: [ + doc: "The role name, an atom", + type: :atom, + required: true + ], + party_type: [ + doc: "The module of the Party kind. An atom module name such as a BaseParty-derived resource.", + type: :any + ], + reference: [ + doc: "If true, no direct PartyRef edge is created; the party is reachable by graph traversal.", + type: :boolean, + default: false + ], + calculate: [ + doc: "Name of an Ash calculation on this resource that produces the party at build time.", + type: :atom + ] + ] + @party_entity %Spark.Dsl.Entity{ name: :party, - describe: "Declares a party role on this Instance", + describe: "Declares a singular party role on this Instance", target: Diffo.Provider.Instance.Extension.PartyDeclaration, args: [:role, :party_type], - schema: [ - role: [ - doc: """ - The role name, an atom - """, - type: :atom, - required: true - ], - party_type: [ - doc: """ - The module of the Party kind. An atom module name such as a BaseParty-derived resource. - """, - type: :any - ] - ] + auto_set_fields: [multiple: false], + schema: @party_schema + } + + @parties_entity %Spark.Dsl.Entity{ + name: :parties, + describe: "Declares a plural party role on this Instance", + target: Diffo.Provider.Instance.Extension.PartyDeclaration, + args: [:role, :party_type], + auto_set_fields: [multiple: true], + schema: + @party_schema ++ + [ + constraints: [ + doc: "Multiplicity constraints on the number of parties in this role, e.g. [min: 1, max: 3]", + type: :keyword_list + ] + ] } @parties %Spark.Dsl.Section{ @@ -180,13 +210,15 @@ defmodule Diffo.Provider.Instance.Extension do examples: [ """ parties do - party :facilitated_by, MyApp.Rsp - party :overseen_by, MyApp.Person + party :provider, MyApp.Provider, calculate: :provider_calculation + parties :technician, MyApp.Technician, constraints: [min: 1, max: 3] + party :owner, MyApp.InfrastructureCo, reference: true end """ ], entities: [ - @party_entity + @party_entity, + @parties_entity ] } diff --git a/lib/diffo/provider/components/instance/extension/action_helper.ex b/lib/diffo/provider/components/instance/extension/action_helper.ex index 39df01e..8dfa7c1 100644 --- a/lib/diffo/provider/components/instance/extension/action_helper.ex +++ b/lib/diffo/provider/components/instance/extension/action_helper.ex @@ -3,12 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Instance.ActionHelper do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - ActionHelper - helping with Instance actions - """ - + @moduledoc false alias Diffo.Provider.Instance.Specification alias Diffo.Provider.Instance.Relationship alias Diffo.Provider.Instance.Feature @@ -24,6 +19,7 @@ defmodule Diffo.Provider.Instance.ActionHelper do |> Specification.set_specified_by_argument() |> Feature.set_features_argument() |> Characteristic.set_characteristics_argument() + |> Party.validate_parties() end @doc """ diff --git a/lib/diffo/provider/components/instance/extension/characteristic.ex b/lib/diffo/provider/components/instance/extension/characteristic.ex index ae0a6b8..43c8d1b 100644 --- a/lib/diffo/provider/components/instance/extension/characteristic.ex +++ b/lib/diffo/provider/components/instance/extension/characteristic.ex @@ -3,12 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Instance.Characteristic do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Characteristic for Instance Extension - """ - + @moduledoc false require Logger alias Diffo.Provider diff --git a/lib/diffo/provider/components/instance/extension/feature.ex b/lib/diffo/provider/components/instance/extension/feature.ex index 85de261..9428419 100644 --- a/lib/diffo/provider/components/instance/extension/feature.ex +++ b/lib/diffo/provider/components/instance/extension/feature.ex @@ -3,12 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Instance.Feature do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Feature for Instance Extension - """ - + @moduledoc false require Logger alias Diffo.Provider diff --git a/lib/diffo/provider/components/instance/extension/party.ex b/lib/diffo/provider/components/instance/extension/party.ex index e8b808e..9505d51 100644 --- a/lib/diffo/provider/components/instance/extension/party.ex +++ b/lib/diffo/provider/components/instance/extension/party.ex @@ -3,19 +3,71 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Instance.Party do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Party for Instance Extension - """ - + @moduledoc false alias Diffo.Provider + alias Diffo.Provider.Instance.Extension.Info, as: InstanceInfo @doc """ Struct for a Party """ defstruct [:id, :role] + @doc false + def validate_parties(changeset) do + declarations = InstanceInfo.parties(changeset.resource) + + if declarations == [] do + changeset + else + parties = Ash.Changeset.get_argument(changeset, :parties) || [] + changeset + |> validate_roles(parties, declarations) + |> validate_constraints(parties, declarations) + end + end + + defp validate_roles(changeset, parties, declarations) do + declared_roles = MapSet.new(declarations, & &1.role) + + Enum.reduce(parties, changeset, fn %{role: role}, cs -> + if MapSet.member?(declared_roles, role) do + cs + else + Ash.Changeset.add_error(cs, + field: :parties, + message: "role #{inspect(role)} is not declared on this resource" + ) + end + end) + end + + defp validate_constraints(changeset, parties, declarations) do + counts = Enum.frequencies_by(parties, & &1.role) + + declarations + |> Enum.reject(&(&1.reference || &1.calculate)) + |> Enum.reduce(changeset, fn decl, cs -> + count = Map.get(counts, decl.role, 0) + constraints = decl.constraints || [] + + cs + |> check_min(decl.role, count, Keyword.get(constraints, :min)) + |> check_max(decl.role, count, Keyword.get(constraints, :max)) + end) + end + + defp check_min(cs, _role, _count, nil), do: cs + defp check_min(cs, _role, count, min) when count >= min, do: cs + defp check_min(cs, role, count, min), + do: Ash.Changeset.add_error(cs, field: :parties, + message: "role #{inspect(role)} requires at least #{min} (got #{count})") + + defp check_max(cs, _role, _count, nil), do: cs + defp check_max(cs, _role, count, max) when count <= max, do: cs + defp check_max(cs, role, count, max), + do: Ash.Changeset.add_error(cs, field: :parties, + message: "role #{inspect(role)} allows at most #{max} (got #{count})") + @doc """ Relates the parties in the changeset with the Extended Instance by creating party_ref """ diff --git a/lib/diffo/provider/components/instance/extension/party_declaration.ex b/lib/diffo/provider/components/instance/extension/party_declaration.ex index 69fb67d..e1cff0c 100644 --- a/lib/diffo/provider/components/instance/extension/party_declaration.ex +++ b/lib/diffo/provider/components/instance/extension/party_declaration.ex @@ -4,12 +4,10 @@ defmodule Diffo.Provider.Instance.Extension.PartyDeclaration do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - PartyDeclaration - DSL entity declaring a party role on an Instance """ - - defstruct [:role, :party_type, __spark_metadata__: nil] + defstruct [:role, :party_type, :multiple, :reference, :calculate, :constraints, + __spark_metadata__: nil] defimpl String.Chars do def to_string(struct), do: inspect(struct) diff --git a/lib/diffo/provider/components/instance/extension/place.ex b/lib/diffo/provider/components/instance/extension/place.ex index 50a3be6..14f7780 100644 --- a/lib/diffo/provider/components/instance/extension/place.ex +++ b/lib/diffo/provider/components/instance/extension/place.ex @@ -3,12 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Instance.Place do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Place for Instance Extension - """ - + @moduledoc false alias Diffo.Provider @doc """ diff --git a/lib/diffo/provider/components/instance/extension/relationship.ex b/lib/diffo/provider/components/instance/extension/relationship.ex index 18e2b95..3d9a54e 100644 --- a/lib/diffo/provider/components/instance/extension/relationship.ex +++ b/lib/diffo/provider/components/instance/extension/relationship.ex @@ -3,12 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Instance.Relationship do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Relationship for Instance Extension - """ - + @moduledoc false alias Diffo.Provider @doc """ diff --git a/lib/diffo/provider/components/instance/extension/specification.ex b/lib/diffo/provider/components/instance/extension/specification.ex index 9469784..8f5720a 100644 --- a/lib/diffo/provider/components/instance/extension/specification.ex +++ b/lib/diffo/provider/components/instance/extension/specification.ex @@ -3,11 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Instance.Specification do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Specification for Instance Extension - """ + @moduledoc false require Logger alias Diffo.Provider diff --git a/lib/diffo/provider/components/instance/util.ex b/lib/diffo/provider/components/instance/util.ex index 6251caf..ad5a604 100644 --- a/lib/diffo/provider/components/instance/util.ex +++ b/lib/diffo/provider/components/instance/util.ex @@ -3,15 +3,8 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Instance.Util do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Util - Methods of general utility to an Instance - """ - - @doc """ - Assists in encoding instance category - """ + @moduledoc false + @doc false def category(result, record) do specification = Map.get(record, :specification) @@ -28,9 +21,7 @@ defmodule Diffo.Provider.Instance.Util do end end - @doc """ - Assists in encoding instance description - """ + @doc false def description(result, record) do specification = Map.get(record, :specification) @@ -47,9 +38,7 @@ defmodule Diffo.Provider.Instance.Util do end end - @doc """ - Assists in encoding instance dates - """ + @doc false def dates(result, record) do result |> Diffo.Util.set( @@ -66,9 +55,7 @@ defmodule Diffo.Provider.Instance.Util do ) end - @doc """ - Assists in encoding instance states - """ + @doc false def states(result, record) do case record.type do :service -> @@ -85,9 +72,7 @@ defmodule Diffo.Provider.Instance.Util do end end - @doc """ - Assists in encoding instance-instance relationships - """ + @doc false def relationships(result) do if relationships = Diffo.Util.get(result, :forward_relationships) do service_relationships = @@ -134,16 +119,7 @@ defmodule Diffo.Provider.Instance.Util do end end - @doc """ - Derives the type prefix from the specification type - ## Examples - iex> Diffo.Provider.Instance.derive_type(:serviceSpecification) - :service - - iex> Diffo.Provider.Instance.derive_type(:resourceSpecification) - :resource - - """ + @doc false def derive_type(specification_type) do case specification_type do :serviceSpecification -> :service @@ -152,16 +128,7 @@ defmodule Diffo.Provider.Instance.Util do end end - @doc """ - Derives the instance feature list name from the instance type - ## Examples - iex> Diffo.Provider.Instance.derive_feature_list_name(:service) - :feature - - iex> Diffo.Provider.Instance.derive_feature_list_name(:resource) - :activationFeature - - """ + @doc false def derive_feature_list_name(type) do case type do :service -> :feature @@ -170,16 +137,7 @@ defmodule Diffo.Provider.Instance.Util do end end - @doc """ - Derives the instance characteristic list name from the instance type - ## Examples - iex> Diffo.Provider.Instance.derive_characteristic_list_name(:service) - :serviceCharacteristic - - iex> Diffo.Provider.Instance.derive_characteristic_list_name(:resource) - :resourceCharacteristic - - """ + @doc false def derive_characteristic_list_name(type) do case type do :service -> :serviceCharacteristic @@ -188,17 +146,7 @@ defmodule Diffo.Provider.Instance.Util do end end - @doc """ - Derives the instance create date name from the instance type - ## Examples - iex> Diffo.Provider.Instance.derive_create_date_name(:service) - :serviceDate - - iex> Diffo.Provider.Instance.derive_create_date_name(:resource) - nil - - """ - + @doc false def derive_create_date_name(type) do case type do :service -> :serviceDate @@ -206,17 +154,7 @@ defmodule Diffo.Provider.Instance.Util do end end - @doc """ - Derives the instance start date name from the instance type - ## Examples - iex> Diffo.Provider.Instance.derive_start_date_name(:service) - :startDate - - iex> Diffo.Provider.Instance.derive_start_date_name(:resource) - :startOperatingDate - - """ - + @doc false def derive_start_date_name(type) do case type do :service -> :startDate @@ -225,17 +163,7 @@ defmodule Diffo.Provider.Instance.Util do end end - @doc """ - Derives the instance end date name from the instance type - ## Examples - iex> Diffo.Provider.Instance.derive_end_date_name(:service) - :endDate - - iex> Diffo.Provider.Instance.derive_end_date_name(:resource) - :endOperatingDate - - """ - + @doc false def derive_end_date_name(type) do case type do :service -> :endDate @@ -244,17 +172,7 @@ defmodule Diffo.Provider.Instance.Util do end end - @doc """ - Given which returns the other which - ## Examples - iex> Diffo.Provider.Instance.other(:actual) - :expected - - iex> Diffo.Provider.Instance.other(:expected) - :actual - - """ - + @doc false def other(which) do case which do :actual -> :expected @@ -263,16 +181,4 @@ defmodule Diffo.Provider.Instance.Util do end end - @doc """ - Compares two instances, by ascending href - ## Examples - iex> compare(%{href: "a"}, %{href: "a"}) - :eq - iex> compare(%{href: "b"}, %{href: "a"}) - :gt - iex> compare(%{href: "a"}, %{href: "b"}) - :lt - - """ - def compare(%{href: href0}, %{href: href1}), do: Diffo.Util.compare(href0, href1) end diff --git a/lib/diffo/provider/components/note.ex b/lib/diffo/provider/components/note.ex index be1e95b..7cc4aaf 100644 --- a/lib/diffo/provider/components/note.ex +++ b/lib/diffo/provider/components/note.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.Note do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Note - Ash Resource for a TMF Note + Ash Resource for a TMF Note """ use Ash.Resource, otp_app: :diffo, @@ -151,17 +149,4 @@ defmodule Diffo.Provider.Note do prepare build(load: [:author], sort: [timestamp: :desc]) end - @doc """ - Compares two note, by most recent insertion order - ## Examples - iex> Diffo.Provider.Note.compare(%{timestamp: "a"}, %{timestamp: "a"}) - :eq - iex> Diffo.Provider.Note.compare(%{timestamp: "b"}, %{timestamp: "a"}) - :gt - iex> Diffo.Provider.Note.compare(%{timestamp: "a"}, %{timestamp: "b"}) - :lt - - """ - def compare(%{timestamp: timestamp0}, %{timestamp: timestamp1}), - do: Diffo.Util.compare(timestamp0, timestamp1) end diff --git a/lib/diffo/provider/components/party.ex b/lib/diffo/provider/components/party.ex index afee95f..2226e38 100644 --- a/lib/diffo/provider/components/party.ex +++ b/lib/diffo/provider/components/party.ex @@ -4,176 +4,37 @@ defmodule Diffo.Provider.Party do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference + Ash Resource for a TMF Party - Party - Ash Resource for a TMF Party + The out-of-the-box TMF Party resource. Uses `BaseParty` as a fragment and adds + JSON serialisation with TMF `@type` / `@referredType` key mapping and outstanding + validation covering the core TMF Party fields. + + Use `Diffo.Provider.Party` directly via the `Diffo.Provider` domain when working with + generic TMF parties (e.g. party refs on instances). For domain-specific parties with + richer identity — such as an RSP or a Customer — extend `BaseParty` directly in your + own domain and define a `build` action that sets `type` or `referred_type` appropriately. + + See `Diffo.Provider.BaseParty` for full usage documentation. """ + alias Diffo.Provider.BaseParty + use Ash.Resource, - otp_app: :diffo, - domain: Diffo.Provider, - data_layer: AshNeo4j.DataLayer, - extensions: [AshOutstanding.Resource, AshJason.Resource] + fragments: [BaseParty], + domain: Diffo.Provider resource do description "An Ash Resource for a TMF Party" plural_name :parties end - neo4j do - relate [ - {:party_refs, :RELATES, :incoming, :PartyRef}, - {:external_identifiers, :OWNS, :outgoing, :ExternalIdentifier}, - {:notes, :AUTHORS, :outgoing, :Note} - ] - - guard [ - {:OWNS, :outgoing, :ExternalIdentifier} - ] - end - jason do - pick [:id, :href, :name, :referredType, :type] + pick [:id, :href, :name, :referred_type, :type] compact true - rename referredType: "@referredType", type: "@type" + rename referred_type: "@referredType", type: "@type" end outstanding do - expect [:id, :name, :referredType, :type] - end - - actions do - defaults [:read, :destroy] - - create :create do - description "creates a party" - accept [:id, :href, :name, :type, :referredType] - upsert? true - end - - read :find_by_id do - description "finds party by id" - get? false - - argument :query, :ci_string do - description "Return only parties with id's including the given value." - end - - filter expr(contains(id, ^arg(:query))) - end - - read :find_by_name do - description "finds party by name" - get? false - - argument :query, :ci_string do - description "Return only parties with names including the given value." - end - - filter expr(contains(name, ^arg(:query))) - end - - read :list do - description "lists all parties" - end - - update :update do - description "updates the party" - accept [:href, :name, :type, :referredType] - end - end - - attributes do - attribute :id, :string do - description "the unique id of the party" - primary_key? true - allow_nil? false - public? true - source :key - end - - attribute :href, :string do - description "the href of the party" - allow_nil? true - public? true - end - - attribute :name, :string do - description "the name of the party" - allow_nil? true - public? true - constraints match: ~r/^[a-zA-Z0-9\s._-]+$/ - end - - attribute :type, :atom do - description "the type of the party" - allow_nil? false - public? true - default :PartyRef - constraints one_of: [:PartyRef, :Individual, :Organization, :Entity] - end - - attribute :referredType, :atom do - description "the type of the party" - allow_nil? true - public? true - constraints one_of: [:Individual, :Organization, :Entity] - end - - create_timestamp :created_at - - update_timestamp :updated_at - end - - relationships do - has_many :party_refs, Diffo.Provider.PartyRef do - description "the party refs relating this party to instances" - destination_attribute :party_id - public? true - end - - has_many :external_identifiers, Diffo.Provider.ExternalIdentifier do - description "the external identifiers owned by this party" - destination_attribute :owner_id - public? true - end - - has_many :notes, Diffo.Provider.Note do - description "the notes authored by this party" - destination_attribute :note_id - public? true - end + expect [:id, :name, :referred_type, :type] end - - validations do - validate {Diffo.Validations.HrefEndsWithId, id: :id, href: :href} do - where [present(:id), present(:href)] - end - - validate attribute_equals(:type, :PartyRef) do - where present(:referredType) - message "when referredType is present, type must be PartyRef" - end - - validate attribute_does_not_equal(:type, :PartyRef) do - where absent(:referredType) - message "when referredType is absent, type must be not be PartyRef" - end - end - - preparations do - prepare build(sort: [id: :asc, name: :asc]) - end - - @doc """ - Compares two party, by ascending id - ## Examples - iex> Diffo.Provider.Party.compare(%{id: "a"}, %{id: "a"}) - :eq - iex> Diffo.Provider.Party.compare(%{id: "b"}, %{id: "a"}) - :gt - iex> Diffo.Provider.Party.compare(%{id: "a"}, %{id: "b"}) - :lt - - """ - def compare(%{id: id0}, %{id: id1}), do: Diffo.Util.compare(id0, id1) end diff --git a/lib/diffo/provider/components/party/extension.ex b/lib/diffo/provider/components/party/extension.ex index 19fea32..865738f 100644 --- a/lib/diffo/provider/components/party/extension.ex +++ b/lib/diffo/provider/components/party/extension.ex @@ -4,9 +4,14 @@ defmodule Diffo.Provider.Party.Extension do @moduledoc """ - DSL Extension customising a Party - """ + DSL Extension customising a Party. + + Provides compile-time declaration blocks for domain-specific Party kinds + built on `Diffo.Provider.BaseParty`. All declarations are introspectable via + `Diffo.Provider.Party.Extension.Info`. + See the [DSL cheat sheet](DSL-Diffo.Provider.Party.Extension.html) for the full DSL reference. + """ @role %Spark.Dsl.Entity{ name: :role, describe: "Declares a role this Party kind plays", @@ -43,12 +48,12 @@ defmodule Diffo.Provider.Party.Extension do ] } - @instance %Spark.Dsl.Section{ - name: :instance, + @instances %Spark.Dsl.Section{ + name: :instances, describe: "Declares the roles this Party kind plays with respect to Instances", examples: [ """ - instance do + instances do role :facilitates, MyApp.AccessService end """ @@ -56,12 +61,12 @@ defmodule Diffo.Provider.Party.Extension do entities: [@role] } - @party %Spark.Dsl.Section{ - name: :party, + @parties %Spark.Dsl.Section{ + name: :parties, describe: "Declares the roles this Party kind plays with respect to other Parties", examples: [ """ - party do + parties do role :managed_by, MyApp.Person end """ @@ -70,5 +75,5 @@ defmodule Diffo.Provider.Party.Extension do } use Spark.Dsl.Extension, - sections: [@instance, @party] + sections: [@instances, @parties] end diff --git a/lib/diffo/provider/components/party/extension/info.ex b/lib/diffo/provider/components/party/extension/info.ex index 66361d7..5638989 100644 --- a/lib/diffo/provider/components/party/extension/info.ex +++ b/lib/diffo/provider/components/party/extension/info.ex @@ -5,5 +5,5 @@ defmodule Diffo.Provider.Party.Extension.Info do use Spark.InfoGenerator, extension: Diffo.Provider.Party.Extension, - sections: [:instance, :party] + sections: [:instances, :parties] end diff --git a/lib/diffo/provider/components/party/extension/instance_role.ex b/lib/diffo/provider/components/party/extension/instance_role.ex index 3a39545..ed2d81e 100644 --- a/lib/diffo/provider/components/party/extension/instance_role.ex +++ b/lib/diffo/provider/components/party/extension/instance_role.ex @@ -4,11 +4,8 @@ defmodule Diffo.Provider.Party.Extension.InstanceRole do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - InstanceRole - DSL entity declaring a role this Party kind plays with respect to Instances """ - defstruct [:role, :party_type, __spark_metadata__: nil] defimpl String.Chars do diff --git a/lib/diffo/provider/components/party/extension/party_role.ex b/lib/diffo/provider/components/party/extension/party_role.ex index d4ba2ab..fea890b 100644 --- a/lib/diffo/provider/components/party/extension/party_role.ex +++ b/lib/diffo/provider/components/party/extension/party_role.ex @@ -4,11 +4,8 @@ defmodule Diffo.Provider.Party.Extension.PartyRole do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - PartyRole - DSL entity declaring a role this Party kind plays with respect to other Parties """ - defstruct [:role, :party_type, __spark_metadata__: nil] defimpl String.Chars do diff --git a/lib/diffo/provider/components/party_ref.ex b/lib/diffo/provider/components/party_ref.ex index f534ad4..1d041df 100644 --- a/lib/diffo/provider/components/party_ref.ex +++ b/lib/diffo/provider/components/party_ref.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.PartyRef do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - PartyRef - Ash Resource for a TMF PartyRef + Ash Resource for a TMF PartyRef """ use Ash.Resource, otp_app: :diffo, @@ -36,7 +34,7 @@ defmodule Diffo.Provider.PartyRef do |> Diffo.Util.extract_suppress(:party, :id, :id) |> Diffo.Util.extract_suppress(:party, :href, :href) |> Diffo.Util.extract_suppress(:party, :name, :name) - |> Diffo.Util.extract_suppress(:party, :referredType, "@referredType") + |> Diffo.Util.extract_suppress(:party, :referred_type, "@referredType") |> Diffo.Util.extract_suppress(:party, :type, "@type") |> Diffo.Util.remove(:party) end @@ -45,7 +43,7 @@ defmodule Diffo.Provider.PartyRef do end outstanding do - expect [:party_id, :name, :role, :referredType, :type] + expect [:party_id, :name, :role, :referred_type, :type] end actions do @@ -203,17 +201,4 @@ defmodule Diffo.Provider.PartyRef do end end - @doc """ - Compares two party ref, by ascending party_id - ## Examples - iex> Diffo.Provider.PartyRef.compare(%{party_id: "a"}, %{party_id: "a"}) - :eq - iex> Diffo.Provider.PartyRef.compare(%{party_id: "b"}, %{party_id: "a"}) - :gt - iex> Diffo.Provider.PartyRef.compare(%{party_id: "a"}, %{party_id: "b"}) - :lt - - """ - def compare(%{party_id: party_id0}, %{party_id: party_id1}), - do: Diffo.Util.compare(party_id0, party_id1) end diff --git a/lib/diffo/provider/components/place.ex b/lib/diffo/provider/components/place.ex index 98ddca1..5210a37 100644 --- a/lib/diffo/provider/components/place.ex +++ b/lib/diffo/provider/components/place.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.Place do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Place - Ash Resource for a TMF Place + Ash Resource for a TMF Place """ use Ash.Resource, otp_app: :diffo, @@ -26,13 +24,13 @@ defmodule Diffo.Provider.Place do end jason do - pick [:id, :href, :name, :referredType, :type] + pick [:id, :href, :name, :referred_type, :type] compact true - rename referredType: "@referredType", type: "@type" + rename referred_type: "@referredType", type: "@type" end outstanding do - expect [:id, :name, :referredType, :type] + expect [:id, :name, :referred_type, :type] end actions do @@ -40,7 +38,7 @@ defmodule Diffo.Provider.Place do create :create do description "creates a place" - accept [:id, :href, :name, :type, :referredType] + accept [:id, :href, :name, :type, :referred_type] upsert? true end @@ -72,7 +70,7 @@ defmodule Diffo.Provider.Place do update :update do description "updates the place" - accept [:href, :name, :type, :referredType] + accept [:href, :name, :type, :referred_type] end end @@ -106,7 +104,7 @@ defmodule Diffo.Provider.Place do constraints one_of: [:PlaceRef, :GeographicSite, :GeographicLocation, :GeographicAddress] end - attribute :referredType, :atom do + attribute :referred_type, :atom do description "the type of the place" allow_nil? true public? true @@ -132,13 +130,13 @@ defmodule Diffo.Provider.Place do end validate attribute_equals(:type, :PlaceRef) do - where present(:referredType) - message "when referredType is present, type must be PlaceRef" + where present(:referred_type) + message "when referred_type is present, type must be PlaceRef" end validate attribute_does_not_equal(:type, :PlaceRef) do - where absent(:referredType) - message "when referredType is absent, type must be not be PlaceRef" + where absent(:referred_type) + message "when referred_type is absent, type must be not be PlaceRef" end end @@ -146,16 +144,4 @@ defmodule Diffo.Provider.Place do prepare build(sort: [id: :asc, name: :asc]) end - @doc """ - Compares two place, by ascending id - ## Examples - iex> Diffo.Provider.Place.compare(%{id: "a"}, %{id: "a"}) - :eq - iex> Diffo.Provider.Place.compare(%{id: "b"}, %{id: "a"}) - :gt - iex> Diffo.Provider.Place.compare(%{id: "a"}, %{id: "b"}) - :lt - - """ - def compare(%{id: id0}, %{id: id1}), do: Diffo.Util.compare(id0, id1) end diff --git a/lib/diffo/provider/components/place_ref.ex b/lib/diffo/provider/components/place_ref.ex index 659e159..a2acd0b 100644 --- a/lib/diffo/provider/components/place_ref.ex +++ b/lib/diffo/provider/components/place_ref.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.PlaceRef do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - PlaceRef - Ash Resource for a TMF Place Reference + Ash Resource for a TMF Place Reference """ use Ash.Resource, otp_app: :diffo, @@ -36,7 +34,7 @@ defmodule Diffo.Provider.PlaceRef do |> Diffo.Util.extract_suppress(:place, :id, :id) |> Diffo.Util.extract_suppress(:place, :href, :href) |> Diffo.Util.extract_suppress(:place, :name, :name) - |> Diffo.Util.extract_suppress(:place, :referredType, "@referredType") + |> Diffo.Util.extract_suppress(:place, :referred_type, "@referredType") |> Diffo.Util.extract_suppress(:place, :type, "@type") |> Diffo.Util.remove(:place) end @@ -172,17 +170,4 @@ defmodule Diffo.Provider.PlaceRef do ) end - @doc """ - Compares two place ref, by ascending place_id - ## Examples - iex> Diffo.Provider.PlaceRef.compare(%{place_id: "a"}, %{place_id: "a"}) - :eq - iex> Diffo.Provider.PlaceRef.compare(%{place_id: "b"}, %{place_id: "a"}) - :gt - iex> Diffo.Provider.PlaceRef.compare(%{place_id: "a"}, %{place_id: "b"}) - :lt - - """ - def compare(%{place_id: place_id0}, %{place_id: place_id1}), - do: Diffo.Util.compare(place_id0, place_id1) end diff --git a/lib/diffo/provider/components/process_status.ex b/lib/diffo/provider/components/process_status.ex index 007b3d0..6843260 100644 --- a/lib/diffo/provider/components/process_status.ex +++ b/lib/diffo/provider/components/process_status.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.ProcessStatus do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - ProcessStatus - Ash Resource for a TMF ProcessStatus + Ash Resource for a TMF ProcessStatus """ use Ash.Resource, otp_app: :diffo, @@ -127,17 +125,4 @@ defmodule Diffo.Provider.ProcessStatus do prepare build(sort: [timestamp: :desc]) end - @doc """ - Compares two process status, by timestamp - ## Examples - iex> Diffo.Provider.ProcessStatus.compare(%{timestamp: "a"}, %{timestamp: "a"}) - :eq - iex> Diffo.Provider.ProcessStatus.compare(%{timestamp: "b"}, %{timestamp: "a"}) - :gt - iex> Diffo.Provider.ProcessStatus.compare(%{timestamp: "a"}, %{timestamp: "b"}) - :lt - - """ - def compare(%{timestamp: timestamp0}, %{timestamp: timestamp1}), - do: Diffo.Util.compare(timestamp0, timestamp1) end diff --git a/lib/diffo/provider/components/relationship.ex b/lib/diffo/provider/components/relationship.ex index 5de0e6a..28ceb03 100644 --- a/lib/diffo/provider/components/relationship.ex +++ b/lib/diffo/provider/components/relationship.ex @@ -4,10 +4,8 @@ defmodule Diffo.Provider.Relationship do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Relationship - Ash Resource for a TMF Service or Resource Relationship + Ash Resource for a TMF Service or Resource Relationship """ use Ash.Resource, otp_app: :diffo, diff --git a/lib/diffo/provider/components/specification.ex b/lib/diffo/provider/components/specification.ex index 5d29493..09d60e8 100644 --- a/lib/diffo/provider/components/specification.ex +++ b/lib/diffo/provider/components/specification.ex @@ -4,9 +4,7 @@ defmodule Diffo.Provider.Specification do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Specification - Ash Resource for a TMF Service or Resource Specification + Ash Resource for a TMF Service or Resource Specification """ require Ash.Resource.Change.Builtins diff --git a/lib/diffo/provider/outstanding.ex b/lib/diffo/provider/outstanding.ex index c89730d..a96c935 100644 --- a/lib/diffo/provider/outstanding.ex +++ b/lib/diffo/provider/outstanding.ex @@ -3,22 +3,8 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Outstanding do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - - Outstanding - utilities relating to Outstanding - """ - - @doc """ - Accumulates outstanding instance with list by key - Outstanding, expected and actual are Diffo.Provider.Instance structs - ## Examples - iex> expected_instance = %Diffo.Provider.Instance{parties: [%Diffo.Provider.PartyRef{role: :Consumer, party: %Diffo.Provider.Party{id: nil, name: nil, type: "PartyRef", referredType: "Entity"}}]} - iex> actual_instance = %Diffo.Provider.Instance{parties: [%Diffo.Provider.PartyRef{role: :Consumer, party: %Diffo.Provider.Party{id: "T5_CONNECTIVITY", name: nil, type: "PartyRef", referredType: "Entity"}}]} - iex> Diffo.Provider.Outstanding.instance_list_by_key(nil, expected_instance, actual_instance, :parties, :role) - nil - """ + @moduledoc false + @doc false def instance_list_by_key(outstanding, expected, actual, list, key) do # assemble keyword lists of expected and actual lists expected_keywords = diff --git a/lib/diffo/provider/reference.ex b/lib/diffo/provider/reference.ex index cef59f9..4f79f27 100644 --- a/lib/diffo/provider/reference.ex +++ b/lib/diffo/provider/reference.ex @@ -3,35 +3,17 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Reference do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - - Reference - utilities relating to reference - """ - + @moduledoc false defstruct id: nil, href: nil - @doc """ - Creates a reference struct from an instance with id and href - ## Examples - iex> instance = %{id: "8bcfbf9a-34a5-427a-8eae-5c3812466432", href: "serviceInventoryManagement/v4/service/8bcfbf9a-34a5-427a-8eae-5c3812466432"} - iex> Diffo.Provider.Reference.reference(instance) - %Diffo.Provider.Reference{id: "8bcfbf9a-34a5-427a-8eae-5c3812466432", href: "serviceInventoryManagement/v4/service/8bcfbf9a-34a5-427a-8eae-5c3812466432"} - """ + @doc false def reference(instance) when is_map(instance) do %Diffo.Provider.Reference{id: instance.id, href: instance.href} end def reference(instance) when is_nil(instance), do: nil - @doc """ - Creates a reference struct from an instance attribute containing a href - ## Examples - iex> instance = %{target_href: "serviceInventoryManagement/v4/service/8bcfbf9a-34a5-427a-8eae-5c3812466432"} - iex> Diffo.Provider.Reference.reference(instance, :target_href) - %Diffo.Provider.Reference{id: "8bcfbf9a-34a5-427a-8eae-5c3812466432", href: "serviceInventoryManagement/v4/service/8bcfbf9a-34a5-427a-8eae-5c3812466432"} - """ + @doc false def reference(instance, attribute) when is_map(instance) and is_atom(attribute) do href = Map.get(instance, attribute) %Diffo.Provider.Reference{id: Diffo.Uuid.trailing_uuid4(href), href: href} diff --git a/lib/diffo/provider/service.ex b/lib/diffo/provider/service.ex index d03aba8..3587681 100644 --- a/lib/diffo/provider/service.ex +++ b/lib/diffo/provider/service.ex @@ -3,13 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Provider.Service do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - - Service - utilities relating to service - """ - + @moduledoc false def service_states() do [ :initial, diff --git a/lib/diffo/repo.ex b/lib/diffo/repo.ex index 937cfec..a4ab6ab 100644 --- a/lib/diffo/repo.ex +++ b/lib/diffo/repo.ex @@ -3,13 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Repo do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - - Repo - persistance - """ - + @moduledoc false use GenServer def init(init_arg) do diff --git a/lib/diffo/type/dynamic.ex b/lib/diffo/type/dynamic.ex index 2407d95..569626f 100644 --- a/lib/diffo/type/dynamic.ex +++ b/lib/diffo/type/dynamic.ex @@ -3,8 +3,6 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Type.Dynamic do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - `Diffo.Type.Dynamic` is an `Ash.Type.NewType` for values whose exact type is not known until runtime. The `:type` field holds the `Ash.Type.NewType` module and `:value` holds the cast value. @@ -14,6 +12,7 @@ defmodule Diffo.Type.Dynamic do In practice, `Diffo.Type.Dynamic` is used as a member of `Diffo.Type.Value` and is not typically used as a standalone attribute type. + Outstanding comparison is implemented inline via `defoutstanding`. ## Nil handling @@ -53,7 +52,6 @@ defmodule Diffo.Type.Dynamic do iex> Diffo.Type.Dynamic.dynamic_constraints(nil) [] """ - defstruct [:type, :value] @type_field_constraints [ @@ -75,10 +73,11 @@ defmodule Diffo.Type.Dynamic do subtype_of: :struct, constraints: @constraints + use Outstand + @doc """ Returns the dynamic constraints from dynamic struct or map """ - def dynamic_constraints(nil), do: [] def dynamic_constraints(%{type: type}) when is_atom(type), do: dynamic_constraints(type) @@ -196,4 +195,31 @@ defmodule Diffo.Type.Dynamic do value |> Diffo.Unwrap.unwrap() |> Jason.Encode.value(opts) end end + + defoutstanding expected :: Diffo.Type.Dynamic, actual :: Any do + type_outstanding = + case actual do + %{type: type} -> Outstanding.outstanding(expected.type, type) + _ -> expected.type + end + + value_outstanding = + case actual do + %{} -> + Outstanding.outstanding( + Diffo.Unwrap.unwrap(expected), + Diffo.Unwrap.unwrap(actual) + ) + + _ -> + Diffo.Unwrap.unwrap(expected) + end + + case {type_outstanding, value_outstanding} do + {nil, nil} -> nil + {nil, _} -> %Diffo.Type.Dynamic{type: nil, value: value_outstanding} + {_, nil} -> %Diffo.Type.Dynamic{type: type_outstanding, value: nil} + {_, _} -> %Diffo.Type.Dynamic{type: type_outstanding, value: value_outstanding} + end + end end diff --git a/lib/diffo/type/outstanding/dynamic.ex b/lib/diffo/type/outstanding/dynamic.ex deleted file mode 100644 index fdf3647..0000000 --- a/lib/diffo/type/outstanding/dynamic.ex +++ /dev/null @@ -1,32 +0,0 @@ -# SPDX-FileCopyrightText: 2025 diffo contributors -# -# SPDX-License-Identifier: MIT - -use Outstand - -defoutstanding expected :: Diffo.Type.Dynamic, actual :: Any do - type_outstanding = - case actual do - %{type: type} -> Outstanding.outstanding(expected.type, type) - _ -> expected.type - end - - value_outstanding = - case actual do - %{} -> - Outstanding.outstanding( - Diffo.Unwrap.unwrap(expected), - Diffo.Unwrap.unwrap(actual) - ) - - _ -> - Diffo.Unwrap.unwrap(expected) - end - - case {type_outstanding, value_outstanding} do - {nil, nil} -> nil - {nil, _} -> %Diffo.Type.Dynamic{type: nil, value: value_outstanding} - {_, nil} -> %Diffo.Type.Dynamic{type: type_outstanding, value: nil} - {_, _} -> %Diffo.Type.Dynamic{type: type_outstanding, value: value_outstanding} - end -end diff --git a/lib/diffo/type/outstanding/primitive.ex b/lib/diffo/type/outstanding/primitive.ex deleted file mode 100644 index 30ae8ee..0000000 --- a/lib/diffo/type/outstanding/primitive.ex +++ /dev/null @@ -1,35 +0,0 @@ -# SPDX-FileCopyrightText: 2025 diffo contributors -# -# SPDX-License-Identifier: MIT - -use Outstand - -defoutstanding expected :: Diffo.Type.Primitive, actual :: Any do - # we return a map since Primitive doesn't allow type nil - type_outstanding = - case actual do - %{type: type} -> Outstanding.outstanding(expected.type, type) - nil -> expected.type - # actual is wrong type entirely - _ -> expected.type - end - - value_outstanding = - case actual do - %{} -> - Outstanding.outstanding( - Diffo.Unwrap.unwrap(expected), - Diffo.Unwrap.unwrap(actual) - ) - - _ -> - Diffo.Unwrap.unwrap(expected) - end - - case {type_outstanding, value_outstanding} do - {nil, nil} -> nil - {nil, _} -> %{value: value_outstanding} - {_, nil} -> %{type: type_outstanding} - {_, _} -> %{type: type_outstanding, value: value_outstanding} - end -end diff --git a/lib/diffo/type/primitive.ex b/lib/diffo/type/primitive.ex index 7b596ad..5082fa4 100644 --- a/lib/diffo/type/primitive.ex +++ b/lib/diffo/type/primitive.ex @@ -3,13 +3,12 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Type.Primitive do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - `Diffo.Type.Primitive` is a discriminated union of primitive types: string, integer, float, boolean, date, time, datetime, and duration. Use `wrap/2` to construct a Primitive from a type name string and a value. Use `Diffo.Unwrap.unwrap/1` to extract the value. + Outstanding comparison is implemented inline via `defoutstanding`. > #### Temporal types {: .info} > @@ -37,6 +36,7 @@ defmodule Diffo.Type.Primitive do nil """ use Ash.TypedStruct + use Outstand typed_struct do field :type, :string, description: "the primitive type discriminator" @@ -94,4 +94,34 @@ defmodule Diffo.Type.Primitive do value |> Diffo.Unwrap.unwrap() |> Jason.encode!() end end + + defoutstanding expected :: Diffo.Type.Primitive, actual :: Any do + # we return a map since Primitive doesn't allow type nil + type_outstanding = + case actual do + %{type: type} -> Outstanding.outstanding(expected.type, type) + nil -> expected.type + # actual is wrong type entirely + _ -> expected.type + end + + value_outstanding = + case actual do + %{} -> + Outstanding.outstanding( + Diffo.Unwrap.unwrap(expected), + Diffo.Unwrap.unwrap(actual) + ) + + _ -> + Diffo.Unwrap.unwrap(expected) + end + + case {type_outstanding, value_outstanding} do + {nil, nil} -> nil + {nil, _} -> %{value: value_outstanding} + {_, nil} -> %{type: type_outstanding} + {_, _} -> %{type: type_outstanding, value: value_outstanding} + end + end end diff --git a/lib/diffo/type/value.ex b/lib/diffo/type/value.ex index be97e86..43b1999 100644 --- a/lib/diffo/type/value.ex +++ b/lib/diffo/type/value.ex @@ -3,8 +3,6 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Type.Value do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - `Diffo.Type.Value` is an `Ash.Type.NewType` union that holds either a `Diffo.Type.Primitive` or a `Diffo.Type.Dynamic` value. @@ -14,6 +12,9 @@ defmodule Diffo.Type.Value do Use `primitive/2` to build a primitive value and `dynamic/1` to build a dynamic value. Use `Diffo.Unwrap.unwrap/1` on the stored `%Ash.Union{}` to extract the underlying Elixir value. + Outstanding comparison is handled by `AshOutstanding.Union`, which delegates to the inner + `Diffo.Type.Primitive` or `Diffo.Type.Dynamic` outstanding implementation. + ## Examples iex> Diffo.Type.Value.primitive("string", "connectivity") |> Diffo.Unwrap.unwrap() @@ -31,7 +32,6 @@ defmodule Diffo.Type.Value do iex> Diffo.Type.Value.primitive("date", ~D[2026-04-24]) |> Diffo.Unwrap.unwrap() "2026-04-24" """ - use Ash.Type.NewType, subtype_of: :union, constraints: [ diff --git a/lib/diffo/unwrap.ex b/lib/diffo/unwrap.ex index 2af850d..5842bb7 100644 --- a/lib/diffo/unwrap.ex +++ b/lib/diffo/unwrap.ex @@ -4,8 +4,6 @@ defprotocol Diffo.Unwrap do @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - `Diffo.Unwrap` is a protocol for extracting the underlying Elixir value from Diffo and Ash wrapper types. It is defined with `@fallback_to_any true`, so any value without an explicit implementation is returned unchanged. @@ -46,7 +44,6 @@ defprotocol Diffo.Unwrap do ...> |> Diffo.Unwrap.unwrap() [1, 2] """ - @fallback_to_any true def unwrap(value) end diff --git a/lib/diffo/unwrap/any.ex b/lib/diffo/unwrap/any.ex index 3f37943..54fafbb 100644 --- a/lib/diffo/unwrap/any.ex +++ b/lib/diffo/unwrap/any.ex @@ -3,5 +3,7 @@ # SPDX-License-Identifier: MIT defimpl Diffo.Unwrap, for: Any do + @moduledoc false + def unwrap(value), do: value end diff --git a/lib/diffo/unwrap/ash_ci_string.ex b/lib/diffo/unwrap/ash_ci_string.ex index 116bec4..0245b81 100644 --- a/lib/diffo/unwrap/ash_ci_string.ex +++ b/lib/diffo/unwrap/ash_ci_string.ex @@ -3,5 +3,7 @@ # SPDX-License-Identifier: MIT defimpl Diffo.Unwrap, for: Ash.CiString do + @moduledoc false + def unwrap(ci_string), do: Ash.CiString.to_comparable_string(ci_string) end diff --git a/lib/diffo/unwrap/ash_custom_expression.ex b/lib/diffo/unwrap/ash_custom_expression.ex index b1361d4..5bdfe54 100644 --- a/lib/diffo/unwrap/ash_custom_expression.ex +++ b/lib/diffo/unwrap/ash_custom_expression.ex @@ -3,6 +3,8 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Unwrap.AshCustomExpression do + @moduledoc false + use Ash.CustomExpression, name: :unwrap, arguments: [ diff --git a/lib/diffo/unwrap/ash_not_loaded.ex b/lib/diffo/unwrap/ash_not_loaded.ex index 4465b42..9f5d727 100644 --- a/lib/diffo/unwrap/ash_not_loaded.ex +++ b/lib/diffo/unwrap/ash_not_loaded.ex @@ -3,6 +3,8 @@ # SPDX-License-Identifier: MIT defimpl Diffo.Unwrap, for: Ash.NotLoaded do + @moduledoc false + def unwrap(%{field: field}) do raise "Diffo.Unwrap: #{field} was not loaded" end diff --git a/lib/diffo/unwrap/ash_union.ex b/lib/diffo/unwrap/ash_union.ex index 69e5933..535abd4 100644 --- a/lib/diffo/unwrap/ash_union.ex +++ b/lib/diffo/unwrap/ash_union.ex @@ -3,5 +3,7 @@ # SPDX-License-Identifier: MIT defimpl Diffo.Unwrap, for: Ash.Union do + @moduledoc false + def unwrap(%{value: value}), do: Diffo.Unwrap.unwrap(value) end diff --git a/lib/diffo/unwrap/list.ex b/lib/diffo/unwrap/list.ex index c3779eb..8fb31e6 100644 --- a/lib/diffo/unwrap/list.ex +++ b/lib/diffo/unwrap/list.ex @@ -3,5 +3,7 @@ # SPDX-License-Identifier: MIT defimpl Diffo.Unwrap, for: List do + @moduledoc false + def unwrap(list), do: Enum.map(list, &Diffo.Unwrap.unwrap/1) end diff --git a/lib/diffo/validations/href_ends_with_id.ex b/lib/diffo/validations/href_ends_with_id.ex index e8a397e..0dee15f 100644 --- a/lib/diffo/validations/href_ends_with_id.ex +++ b/lib/diffo/validations/href_ends_with_id.ex @@ -3,12 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Validations.HrefEndsWithId do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - - HrefEndsWithId - Ash Resource Validation checking href ends with id - """ + @moduledoc false use Ash.Resource.Validation @impl true diff --git a/lib/diffo/validations/is_related_different.ex b/lib/diffo/validations/is_related_different.ex index e64b10a..4b69f39 100644 --- a/lib/diffo/validations/is_related_different.ex +++ b/lib/diffo/validations/is_related_different.ex @@ -3,12 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Validations.IsRelatedDifferent do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - - IsRelatedDifferent - Ash Resource Validation checking related Instance has different attribute value - """ + @moduledoc false use Ash.Resource.Validation @impl true diff --git a/lib/diffo/validations/is_uuid4_or_nil.ex b/lib/diffo/validations/is_uuid4_or_nil.ex index 5c594f9..5e7dd7c 100644 --- a/lib/diffo/validations/is_uuid4_or_nil.ex +++ b/lib/diffo/validations/is_uuid4_or_nil.ex @@ -3,12 +3,7 @@ # SPDX-License-Identifier: MIT defmodule Diffo.Validations.IsUuid4OrNil do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - - IsUuid4OrNil - Ash Resource Validation checking uuid is v4 if supplied - """ + @moduledoc false use Ash.Resource.Validation @impl true diff --git a/logos/diffo.jpg.license b/logos/diffo.jpg.license deleted file mode 100644 index 40c9cb0..0000000 --- a/logos/diffo.jpg.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2025 diffo contributors - -SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/mix.exs b/mix.exs index c0e70ef..eacb613 100644 --- a/mix.exs +++ b/mix.exs @@ -20,14 +20,11 @@ defmodule Diffo.MixProject do elixir: "~> 1.18", start_permanent: Mix.env() == :prod, package: package(), - # ex_doc source_url: "https://github.com/diffo-dev/diffo/", homepage_url: "http://diffo.dev/diffo/", - docs: [main: "readme", extras: ["README.md"]], elixirc_paths: elixirc_paths(Mix.env()), - # hex.pm stuff - deps: deps(), docs: &docs/0, + deps: deps(), aliases: aliases(), consolidate_protocols: Mix.env() != :dev ] @@ -72,7 +69,14 @@ defmodule Diffo.MixProject do "documentation/dsls/DSL-Diffo.Provider.Instance.Extension.md": [ title: "DSL: Diffo.Provider.Instance.Extension", search_data: Spark.Docs.search_data_for(Diffo.Provider.Instance.Extension) + ], + "documentation/dsls/DSL-Diffo.Provider.Party.Extension.md": [ + title: "DSL: Diffo.Provider.Party.Extension", + search_data: Spark.Docs.search_data_for(Diffo.Provider.Party.Extension) ] + ], + groups_for_extras: [ + "DSLs": ~r/documentation\/dsls\// ] ] end diff --git a/mix.lock.license b/mix.lock.license deleted file mode 100644 index 40c9cb0..0000000 --- a/mix.lock.license +++ /dev/null @@ -1,3 +0,0 @@ -SPDX-FileCopyrightText: 2025 diffo contributors - -SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/test/instance_extension/assigner_test.exs b/test/instance_extension/assigner_test.exs index 65d5097..d03ef75 100644 --- a/test/instance_extension/assigner_test.exs +++ b/test/instance_extension/assigner_test.exs @@ -10,6 +10,7 @@ defmodule Diffo.InstanceExtension.AssignerTest do alias Diffo.Provider.Assignment alias Diffo.Test.Characteristics + alias Diffo.Test.Parties alias Diffo.Test.Servo alias Diffo.Test.Card @@ -84,7 +85,7 @@ defmodule Diffo.InstanceExtension.AssignerTest do end test "auto assign port to resource" do - {:ok, assignee} = Servo.build_shelf() + {:ok, assignee} = Parties.build_shelf_with_installer() {:ok, card} = Servo.build_card(%{}) @@ -109,7 +110,7 @@ defmodule Diffo.InstanceExtension.AssignerTest do end test "auto assign two ports to same resource" do - {:ok, assignee} = Servo.build_shelf() + {:ok, assignee} = Parties.build_shelf_with_installer() {:ok, card} = Servo.build_card(%{}) @@ -139,7 +140,7 @@ defmodule Diffo.InstanceExtension.AssignerTest do end test "specific assignment rejects duplicate request" do - {:ok, assignee} = Servo.build_shelf() + {:ok, assignee} = Parties.build_shelf_with_installer() {:ok, card} = Servo.build_card(%{}) @@ -169,7 +170,7 @@ defmodule Diffo.InstanceExtension.AssignerTest do end test "unassign an auto-assigned port from a resource" do - {:ok, assignee} = Servo.build_shelf() + {:ok, assignee} = Parties.build_shelf_with_installer() {:ok, card} = Servo.build_card(%{}) diff --git a/test/instance_extension/characteristic_test.exs b/test/instance_extension/characteristic_test.exs index 13f500b..4748c28 100644 --- a/test/instance_extension/characteristic_test.exs +++ b/test/instance_extension/characteristic_test.exs @@ -6,6 +6,7 @@ defmodule Diffo.InstanceExtension.CharacteristicTest do @moduledoc false use ExUnit.Case alias Diffo.Test.Servo + alias Diffo.Test.Parties setup_all do AshNeo4j.BoltyHelper.start() @@ -27,7 +28,7 @@ defmodule Diffo.InstanceExtension.CharacteristicTest do end test "create resource with array characteristic - success" do - {:ok, shelf} = Servo.build_shelf(%{}) + {:ok, shelf} = Parties.build_shelf_with_installer() shelves = Enum.find(shelf.characteristics, fn c -> c.name == :shelves end) assert shelves.is_array == true diff --git a/test/instance_extension/feature_test.exs b/test/instance_extension/feature_test.exs index 4cf9825..84b778f 100644 --- a/test/instance_extension/feature_test.exs +++ b/test/instance_extension/feature_test.exs @@ -6,6 +6,7 @@ defmodule Diffo.InstanceExtension.FeatureTest do @moduledoc false use ExUnit.Case alias Diffo.Test.Servo + alias Diffo.Test.Parties setup_all do AshNeo4j.BoltyHelper.start() @@ -27,7 +28,7 @@ defmodule Diffo.InstanceExtension.FeatureTest do end test "create resource with array feature characteristic - success" do - {:ok, shelf} = Servo.build_shelf(%{}) + {:ok, shelf} = Parties.build_shelf_with_installer() spectral = Enum.find(shelf.features, fn f -> f.name == :spectralManagement end) deployment_classes = Enum.find(spectral.characteristics, fn c -> c.name == :deploymentClasses end) diff --git a/test/instance_extension/party_test.exs b/test/instance_extension/party_test.exs index 9b91b9e..35deb16 100644 --- a/test/instance_extension/party_test.exs +++ b/test/instance_extension/party_test.exs @@ -8,10 +8,12 @@ defmodule Diffo.InstanceExtension.PartyTest do alias Diffo.Provider.Instance.Extension.Info, as: InstanceInfo alias Diffo.Provider.Party.Extension.Info, as: PartyInfo - alias Diffo.Test.Organisation + alias Diffo.Test.Organization alias Diffo.Test.Person alias Diffo.Test.Shelf alias Diffo.Test.Nbn + alias Diffo.Test.Servo + alias Diffo.Provider.Instance.Party setup_all do AshNeo4j.BoltyHelper.start() @@ -23,29 +25,29 @@ defmodule Diffo.InstanceExtension.PartyTest do end) end - describe "Party DSL — Organisation" do + describe "Party DSL — Organization" do test "instance roles are declared" do - roles = PartyInfo.instance(Organisation) + roles = PartyInfo.instances(Organization) assert length(roles) == 1 - assert hd(roles).role == :facilitates + assert hd(roles).role == :facilitator assert hd(roles).party_type == Diffo.Provider.Instance end test "no party roles declared" do - assert PartyInfo.party(Organisation) == [] + assert PartyInfo.parties(Organization) == [] end end describe "Party DSL — Person" do test "party roles are declared" do - roles = PartyInfo.party(Person) + roles = PartyInfo.parties(Person) assert length(roles) == 1 - assert hd(roles).role == :managed_by + assert hd(roles).role == :manager assert hd(roles).party_type == Diffo.Test.Person end test "no instance roles declared" do - assert PartyInfo.instance(Person) == [] + assert PartyInfo.instances(Person) == [] end end @@ -53,35 +55,120 @@ defmodule Diffo.InstanceExtension.PartyTest do test "party declarations are accessible via info" do parties = InstanceInfo.parties(Shelf) roles = Enum.map(parties, & &1.role) - assert :facilitated_by in roles - assert :overseen_by in roles + assert :facilitator in roles + assert :overseer in roles end test "party types are correct" do parties = InstanceInfo.parties(Shelf) - facilitated_by = Enum.find(parties, &(&1.role == :facilitated_by)) - overseen_by = Enum.find(parties, &(&1.role == :overseen_by)) - assert facilitated_by.party_type == Organisation - assert overseen_by.party_type == Person + facilitator = Enum.find(parties, &(&1.role == :facilitator)) + overseer = Enum.find(parties, &(&1.role == :overseer)) + assert facilitator.party_type == Organization + assert overseer.party_type == Person + end + + test "singular party defaults to multiple: false" do + parties = InstanceInfo.parties(Shelf) + facilitator = Enum.find(parties, &(&1.role == :facilitator)) + assert facilitator.multiple == false + end + + test "reference: true is declared" do + parties = InstanceInfo.parties(Shelf) + provider = Enum.find(parties, &(&1.role == :provider)) + assert provider.reference == true + assert provider.multiple == false + end + + test "reference defaults to false" do + parties = InstanceInfo.parties(Shelf) + facilitator = Enum.find(parties, &(&1.role == :facilitator)) + assert facilitator.reference == false + end + + test "calculate: is declared" do + parties = InstanceInfo.parties(Shelf) + manager = Enum.find(parties, &(&1.role == :manager)) + assert manager.calculate == :manager_calc + end + + test "parties (plural) sets multiple: true" do + parties = InstanceInfo.parties(Shelf) + installer = Enum.find(parties, &(&1.role == :installer)) + assert installer.multiple == true + end + + test "parties (plural) constraints are declared" do + parties = InstanceInfo.parties(Shelf) + installer = Enum.find(parties, &(&1.role == :installer)) + assert installer.constraints == [min: 1, max: 3] + end + end + + describe "Instance DSL — parties enforcement" do + setup do + {:ok, org} = Nbn.create_organization(%{name: "Acme"}) + {:ok, p1} = Nbn.create_person(%{name: "Alice"}) + {:ok, p2} = Nbn.create_person(%{name: "Bob"}) + {:ok, p3} = Nbn.create_person(%{name: "Carol"}) + {:ok, p4} = Nbn.create_person(%{name: "Dave"}) + %{org: org, p1: p1, p2: p2, p3: p3, p4: p4} + end + + test "undeclared role is rejected", %{p1: p1} do + parties = [%Party{id: p1.id, role: :unknown}] + assert {:error, _} = Servo.build_shelf(%{name: "s", parties: parties}) + end + + test "installer below min (0 < 1) is rejected" do + assert {:error, _} = Servo.build_shelf(%{name: "s", parties: []}) + end + + test "installer above max (4 > 3) is rejected", %{p1: p1, p2: p2, p3: p3, p4: p4} do + parties = [ + %Party{id: p1.id, role: :installer}, + %Party{id: p2.id, role: :installer}, + %Party{id: p3.id, role: :installer}, + %Party{id: p4.id, role: :installer} + ] + assert {:error, _} = Servo.build_shelf(%{name: "s", parties: parties}) + end + + test "valid single installer is accepted", %{org: org, p1: p1} do + parties = [ + %Party{id: org.id, role: :facilitator}, + %Party{id: p1.id, role: :installer} + ] + assert {:ok, shelf} = Servo.build_shelf(%{name: "s", parties: parties}) + assert length(shelf.parties) == 2 + end + + test "valid max installers (3) is accepted", %{p1: p1, p2: p2, p3: p3} do + parties = [ + %Party{id: p1.id, role: :installer}, + %Party{id: p2.id, role: :installer}, + %Party{id: p3.id, role: :installer} + ] + assert {:ok, _shelf} = Servo.build_shelf(%{name: "s", parties: parties}) end end - describe "BaseParty — Organisation CRUD" do - test "create and read organisation" do - {:ok, org} = Nbn.create_organisation(%{name: "Acme Corp", kind: :organization}) + describe "BaseParty — Organization CRUD" do + test "create and read organization" do + {:ok, org} = Nbn.create_organization(%{name: "Acme Corp"}) assert org.name == "Acme Corp" - assert org.kind == :organization + assert org.type == :Organization - {:ok, loaded} = Nbn.get_organisation_by_id(org.id) + {:ok, loaded} = Nbn.get_organization_by_id(org.id) assert loaded.name == "Acme Corp" end end describe "BaseParty — Person CRUD" do test "create and read person" do - {:ok, person} = Nbn.create_person(%{name: "Alice", kind: :individual}) + {:ok, person} = Nbn.create_person(%{name: "Alice"}) assert person.name == "Alice" - assert person.kind == :individual + assert person.type == :Individual {:ok, loaded} = Nbn.get_person_by_id(person.id) assert loaded.name == "Alice" diff --git a/test/provider/entity_ref_test.exs b/test/provider/entity_ref_test.exs index 1e83e17..5a3c727 100644 --- a/test/provider/entity_ref_test.exs +++ b/test/provider/entity_ref_test.exs @@ -29,7 +29,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "11b6ba17-2865-41c5-b469-2939249631e8", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/11b6ba17-2865-41c5-b469-2939249631e8", - referredType: :serviceProblem + referred_type: :serviceProblem }) entity2 = @@ -37,7 +37,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "22b85e20-06a9-4e51-baa3-41c2a72958c5", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/22b85e20-06a9-4e51-baa3-41c2a72958c5", - referredType: :serviceProblem + referred_type: :serviceProblem }) entity3 = @@ -45,7 +45,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "33db60a1-62bf-4c11-abf3-265287a729c1", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/33db60a1-62bf-4c11-abf3-265287a729c1", - referredType: :serviceProblem + referred_type: :serviceProblem }) Diffo.Provider.create_entity_ref!(%{ @@ -84,7 +84,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "11b6ba17-2865-41c5-b469-2939249631e8", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/11b6ba17-2865-41c5-b469-2939249631e8", - referredType: :serviceProblem + referred_type: :serviceProblem }) entity2 = @@ -92,7 +92,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "22b85e20-06a9-4e51-baa3-41c2a72958c5", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/22b85e20-06a9-4e51-baa3-41c2a72958c5", - referredType: :serviceProblem + referred_type: :serviceProblem }) entity3 = @@ -100,7 +100,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "33db60a1-62bf-4c11-abf3-265287a729c1", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/33db60a1-62bf-4c11-abf3-265287a729c1", - referredType: :serviceProblem + referred_type: :serviceProblem }) Diffo.Provider.create_entity_ref!(%{ @@ -137,7 +137,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "11b6ba17-2865-41c5-b469-2939249631e8", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/11b6ba17-2865-41c5-b469-2939249631e8", - referredType: :serviceProblem + referred_type: :serviceProblem }) entity2 = @@ -145,7 +145,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "22b85e20-06a9-4e51-baa3-41c2a72958c5", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/22b85e20-06a9-4e51-baa3-41c2a72958c5", - referredType: :serviceProblem + referred_type: :serviceProblem }) entity3 = @@ -153,7 +153,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "33db60a1-62bf-4c11-abf3-265287a729c1", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/33db60a1-62bf-4c11-abf3-265287a729c1", - referredType: :serviceProblem + referred_type: :serviceProblem }) Diffo.Provider.create_entity_ref!(%{ @@ -193,7 +193,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "11b6ba17-2865-41c5-b469-2939249631e8", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/11b6ba17-2865-41c5-b469-2939249631e8", - referredType: :serviceProblem + referred_type: :serviceProblem }) entity_ref = @@ -239,7 +239,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "11b6ba17-2865-41c5-b469-2939249631e8", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/11b6ba17-2865-41c5-b469-2939249631e8", - referredType: :serviceProblem + referred_type: :serviceProblem }) entity_ref = @@ -262,7 +262,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "11b6ba17-2865-41c5-b469-2939249631e8", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/11b6ba17-2865-41c5-b469-2939249631e8", - referredType: :serviceProblem + referred_type: :serviceProblem }) entity_ref = @@ -283,7 +283,7 @@ defmodule Diffo.Provider.EntityRefTest do entity = Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -305,7 +305,7 @@ defmodule Diffo.Provider.EntityRefTest do entity = Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -327,7 +327,7 @@ defmodule Diffo.Provider.EntityRefTest do entity = Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -338,7 +338,7 @@ defmodule Diffo.Provider.EntityRefTest do entity_id: entity.id }) - other_entity = Diffo.Provider.create_entity!(%{id: "COR000000767342", referredType: :cost}) + other_entity = Diffo.Provider.create_entity!(%{id: "COR000000767342", referred_type: :cost}) {:error, _error} = entity_ref |> Diffo.Provider.update_entity_ref(%{entity_id: other_entity.id}) @@ -372,14 +372,14 @@ defmodule Diffo.Provider.EntityRefTest do "{\"id\":\"11b6ba17-2865-41c5-b469-2939249631e8\",\"href\":\"serviceProblemManagement/v4/serviceProblem/nbnAccess/11b6ba17-2865-41c5-b469-2939249631e8\",\"role\":\"reportedOn\",\"@type\":\"serviceProblem\"}" end - test "encode json entity ref referredType - success" do + test "encode json entity ref referred_type - success" do specification = Diffo.Provider.create_specification!(%{name: "nbnAccess"}) instance = Diffo.Provider.create_instance!(%{specified_by: specification.id}) entity = Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -406,14 +406,14 @@ defmodule Diffo.Provider.EntityRefTest do id: "COR000000123456", href: "costManagement/v2/cost/COR000000123456", name: "2025-01", - referredType: :cost, + referred_type: :cost, type: :EntityRef } } @id_only %EntityRef{entity: %Entity{id: "COR000000123456"}} @href_only %EntityRef{entity: %Entity{href: "costManagement/v2/cost/COR000000123456"}} @name_only %EntityRef{entity: %Entity{name: "2025-01"}} - @referredType_only %EntityRef{entity: %Entity{referredType: :cost}} + @referred_type_only %EntityRef{entity: %Entity{referred_type: :cost}} @type_only %EntityRef{entity: %Entity{type: :EntityRef}} @specific_cost %EntityRef{ role: :expected, @@ -421,7 +421,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "COR000000123456", href: "costManagement/v2/cost/COR000000123456", name: "2025-01", - referredType: :cost, + referred_type: :cost, type: :EntityRef } } @@ -431,7 +431,7 @@ defmodule Diffo.Provider.EntityRefTest do id: &__MODULE__.generic_cost_id/1, href: nil, name: &Outstand.any_bitstring/1, - referredType: :cost, + referred_type: :cost, type: :EntityRef } } @@ -441,7 +441,7 @@ defmodule Diffo.Provider.EntityRefTest do id: "COR000000123456", href: "costManagement/v2/cost/COR000000123456", name: "2025-01", - referredType: :cost, + referred_type: :cost, type: :EntityRef } } @@ -491,10 +491,10 @@ defmodule Diffo.Provider.EntityRefTest do ) gen_result_outstanding_test( - "specific referredType result", + "specific referred_type result", @specific_cost, - update_in(@actual_cost.entity.referredType, fn _ -> nil end), - Ash.Test.strip_metadata(@referredType_only) + update_in(@actual_cost.entity.referred_type, fn _ -> nil end), + Ash.Test.strip_metadata(@referred_type_only) ) gen_result_outstanding_test( @@ -515,7 +515,7 @@ defmodule Diffo.Provider.EntityRefTest do entity = Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) diff --git a/test/provider/entity_test.exs b/test/provider/entity_test.exs index cbd7ca1..ce7fa29 100644 --- a/test/provider/entity_test.exs +++ b/test/provider/entity_test.exs @@ -23,21 +23,21 @@ defmodule Diffo.Provider.EntityTest do id: "11b6ba17-2865-41c5-b469-2939249631e8", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/11b6ba17-2865-41c5-b469-2939249631e8", - referredType: :serviceProblem + referred_type: :serviceProblem }) Diffo.Provider.create_entity!(%{ id: "22b85e20-06a9-4e51-baa3-41c2a72958c5", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/22b85e20-06a9-4e51-baa3-41c2a72958c5", - referredType: :serviceProblem + referred_type: :serviceProblem }) Diffo.Provider.create_entity!(%{ id: "33db60a1-62bf-4c11-abf3-265287a729c1", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/33db60a1-62bf-4c11-abf3-265287a729c1", - referredType: :serviceProblem + referred_type: :serviceProblem }) entities = Diffo.Provider.list_entities!() @@ -50,7 +50,7 @@ defmodule Diffo.Provider.EntityTest do test "find entities by id - success" do Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -58,12 +58,12 @@ defmodule Diffo.Provider.EntityTest do id: "22b85e20-06a9-4e51-baa3-41c2a72958c5", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/22b85e20-06a9-4e51-baa3-41c2a72958c5", - referredType: :serviceProblem + referred_type: :serviceProblem }) Diffo.Provider.create_entity!(%{ id: "COR000000767342", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -77,7 +77,7 @@ defmodule Diffo.Provider.EntityTest do test "find entities by name - success" do Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -85,12 +85,12 @@ defmodule Diffo.Provider.EntityTest do id: "22b85e20-06a9-4e51-baa3-41c2a72958c5", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/22b85e20-06a9-4e51-baa3-41c2a72958c5", - referredType: :serviceProblem + referred_type: :serviceProblem }) Diffo.Provider.create_entity!(%{ id: "COR000000767342", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -103,23 +103,23 @@ defmodule Diffo.Provider.EntityTest do end describe "Diffo.Provider create Entities" do - test "create a service problem referredType entity - success" do + test "create a service problem referred_type entity - success" do entity = Diffo.Provider.create_entity!(%{ id: "11b6ba17-2865-41c5-b469-2939249631e8", href: "serviceProblemManagement/v4/serviceProblem/nbnAccess/11b6ba17-2865-41c5-b469-2939249631e8", - referredType: :serviceProblem + referred_type: :serviceProblem }) assert entity.type == :EntityRef end - test "create a cost referredType entity - success" do + test "create a cost referred_type entity - success" do entity = Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -135,14 +135,14 @@ defmodule Diffo.Provider.EntityTest do type: :serviceProblem }) - assert entity.referredType == nil + assert entity.referred_type == nil end test "create a cost type entity - success" do entity = Diffo.Provider.create_entity!(%{id: "COR000000123456", type: :cost, name: "2025-01"}) - assert entity.referredType == nil + assert entity.referred_type == nil end test "create an Entity that already exists, preserving attributes - success" do @@ -191,7 +191,7 @@ defmodule Diffo.Provider.EntityTest do entity = Diffo.Provider.create_entity!(%{ id: "11b6ba17-2865-41c5-b469-2939249631e8", - referredType: :serviceProblem + referred_type: :serviceProblem }) updated_entity = @@ -209,7 +209,7 @@ defmodule Diffo.Provider.EntityTest do entity = Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -225,47 +225,47 @@ defmodule Diffo.Provider.EntityTest do assert updated_entity.type == :sla end - test "update entity referredType - success" do + test "update entity referred_type - success" do entity = Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) - updated_entity = entity |> Diffo.Provider.update_entity!(%{referredType: :sla}) - assert updated_entity.referredType == :sla + updated_entity = entity |> Diffo.Provider.update_entity!(%{referred_type: :sla}) + assert updated_entity.referred_type == :sla end - test "update entity type to referredType - success" do + test "update entity type to referred_type - success" do entity = Diffo.Provider.create_entity!(%{id: "COR000000123456", type: :cost, name: "2025-01"}) updated_entity = - entity |> Diffo.Provider.update_entity!(%{type: :EntityRef, referredType: :cost}) + entity |> Diffo.Provider.update_entity!(%{type: :EntityRef, referred_type: :cost}) assert updated_entity.type == :EntityRef - assert updated_entity.referredType == :cost + assert updated_entity.referred_type == :cost end - test "update entity referredType to type - success" do + test "update entity referred_type to type - success" do entity = Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) - updated_entity = entity |> Diffo.Provider.update_entity!(%{type: :cost, referredType: nil}) + updated_entity = entity |> Diffo.Provider.update_entity!(%{type: :cost, referred_type: nil}) assert updated_entity.type == :cost - assert updated_entity.referredType == nil + assert updated_entity.referred_type == nil end test "update id - failure - href does not end with id" do entity = Diffo.Provider.create_entity!(%{ id: "COR000000897353", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -273,23 +273,23 @@ defmodule Diffo.Provider.EntityTest do entity |> Diffo.Provider.update_entity(%{href: "entity/nbnco/COR000000897354"}) end - test "update referredType - failure - type Party cannot have referredType" do + test "update referred_type - failure - type Party cannot have referred_type" do entity = Diffo.Provider.create_entity!(%{id: "COR000000897353", type: :cost, name: "2025-01"}) - {:error, _error} = entity |> Diffo.Provider.update_entity(%{referredType: :cost}) + {:error, _error} = entity |> Diffo.Provider.update_entity(%{referred_type: :cost}) end - test "update referredType - failure - EntityRef requires referredType" do + test "update referred_type - failure - EntityRef requires referred_type" do entity = Diffo.Provider.create_entity!(%{ id: "COR000000897353", type: :EntityRef, - referredType: :cost, + referred_type: :cost, name: "2025-01" }) - {:error, _error} = entity |> Diffo.Provider.update_entity(%{referredType: nil}) + {:error, _error} = entity |> Diffo.Provider.update_entity(%{referred_type: nil}) end test "update id - failure - not updatable" do @@ -314,11 +314,11 @@ defmodule Diffo.Provider.EntityTest do "{\"id\":\"11b6ba17-2865-41c5-b469-2939249631e8\",\"href\":\"serviceProblemManagement/v4/serviceProblem/nbnAccess/11b6ba17-2865-41c5-b469-2939249631e8\",\"@type\":\"serviceProblem\"}" end - test "encode json entity referredType - success" do + test "encode json entity referred_type - success" do entity = Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -337,14 +337,14 @@ defmodule Diffo.Provider.EntityTest do name: "2025-01", href: "costManagement/v2/cost/COR000000123456", type: :EntityRef, - referredType: :cost + referred_type: :cost }) expected_entity = %Diffo.Provider.Entity{ id: ~r/COR\d{12}/, name: ~r/\d{4}-\d{2}/, type: :EntityRef, - referredType: :cost + referred_type: :cost } refute expected_entity >>> entity @@ -356,7 +356,7 @@ defmodule Diffo.Provider.EntityTest do entity = Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -368,7 +368,7 @@ defmodule Diffo.Provider.EntityTest do entity = Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) diff --git a/test/provider/external_identifier_test.exs b/test/provider/external_identifier_test.exs index 105fcf8..9c88b8c 100644 --- a/test/provider/external_identifier_test.exs +++ b/test/provider/external_identifier_test.exs @@ -29,7 +29,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) t3_party = @@ -37,7 +37,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T3_CONNECTIVITY", name: :entityId, href: "entity/internal/T3_CONNECTIVITY", - referredType: :Entity + referred_type: :Entity }) Diffo.Provider.create_external_identifier!(%{ @@ -71,7 +71,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) t3_party = @@ -79,7 +79,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T3_CONNECTIVITY", name: :entityId, href: "entity/internal/T3_CONNECTIVITY", - referredType: :Entity + referred_type: :Entity }) t3_party2 = @@ -87,7 +87,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T3_ADAPTIVE_NETWORKS", name: :entityId, href: "entity/internal/T3_ADAPTIVE_NETWORKS", - referredType: :Entity + referred_type: :Entity }) Diffo.Provider.create_external_identifier!(%{ @@ -142,7 +142,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) t3_party = @@ -150,7 +150,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T3_CONNECTIVITY", name: :entityId, href: "entity/internal/T3_CONNECTIVITY", - referredType: :Entity + referred_type: :Entity }) t3_party2 = @@ -158,7 +158,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T3_ADAPTIVE_NETWORKS", name: :entityId, href: "entity/internal/T3_ADAPTIVE_NETWORKS", - referredType: :Entity + referred_type: :Entity }) Diffo.Provider.create_external_identifier!(%{ @@ -216,7 +216,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) t3_party = @@ -224,7 +224,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T3_CONNECTIVITY", name: :entityId, href: "entity/internal/T3_CONNECTIVITY", - referredType: :Entity + referred_type: :Entity }) t3_party2 = @@ -232,7 +232,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T3_ADAPTIVE_NETWORKS", name: :entityId, href: "entity/internal/T3_ADAPTIVE_NETWORKS", - referredType: :Entity + referred_type: :Entity }) Diffo.Provider.create_external_identifier!(%{ @@ -298,7 +298,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) external_identifier = @@ -324,7 +324,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) {:error, _error} = @@ -346,7 +346,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) external_identifier = @@ -372,7 +372,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) external_identifier = @@ -399,7 +399,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) external_identifier = @@ -426,7 +426,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) t3_party = @@ -434,7 +434,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T3_CONNECTIVITY", name: :entityId, href: "entity/internal/T3_CONNECTIVITY", - referredType: :Entity + referred_type: :Entity }) external_identifier = @@ -462,7 +462,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) external_identifier = @@ -488,7 +488,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) external_identifier = @@ -520,7 +520,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) external_identifier = @@ -565,7 +565,7 @@ defmodule Diffo.Provider.ExternalIdentifierTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) external_identifier = diff --git a/test/provider/instance_test.exs b/test/provider/instance_test.exs index 1d92465..e59d337 100644 --- a/test/provider/instance_test.exs +++ b/test/provider/instance_test.exs @@ -648,7 +648,7 @@ defmodule Diffo.Provider.InstanceTest do id: "LOC000000897353", name: :locationId, href: "place/nbnco/LOC000000897353", - referredType: :GeographicAddress + referred_type: :GeographicAddress }) Diffo.Provider.create_place_ref!(%{ @@ -668,7 +668,7 @@ defmodule Diffo.Provider.InstanceTest do id: "T3_CONNECTIVITY", name: :entityId, href: "entity/internal/T3_CONNECTIVITY", - referredType: :Entity + referred_type: :Entity }) t3_party2 = @@ -676,7 +676,7 @@ defmodule Diffo.Provider.InstanceTest do id: "T3_ADAPTIVE_NETWORKS", name: :entityId, href: "entity/internal/T3_ADAPTIVE_NETWORKS", - referredType: :Entity + referred_type: :Entity }) t4_party = @@ -684,7 +684,7 @@ defmodule Diffo.Provider.InstanceTest do id: "T4_CPE", name: :entityId, href: "entity/internal/T4_CPE", - referredType: :Entity + referred_type: :Entity }) Diffo.Provider.create_party_ref!(%{ @@ -763,7 +763,7 @@ defmodule Diffo.Provider.InstanceTest do entity = Diffo.Provider.create_entity!(%{ id: "COR000000123456", - referredType: :cost, + referred_type: :cost, name: "2025-01" }) @@ -860,7 +860,7 @@ defmodule Diffo.Provider.InstanceTest do id: "LOC000000897353", name: :locationId, href: "place/nbnco/LOC000000897353", - referredType: :GeographicAddress + referred_type: :GeographicAddress }) Diffo.Provider.create_place_ref!(%{ @@ -880,7 +880,7 @@ defmodule Diffo.Provider.InstanceTest do id: "T3_CONNECTIVITY", name: :entityId, href: "entity/internal/T3_CONNECTIVITY", - referredType: :Entity + referred_type: :Entity }) t3_party2 = @@ -888,7 +888,7 @@ defmodule Diffo.Provider.InstanceTest do id: "T3_ADAPTIVE_NETWORKS", name: :entityId, href: "entity/internal/T3_ADAPTIVE_NETWORKS", - referredType: :Entity + referred_type: :Entity }) t4_party = @@ -896,7 +896,7 @@ defmodule Diffo.Provider.InstanceTest do id: "T4_CPE", name: :entityId, href: "entity/internal/T4_CPE", - referredType: :Entity + referred_type: :Entity }) Diffo.Provider.create_external_identifier!(%{ @@ -1328,7 +1328,7 @@ defmodule Diffo.Provider.InstanceTest do id: "T3_CONNECTIVITY", name: :entityId, href: "entity/internal/T3_CONNECTIVITY", - referredType: :Entity, + referred_type: :Entity, type: :PartyRef }) diff --git a/test/provider/instance_util_test.exs b/test/provider/instance_util_test.exs new file mode 100644 index 0000000..53c93e9 --- /dev/null +++ b/test/provider/instance_util_test.exs @@ -0,0 +1,88 @@ +# SPDX-FileCopyrightText: 2025 diffo contributors +# +# SPDX-License-Identifier: MIT + +defmodule Diffo.Provider.Instance.UtilTest do + @moduledoc false + use ExUnit.Case + + alias Diffo.Provider.Instance.Util + + describe "derive_type/1" do + test "service specification" do + assert Util.derive_type(:serviceSpecification) == :service + end + + test "resource specification" do + assert Util.derive_type(:resourceSpecification) == :resource + end + + test "unknown returns nil" do + assert Util.derive_type(:other) == nil + end + end + + describe "derive_feature_list_name/1" do + test "service" do + assert Util.derive_feature_list_name(:service) == :feature + end + + test "resource" do + assert Util.derive_feature_list_name(:resource) == :activationFeature + end + end + + describe "derive_characteristic_list_name/1" do + test "service" do + assert Util.derive_characteristic_list_name(:service) == :serviceCharacteristic + end + + test "resource" do + assert Util.derive_characteristic_list_name(:resource) == :resourceCharacteristic + end + end + + describe "derive_create_date_name/1" do + test "service" do + assert Util.derive_create_date_name(:service) == :serviceDate + end + + test "resource" do + assert Util.derive_create_date_name(:resource) == nil + end + end + + describe "derive_start_date_name/1" do + test "service" do + assert Util.derive_start_date_name(:service) == :startDate + end + + test "resource" do + assert Util.derive_start_date_name(:resource) == :startOperatingDate + end + end + + describe "derive_end_date_name/1" do + test "service" do + assert Util.derive_end_date_name(:service) == :endDate + end + + test "resource" do + assert Util.derive_end_date_name(:resource) == :endOperatingDate + end + end + + describe "other/1" do + test "actual returns expected" do + assert Util.other(:actual) == :expected + end + + test "expected returns actual" do + assert Util.other(:expected) == :actual + end + + test "unknown returns nil" do + assert Util.other(:unknown) == nil + end + end +end diff --git a/test/provider/note_test.exs b/test/provider/note_test.exs index 4ca9dd6..4e9500c 100644 --- a/test/provider/note_test.exs +++ b/test/provider/note_test.exs @@ -28,7 +28,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) t3_party = @@ -36,7 +36,7 @@ defmodule Diffo.Provider.NoteTest do id: "T3_CONNECTIVITY", name: :entityId, href: "entity/internal/T3_CONNECTIVITY", - referredType: :Entity + referred_type: :Entity }) Diffo.Provider.create_note!(%{ @@ -70,7 +70,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) t3_party = @@ -78,7 +78,7 @@ defmodule Diffo.Provider.NoteTest do id: "T3_CONNECTIVITY", name: :entityId, href: "entity/internal/T3_CONNECTIVITY", - referredType: :Entity + referred_type: :Entity }) Diffo.Provider.create_note!(%{ @@ -126,7 +126,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) t3_party = @@ -134,7 +134,7 @@ defmodule Diffo.Provider.NoteTest do id: "T3_CONNECTIVITY", name: :entityId, href: "entity/internal/T3_CONNECTIVITY", - referredType: :Entity + referred_type: :Entity }) Diffo.Provider.create_note!(%{ @@ -181,7 +181,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) t3_party = @@ -189,7 +189,7 @@ defmodule Diffo.Provider.NoteTest do id: "T3_CONNECTIVITY", name: :entityId, href: "entity/internal/T3_CONNECTIVITY", - referredType: :Entity + referred_type: :Entity }) Diffo.Provider.create_note!(%{ @@ -251,7 +251,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) note = @@ -280,7 +280,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) Diffo.Provider.create_note!(%{ @@ -305,7 +305,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) Diffo.Provider.create_note!(%{ @@ -334,7 +334,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) note = @@ -358,7 +358,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) note = @@ -382,7 +382,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) note = @@ -409,7 +409,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) t3_party = @@ -417,7 +417,7 @@ defmodule Diffo.Provider.NoteTest do id: "T3_CONNECTIVITY", name: :entityId, href: "entity/internal/T3_CONNECTIVITY", - referredType: :Entity + referred_type: :Entity }) note = @@ -442,7 +442,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) note = @@ -466,7 +466,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) note = @@ -491,7 +491,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) note = @@ -531,7 +531,7 @@ defmodule Diffo.Provider.NoteTest do id: "T4_ACCESS", name: :entityId, href: "entity/internal/T4_ACCESS", - referredType: :Entity + referred_type: :Entity }) note = diff --git a/test/provider/party_ref_test.exs b/test/provider/party_ref_test.exs index d5d6443..42a62a6 100644 --- a/test/provider/party_ref_test.exs +++ b/test/provider/party_ref_test.exs @@ -65,21 +65,21 @@ defmodule Diffo.Provider.PartyRefTest do Diffo.Provider.create_party!(%{ id: "IND000000897353", name: :individualId, - referredType: :Individual + referred_type: :Individual }) party2 = Diffo.Provider.create_party!(%{ id: "IND000000897354", name: :individualId, - referredType: :Individual + referred_type: :Individual }) party3 = Diffo.Provider.create_party!(%{ id: "ORG000163435034", name: :organizationId, - referredType: :Organization + referred_type: :Organization }) Diffo.Provider.create_party_ref!(%{ @@ -124,35 +124,35 @@ defmodule Diffo.Provider.PartyRefTest do Diffo.Provider.create_place!(%{ id: "LOC000000123456", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) place2 = Diffo.Provider.create_place!(%{ id: "LOC000000897353", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) party1 = Diffo.Provider.create_party!(%{ id: "IND000000897353", name: :individualId, - referredType: :Individual + referred_type: :Individual }) party2 = Diffo.Provider.create_party!(%{ id: "IND000000897354", name: :individualId, - referredType: :Individual + referred_type: :Individual }) party3 = Diffo.Provider.create_party!(%{ id: "ORG000163435034", name: :organizationId, - referredType: :Organization + referred_type: :Organization }) Diffo.Provider.create_party_ref!(%{ @@ -201,21 +201,21 @@ defmodule Diffo.Provider.PartyRefTest do Diffo.Provider.create_party!(%{ id: "IND000000897353", name: :individualId, - referredType: :Individual + referred_type: :Individual }) party2 = Diffo.Provider.create_party!(%{ id: "IND000000897354", name: :individualId, - referredType: :Individual + referred_type: :Individual }) party3 = Diffo.Provider.create_party!(%{ id: "ORG000000123456", name: :organizationId, - referredType: :Organization + referred_type: :Organization }) Diffo.Provider.create_party_ref!(%{ @@ -260,21 +260,21 @@ defmodule Diffo.Provider.PartyRefTest do Diffo.Provider.create_party!(%{ id: "IND000000897353", name: :individualId, - referredType: :Individual + referred_type: :Individual }) party2 = Diffo.Provider.create_party!(%{ id: "IND000000897354", name: :individualId, - referredType: :Individual + referred_type: :Individual }) party3 = Diffo.Provider.create_party!(%{ id: "ORG000000123456", name: :organizationId, - referredType: :Organization + referred_type: :Organization }) Diffo.Provider.create_party_ref!(%{ @@ -473,7 +473,7 @@ defmodule Diffo.Provider.PartyRefTest do "{\"id\":\"IND000000897353\",\"href\":\"party/internal/IND000000897353\",\"name\":\"individualId\",\"role\":\"PrimaryContact\",\"@type\":\"Individual\"}" end - test "encode json party referredType - success" do + test "encode json party referred_type - success" do specification = Diffo.Provider.create_specification!(%{name: "nbnAccess"}) instance = Diffo.Provider.create_instance!(%{specified_by: specification.id}) @@ -482,7 +482,7 @@ defmodule Diffo.Provider.PartyRefTest do id: "IND000000897353", name: :individualId, href: "party/internal/IND000000897353", - referredType: :Individual + referred_type: :Individual }) party_ref = @@ -509,7 +509,7 @@ defmodule Diffo.Provider.PartyRefTest do id: "IND000000897353", name: "individualId", href: "party/internal/IND000000897353", - referredType: :Individual + referred_type: :Individual }) party_ref = @@ -525,7 +525,7 @@ defmodule Diffo.Provider.PartyRefTest do id: ~r/IND\d{12}/, name: "individualId", type: :PartyRef, - referredType: :Individual + referred_type: :Individual } } @@ -543,7 +543,7 @@ defmodule Diffo.Provider.PartyRefTest do id: "IND000000897353", name: :individualId, href: "party/internal/IND000000897353", - referredType: :Individual + referred_type: :Individual }) party_ref = @@ -562,7 +562,7 @@ defmodule Diffo.Provider.PartyRefTest do Diffo.Provider.create_place!(%{ id: "LOC000000897353", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) party = @@ -570,7 +570,7 @@ defmodule Diffo.Provider.PartyRefTest do id: "IND000000897353", name: :individualId, href: "party/internal/IND000000897353", - referredType: :Individual + referred_type: :Individual }) party_ref = @@ -589,7 +589,7 @@ defmodule Diffo.Provider.PartyRefTest do Diffo.Provider.create_party!(%{ id: "ORG000163435034", name: :organizationId, - referredType: :Organization + referred_type: :Organization }) party = @@ -597,7 +597,7 @@ defmodule Diffo.Provider.PartyRefTest do id: "IND000000897353", name: :individualId, href: "party/internal/IND000000897353", - referredType: :Individual + referred_type: :Individual }) party_ref = diff --git a/test/provider/party_test.exs b/test/provider/party_test.exs index 4a26765..2bfa727 100644 --- a/test/provider/party_test.exs +++ b/test/provider/party_test.exs @@ -24,13 +24,13 @@ defmodule Diffo.Provider.PartyTest do Diffo.Provider.create_party!(%{ id: "IND000000123456", name: :individualId, - referredType: :Individual + referred_type: :Individual }) Diffo.Provider.create_party!(%{ id: "IND000000897353", name: :individualId, - referredType: :Individual + referred_type: :Individual }) parties = Diffo.Provider.list_parties!() @@ -44,19 +44,19 @@ defmodule Diffo.Provider.PartyTest do Diffo.Provider.create_party!(%{ id: "IND000000897353", name: :individualId, - referredType: :Individual + referred_type: :Individual }) Diffo.Provider.create_party!(%{ id: "IND000000123456", name: :individualId, - referredType: :Individual + referred_type: :Individual }) Diffo.Provider.create_party!(%{ id: "ORG000163435034", name: :organizationId, - referredType: :Organization + referred_type: :Organization }) parties = Diffo.Provider.find_parties_by_id!("IND") @@ -70,19 +70,19 @@ defmodule Diffo.Provider.PartyTest do Diffo.Provider.create_party!(%{ id: "IND000000897353", name: :individualId, - referredType: :Individual + referred_type: :Individual }) Diffo.Provider.create_party!(%{ id: "IND000000123456", name: :individualId, - referredType: :Individual + referred_type: :Individual }) Diffo.Provider.create_party!(%{ id: "ORG000163435034", name: :organizationId, - referredType: :Organization + referred_type: :Organization }) parties = Diffo.Provider.find_parties_by_name!("individual") @@ -94,31 +94,31 @@ defmodule Diffo.Provider.PartyTest do end describe "Diffo.Provider create Parties" do - test "create a Individual referredType party - success" do + test "create a Individual referred_type party - success" do party = Diffo.Provider.create_party!(%{ id: "IND000000897353", name: :individualId, - referredType: :Individual + referred_type: :Individual }) assert party.type == :PartyRef end - test "create a Organization referredType party - success" do + test "create a Organization referred_type party - success" do party = Diffo.Provider.create_party!(%{ id: "ORG000000124343", name: :organizationId, - referredType: :Organization + referred_type: :Organization }) assert party.type == :PartyRef end - test "create a Entity party referredType - success" do + test "create a Entity party referred_type - success" do party = - Diffo.Provider.create_party!(%{id: "T8_NUMBERS", name: :entityId, referredType: :Entity}) + Diffo.Provider.create_party!(%{id: "T8_NUMBERS", name: :entityId, referred_type: :Entity}) assert party.type == :PartyRef end @@ -131,7 +131,7 @@ defmodule Diffo.Provider.PartyTest do type: :Individual }) - assert party.referredType == nil + assert party.referred_type == nil end test "create a Organization type party - success" do @@ -142,12 +142,12 @@ defmodule Diffo.Provider.PartyTest do type: :Organization }) - assert party.referredType == nil + assert party.referred_type == nil end test "create a Entity party type - success" do party = Diffo.Provider.create_party!(%{id: "T8_NUMBERS", name: :entityId, type: :Entity}) - assert party.referredType == nil + assert party.referred_type == nil end test "create a Entity party type with a href - success" do @@ -159,7 +159,7 @@ defmodule Diffo.Provider.PartyTest do type: :Entity }) - assert party.referredType == nil + assert party.referred_type == nil end test "create a Party that already exists, preserving attributes - success" do @@ -230,19 +230,19 @@ defmodule Diffo.Provider.PartyTest do assert updated_party.type == :Entity end - test "update party referredType - success" do + test "update party referred_type - success" do party = Diffo.Provider.create_party!(%{ id: "5ADE", name: :individualId, - referredType: :Individual + referred_type: :Individual }) - updated_party = party |> Diffo.Provider.update_party!(%{referredType: :Entity}) - assert updated_party.referredType == :Entity + updated_party = party |> Diffo.Provider.update_party!(%{referred_type: :Entity}) + assert updated_party.referred_type == :Entity end - test "update party type to referredType - success" do + test "update party type to referred_type - success" do party = Diffo.Provider.create_party!(%{ id: "IND000000897353", @@ -251,25 +251,25 @@ defmodule Diffo.Provider.PartyTest do }) updated_party = - party |> Diffo.Provider.update_party!(%{type: :PartyRef, referredType: :Individual}) + party |> Diffo.Provider.update_party!(%{type: :PartyRef, referred_type: :Individual}) assert updated_party.type == :PartyRef - assert updated_party.referredType == :Individual + assert updated_party.referred_type == :Individual end - test "update party referredType to type - success" do + test "update party referred_type to type - success" do party = Diffo.Provider.create_party!(%{ id: "IND000000897353", name: :individualId, - referredType: :Individual + referred_type: :Individual }) updated_party = - party |> Diffo.Provider.update_party!(%{type: :Individual, referredType: nil}) + party |> Diffo.Provider.update_party!(%{type: :Individual, referred_type: nil}) assert updated_party.type == :Individual - assert updated_party.referredType == nil + assert updated_party.referred_type == nil end test "update id - failure - href does not end with id" do @@ -284,7 +284,7 @@ defmodule Diffo.Provider.PartyTest do party |> Diffo.Provider.update_party(%{href: "party/nbnco/IND000000897354"}) end - test "update referredType - failure - type Party cannot have referredTYpe" do + test "update referred_type - failure - type Party cannot have referredTYpe" do party = Diffo.Provider.create_party!(%{ id: "IND000000897353", @@ -292,19 +292,19 @@ defmodule Diffo.Provider.PartyTest do type: :Individual }) - {:error, _error} = party |> Diffo.Provider.update_party(%{referredType: :Individual}) + {:error, _error} = party |> Diffo.Provider.update_party(%{referred_type: :Individual}) end - test "update referredType - failure - PartyRef requires referredType" do + test "update referred_type - failure - PartyRef requires referred_type" do party = Diffo.Provider.create_party!(%{ id: "IND000000897353", name: :individualId, type: :PartyRef, - referredType: :Individual + referred_type: :Individual }) - {:error, _error} = party |> Diffo.Provider.update_party(%{referredType: nil}) + {:error, _error} = party |> Diffo.Provider.update_party(%{referred_type: nil}) end test "update id - failure - not updatable" do @@ -335,13 +335,13 @@ defmodule Diffo.Provider.PartyTest do "{\"id\":\"IND000000897353\",\"href\":\"party/internal/IND000000897353\",\"name\":\"individualId\",\"@type\":\"Individual\"}" end - test "encode json party referredType - success" do + test "encode json party referred_type - success" do party = Diffo.Provider.create_party!(%{ id: "IND000000897353", name: :individualId, href: "party/internal/IND000000897353", - referredType: :Individual + referred_type: :Individual }) encoding = Jason.encode!(party) @@ -358,13 +358,13 @@ defmodule Diffo.Provider.PartyTest do id: "IND000000897353", name: "individualId", href: "party/internal/IND000000897353", - referredType: :Individual + referred_type: :Individual }) expected_party = %Diffo.Provider.Party{ id: ~r/IND\d{12}/, name: "individualId", - referredType: :Individual + referred_type: :Individual } refute expected_party >>> party @@ -394,7 +394,7 @@ defmodule Diffo.Provider.PartyTest do id: "T5_VALUE_ADD", name: :entityId, href: "entity/internal/T5_VALUE_ADD", - referredType: :Entity + referred_type: :Entity }) external_identifier = @@ -422,7 +422,7 @@ defmodule Diffo.Provider.PartyTest do id: "T3_FIXED", name: :entityId, href: "entity/internal/T3_FIXED", - referredType: :Entity + referred_type: :Entity }) party_ref = diff --git a/test/provider/place_ref_test.exs b/test/provider/place_ref_test.exs index 6781f7c..8f7f743 100644 --- a/test/provider/place_ref_test.exs +++ b/test/provider/place_ref_test.exs @@ -65,21 +65,21 @@ defmodule Diffo.Provider.PlaceRefTest do Diffo.Provider.create_place!(%{ id: "LOC000000897353", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) place2 = Diffo.Provider.create_place!(%{ id: "LOC000000897354", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) place3 = Diffo.Provider.create_place!(%{ id: "CSA000000123456", name: :csaId, - referredType: :GeographicLocation + referred_type: :GeographicLocation }) Diffo.Provider.create_place_ref!(%{ @@ -118,35 +118,35 @@ defmodule Diffo.Provider.PlaceRefTest do Diffo.Provider.create_party!(%{ id: "IND000000897353", name: :individualId, - referredType: :Individual + referred_type: :Individual }) party2 = Diffo.Provider.create_party!(%{ id: "IND000000897354", name: :individualId, - referredType: :Individual + referred_type: :Individual }) party3 = Diffo.Provider.create_party!(%{ id: "ORG000163435034", name: :organizationId, - referredType: :Organization + referred_type: :Organization }) place1 = Diffo.Provider.create_place!(%{ id: "LOC000000123456", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) place2 = Diffo.Provider.create_place!(%{ id: "LOC000000897353", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) Diffo.Provider.create_place_ref!(%{ @@ -190,21 +190,21 @@ defmodule Diffo.Provider.PlaceRefTest do Diffo.Provider.create_place!(%{ id: "LOC000000897353", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) place2 = Diffo.Provider.create_place!(%{ id: "LOC000000897354", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) place3 = Diffo.Provider.create_place!(%{ id: "CSA000000123456", name: :csaId, - referredType: :GeographicLocation + referred_type: :GeographicLocation }) Diffo.Provider.create_place_ref!(%{ @@ -465,7 +465,7 @@ defmodule Diffo.Provider.PlaceRefTest do "{\"id\":\"LOC000000897353\",\"href\":\"place/nbnco/LOC000000897353\",\"name\":\"locationId\",\"role\":\"CustomerSite\",\"@type\":\"GeographicAddress\"}" end - test "encode json place referredType - success" do + test "encode json place referred_type - success" do specification = Diffo.Provider.create_specification!(%{name: "nbnAccess"}) instance = Diffo.Provider.create_instance!(%{specified_by: specification.id}) @@ -474,7 +474,7 @@ defmodule Diffo.Provider.PlaceRefTest do id: "LOC000000897353", name: :locationId, href: "place/nbnco/LOC000000897353", - referredType: :GeographicAddress + referred_type: :GeographicAddress }) place_ref = @@ -501,7 +501,7 @@ defmodule Diffo.Provider.PlaceRefTest do id: "LOC000000897353", name: "locationId", href: "place/nbnco/LOC000000897353", - referredType: :GeographicAddress + referred_type: :GeographicAddress }) place_ref = @@ -517,7 +517,7 @@ defmodule Diffo.Provider.PlaceRefTest do id: ~r/LOC\d{12}/, name: "locationId", type: :PlaceRef, - referredType: :GeographicAddress + referred_type: :GeographicAddress } } @@ -535,7 +535,7 @@ defmodule Diffo.Provider.PlaceRefTest do id: "LOC000000897353", name: :locationId, href: "place/nbnco/LOC000000897353", - referredType: :GeographicAddress + referred_type: :GeographicAddress }) place_ref = @@ -555,14 +555,14 @@ defmodule Diffo.Provider.PlaceRefTest do id: "IND000000897353", name: :individualId, href: "party/internal/IND000000897353", - referredType: :Individual + referred_type: :Individual }) place = Diffo.Provider.create_place!(%{ id: "LOC000000897353", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) place_ref = diff --git a/test/provider/place_test.exs b/test/provider/place_test.exs index d31c220..07a2e9b 100644 --- a/test/provider/place_test.exs +++ b/test/provider/place_test.exs @@ -24,13 +24,13 @@ defmodule Diffo.Provider.PlaceTest do Diffo.Provider.create_place!(%{ id: "LOC000000123456", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) Diffo.Provider.create_place!(%{ id: "LOC000000897353", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) places = Diffo.Provider.list_places!() @@ -44,19 +44,19 @@ defmodule Diffo.Provider.PlaceTest do Diffo.Provider.create_place!(%{ id: "LOC000000897353", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) Diffo.Provider.create_place!(%{ id: "LOC000000123456", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) Diffo.Provider.create_place!(%{ id: "163435034", name: :adborId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) places = Diffo.Provider.find_places_by_id!("LOC") @@ -70,19 +70,19 @@ defmodule Diffo.Provider.PlaceTest do Diffo.Provider.create_place!(%{ id: "LOC000000897353", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) Diffo.Provider.create_place!(%{ id: "LOC000000123456", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) Diffo.Provider.create_place!(%{ id: "163435034", name: :adborId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) places = Diffo.Provider.find_places_by_name!("location") @@ -94,31 +94,31 @@ defmodule Diffo.Provider.PlaceTest do end describe "Diffo.Provider create Places" do - test "create a GeographicAddress referredType place - success" do + test "create a GeographicAddress referred_type place - success" do place = Diffo.Provider.create_place!(%{ id: "LOC000000897353", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) assert place.type == :PlaceRef end - test "create a GeographicLocation referredType place - success" do + test "create a GeographicLocation referred_type place - success" do place = Diffo.Provider.create_place!(%{ id: "CSA000000124343", name: :csaId, - referredType: :GeographicLocation + referred_type: :GeographicLocation }) assert place.type == :PlaceRef end - test "create a GeographicSite place referredType - success" do + test "create a GeographicSite place referred_type - success" do place = - Diffo.Provider.create_place!(%{id: "3NBA", name: :poiId, referredType: :GeographicSite}) + Diffo.Provider.create_place!(%{id: "3NBA", name: :poiId, referred_type: :GeographicSite}) assert place.type == :PlaceRef end @@ -131,7 +131,7 @@ defmodule Diffo.Provider.PlaceTest do type: :GeographicAddress }) - assert place.referredType == nil + assert place.referred_type == nil end test "create a GeographicLocation type place - success" do @@ -142,12 +142,12 @@ defmodule Diffo.Provider.PlaceTest do type: :GeographicLocation }) - assert place.referredType == nil + assert place.referred_type == nil end test "create a GeographicSite place type - success" do place = Diffo.Provider.create_place!(%{id: "3NBA", name: :poiId, type: :GeographicSite}) - assert place.referredType == nil + assert place.referred_type == nil end test "create a GeographicSite place type with a href - success" do @@ -159,7 +159,7 @@ defmodule Diffo.Provider.PlaceTest do type: :GeographicSite }) - assert place.referredType == nil + assert place.referred_type == nil end test "create a Place that already exists, preserving attributes - success" do @@ -226,19 +226,19 @@ defmodule Diffo.Provider.PlaceTest do assert updated_place.type == :GeographicSite end - test "update place referredType - success" do + test "update place referred_type - success" do place = Diffo.Provider.create_place!(%{ id: "5ADE", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) - updated_place = place |> Diffo.Provider.update_place!(%{referredType: :GeographicSite}) - assert updated_place.referredType == :GeographicSite + updated_place = place |> Diffo.Provider.update_place!(%{referred_type: :GeographicSite}) + assert updated_place.referred_type == :GeographicSite end - test "update place type to referredType - success" do + test "update place type to referred_type - success" do place = Diffo.Provider.create_place!(%{ id: "LOC000000897353", @@ -248,25 +248,25 @@ defmodule Diffo.Provider.PlaceTest do updated_place = place - |> Diffo.Provider.update_place!(%{type: :PlaceRef, referredType: :GeographicAddress}) + |> Diffo.Provider.update_place!(%{type: :PlaceRef, referred_type: :GeographicAddress}) assert updated_place.type == :PlaceRef - assert updated_place.referredType == :GeographicAddress + assert updated_place.referred_type == :GeographicAddress end - test "update place referredType to type - success" do + test "update place referred_type to type - success" do place = Diffo.Provider.create_place!(%{ id: "LOC000000897353", name: :locationId, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) updated_place = - place |> Diffo.Provider.update_place!(%{type: :GeographicAddress, referredType: nil}) + place |> Diffo.Provider.update_place!(%{type: :GeographicAddress, referred_type: nil}) assert updated_place.type == :GeographicAddress - assert updated_place.referredType == nil + assert updated_place.referred_type == nil end test "update id - failure - href does not end with id" do @@ -281,7 +281,7 @@ defmodule Diffo.Provider.PlaceTest do place |> Diffo.Provider.update_place(%{href: "place/nbnco/LOC000000897354"}) end - test "update referredType - failure - type Place cannot have referredTYpe" do + test "update referred_type - failure - type Place cannot have referredTYpe" do place = Diffo.Provider.create_place!(%{ id: "LOC000000897353", @@ -289,19 +289,19 @@ defmodule Diffo.Provider.PlaceTest do type: :GeographicAddress }) - {:error, _error} = place |> Diffo.Provider.update_place(%{referredType: :GeographicAddress}) + {:error, _error} = place |> Diffo.Provider.update_place(%{referred_type: :GeographicAddress}) end - test "update referredType - failure - PlaceRef requires referredType" do + test "update referred_type - failure - PlaceRef requires referred_type" do place = Diffo.Provider.create_place!(%{ id: "LOC000000897353", name: :locationId, type: :PlaceRef, - referredType: :GeographicAddress + referred_type: :GeographicAddress }) - {:error, _error} = place |> Diffo.Provider.update_place(%{referredType: nil}) + {:error, _error} = place |> Diffo.Provider.update_place(%{referred_type: nil}) end test "update id - failure - not updatable" do @@ -332,13 +332,13 @@ defmodule Diffo.Provider.PlaceTest do "{\"id\":\"LOC000000897353\",\"href\":\"place/nbnco/LOC000000897353\",\"name\":\"locationId\",\"@type\":\"GeographicAddress\"}" end - test "encode json place referredType - success" do + test "encode json place referred_type - success" do place = Diffo.Provider.create_place!(%{ id: "LOC000000897353", name: :locationId, href: "place/nbnco/LOC000000897353", - referredType: :GeographicAddress + referred_type: :GeographicAddress }) encoding = Jason.encode!(place) @@ -355,14 +355,14 @@ defmodule Diffo.Provider.PlaceTest do id: "LOC000000897353", name: "locationId", href: "place/nbnco/LOC000000897353", - referredType: :GeographicAddress + referred_type: :GeographicAddress }) expected_place = %Diffo.Provider.Place{ id: ~r/LOC\d{12}/, name: "locationId", type: :PlaceRef, - referredType: :GeographicAddress + referred_type: :GeographicAddress } refute expected_place >>> place @@ -376,7 +376,7 @@ defmodule Diffo.Provider.PlaceTest do id: "LOC000000898353", name: :locationId, href: "place/nbnco/LOC000000898353", - referredType: :GeographicAddress + referred_type: :GeographicAddress }) :ok = Diffo.Provider.delete_place(place) @@ -392,7 +392,7 @@ defmodule Diffo.Provider.PlaceTest do id: "LOC000000899353", name: :locationId, href: "place/nbnco/LOC000000899353", - referredType: :GeographicAddress + referred_type: :GeographicAddress }) place_ref = diff --git a/test/provider/reference_test.exs b/test/provider/reference_test.exs index 3e349bb..2017b85 100644 --- a/test/provider/reference_test.exs +++ b/test/provider/reference_test.exs @@ -6,6 +6,37 @@ defmodule Diffo.Provider.ReferenceTest do @moduledoc false use ExUnit.Case + alias Diffo.Provider.Reference + + describe "Diffo.Provider.Reference construction" do + test "reference/1 from id and href" do + instance = %{ + id: "8bcfbf9a-34a5-427a-8eae-5c3812466432", + href: "serviceInventoryManagement/v4/service/8bcfbf9a-34a5-427a-8eae-5c3812466432" + } + + assert Reference.reference(instance) == %Reference{ + id: "8bcfbf9a-34a5-427a-8eae-5c3812466432", + href: "serviceInventoryManagement/v4/service/8bcfbf9a-34a5-427a-8eae-5c3812466432" + } + end + + test "reference/2 extracts id from trailing uuid in href attribute" do + instance = %{ + target_href: "serviceInventoryManagement/v4/service/8bcfbf9a-34a5-427a-8eae-5c3812466432" + } + + assert Reference.reference(instance, :target_href) == %Reference{ + id: "8bcfbf9a-34a5-427a-8eae-5c3812466432", + href: "serviceInventoryManagement/v4/service/8bcfbf9a-34a5-427a-8eae-5c3812466432" + } + end + + test "reference/1 nil returns nil" do + assert Reference.reference(nil) == nil + end + end + describe "Diffo.Provider.Reference encode" do test "encode json - success" do reference = %Diffo.Provider.Reference{ diff --git a/test/support/nbn.ex b/test/support/nbn.ex index 6ac259e..c55292d 100644 --- a/test/support/nbn.ex +++ b/test/support/nbn.ex @@ -12,7 +12,7 @@ defmodule Diffo.Test.Nbn do otp_app: :diffo, validate_config_inclusion?: false - alias Diffo.Test.Organisation + alias Diffo.Test.Organization alias Diffo.Test.Person domain do @@ -20,14 +20,14 @@ defmodule Diffo.Test.Nbn do end resources do - resource Organisation do - define :create_organisation, action: :create - define :get_organisation_by_id, action: :read, get_by: :id - define :list_organisations, action: :list + resource Organization do + define :create_organization, action: :build + define :get_organization_by_id, action: :read, get_by: :id + define :list_organizations, action: :list end resource Person do - define :create_person, action: :create + define :create_person, action: :build define :get_person_by_id, action: :read, get_by: :id define :list_persons, action: :list end diff --git a/test/support/parties.ex b/test/support/parties.ex index 37f0b71..e14a1b4 100644 --- a/test/support/parties.ex +++ b/test/support/parties.ex @@ -11,6 +11,13 @@ defmodule Diffo.Test.Parties do import ExUnit.Assertions + alias Diffo.Provider.Instance.Party + + def build_shelf_with_installer do + {:ok, person} = Diffo.Test.Nbn.create_person(%{name: "Installer"}) + Diffo.Test.Servo.build_shelf(%{parties: [%Party{id: person.id, role: :installer}]}) + end + def check_parties(expected_parties, instance) when is_list(expected_parties) and is_struct(instance) do Enum.zip_reduce(expected_parties, instance.parties, [], fn _expected_party, diff --git a/test/support/resource/organisation.ex b/test/support/resource/organisation.ex deleted file mode 100644 index b911948..0000000 --- a/test/support/resource/organisation.ex +++ /dev/null @@ -1,27 +0,0 @@ -# SPDX-FileCopyrightText: 2025 diffo contributors -# -# SPDX-License-Identifier: MIT - -defmodule Diffo.Test.Organisation do - @moduledoc """ - Diffo - TMF Service and Resource Management with a difference - - Organisation - Organisation Party - """ - - alias Diffo.Provider.BaseParty - alias Diffo.Test.Nbn - - use Ash.Resource, - fragments: [BaseParty], - domain: Nbn - - resource do - description "An Organisation" - plural_name :organisations - end - - instance do - role :facilitates, Diffo.Provider.Instance - end -end diff --git a/test/support/resource/organization.ex b/test/support/resource/organization.ex new file mode 100644 index 0000000..f50930c --- /dev/null +++ b/test/support/resource/organization.ex @@ -0,0 +1,43 @@ +# SPDX-FileCopyrightText: 2025 diffo contributors +# +# SPDX-License-Identifier: MIT + +defmodule Diffo.Test.Organization do + @moduledoc """ + Diffo - TMF Service and Resource Management with a difference + + Organization - Organization Party + """ + + alias Diffo.Provider.BaseParty + alias Diffo.Test.Nbn + + use Ash.Resource, + fragments: [BaseParty], + domain: Nbn + + resource do + description "An Organization" + plural_name :organizations + end + + jason do + pick [:id, :name, :type] + compact true + end + + outstanding do + expect [:id, :name, :type] + end + + actions do + create :build do + accept [:id, :href, :name] + change set_attribute(:type, :Organization) + end + end + + instances do + role :facilitator, Diffo.Provider.Instance + end +end diff --git a/test/support/resource/person.ex b/test/support/resource/person.ex index ab27e2a..55aeb0b 100644 --- a/test/support/resource/person.ex +++ b/test/support/resource/person.ex @@ -21,7 +21,23 @@ defmodule Diffo.Test.Person do plural_name :persons end - party do - role :managed_by, Diffo.Test.Person + jason do + pick [:id, :name, :type] + compact true + end + + outstanding do + expect [:id, :name, :type] + end + + actions do + create :build do + accept [:id, :href, :name] + change set_attribute(:type, :Individual) + end + end + + parties do + role :manager, Diffo.Test.Person end end diff --git a/test/support/resource/shelf.ex b/test/support/resource/shelf.ex index b9e1ecc..71350ce 100644 --- a/test/support/resource/shelf.ex +++ b/test/support/resource/shelf.ex @@ -53,8 +53,11 @@ defmodule Diffo.Test.Shelf do end parties do - party :facilitated_by, Diffo.Test.Organisation - party :overseen_by, Diffo.Test.Person + party :facilitator, Diffo.Test.Organization + party :overseer, Diffo.Test.Person + party :provider, Diffo.Test.Organization, reference: true + party :manager, Diffo.Test.Organization, calculate: :manager_calc + parties :installer, Diffo.Test.Person, constraints: [min: 1, max: 3] end actions do