Skip to content

Commit 0cee37b

Browse files
Merge pull request #110 from diffo-dev/dev
dev
2 parents e4b19da + 748a855 commit 0cee37b

158 files changed

Lines changed: 6837 additions & 1997 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore.license

Lines changed: 0 additions & 3 deletions
This file was deleted.

.tool-versions.license

Lines changed: 0 additions & 3 deletions
This file was deleted.

.vscode/launch.json

Lines changed: 0 additions & 34 deletions
This file was deleted.

CHANGELOG.md

Lines changed: 65 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,56 +11,26 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
1111

1212
<!-- changelog -->
1313

14-
## [v0.1.0](https://github.com/diffo-dev/diffo/compare/v0.1.0...v0.1.0) (2025-08-11)
15-
16-
### Features:
17-
* initial version on AshNeo4j DataLayer
18-
19-
## [v0.1.1](https://github.com/diffo-dev/diffo/compare/v0.1.0...v0.1.1) (2025-09-09)
20-
21-
### Features:
22-
* update for AshNeo4j DSL changes
23-
* refactor specification relationships
24-
* characteristic value schemas
25-
* customise instance via specification
26-
* improve relationships to avoid circular loads
27-
28-
## [v0.1.2](https://github.com/diffo-dev/diffo/compare/v0.1.1...v0.1.2) (2025-10-20)
29-
30-
### Features
31-
32-
* REUSE compliant
33-
34-
## [v0.1.3](https://github.com/diffo-dev/diffo/compare/v0.1.2...v0.1.3) (2025-12-01)
35-
36-
### Features
14+
## [v0.2.1](https://github.com/diffo-dev/diffo/compare/v0.2.0...v0.2.1) (2026-05-06)
3715

38-
* place_ref source party or place
39-
* party_ref source place or party
40-
* instance events
41-
42-
### Maintenance
43-
44-
* remove access domain
45-
46-
## [v0.1.4](https://github.com/diffo-dev/diffo/compare/v0.1.3...v0.1.4) (2026-03-12)
16+
## Notable Changes
17+
* Updated to ash_neo4j 0.4.1 and bolty 0.0.12, now supporting transactions and test sandbox
18+
* Improvements to provider DSL and documentation
4719

48-
### Features
20+
## What's Changed
21+
* base party and related DSL and livebook by @matt-beanland in https://github.com/diffo-dev/diffo/pull/82
22+
* Instance DSL parties — multiplicity, validation, and enforcement by @matt-beanland in https://github.com/diffo-dev/diffo/pull/89
23+
* 86 transformers persisters verifiers by @matt-beanland in https://github.com/diffo-dev/diffo/pull/92
24+
* 91 place dsl by @matt-beanland in https://github.com/diffo-dev/diffo/pull/93
25+
* 79 provider instance specification doesnt set description by @matt-beanland in https://github.com/diffo-dev/diffo/pull/95
26+
* 94 provider instance specification dsl additional fields by @matt-beanland in https://github.com/diffo-dev/diffo/pull/97
27+
* document instance versioning lifecycle by @matt-beanland in https://github.com/diffo-dev/diffo/pull/98
28+
* accept raw dynamic by @matt-beanland in https://github.com/diffo-dev/diffo/pull/100
29+
* removed duplicate tests by @matt-beanland in https://github.com/diffo-dev/diffo/pull/108
30+
* 105 latest ash neo4j by @matt-beanland in https://github.com/diffo-dev/diffo/pull/109
4931

50-
* assigner unassign operation
51-
52-
### Maintenance
53-
54-
* updated ash_neo4j, uses bolty rather than boltx
55-
56-
## [v0.1.5](https://github.com/diffo-dev/diffo/compare/v0.1.4...v0.1.5) (2026-03-19)
57-
58-
### Fixes
59-
60-
* fixed relationship enrichment inconsistent across neo4j versions
6132

6233
## [v0.2.0](https://github.com/diffo-dev/diffo/compare/v0.1.6...v0.2.0) (2026-04-24)
63-
6434
### Breaking Changes
6535

6636
* Updated to ash_neo4j 0.3.1 and bolty 0.0.10 — no database compatibility with prior versions due to significant changes in the data layer and Bolt protocol handling
@@ -94,4 +64,53 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
9464

9565
### Maintenance
9666

97-
* improved error handling
67+
* improved error handling
68+
69+
[v0.1.5](https://github.com/diffo-dev/diffo/compare/v0.1.4...v0.1.5) (2026-03-19)
70+
71+
### Fixes
72+
73+
* fixed relationship enrichment inconsistent across neo4j versions
74+
75+
## [v0.1.4](https://github.com/diffo-dev/diffo/compare/v0.1.3...v0.1.4) (2026-03-12)
76+
77+
### Features
78+
79+
* assigner unassign operation
80+
81+
### Maintenance
82+
83+
* updated ash_neo4j, uses bolty rather than boltx
84+
85+
## [v0.1.3](https://github.com/diffo-dev/diffo/compare/v0.1.2...v0.1.3) (2025-12-01)
86+
87+
### Features
88+
89+
* place_ref source party or place
90+
* party_ref source place or party
91+
* instance events
92+
93+
### Maintenance
94+
95+
* remove access domain
96+
97+
## [v0.1.2](https://github.com/diffo-dev/diffo/compare/v0.1.1...v0.1.2) (2025-10-20)
98+
99+
### Features
100+
101+
* REUSE compliant
102+
103+
## [v0.1.1](https://github.com/diffo-dev/diffo/compare/v0.1.0...v0.1.1) (2025-09-09)
104+
105+
### Features:
106+
* update for AshNeo4j DSL changes
107+
* refactor specification relationships
108+
* characteristic value schemas
109+
* customise instance via specification
110+
* improve relationships to avoid circular loads
111+
112+
## [v0.1.0](https://github.com/diffo-dev/diffo/compare/v0.1.0...v0.1.0) (2025-08-11)
113+
114+
### Features:
115+
* initial version on AshNeo4j DataLayer
116+

REUSE.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
version = 1
2+
3+
[[annotations]]
4+
path = [
5+
".gitignore",
6+
".tool-versions",
7+
"mix.lock",
8+
"logos/diffo.jpg",
9+
"documentation/dsls/**",
10+
]
11+
SPDX-FileCopyrightText = "2025 diffo contributors <https://github.com/diffo-dev/diffo/graphs.contributors>"
12+
SPDX-License-Identifier = "MIT"

diffo.livemd

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!--
1+
<!--
22
SPDX-FileCopyrightText: 2025 diffo contributors <https://github.com/diffo-dev/diffo/graphs.contributors>
33
44
SPDX-License-Identifier: MIT
@@ -9,7 +9,7 @@ SPDX-License-Identifier: MIT
99
```elixir
1010
Mix.install(
1111
[
12-
{:diffo, "~> 0.2.0"}
12+
{:diffo, "~> 0.2.1"}
1313
],
1414
consolidate_protocols: false
1515
)
@@ -113,10 +113,41 @@ alias Diffo.Provider.PartyRef
113113
alias Diffo.Provider.Place
114114
alias Diffo.Provider.PartyRef
115115
alias Diffo.Uuid
116+
alias Diffo.Type.Value
116117
import Jason, only: [encode: 2]
117118
use Outstand
118119
```
119120

121+
The value types used in this livebook are defined without the Provider Extension DSL — each requires a dedicated `Ash.TypedStruct` so that `Diffo.Type.Dynamic` can round-trip values through Neo4j storage.
122+
123+
```elixir
124+
defmodule Diffo.Livebook.E2eValue do
125+
@derive Jason.Encoder
126+
use Ash.TypedStruct
127+
typed_struct do
128+
field :downstream, :integer
129+
field :upstream, :integer
130+
field :units, :atom
131+
end
132+
end
133+
134+
defmodule Diffo.Livebook.OptionsValue do
135+
@derive Jason.Encoder
136+
use Ash.TypedStruct
137+
typed_struct do
138+
field :options, {:array, :atom}
139+
end
140+
end
141+
142+
defmodule Diffo.Livebook.TechnologyValue do
143+
@derive Jason.Encoder
144+
use Ash.TypedStruct
145+
typed_struct do
146+
field :access, :atom
147+
end
148+
end
149+
```
150+
120151
We can either create specification instances with Ash directly, or use the Diffo.Provider code interface.
121152

122153
```elixir
@@ -173,13 +204,13 @@ individual =
173204
Diffo.Provider.create_party!(%{
174205
id: "IND000000897354",
175206
name: :individualId,
176-
referredType: :Individual
207+
referred_type: :Individual
177208
})
178209
org =
179210
Diffo.Provider.create_party!(%{
180211
id: "ORG000000123456",
181212
name: :organizationId,
182-
referredType: :Organization
213+
referred_type: :Organization
183214
})
184215
parties = [individual, org]
185216
Jason.encode!(parties, pretty: true) |> IO.puts
@@ -197,7 +228,7 @@ Jason.encode!(parties, pretty: true) |> IO.puts
197228
We'll also add a CustomerSite place where the service is to be delivered to the customer. Historically this is the Z-end.
198229

199230
```elixir
200-
z_end = Provider.create_place!(%{id: "1657363", name: :addressId, href: "place/telco/1657363", referredType: :GeographicAddress})
231+
z_end = Provider.create_place!(%{id: "1657363", name: :addressId, href: "place/telco/1657363", referred_type: :GeographicAddress})
201232
Jason.encode!(z_end, pretty: true) |> IO.puts
202233
```
203234

@@ -230,7 +261,7 @@ First we'll create a backup feature to indicate that we want mobile backup, and
230261
We'll create an e2e 'instance' characteristic to detail our bandwidth and latency requirements:
231262

232263
```elixir
233-
e2e = Provider.create_characteristic!(%{type: :instance, name: :e2e, value: %{bandwidth: %{downstream: 250, upstream: 25, units: :Mbps}}})
264+
e2e = Provider.create_characteristic!(%{type: :instance, name: :e2e, value: Value.dynamic(%Diffo.Livebook.E2eValue{downstream: 250, upstream: 25, units: :Mbps})})
234265
broadband_0001 = broadband_0001
235266
|> Provider.relate_instance_characteristics!(%{characteristics: [e2e.id]})
236267
broadband_0001 |> Jason.encode!(pretty: true) |> IO.puts
@@ -240,7 +271,7 @@ We'll create mobile backup and device management features. The device management
240271

241272
```elixir
242273
backup = Provider.create_feature!(%{name: :backup, isEnabled: true})
243-
options = Provider.create_characteristic!(%{type: :feature, name: :options, value: [:updates, :monitoring]})
274+
options = Provider.create_characteristic!(%{type: :feature, name: :options, value: Value.dynamic(%Diffo.Livebook.OptionsValue{options: [:updates, :monitoring]})})
244275
device_management = Provider.create_feature!(%{name: :deviceManagement, isEnabled: true, characteristics: [options.id]})
245276
broadband_0001 = broadband_0001
246277
|> Provider.relate_instance_features!(%{features: [backup.id, device_management.id]})
@@ -305,13 +336,13 @@ We'll have a few things outstanding which we would normally find out during serv
305336
We recommend using outstanding to drive next task logic, so that the orchestration is directed by the difference engine. This could look like an address lookup (where we learn the provider) followed by a provider service qualification (where we learn the technology) and the related network places.
306337

307338
```elixir
308-
nbn = Provider.create_party!(%{id: :nbn, name: "NBNCo", referredType: :Organization})
339+
nbn = Provider.create_party!(%{id: "nbn", name: "NBNCo", referred_type: :Organization})
309340
nbn_party_ref = Provider.create_party_ref!(%{instance_id: broadband_0001.id, party_id: nbn.id, role: :Provider})
310-
provider_z_end = Provider.create_place!(%{id: "LOC000000899353", name: "locationId", href: "place/nbnco/LOC000000899353",referredType: :GeographicAddress})
341+
provider_z_end = Provider.create_place!(%{id: "LOC000000899353", name: "locationId", href: "place/nbnco/LOC000000899353", referred_type: :GeographicAddress})
311342
provider_z_end_place_ref = Provider.create_place_ref!(%{instance_id: broadband_0001.id, role: :CustomerSite, place_id: provider_z_end.id})
312-
csa = Provider.create_place!(%{id: "CSA200000000685", name: "csaId", href: "place/nbnco/CSA200000000685", referredType: :GeographicLocation})
343+
csa = Provider.create_place!(%{id: "CSA200000000685", name: "csaId", href: "place/nbnco/CSA200000000685", referred_type: :GeographicLocation})
313344
csa_place_ref = Provider.create_place_ref!(%{instance_id: broadband_0001.id, role: :ServingArea, place_id: csa.id})
314-
poi = Provider.create_place!(%{id: "2CAR", name: "poiId", href: "place/nbnco/2CAR",referredType: :GeographicSite})
345+
poi = Provider.create_place!(%{id: "2CAR", name: "poiId", href: "place/nbnco/2CAR", referred_type: :GeographicSite})
315346
poi_place_ref = Provider.create_place_ref!(%{instance_id: broadband_0001.id, role: :AccessNNI, place_id: poi.id})
316347

317348
places = Diffo.Provider.list_place_refs!()
@@ -331,7 +362,7 @@ outstanding = expected_instance --- broadband_0001
331362
We create and add the technology characteristic to the actual service. This should resolve the characteristic expectation.
332363

333364
```elixir
334-
technology = Provider.create_characteristic!(%{type: :instance, name: :technology, value: %{access: :nbnEthernet}})
365+
technology = Provider.create_characteristic!(%{type: :instance, name: :technology, value: Value.dynamic(%Diffo.Livebook.TechnologyValue{access: :nbnEthernet})})
335366
broadband_0001 |> Provider.relate_instance_characteristics!(%{characteristics: [technology.id]})
336367

337368

@@ -358,6 +389,7 @@ Given that our feasibilityCheck above was complete we want to set the :feasibili
358389

359390
```elixir
360391
broadband_0001 = broadband_0001 |> Provider.feasibilityCheck_service!(%{service_operating_status: :feasible})
392+
broadband_0001 = Provider.get_instance_by_id!(broadband_0001.id)
361393
broadband_0001 |> Jason.encode!(pretty: true) |> IO.puts
362394
```
363395

@@ -450,4 +482,6 @@ broadband_0001 |> Jason.encode!(pretty: true) |> IO.puts
450482
In this tutorial you've used Diffo to create, relate and update some TMF Service and Resources, simulating activities over the service and resource lifecycle, and you've learned how this functionality is underpinned by open source Neo4j, Ash Framework and Elixir.
451483
Diffo contains an example Access domain showing how to specialise the structure and behaviour of TMF Services and Resources.
452484

485+
But there is a lot of friction here and we still only have structure and not much behaviour. In practice, you'd use the Provider Extension DSLs to do the heavy lifting. But what you've learned here is foundational to help you move on to the other livebooks.
486+
453487
If you find Diffo useful please visit and star on [github](https://github.com/diffo-dev/diffo/). Feel free to join discussions and raise issues to discuss PR's.

0 commit comments

Comments
 (0)