diff --git a/SysML2.NET.Serializer.Json.Tests/ApiSerializerTestFixture.cs b/SysML2.NET.Serializer.Json.Tests/ApiSerializerTestFixture.cs
index da6673267..e8a6bd10e 100644
--- a/SysML2.NET.Serializer.Json.Tests/ApiSerializerTestFixture.cs
+++ b/SysML2.NET.Serializer.Json.Tests/ApiSerializerTestFixture.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
+//
// Copyright 2022-2025 Starion Group S.A.
-//
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -73,7 +73,7 @@ private void CreateTestData()
Created = new DateTime(1976, 8, 20, 0, 0, 0, DateTimeKind.Utc),
Description = "",
OwningProject = Guid.Parse("9b0e1914-3241-461e-b9ee-a3ff5120de4e"),
- PreviousCommit = Guid.Empty,
+ PreviousCommits = [Guid.Parse("8d3c3f31-2b2f-4f4b-8f35-6b2e0f4a4a11")],
ResourceIdentifier = "http://www.stariongroup.eu/commit",
};
diff --git a/SysML2.NET.Serializer.Json.Tests/DeSerializerTestFixture.cs b/SysML2.NET.Serializer.Json.Tests/DeSerializerTestFixture.cs
index ffe351f42..57ba1154f 100644
--- a/SysML2.NET.Serializer.Json.Tests/DeSerializerTestFixture.cs
+++ b/SysML2.NET.Serializer.Json.Tests/DeSerializerTestFixture.cs
@@ -64,6 +64,20 @@ public class DeSerializerTestFixture
///
private const int LargePayloadElementCount = 4000;
+ ///
+ /// A merge commit json object that names two immediately preceding commits
+ ///
+ private const string MergeCommit = """[{"@id":"6d7ad9fd-6520-4ff2-885b-8c5c129e6c27","@type":"Commit","created":"2023-03-13T17:53:59.111354-04:00","description":null,"owningProject":{"@id":"000e9890-6935-43e6-a5d7-5d7cac601f4c"},"previousCommit":[{"@id":"1e4c2a06-0f2f-4a3c-9d64-0f4b2f6d9a11"},{"@id":"2b7d5e18-6a4f-4d1e-8c32-7d5a1c8e4b22"}]}]""";
+
+ ///
+ /// The identifiers that the payload names as preceding commits
+ ///
+ private static readonly Guid[] MergeCommitPredecessors =
+ [
+ Guid.Parse("1e4c2a06-0f2f-4a3c-9d64-0f4b2f6d9a11"),
+ Guid.Parse("2b7d5e18-6a4f-4d1e-8c32-7d5a1c8e4b22")
+ ];
+
private DeSerializer deSerializer;
[SetUp]
@@ -209,7 +223,7 @@ public void Verify_that_particular_project_and_commits_from_restapi_json_can_be_
using (Assert.EnterMultipleScope())
{
Assert.That(firstCommit.OwningProject, Is.EqualTo(Guid.Parse("000e9890-6935-43e6-a5d7-5d7cac601f4c")));
- Assert.That(firstCommit.PreviousCommit, Is.EqualTo(Guid.Empty));
+ Assert.That(firstCommit.PreviousCommits, Has.Count.EqualTo(0));
Assert.That(firstCommit.Description, Is.Null);
Assert.That(firstCommit.Created, Is.EqualTo(DateTime.Parse("2023-03-13T17:53:59.111354-04:00", CultureInfo.InvariantCulture)));
}
@@ -232,12 +246,30 @@ public void Verify_that_particular_project_and_particular_commit_from_restapi_js
using (Assert.EnterMultipleScope())
{
Assert.That(firstCommit.OwningProject, Is.EqualTo(Guid.Parse("000e9890-6935-43e6-a5d7-5d7cac601f4c")));
- Assert.That(firstCommit.PreviousCommit, Is.EqualTo(Guid.Empty));
+ Assert.That(firstCommit.PreviousCommits, Has.Count.EqualTo(0));
Assert.That(firstCommit.Description, Is.Null);
Assert.That(firstCommit.Created, Is.EqualTo(DateTime.Parse("2023-03-13T17:53:59.111354-04:00", CultureInfo.InvariantCulture)));
}
}
+ [Test]
+ [TestCase(false)]
+ [TestCase(true)]
+ public void Verify_that_a_merge_commit_from_restapi_json_can_be_deserialized(bool shouldDeserializeDerivedProperties)
+ {
+ using var stream = new MemoryStream(Encoding.UTF8.GetBytes(MergeCommit));
+
+ var data = this.deSerializer.DeSerialize(stream, SerializationModeKind.JSON, SerializationTargetKind.PSM, shouldDeserializeDerivedProperties);
+
+ var mergeCommit = data.OfType().Single();
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(mergeCommit.PreviousCommits, Is.EqualTo(MergeCommitPredecessors));
+ Assert.That(mergeCommit.OwningProject, Is.EqualTo(Guid.Parse("000e9890-6935-43e6-a5d7-5d7cac601f4c")));
+ }
+ }
+
[Test]
[TestCase(false)]
[TestCase(true)]
diff --git a/SysML2.NET.Serializer.Json/PIM/CommitDeSerializer.cs b/SysML2.NET.Serializer.Json/PIM/CommitDeSerializer.cs
index 62d99b6ba..d0b3f9d7e 100644
--- a/SysML2.NET.Serializer.Json/PIM/CommitDeSerializer.cs
+++ b/SysML2.NET.Serializer.Json/PIM/CommitDeSerializer.cs
@@ -145,18 +145,17 @@ internal static Commit DeSerialize(JsonElement jsonElement, SerializationModeKin
if (jsonElement.TryGetProperty("previousCommit"u8, out JsonElement previousCommitProperty))
{
- if (previousCommitProperty.ValueKind == JsonValueKind.Null)
+ if (previousCommitProperty.ValueKind == JsonValueKind.Array)
{
- dtoInstance.PreviousCommit = Guid.Empty;
- }
- else
- {
- if (previousCommitProperty.TryGetProperty("@id"u8, out JsonElement previousCommitPropertyIdProperty))
+ foreach (var previousCommitItem in previousCommitProperty.EnumerateArray())
{
- var propertyValue = previousCommitPropertyIdProperty.GetString();
- if (propertyValue != null)
+ if (previousCommitItem.TryGetProperty("@id"u8, out JsonElement previousCommitItemIdProperty))
{
- dtoInstance.PreviousCommit = Guid.Parse(propertyValue);
+ var propertyValue = previousCommitItemIdProperty.GetString();
+ if (propertyValue != null)
+ {
+ dtoInstance.PreviousCommits.Add(Guid.Parse(propertyValue));
+ }
}
}
}
@@ -165,7 +164,7 @@ internal static Commit DeSerialize(JsonElement jsonElement, SerializationModeKin
{
if (logger.IsEnabled(LogLevel.Debug))
{
- logger.LogDebug("the owningProject Json property was not found in the Commit: {Id}", dtoInstance.Id);
+ logger.LogDebug("the previousCommit Json property was not found in the Commit: {Id}", dtoInstance.Id);
}
}
diff --git a/SysML2.NET.Serializer.Json/PIM/CommitSerializer.cs b/SysML2.NET.Serializer.Json/PIM/CommitSerializer.cs
index 53405053c..8b6528f9c 100644
--- a/SysML2.NET.Serializer.Json/PIM/CommitSerializer.cs
+++ b/SysML2.NET.Serializer.Json/PIM/CommitSerializer.cs
@@ -75,9 +75,17 @@ internal static void Serialize(object obj, Utf8JsonWriter writer, SerializationM
writer.WriteString("@id"u8, commit.OwningProject);
writer.WriteEndObject();
writer.WriteString("resourceIdentifier"u8, commit.ResourceIdentifier);
- writer.WriteStartObject("previousCommit"u8);
- writer.WriteString("@id"u8, commit.PreviousCommit);
- writer.WriteEndObject();
+ writer.WriteStartArray("previousCommit"u8);
+ if (commit.PreviousCommits != null)
+ {
+ foreach (var item in commit.PreviousCommits)
+ {
+ writer.WriteStartObject();
+ writer.WriteString("@id"u8, item);
+ writer.WriteEndObject();
+ }
+ }
+ writer.WriteEndArray();
writer.WriteEndObject();
break;
diff --git a/SysML2.NET.Tests/PSM/DTO/MergeOutcomeTestFixture.cs b/SysML2.NET.Tests/PSM/DTO/MergeOutcomeTestFixture.cs
new file mode 100644
index 000000000..a0c8af964
--- /dev/null
+++ b/SysML2.NET.Tests/PSM/DTO/MergeOutcomeTestFixture.cs
@@ -0,0 +1,93 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.Tests.PSM.DTO
+{
+ using System;
+
+ using NUnit.Framework;
+
+ using SysML2.NET.PSM.DTO;
+
+ [TestFixture]
+ public class MergeOutcomeTestFixture
+ {
+ private static readonly DataIdentity[] NoIdentities = [];
+
+ [Test]
+ public void VerifyMerged()
+ {
+ Assert.That(() => MergeOutcome.Merged(null), Throws.TypeOf());
+
+ var commit = new Commit { Id = Guid.NewGuid() };
+ var outcome = MergeOutcome.Merged(commit);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(outcome.Kind, Is.EqualTo(MergeOutcomeKind.Merged));
+ Assert.That(outcome.IsMerged, Is.True);
+ Assert.That(outcome.TryGetMergeCommit(out var held), Is.True);
+ Assert.That(held, Is.SameAs(commit));
+ Assert.That(outcome.TryGetConflict(out var conflict), Is.False);
+ Assert.That(conflict, Is.Empty);
+ }
+ }
+
+ [Test]
+ public void VerifyConflicted()
+ {
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(() => MergeOutcome.Conflicted(null), Throws.TypeOf());
+ Assert.That(() => MergeOutcome.Conflicted(NoIdentities), Throws.TypeOf());
+ }
+
+ var identity = new DataIdentity { Id = Guid.NewGuid() };
+ var outcome = MergeOutcome.Conflicted([identity]);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(outcome.Kind, Is.EqualTo(MergeOutcomeKind.Conflicted));
+ Assert.That(outcome.IsMerged, Is.False);
+ Assert.That(outcome.TryGetConflict(out var held), Is.True);
+ Assert.That(held, Has.Count.EqualTo(1));
+ Assert.That(held[0], Is.SameAs(identity));
+ Assert.That(outcome.TryGetMergeCommit(out var commit), Is.False);
+ Assert.That(commit, Is.Null);
+ }
+ }
+
+ [Test]
+ public void VerifyMatch()
+ {
+ var merged = MergeOutcome.Merged(new Commit { Id = Guid.NewGuid() });
+ var conflicted = MergeOutcome.Conflicted([new DataIdentity { Id = Guid.NewGuid() }]);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(() => merged.Match(null, conflict => conflict.Count), Throws.TypeOf());
+ Assert.That(() => merged.Match(commit => 1, null), Throws.TypeOf());
+ Assert.That(merged.Match(commit => "merged", conflict => "conflicted"), Is.EqualTo("merged"));
+ Assert.That(conflicted.Match(commit => "merged", conflict => "conflicted"), Is.EqualTo("conflicted"));
+ Assert.That(conflicted.Match(commit => 0, conflict => conflict.Count), Is.EqualTo(1));
+ }
+ }
+ }
+}
diff --git a/SysML2.NET.Tests/PSM/DTO/MergeResultMapperTestFixture.cs b/SysML2.NET.Tests/PSM/DTO/MergeResultMapperTestFixture.cs
new file mode 100644
index 000000000..b4d6fc679
--- /dev/null
+++ b/SysML2.NET.Tests/PSM/DTO/MergeResultMapperTestFixture.cs
@@ -0,0 +1,119 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.Tests.PSM.DTO
+{
+ using System;
+
+ using NUnit.Framework;
+
+ using SysML2.NET.Exceptions;
+ using SysML2.NET.PIM.DTO;
+ using SysML2.NET.PSM.DTO;
+
+ using Commit = SysML2.NET.PSM.DTO.Commit;
+ using DataIdentity = SysML2.NET.PSM.DTO.DataIdentity;
+
+ [TestFixture]
+ public class MergeResultMapperTestFixture
+ {
+ [Test]
+ public void VerifyToPsm()
+ {
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(MergeResultMapper.ToPsm(null), Is.Null);
+ Assert.That(() => MergeResultMapper.ToPsm(new MergeResult()), Throws.TypeOf());
+ }
+
+ var mergeCommit = Guid.NewGuid();
+ var merged = MergeResultMapper.ToPsm(new PIM.DTO.MergeResult { MergeCommit = mergeCommit });
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(merged.Kind, Is.EqualTo(MergeOutcomeKind.Merged));
+ Assert.That(merged.IsMerged, Is.True);
+ Assert.That(merged.TryGetMergeCommit(out var commit), Is.True);
+ Assert.That(merged.TryGetConflict(out var noConflict), Is.False);
+ Assert.That(commit.Id, Is.EqualTo(mergeCommit));
+ Assert.That(noConflict, Is.Empty);
+ }
+
+ var firstIdentity = Guid.NewGuid();
+ var secondIdentity = Guid.NewGuid();
+ var conflicted = MergeResultMapper.ToPsm(new PIM.DTO.MergeResult { Conflict = [firstIdentity, secondIdentity] });
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(conflicted.Kind, Is.EqualTo(MergeOutcomeKind.Conflicted));
+ Assert.That(conflicted.IsMerged, Is.False);
+ Assert.That(conflicted.TryGetMergeCommit(out var absentCommit), Is.False);
+ Assert.That(absentCommit, Is.Null);
+ Assert.That(conflicted.TryGetConflict(out var conflict), Is.True);
+ Assert.That(conflict, Has.Count.EqualTo(2));
+ Assert.That(conflict[0].Id, Is.EqualTo(firstIdentity));
+ Assert.That(conflict[1].Id, Is.EqualTo(secondIdentity));
+ }
+
+ var both = MergeResultMapper.ToPsm(new PIM.DTO.MergeResult { MergeCommit = mergeCommit, Conflict = [firstIdentity] });
+
+ Assert.That(both.Kind, Is.EqualTo(MergeOutcomeKind.Conflicted));
+ }
+
+ [Test]
+ public void VerifyToPim()
+ {
+ Assert.That(MergeResultMapper.ToPim(null), Is.Null);
+
+ var mergeCommit = Guid.NewGuid();
+ var merged = MergeResultMapper.ToPim(MergeOutcome.Merged(new Commit { Id = mergeCommit }));
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(merged.MergeCommit, Is.EqualTo(mergeCommit));
+ Assert.That(merged.Conflict, Has.Count.EqualTo(0));
+ }
+
+ var identity = Guid.NewGuid();
+ var conflicted = MergeResultMapper.ToPim(MergeOutcome.Conflicted([new DataIdentity { Id = identity }]));
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(conflicted.MergeCommit, Is.EqualTo(Guid.Empty));
+ Assert.That(conflicted.Conflict, Is.EqualTo([identity]));
+ }
+ }
+
+ [Test]
+ public void VerifyRoundTrip()
+ {
+ var merged = new PIM.DTO.MergeResult { MergeCommit = Guid.NewGuid() };
+ var conflicted = new PIM.DTO.MergeResult { Conflict = [Guid.NewGuid(), Guid.NewGuid()] };
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(MergeResultMapper.ToPim(MergeResultMapper.ToPsm(merged)).MergeCommit, Is.EqualTo(merged.MergeCommit));
+ Assert.That(MergeResultMapper.ToPim(MergeResultMapper.ToPsm(merged)).Conflict, Has.Count.EqualTo(0));
+ Assert.That(MergeResultMapper.ToPim(MergeResultMapper.ToPsm(conflicted)).Conflict, Is.EqualTo(conflicted.Conflict));
+ Assert.That(MergeResultMapper.ToPim(MergeResultMapper.ToPsm(conflicted)).MergeCommit, Is.EqualTo(Guid.Empty));
+ }
+ }
+ }
+}
diff --git a/SysML2.NET.Tests/PSM/DTO/PimMappingTestFixture.cs b/SysML2.NET.Tests/PSM/DTO/PimMappingTestFixture.cs
new file mode 100644
index 000000000..c909241b6
--- /dev/null
+++ b/SysML2.NET.Tests/PSM/DTO/PimMappingTestFixture.cs
@@ -0,0 +1,490 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.Tests.PSM.DTO
+{
+ using System;
+ using System.Linq;
+ using System.Runtime.CompilerServices;
+
+ using NUnit.Framework;
+
+ using SysML2.NET.PIM;
+ using SysML2.NET.PSM.DTO;
+
+ [TestFixture]
+ public class PimMappingTestFixture
+ {
+ private static readonly string[] TwoAliases = ["the first alias", "the second alias"];
+
+ private static readonly DateTime Timestamp = new(1976, 8, 20, 0, 0, 0, DateTimeKind.Utc);
+
+ [Test]
+ public void VerifyMap()
+ {
+ Assert.That(() => PimMapper.MapAll(null), Throws.TypeOf());
+ Assert.That(PimMapper.Map(null), Is.Null);
+
+ var record = new PIM.DTO.Project { Id = Guid.NewGuid(), Name = "the project" };
+ var mapped = PimMapper.Map(record);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(mapped, Is.Not.Null);
+ Assert.That(mapped.Id, Is.EqualTo(record.Id));
+ Assert.That(PimMapper.MapAll([record, record]), Has.Count.EqualTo(2));
+ Assert.That(PimMapper.MapAll([]), Has.Count.EqualTo(0));
+ }
+ }
+
+ [Test]
+ public void VerifyProjectRoundTrip()
+ {
+ Assert.That(() => new Project().FromPim(null), Throws.TypeOf());
+
+ var record = new PIM.DTO.Project
+ {
+ Id = Guid.NewGuid(),
+ Alias = [.. TwoAliases],
+ Created = Timestamp,
+ DefaultBranch = Guid.NewGuid(),
+ Description = "the description",
+ Name = "the project",
+ Commits = [Guid.NewGuid()],
+ Queries = [Guid.NewGuid()]
+ };
+
+ var result = RoundTrip(record);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(result.Id, Is.EqualTo(record.Id));
+ Assert.That(result.Alias, Is.EqualTo(TwoAliases));
+ Assert.That(result.Created, Is.EqualTo(record.Created));
+ Assert.That(result.DefaultBranch, Is.EqualTo(record.DefaultBranch));
+ Assert.That(result.Description, Is.EqualTo(record.Description));
+ Assert.That(result.Name, Is.EqualTo(record.Name));
+ Assert.That(result.Commits, Has.Count.EqualTo(0));
+ Assert.That(result.Queries, Has.Count.EqualTo(0));
+ }
+
+ var request = RoundTrip(record);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(request.Name, Is.EqualTo(record.Name));
+ Assert.That(request.DefaultBranch, Is.EqualTo(record.DefaultBranch));
+ Assert.That(request.Id, Is.EqualTo(Guid.Empty));
+ }
+ }
+
+ [Test]
+ public void VerifyCommitRoundTrip()
+ {
+ Assert.That(() => new Commit().FromPim(null), Throws.TypeOf());
+
+ var record = new PIM.DTO.Commit
+ {
+ Id = Guid.NewGuid(),
+ Alias = [.. TwoAliases],
+ Created = Timestamp,
+ Description = "the description",
+ Name = "the commit",
+ OwningProject = Guid.NewGuid(),
+ Change = [Guid.NewGuid()]
+ };
+
+ Assert.That(RoundTrip(record).PreviousCommits, Has.Count.EqualTo(0));
+
+ record.PreviousCommits = [Guid.NewGuid(), Guid.NewGuid()];
+
+ var result = RoundTrip(record);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(result.Id, Is.EqualTo(record.Id));
+ Assert.That(result.Alias, Is.EqualTo(TwoAliases));
+ Assert.That(result.Created, Is.EqualTo(record.Created));
+ Assert.That(result.OwningProject, Is.EqualTo(record.OwningProject));
+ Assert.That(result.PreviousCommits, Is.EqualTo(record.PreviousCommits));
+ Assert.That(result.Change, Has.Count.EqualTo(0));
+ }
+ }
+
+ [Test]
+ public void VerifyBranchRoundTrip()
+ {
+ Assert.That(() => new Branch().FromPim(null), Throws.TypeOf());
+
+ var record = new PIM.DTO.Branch
+ {
+ Id = Guid.NewGuid(),
+ Alias = [.. TwoAliases],
+ Created = Timestamp,
+ Deleted = Timestamp,
+ Description = "the description",
+ Head = Guid.NewGuid(),
+ Name = "the branch",
+ OwningProject = Guid.NewGuid()
+ };
+
+ var model = new Branch();
+ model.FromPim(record);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(model.Head, Is.EqualTo(record.Head));
+ Assert.That(model.ReferencedCommit, Is.EqualTo(record.Head));
+ }
+
+ var result = model.ToPim();
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(result.Id, Is.EqualTo(record.Id));
+ Assert.That(result.Head, Is.EqualTo(record.Head));
+ Assert.That(result.Created, Is.EqualTo(record.Created));
+ Assert.That(result.Deleted, Is.EqualTo(record.Deleted));
+ Assert.That(result.OwningProject, Is.EqualTo(record.OwningProject));
+ Assert.That(RoundTrip(record).Head, Is.EqualTo(record.Head));
+ }
+ }
+
+ [Test]
+ public void VerifyTagRoundTrip()
+ {
+ Assert.That(() => new Tag().FromPim(null), Throws.TypeOf());
+
+ var record = new PIM.DTO.Tag
+ {
+ Id = Guid.NewGuid(),
+ Alias = [.. TwoAliases],
+ Created = Timestamp,
+ Deleted = Timestamp,
+ Description = "the description",
+ Name = "the tag",
+ OwningProject = Guid.NewGuid(),
+ TaggedCommit = Guid.NewGuid()
+ };
+
+ var model = new Tag();
+ model.FromPim(record);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(model.TaggedCommit, Is.EqualTo(record.TaggedCommit));
+ Assert.That(model.ReferencedCommit, Is.EqualTo(record.TaggedCommit));
+ }
+
+ var result = model.ToPim();
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(result.Id, Is.EqualTo(record.Id));
+ Assert.That(result.TaggedCommit, Is.EqualTo(record.TaggedCommit));
+ Assert.That(result.OwningProject, Is.EqualTo(record.OwningProject));
+ Assert.That(RoundTrip(record).TaggedCommit, Is.EqualTo(record.TaggedCommit));
+ }
+ }
+
+ [Test]
+ public void VerifyQueryRoundTrip()
+ {
+ Assert.That(() => new Query().FromPim(null), Throws.TypeOf());
+
+ var record = new PIM.DTO.Query
+ {
+ Id = Guid.NewGuid(),
+ Alias = [.. TwoAliases],
+ Description = "the description",
+ Name = "the query",
+ Project = Guid.NewGuid(),
+ Select = ["name"],
+ OrderBy = ["name"],
+ Scope = [Guid.NewGuid()]
+ };
+
+ Assert.That(RoundTrip(record).Where, Is.Null);
+
+ var leaf = new PIM.DTO.PrimitiveConstraint
+ {
+ Property = "mass",
+ Operator = Operator.lessthanorequalto,
+ Inverse = true,
+ Value = ["4", null]
+ };
+
+ record.Where = leaf;
+
+ var result = RoundTrip(record);
+ var mappedLeaf = result.Where as PIM.DTO.PrimitiveConstraint;
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(result.Project, Is.EqualTo(record.Project));
+ Assert.That(result.Select, Is.EqualTo(["name"]));
+ Assert.That(mappedLeaf, Is.Not.Null);
+ Assert.That(mappedLeaf.Property, Is.EqualTo("mass"));
+ Assert.That(mappedLeaf.Operator, Is.EqualTo(Operator.lessthanorequalto));
+ Assert.That(mappedLeaf.Inverse, Is.True);
+ Assert.That(mappedLeaf.Value, Is.EqualTo(["4", null]));
+ Assert.That(result.OrderBy, Has.Count.EqualTo(0));
+ Assert.That(result.Scope, Has.Count.EqualTo(0));
+ }
+
+ var requestResult = RoundTrip(record);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(requestResult.Where, Is.TypeOf());
+ Assert.That(requestResult.Project, Is.EqualTo(Guid.Empty));
+ }
+ }
+
+ [Test]
+ public void VerifyCompositeConstraintRoundTrip()
+ {
+ Assert.That(() => new CompositeConstraint().FromPim(null), Throws.TypeOf());
+
+ var record = new PIM.DTO.CompositeConstraint { Operator = JoinOperator.OR };
+
+ Assert.That(RoundTrip(record).Constraint, Has.Count.EqualTo(0));
+
+ var leaf = new PIM.DTO.PrimitiveConstraint { Property = "name", Operator = Operator.instanceOf };
+ var nested = new PIM.DTO.CompositeConstraint { Operator = JoinOperator.AND };
+ record.Constraint = [leaf, nested];
+
+ var result = RoundTrip(record);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(result.Operator, Is.EqualTo(JoinOperator.OR));
+ Assert.That(result.Constraint, Has.Count.EqualTo(2));
+ Assert.That(result.Constraint[0], Is.TypeOf());
+ Assert.That(result.Constraint[1], Is.TypeOf());
+ Assert.That(((PIM.DTO.CompositeConstraint)result.Constraint[1]).Operator, Is.EqualTo(JoinOperator.AND));
+ Assert.That(RoundTrip(record).Operator, Is.EqualTo(JoinOperator.OR));
+ }
+ }
+
+ [Test]
+ public void VerifyPrimitiveConstraintRoundTrip()
+ {
+ Assert.That(() => new PrimitiveConstraint().FromPim(null), Throws.TypeOf());
+
+ foreach (var comparisonOperator in Enum.GetValues())
+ {
+ var record = new PIM.DTO.PrimitiveConstraint
+ {
+ Property = "mass",
+ Operator = comparisonOperator,
+ Value = ["4"]
+ };
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(RoundTrip(record).Operator, Is.EqualTo(comparisonOperator));
+ Assert.That(RoundTrip(record).Operator, Is.EqualTo(comparisonOperator));
+ }
+ }
+ }
+
+ [Test]
+ public void VerifyDataVersionRoundTrip()
+ {
+ Assert.That(() => new DataVersion().FromPim(null), Throws.TypeOf());
+
+ var record = new PIM.DTO.DataVersion
+ {
+ Id = Guid.NewGuid(),
+ Alias = [.. TwoAliases],
+ Description = "the description",
+ Name = "the version",
+ Commit = Guid.NewGuid()
+ };
+
+ Assert.That(RoundTrip(record).Identity, Is.Null);
+
+ var identity = new PIM.DTO.DataIdentity { Id = Guid.NewGuid(), Name = "the identity" };
+ record.Identity = identity;
+
+ var result = RoundTrip(record);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(result.Id, Is.EqualTo(record.Id));
+ Assert.That(result.Identity.Id, Is.EqualTo(identity.Id));
+ Assert.That(result.Identity.Name, Is.EqualTo(identity.Name));
+ Assert.That(result.Payload, Is.Null);
+ Assert.That(result.Commit, Is.EqualTo(Guid.Empty));
+ }
+ }
+
+ [Test]
+ public void VerifyDataDifferenceRoundTrip()
+ {
+ Assert.That(() => new DataDifference().FromPim(null), Throws.TypeOf());
+
+ var record = new PIM.DTO.DataDifference();
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(RoundTrip(record).BaseData, Is.Null);
+ Assert.That(RoundTrip(record).CompareData, Is.Null);
+ }
+
+ record.BaseData = Guid.NewGuid();
+ record.CompareData = Guid.NewGuid();
+
+ var result = RoundTrip(record);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(result.BaseData, Is.EqualTo(record.BaseData));
+ Assert.That(result.CompareData, Is.EqualTo(record.CompareData));
+ }
+ }
+
+ [Test]
+ public void VerifyExternalDataRoundTrip()
+ {
+ Assert.That(() => new ExternalData().FromPim(null), Throws.TypeOf());
+
+ var record = new PIM.DTO.ExternalData { Id = Guid.NewGuid() };
+
+ Assert.That(RoundTrip(record).ResourceIdentifier, Is.Null);
+
+ record.ResourceIdentifier = "https://www.stariongroup.eu/Resource?q=1";
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(RoundTrip(record).ResourceIdentifier, Is.EqualTo(record.ResourceIdentifier));
+ Assert.That(RoundTrip(record).Id, Is.EqualTo(record.Id));
+ Assert.That(RoundTrip(record).ResourceIdentifier, Is.EqualTo(record.ResourceIdentifier));
+ }
+ }
+
+ [Test]
+ public void VerifyExternalRelationshipRoundTrip()
+ {
+ Assert.That(() => new ExternalRelationship().FromPim(null), Throws.TypeOf());
+
+ var record = new PIM.DTO.ExternalRelationship
+ {
+ Id = Guid.NewGuid(),
+ ElementEnd = Guid.NewGuid(),
+ ExternalDataEnd = Guid.NewGuid(),
+ Language = "OCL",
+ Specification = "the specification"
+ };
+
+ var result = RoundTrip(record);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(result.Id, Is.EqualTo(record.Id));
+ Assert.That(result.ElementEnd, Is.EqualTo(record.ElementEnd));
+ Assert.That(result.ExternalDataEnd, Is.EqualTo(record.ExternalDataEnd));
+ Assert.That(result.Language, Is.EqualTo(record.Language));
+ Assert.That(result.Specification, Is.EqualTo(record.Specification));
+ Assert.That(RoundTrip(record).ElementEnd, Is.EqualTo(record.ElementEnd));
+ }
+ }
+
+ [Test]
+ public void VerifyProjectUsageRoundTrip()
+ {
+ Assert.That(() => new ProjectUsage().FromPim(null), Throws.TypeOf());
+
+ var record = new PIM.DTO.ProjectUsage
+ {
+ Id = Guid.NewGuid(),
+ UsedCommit = Guid.NewGuid(),
+ UsedProject = Guid.NewGuid()
+ };
+
+ var result = RoundTrip(record);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(result.Id, Is.EqualTo(record.Id));
+ Assert.That(result.UsedCommit, Is.EqualTo(record.UsedCommit));
+ Assert.That(result.UsedProject, Is.EqualTo(record.UsedProject));
+ Assert.That(RoundTrip(record).UsedProject, Is.EqualTo(record.UsedProject));
+ }
+ }
+
+ [Test]
+ public void VerifyDataIdentityRoundTrip()
+ {
+ Assert.That(() => new DataIdentity().FromPim(null), Throws.TypeOf());
+
+ var record = new PIM.DTO.DataIdentity
+ {
+ Id = Guid.NewGuid(),
+ Alias = [.. TwoAliases],
+ Description = "the description",
+ Name = "the identity"
+ };
+
+ var result = RoundTrip(record);
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(result.Id, Is.EqualTo(record.Id));
+ Assert.That(result.Alias, Is.EqualTo(TwoAliases));
+ Assert.That(result.Description, Is.EqualTo(record.Description));
+ Assert.That(result.Name, Is.EqualTo(record.Name));
+ Assert.That(RoundTrip(record).Id, Is.EqualTo(record.Id));
+ }
+ }
+
+ [Test]
+ public void VerifyContractCoverage()
+ {
+ var models = typeof(IResponse).Assembly.GetTypes()
+ .Where(type => type.Namespace == "SysML2.NET.PSM.DTO" && type.IsClass && !type.IsAbstract)
+ .Where(type => !type.IsDefined(typeof(CompilerGeneratedAttribute), false))
+ .ToList();
+
+ var mappable = models
+ .Where(type => type.GetInterfaces().Any(contract =>
+ contract.IsGenericType && contract.GetGenericTypeDefinition() == typeof(IPimMappable<>)))
+ .Select(type => type.Name)
+ .ToList();
+
+ var unmapped = models.Select(type => type.Name).Except(mappable).ToList();
+
+ using (Assert.EnterMultipleScope())
+ {
+ Assert.That(mappable, Has.Count.EqualTo(23));
+ Assert.That(unmapped, Is.EquivalentTo(["Error", "CommitRequest", "DataVersionRequest", "MergeOutcome"]));
+ Assert.That(mappable, Does.Contain("PrimitiveConstraint"));
+ }
+ }
+
+ private static TRecord RoundTrip(TRecord record)
+ where TPsm : class, IPimMappable, new()
+ where TRecord : class
+ {
+ return PimMapper.Map(record).ToPim();
+ }
+ }
+}
diff --git a/SysML2.NET/PIM/DTO/Branch.cs b/SysML2.NET/PIM/DTO/Branch.cs
index ca048e762..244d3ec92 100644
--- a/SysML2.NET/PIM/DTO/Branch.cs
+++ b/SysML2.NET/PIM/DTO/Branch.cs
@@ -22,10 +22,12 @@ namespace SysML2.NET.PIM.DTO
{
using System;
+ using SysML2.NET.Decorators;
+
///
/// A is a type of CommitReference. A is a pointer to a (Branch.head).
/// The history of a on a given branch can be computed by recursively navigating
- /// , starting from the head of the (Branch.head)
+ /// , starting from the head of the (Branch.head)
///
public class Branch : CommitReference
{
@@ -33,6 +35,7 @@ public class Branch : CommitReference
/// Gets or sets the commit to which the branch is currently pointing. It represents the latest state of the
/// on the given branch
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Guid Head { get; set; }
}
}
diff --git a/SysML2.NET/PIM/DTO/Commit.cs b/SysML2.NET/PIM/DTO/Commit.cs
index cc4cd9f25..5e0f144bc 100644
--- a/SysML2.NET/PIM/DTO/Commit.cs
+++ b/SysML2.NET/PIM/DTO/Commit.cs
@@ -23,6 +23,7 @@ namespace SysML2.NET.PIM.DTO
using System;
using System.Collections.Generic;
+ using SysML2.NET.Decorators;
using SysML2.NET.PIM;
///
@@ -31,9 +32,9 @@ namespace SysML2.NET.PIM.DTO
/// a . A has 0 or more s
///
///
- /// s are immutable. For a given record, the value of change
+ /// s are immutable. For a given record, the value of
/// cannot be modified after a has been created. If a modification is required, a new
- /// record can be created with a different value of change.
+ /// record can be created with a different value of .
/// s are not destructible1. A record cannot be deleted during normal
/// end-user operation. s represent the history and evolution of a .
/// Deleting and mutating records must be disabled for the normal end-user operations
@@ -44,16 +45,39 @@ public class Commit : Record
///
/// Gets or sets the timestamp at which the was created
///
+ [Property(lowerValue: 1, upperValue: 1)]
public DateTime Created { get; set; }
///
/// Gets or sets the that owns the .
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Guid OwningProject { get; set; }
///
- /// Gets or sets the immediately preceding s
+ /// Gets or sets the set of immediately preceding s
///
- public Guid PreviousCommit { get; set; }
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
+ public List PreviousCommits { get; set; } = [];
+
+ ///
+ /// Gets or sets the set of records representing data that is created, updated,
+ /// or deleted in the
+ ///
+ ///
+ /// A deletion is recorded by a whose payload is null.
+ ///
+ [Property(lowerValue: 1, upperValue: int.MaxValue)]
+ public List Change { get; set; } = [];
+
+ ///
+ /// Gets or sets the set of cumulative records in a at the
+ ///
+ ///
+ /// Derived by Systems Modeling API and Services, Clause 7.1.2 from and the
+ /// versioned data of .
+ ///
+ [Property(lowerValue: 0, upperValue: int.MaxValue, isDerived: true)]
+ public List VersionedData { get; set; } = [];
}
}
diff --git a/SysML2.NET/PIM/DTO/CommitReference.cs b/SysML2.NET/PIM/DTO/CommitReference.cs
index a12e5bba5..5e4b80ad4 100644
--- a/SysML2.NET/PIM/DTO/CommitReference.cs
+++ b/SysML2.NET/PIM/DTO/CommitReference.cs
@@ -23,6 +23,7 @@ namespace SysML2.NET.PIM.DTO
using System;
using SysML2.NET.Common;
+ using SysML2.NET.Decorators;
///
/// An abstract subclass of that references a specific (Commit Reference.referencedCommit). Project.commit is the set of all the Commit records for a given Project.
@@ -34,21 +35,26 @@ public abstract class CommitReference : Record
///
/// Gets or sets the timestamp at which the was created.
///
+ [Property(lowerValue: 1, upperValue: 1)]
public DateTime Created { get; set; }
///
/// Gets or sets the timestamp at which the was deleted
///
+ [Property(lowerValue: 1, upperValue: 1)]
public DateTime Deleted { get; set; }
///
/// Gets or sets the Project that owns the given
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Guid OwningProject { get; set; }
///
/// Gets or sets the name of the
///
+ [Property(lowerValue: 1, upperValue: 1)]
+ [RedefinedProperty(propertyName: "Record.Name")]
public new string Name { get; set; }
}
}
diff --git a/SysML2.NET/PIM/DTO/CompositeConstraint.cs b/SysML2.NET/PIM/DTO/CompositeConstraint.cs
index 7f01a7a11..c1398dbe2 100644
--- a/SysML2.NET/PIM/DTO/CompositeConstraint.cs
+++ b/SysML2.NET/PIM/DTO/CompositeConstraint.cs
@@ -22,8 +22,10 @@ namespace SysML2.NET.PIM.DTO
{
using System.Collections.Generic;
+ using SysML2.NET.Decorators;
+
///
- /// a subtype of that represents complex conditions composed of two or more
+ /// a concrete subtype of that represents complex conditions composed of two or more
/// s or s using logical AND or OR operators
///
public class CompositeConstraint : Constraint
@@ -34,11 +36,13 @@ public class CompositeConstraint : Constraint
///
/// There must be at least 2
///
+ [Property(lowerValue: 2, upperValue: int.MaxValue)]
public List Constraint { get; set; } = [];
///
/// Gets or sets the logical operator for composing the s
///
+ [Property(lowerValue: 1, upperValue: 1)]
public JoinOperator Operator { get; set; }
}
}
diff --git a/SysML2.NET/PIM/DTO/DataDifference.cs b/SysML2.NET/PIM/DTO/DataDifference.cs
index a766e11c4..6edaf8ea8 100644
--- a/SysML2.NET/PIM/DTO/DataDifference.cs
+++ b/SysML2.NET/PIM/DTO/DataDifference.cs
@@ -22,6 +22,8 @@ namespace SysML2.NET.PIM.DTO
{
using System;
+ using SysML2.NET.Decorators;
+
///
/// Represents a single difference between two compared versions of the same
///
@@ -30,11 +32,13 @@ public class DataDifference
///
/// Gets or sets the taken as the baseline of the comparison, or null when the data was added
///
+ [Property(lowerValue: 0, upperValue: 1)]
public Guid? BaseData { get; set; }
///
/// Gets or sets the compared against the baseline, or null when the data was deleted
///
+ [Property(lowerValue: 0, upperValue: 1)]
public Guid? CompareData { get; set; }
}
}
diff --git a/SysML2.NET/PIM/DTO/DataVersion.cs b/SysML2.NET/PIM/DTO/DataVersion.cs
index a8f2250e1..7b1c3e169 100644
--- a/SysML2.NET/PIM/DTO/DataVersion.cs
+++ b/SysML2.NET/PIM/DTO/DataVersion.cs
@@ -23,6 +23,7 @@ namespace SysML2.NET.PIM.DTO
using System;
using SysML2.NET.Common;
+ using SysML2.NET.Decorators;
///
/// A subclass of that represents at a specific version in its lifecycle.
@@ -32,18 +33,33 @@ namespace SysML2.NET.PIM.DTO
public class DataVersion : Record
{
///
- /// Gets or sets the at which the wrapped data (payload) was created, modified, or deleted.
+ /// Gets or sets the at which the wrapped data (payload) was created, modified, or deleted.
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Guid Commit { get; set; }
+ ///
+ /// Gets or sets the that owns the
+ ///
+ ///
+ /// Derived by Systems Modeling API and Services, Clause 7.1.2 from the owning project of .
+ ///
+ [Property(lowerValue: 1, upperValue: 1, isDerived: true)]
+ public Guid Project { get; set; }
+
///
/// Gets or sets the contained
///
+ [Property(lowerValue: 1, upperValue: 1)]
public DataIdentity Identity { get; set; }
///
/// Gets or sets the that is the payload
///
+ ///
+ /// null when no data with the given identity is present at the .
+ ///
+ [Property(lowerValue: 0, upperValue: 1)]
public IData Payload { get; set; }
}
}
diff --git a/SysML2.NET/PIM/DTO/ExternalData.cs b/SysML2.NET/PIM/DTO/ExternalData.cs
index bfeea1909..cbbe69ba5 100644
--- a/SysML2.NET/PIM/DTO/ExternalData.cs
+++ b/SysML2.NET/PIM/DTO/ExternalData.cs
@@ -23,6 +23,7 @@ namespace SysML2.NET.PIM.DTO
using System;
using SysML2.NET.Common;
+ using SysML2.NET.Decorators;
///
/// ExternalData is a realization of Data, and represents a resource external to a given tool or
@@ -33,11 +34,13 @@ public class ExternalData : IData
///
/// Gets or sets the unique identifier
///
+ [Property(lowerValue: 1, upperValue: 1, isReadOnly: true)]
public Guid Id { get; set; }
///
/// Gets or sets the string representation of the IRI of the resource represented by the ExternalData
///
+ [Property(lowerValue: 1, upperValue: 1)]
public string ResourceIdentifier { get; set; }
}
}
diff --git a/SysML2.NET/PIM/DTO/ExternalRelationship.cs b/SysML2.NET/PIM/DTO/ExternalRelationship.cs
index 959cf816e..413bb2734 100644
--- a/SysML2.NET/PIM/DTO/ExternalRelationship.cs
+++ b/SysML2.NET/PIM/DTO/ExternalRelationship.cs
@@ -23,6 +23,7 @@ namespace SysML2.NET.PIM.DTO
using System;
using SysML2.NET.Common;
+ using SysML2.NET.Decorators;
///
/// ExternalRelationship is a realization of Data, and represents the relationship between a
@@ -35,6 +36,7 @@ public class ExternalRelationship : IData
///
/// Gets or sets the unique identifier
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Guid Id { get; set; }
///
@@ -44,21 +46,25 @@ public class ExternalRelationship : IData
/// would contain mathematical expressions, such as equations, representing the mapping.This is an optional
/// attribute.
///
+ [Property(lowerValue: 0, upperValue: 1)]
public string Specification { get; set; }
///
/// Gets or sets the name of the expression language used for the specification. This is an optional attribute.
///
+ [Property(lowerValue: 0, upperValue: 1)]
public string Language { get; set; }
///
/// Gets or sets the
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Guid ElementEnd { get; set; }
///
/// Gets or sets the
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Guid ExternalDataEnd { get; set; }
}
}
diff --git a/SysML2.NET/PIM/DTO/MergeResult.cs b/SysML2.NET/PIM/DTO/MergeResult.cs
index 4ccde2c02..3550aba8a 100644
--- a/SysML2.NET/PIM/DTO/MergeResult.cs
+++ b/SysML2.NET/PIM/DTO/MergeResult.cs
@@ -23,6 +23,8 @@ namespace SysML2.NET.PIM.DTO
using System;
using System.Collections.Generic;
+ using SysML2.NET.Decorators;
+
///
/// Represents the outcome of merging one into another
///
@@ -31,11 +33,13 @@ public class MergeResult
///
/// Gets or sets the records that could not be merged automatically
///
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
public List Conflict { get; set; } = [];
///
/// Gets or sets the that records the merge
///
+ [Property(lowerValue: 0, upperValue: 1)]
public Guid MergeCommit { get; set; }
}
}
\ No newline at end of file
diff --git a/SysML2.NET/PIM/DTO/PrimitiveConstraint.cs b/SysML2.NET/PIM/DTO/PrimitiveConstraint.cs
index f1de4a81a..8c0978d3b 100644
--- a/SysML2.NET/PIM/DTO/PrimitiveConstraint.cs
+++ b/SysML2.NET/PIM/DTO/PrimitiveConstraint.cs
@@ -22,30 +22,36 @@ namespace SysML2.NET.PIM.DTO
{
using System.Collections.Generic;
+ using SysML2.NET.Decorators;
+
///
- /// a subtype of Constraint that represents simple conditions that be modeled using the
+ /// a concrete subtype of that represents simple conditions that be modeled using the
/// property-operator -value tuple. e.g. mass <= 4 kg, or type instanceOf Generalization
///
- public class PrimitiveConstraint
+ public class PrimitiveConstraint : Constraint
{
///
/// Gets or sets the name of a property of Element or its subtypes that is being constrained
///
+ [Property(lowerValue: 1, upperValue: 1)]
public string Property { get; set; }
///
/// Gets or sets the mathematical operators
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Operator Operator { get; set; }
///
/// Gets or sets list of primitive objects, such as String, Boolean, Integer, Double, and UUID
///
+ [Property(lowerValue: 1, upperValue: int.MaxValue)]
public List Value { get; set;} = [];
///
/// Gets or sets a value indicating a logical NOT operator is applied to the
///
+ [Property(lowerValue: 1, upperValue: 1)]
public bool Inverse { get; set; }
}
}
diff --git a/SysML2.NET/PIM/DTO/Project.cs b/SysML2.NET/PIM/DTO/Project.cs
index f85036624..5c5484b5b 100644
--- a/SysML2.NET/PIM/DTO/Project.cs
+++ b/SysML2.NET/PIM/DTO/Project.cs
@@ -23,6 +23,7 @@ namespace SysML2.NET.PIM.DTO
using System;
using System.Collections.Generic;
+ using SysML2.NET.Decorators;
using SysML2.NET.PIM;
///
@@ -34,26 +35,56 @@ public class Project : Record
///
/// Gets or sets the collection of
///
- public List Commits { get; set; } = new List();
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
+ public List Commits { get; set; } = [];
+
+ ///
+ /// Gets or sets the set of all s in the
+ ///
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
+ public List CommitReferences { get; set; } = [];
+
+ ///
+ /// Gets or sets the set of all es in the
+ ///
+ ///
+ /// A has one or more branches; a default branch is created with the .
+ ///
+ [Property(lowerValue: 1, upperValue: int.MaxValue)]
+ [SubsettedProperty(propertyName: "Project.CommitReferences")]
+ public List Branches { get; set; } = [];
+
+ ///
+ /// Gets or sets the set of all s in the
+ ///
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
+ [SubsettedProperty(propertyName: "Project.CommitReferences")]
+ public List Tags { get; set; } = [];
///
/// Gets or sets the when the project was created
///
+ [Property(lowerValue: 1, upperValue: 1)]
public DateTime Created { get; set; }
///
/// Gets or sets the human readable name
///
+ [Property(lowerValue: 1, upperValue: 1)]
+ [RedefinedProperty(propertyName: "Record.Name")]
public new string Name { get; set; }
///
/// Gets or sets the default in the which is a subset of
///
+ [Property(lowerValue: 1, upperValue: 1)]
+ [SubsettedProperty(propertyName: "Project.Branches")]
public Guid DefaultBranch { get; set; }
///
/// Gets or sets the collection of
///
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
public List Queries { get; set; } = [];
}
}
diff --git a/SysML2.NET/PIM/DTO/ProjectUsage.cs b/SysML2.NET/PIM/DTO/ProjectUsage.cs
index 03ce74367..0b4c05dc8 100644
--- a/SysML2.NET/PIM/DTO/ProjectUsage.cs
+++ b/SysML2.NET/PIM/DTO/ProjectUsage.cs
@@ -23,6 +23,7 @@ namespace SysML2.NET.PIM.DTO
using System;
using SysML2.NET.Common;
+ using SysML2.NET.Decorators;
///
/// a realization of that represents the use of a in the context of another
@@ -33,16 +34,19 @@ public class ProjectUsage : IData
///
/// Gets or sets the unique identifier
///
+ [Property(lowerValue: 1, upperValue: 1, isReadOnly: true)]
public Guid Id { get; set; }
///
/// Gets or sets the reference to the of the being used.
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Guid UsedCommit { get; set; }
///
/// Gets or sets the reference to the of the being used.
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Guid UsedProject { get; set; }
}
}
diff --git a/SysML2.NET/PIM/DTO/Query.cs b/SysML2.NET/PIM/DTO/Query.cs
index e178a3d1d..22df598c4 100644
--- a/SysML2.NET/PIM/DTO/Query.cs
+++ b/SysML2.NET/PIM/DTO/Query.cs
@@ -23,6 +23,8 @@ namespace SysML2.NET.PIM.DTO
using System;
using System.Collections.Generic;
+ using SysML2.NET.Decorators;
+
///
/// is a subclass of that represents a precise and language-independent
/// request for information retrieval using the Systems Modeling API and Services.
@@ -33,24 +35,44 @@ public class Query : Record
///
/// Gets or sets the name of the Query
///
+ [Property(lowerValue: 1, upperValue: 1)]
+ [RedefinedProperty(propertyName: "Record.Name")]
public new string Name { get; set; }
+ ///
+ /// Gets or sets the that owns the
+ ///
+ [Property(lowerValue: 1, upperValue: 1)]
+ public Guid Project { get; set; }
+
///
/// list of properties of Element or its subtypes that will be included for each Element object in the
/// query response. Element is the root-metaclass in KerML. If no properties are specified, then all the
/// properties will be included for each Element in the query response
///
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
public List Select { get; set; } = [];
///
/// represents the conditions that Elements in the query response must satisfy
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Constraint Where { get; set; }
///
/// list of Data objects that define the scope context for query execution. The default scope of a
/// Query is the owning Project
///
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
public List Scope { get; set; } = [];
+
+ ///
+ /// Gets or sets the list of properties used for sorting the data objects in the query response
+ ///
+ ///
+ /// The order of the properties in the list governs the sorting order.
+ ///
+ [Property(lowerValue: 0, upperValue: int.MaxValue, isOrdered: true)]
+ public List OrderBy { get; set; } = [];
}
}
diff --git a/SysML2.NET/PIM/DTO/Tag.cs b/SysML2.NET/PIM/DTO/Tag.cs
index e0e50414e..1e073e48e 100644
--- a/SysML2.NET/PIM/DTO/Tag.cs
+++ b/SysML2.NET/PIM/DTO/Tag.cs
@@ -22,6 +22,8 @@ namespace SysML2.NET.PIM.DTO
{
using System;
+ using SysML2.NET.Decorators;
+
///
/// a is used for annotating specific commits-of-interest during development,
/// such as for representing milestones, releases, baselines, or snapshots. A
@@ -32,6 +34,7 @@ public class Tag : CommitReference
///
/// Gets or sets a reference to the tagged
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Guid TaggedCommit { get; set; }
}
}
diff --git a/SysML2.NET/PIM/POCO/Branch.cs b/SysML2.NET/PIM/POCO/Branch.cs
index 9f549c9ff..864c006ff 100644
--- a/SysML2.NET/PIM/POCO/Branch.cs
+++ b/SysML2.NET/PIM/POCO/Branch.cs
@@ -20,10 +20,12 @@
namespace SysML2.NET.PIM.POCO
{
+ using SysML2.NET.Decorators;
+
///
/// A is a type of . A is a pointer to a (Branch.head).
/// The history of a on a given can be computed by recursively navigating
- /// , starting from the head of the (Branch.head)
+ /// , starting from the head of the (Branch.head)
///
public class Branch : CommitReference
{
@@ -31,6 +33,7 @@ public class Branch : CommitReference
/// Gets or sets the commit to which the branch is currently pointing. It represents the latest state of the
/// on the given branch
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Commit Head { get; set; }
}
}
\ No newline at end of file
diff --git a/SysML2.NET/PIM/POCO/Commit.cs b/SysML2.NET/PIM/POCO/Commit.cs
index 3b5c23993..7e9a8b818 100644
--- a/SysML2.NET/PIM/POCO/Commit.cs
+++ b/SysML2.NET/PIM/POCO/Commit.cs
@@ -23,6 +23,7 @@ namespace SysML2.NET.PIM.POCO
using System;
using System.Collections.Generic;
+ using SysML2.NET.Decorators;
using SysML2.NET.PIM;
///
@@ -44,27 +45,35 @@ public class Commit : Record
///
/// Gets or sets the timestamp at which the was created
///
+ [Property(lowerValue: 1, upperValue: 1)]
public DateTime Created { get; set; }
///
/// Gets or sets the that owns the .
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Project OwningProject { get; set; }
///
/// Gets or sets the set of immediately preceding s
///
- public List PreviousCommit { get; set; } = new List();
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
+ public List PreviousCommits { get; set; } = [];
///
/// Gets or sets the the set of records representing that is
/// created, updated, or deleted in the
///
- public List Change { get; set; } = new List();
+ [Property(lowerValue: 1, upperValue: int.MaxValue)]
+ public List Change { get; set; } = [];
///
/// Queries the derived property VersionedData
///
+ /// The set of cumulative records at the .
+ /// Thrown until the derivation is supported.
+ [Property(lowerValue: 0, upperValue: int.MaxValue, isDerived: true)]
+ [DerivedProperty(name: "VersionedData")]
public List QueryVersionedData()
{
throw new NotImplementedException("Derived property VersionedData not yet supported");
diff --git a/SysML2.NET/PIM/POCO/CommitReference.cs b/SysML2.NET/PIM/POCO/CommitReference.cs
index 9a8c1053b..a296c0465 100644
--- a/SysML2.NET/PIM/POCO/CommitReference.cs
+++ b/SysML2.NET/PIM/POCO/CommitReference.cs
@@ -22,9 +22,11 @@ namespace SysML2.NET.PIM.POCO
{
using System;
+ using SysML2.NET.Decorators;
+
///
/// An abstract subclass of that references a specific (Commit Reference.referencedCommit). Project.commit is the set of all the Commit records for a given Project.
- /// identifies specific records in a that provide the context for navigating the
+ /// identifies specific records in a that provide the context for navigating the
/// in a Project. Two special types of are and
///
public abstract class CommitReference : Record
@@ -32,21 +34,26 @@ public abstract class CommitReference : Record
///
/// Gets or sets the timestamp at which the was created.
///
+ [Property(lowerValue: 1, upperValue: 1)]
public DateTime Created { get; set; }
///
/// Gets or sets the timestamp at which the was deleted
///
+ [Property(lowerValue: 1, upperValue: 1)]
public DateTime Deleted { get; set; }
///
/// Gets or sets the name of the
///
+ [Property(lowerValue: 1, upperValue: 1)]
+ [RedefinedProperty(propertyName: "Record.Name")]
public new string Name { get; set; }
///
/// Gets or sets the Project that owns the given
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Project OwningProject { get; set; }
}
}
diff --git a/SysML2.NET/PIM/POCO/CompositeConstraint.cs b/SysML2.NET/PIM/POCO/CompositeConstraint.cs
index 7a49f2845..08172eea0 100644
--- a/SysML2.NET/PIM/POCO/CompositeConstraint.cs
+++ b/SysML2.NET/PIM/POCO/CompositeConstraint.cs
@@ -22,8 +22,10 @@ namespace SysML2.NET.PIM.POCO
{
using System.Collections.Generic;
+ using SysML2.NET.Decorators;
+
///
- /// a subtype of that represents complex conditions composed of two or more
+ /// a concrete subtype of that represents complex conditions composed of two or more
/// s or s using logical AND or OR operators
///
public class CompositeConstraint : Constraint
@@ -34,11 +36,13 @@ public class CompositeConstraint : Constraint
///
/// There must be at least 2
///
+ [Property(lowerValue: 2, upperValue: int.MaxValue)]
public List Constraint { get; set; } = [];
///
/// Gets or sets the logical operator for composing the s
///
+ [Property(lowerValue: 1, upperValue: 1)]
public JoinOperator Operator { get; set; }
}
}
diff --git a/SysML2.NET/PIM/POCO/DataDifference.cs b/SysML2.NET/PIM/POCO/DataDifference.cs
index 67fb80d7d..fe3accbff 100644
--- a/SysML2.NET/PIM/POCO/DataDifference.cs
+++ b/SysML2.NET/PIM/POCO/DataDifference.cs
@@ -20,6 +20,7 @@
namespace SysML2.NET.PIM.POCO
{
+ using SysML2.NET.Decorators;
///
/// Represents a single difference between two compared versions of the same
@@ -29,11 +30,13 @@ public class DataDifference
///
/// Gets or sets the taken as the baseline of the comparison, or null when the data was added
///
+ [Property(lowerValue: 0, upperValue: 1)]
public DataVersion BaseData { get; set; }
///
/// Gets or sets the compared against the baseline, or null when the data was deleted
///
+ [Property(lowerValue: 0, upperValue: 1)]
public DataVersion CompareData { get; set; }
}
}
\ No newline at end of file
diff --git a/SysML2.NET/PIM/POCO/DataIdentity.cs b/SysML2.NET/PIM/POCO/DataIdentity.cs
index 5f95d8d3e..05f0b052f 100644
--- a/SysML2.NET/PIM/POCO/DataIdentity.cs
+++ b/SysML2.NET/PIM/POCO/DataIdentity.cs
@@ -22,6 +22,8 @@ namespace SysML2.NET.PIM.POCO
{
using System.Collections.Generic;
+ using SysML2.NET.Decorators;
+
///
/// A subclass of that represents a unique, version-independent representation of
/// through its lifecycle. A is associated with 1 or more Version
@@ -32,6 +34,7 @@ public class DataIdentity : Record
///
/// Gets or sets the the set of records representing all versions of the given
///
- public List Version = new List();
+ [Property(lowerValue: 1, upperValue: int.MaxValue)]
+ public List Version { get; set; } = [];
}
}
diff --git a/SysML2.NET/PIM/POCO/DataVersion.cs b/SysML2.NET/PIM/POCO/DataVersion.cs
index 8aad1d49d..710bbc6f5 100644
--- a/SysML2.NET/PIM/POCO/DataVersion.cs
+++ b/SysML2.NET/PIM/POCO/DataVersion.cs
@@ -23,7 +23,8 @@ namespace SysML2.NET.PIM.POCO
using System;
using SysML2.NET.Common;
-
+ using SysML2.NET.Decorators;
+
///
/// A subclass of that represents at a specific version in its lifecycle.
/// A record is associated with only one (1) record.
@@ -34,23 +35,31 @@ public class DataVersion : Record
///
/// Gets or sets the at which the wrapped data (payload) was created, modified, or deleted.
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Commit Commit { get; set; }
///
/// Gets or sets a reference to corresponding the
///
+ [Property(lowerValue: 1, upperValue: 1)]
public DataIdentity Identity { get; set; }
///
/// Gets or sets the payload
///
+ ///
+ /// null when no data with the given identity is present at the .
+ ///
+ [Property(lowerValue: 0, upperValue: 1)]
public IData Payload { get; set; }
///
/// Queries the derived property
///
- ///
- ///
+ /// The that owns the .
+ /// Thrown until the derivation is supported.
+ [Property(lowerValue: 1, upperValue: 1, isDerived: true)]
+ [DerivedProperty(name: "Project")]
public Project QueryProject()
{
throw new NotImplementedException("Derived property Project not yet supported");
diff --git a/SysML2.NET/PIM/POCO/ExternalData.cs b/SysML2.NET/PIM/POCO/ExternalData.cs
index 868a29a7d..45ee9a646 100644
--- a/SysML2.NET/PIM/POCO/ExternalData.cs
+++ b/SysML2.NET/PIM/POCO/ExternalData.cs
@@ -23,6 +23,7 @@ namespace SysML2.NET.PIM.POCO
using System;
using SysML2.NET.Common;
+ using SysML2.NET.Decorators;
///
/// ExternalData is a realization of Data, and represents a resource external to a given tool or
@@ -33,11 +34,13 @@ public class ExternalData : IData
///
/// Gets or sets the unique identifier
///
+ [Property(lowerValue: 1, upperValue: 1, isReadOnly: true)]
public Guid Id { get; set; }
///
/// Gets or sets the string representation of the IRI of the resource represented by the ExternalData
///
+ [Property(lowerValue: 1, upperValue: 1)]
public string ResourceIdentifier { get; set; }
}
}
diff --git a/SysML2.NET/PIM/POCO/ExternalRelationship.cs b/SysML2.NET/PIM/POCO/ExternalRelationship.cs
index 6fbb1af54..4f6b36867 100644
--- a/SysML2.NET/PIM/POCO/ExternalRelationship.cs
+++ b/SysML2.NET/PIM/POCO/ExternalRelationship.cs
@@ -25,6 +25,7 @@ namespace SysML2.NET.PIM.POCO
using SysML2.NET.Common;
using SysML2.NET.Core.POCO;
using SysML2.NET.Core.POCO.Root.Elements;
+ using SysML2.NET.Decorators;
///
/// ExternalRelationship is a realization of Data, and represents the relationship between a
@@ -37,6 +38,7 @@ public class ExternalRelationship : IData
///
/// Gets or sets the unique identifier
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Guid Id { get; set; }
///
@@ -46,21 +48,25 @@ public class ExternalRelationship : IData
/// would contain mathematical expressions, such as equations, representing the mapping.This is an optional
/// attribute.
///
+ [Property(lowerValue: 0, upperValue: 1)]
public string Specification { get; set; }
///
/// Gets or sets the name of the expression language used for the specification. This is an optional attribute.
///
+ [Property(lowerValue: 0, upperValue: 1)]
public string Language { get; set; }
///
/// Gets or sets the
///
+ [Property(lowerValue: 1, upperValue: 1)]
public IElement ElementEnd { get; set; }
///
/// Gets or sets the
///
+ [Property(lowerValue: 1, upperValue: 1)]
public ExternalData ExternalDataEnd { get; set; }
}
}
diff --git a/SysML2.NET/PIM/POCO/MergeResult.cs b/SysML2.NET/PIM/POCO/MergeResult.cs
index ed377a44e..17c44ecd0 100644
--- a/SysML2.NET/PIM/POCO/MergeResult.cs
+++ b/SysML2.NET/PIM/POCO/MergeResult.cs
@@ -22,6 +22,8 @@ namespace SysML2.NET.PIM.POCO
{
using System.Collections.Generic;
+ using SysML2.NET.Decorators;
+
///
/// Represents the outcome of merging one into another
///
@@ -30,11 +32,13 @@ public class MergeResult
///
/// Gets or sets the records that could not be merged automatically
///
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
public List Conflict { get; set; } = [];
///
/// Gets or sets the that records the merge
///
+ [Property(lowerValue: 0, upperValue: 1)]
public Commit MergeCommit { get; set; }
}
}
\ No newline at end of file
diff --git a/SysML2.NET/PIM/POCO/PrimitiveConstraint.cs b/SysML2.NET/PIM/POCO/PrimitiveConstraint.cs
index 5a106a9ad..1b1ed9196 100644
--- a/SysML2.NET/PIM/POCO/PrimitiveConstraint.cs
+++ b/SysML2.NET/PIM/POCO/PrimitiveConstraint.cs
@@ -22,8 +22,10 @@ namespace SysML2.NET.PIM.POCO
{
using System.Collections.Generic;
+ using SysML2.NET.Decorators;
+
///
- /// a subtype of Constraint that represents simple conditions that be modeled using the
+ /// a concrete subtype of that represents simple conditions that be modeled using the
/// property-operator -value tuple. e.g. mass <= 4 kg, or type instanceOf Generalization
///
public class PrimitiveConstraint : Constraint
@@ -31,21 +33,25 @@ public class PrimitiveConstraint : Constraint
///
/// Gets or sets the name of a property of Element or its subtypes that is being constrained
///
+ [Property(lowerValue: 1, upperValue: 1)]
public string Property { get; set; }
///
/// Gets or sets the mathematical operatores
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Operator Operator { get; set; }
///
/// Gets or sets list of primitive objects, such as String, Boolean, Integer, Double, and UUID
///
- public List Value { get; set; } = new List();
+ [Property(lowerValue: 1, upperValue: int.MaxValue)]
+ public List Value { get; set; } = [];
///
/// Gets or sets a value indicating a logical NOT operator is applied to the
///
+ [Property(lowerValue: 1, upperValue: 1)]
public bool Inverse { get; set; }
}
}
\ No newline at end of file
diff --git a/SysML2.NET/PIM/POCO/Project.cs b/SysML2.NET/PIM/POCO/Project.cs
index added9758..07626e172 100644
--- a/SysML2.NET/PIM/POCO/Project.cs
+++ b/SysML2.NET/PIM/POCO/Project.cs
@@ -25,6 +25,7 @@ namespace SysML2.NET.PIM.POCO
using System.Linq;
using SysML2.NET.Common;
+ using SysML2.NET.Decorators;
using SysML2.NET.PIM;
///
@@ -36,11 +37,14 @@ public class Project : Record
///
/// Gets or sets a human-friendly identifier for a Project
///
+ [Property(lowerValue: 1, upperValue: 1)]
+ [RedefinedProperty(propertyName: "Record.Name")]
public new string Name { get; set; }
///
/// Gets or sets the timestamp at which the was created
///
+ [Property(lowerValue: 1, upperValue: 1)]
public DateTime Created { get; set; }
///
@@ -50,37 +54,47 @@ public class Project : Record
///
/// this is a derived attribute
///
+ [Property(lowerValue: 0, upperValue: int.MaxValue, isDerived: true)]
public IEnumerable IdentifiedData => throw new NotImplementedException();
///
/// Gets all the s in the
///
- public List Commits { get; set; } = new List();
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
+ public List Commits { get; set; } = [];
///
/// Gets or sets all s in the
///
- public List CommitReference { get; set; } = new List();
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
+ public List CommitReferences { get; set; } = [];
///
- /// Gets or sets all the branches in the Project which is a subset of
+ /// Gets all the branches in the which is a subset of
///
- public IEnumerable Branches => this.CommitReference.OfType();
+ [Property(lowerValue: 1, upperValue: int.MaxValue, isDerived: true)]
+ [SubsettedProperty(propertyName: "Project.CommitReferences")]
+ public IEnumerable Branches => this.CommitReferences.OfType();
///
/// Gets or sets the default in the which is a subset of
///
+ [Property(lowerValue: 1, upperValue: 1)]
+ [SubsettedProperty(propertyName: "Project.Branches")]
public Branch DefaultBranch { get; set; }
///
- /// Gets all the s in the which is a subset of
+ /// Gets all the s in the which is a subset of
///
- public IEnumerable Tags => this.CommitReference.OfType();
+ [Property(lowerValue: 0, upperValue: int.MaxValue, isDerived: true)]
+ [SubsettedProperty(propertyName: "Project.CommitReferences")]
+ public IEnumerable Tags => this.CommitReferences.OfType();
///
/// Gets or sets the records owned by the . Each record represents a
/// saved for the given .
///
- public List Queries { get; set; } = new List();
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
+ public List Queries { get; set; } = [];
}
}
diff --git a/SysML2.NET/PIM/POCO/ProjectUsage.cs b/SysML2.NET/PIM/POCO/ProjectUsage.cs
index 29e1a375c..d5e91c605 100644
--- a/SysML2.NET/PIM/POCO/ProjectUsage.cs
+++ b/SysML2.NET/PIM/POCO/ProjectUsage.cs
@@ -23,6 +23,7 @@ namespace SysML2.NET.PIM.POCO
using System;
using SysML2.NET.Common;
+ using SysML2.NET.Decorators;
///
/// a realization of that represents the use of a in the context of another
@@ -33,16 +34,19 @@ public class ProjectUsage : IData
///
/// Gets or sets the unique identifier
///
+ [Property(lowerValue: 1, upperValue: 1, isReadOnly: true)]
public Guid Id { get; set; }
///
/// Gets or sets the reference to the of the being used.
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Commit UsedCommit { get; set; }
///
/// Gets or sets the reference to the being used.
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Project UsedProject { get; set; }
}
}
diff --git a/SysML2.NET/PIM/POCO/Query.cs b/SysML2.NET/PIM/POCO/Query.cs
index 1e64da087..a31388a2a 100644
--- a/SysML2.NET/PIM/POCO/Query.cs
+++ b/SysML2.NET/PIM/POCO/Query.cs
@@ -23,6 +23,7 @@ namespace SysML2.NET.PIM.POCO
using System.Collections.Generic;
using SysML2.NET.Common;
+ using SysML2.NET.Decorators;
///
/// is a subclass of that represents a precise and language-independent
@@ -34,30 +35,42 @@ public class Query : Record
///
/// Gets or sets the name of the Query
///
+ [Property(lowerValue: 1, upperValue: 1)]
+ [RedefinedProperty(propertyName: "Record.Name")]
public new string Name { get; set; }
+ ///
+ /// Gets or sets the that owns the
+ ///
+ [Property(lowerValue: 1, upperValue: 1)]
+ public Project Project { get; set; }
+
///
/// list of properties of Element or its subtypes that will be included for each Element object in the
/// query response. Element is the root-metaclass in KerML. If no properties are specified, then all the
/// properties will be included for each Element in the query response
///
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
public List Select { get; set; } = [];
///
/// Gets or sets the list of Element objects that define the scope for query execution. The default scope of a is
- /// the owning
+ /// the owning
///
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
public List Scope { get; set; } = [];
///
/// represents the conditions that Elements in the query response must satisfy
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Constraint Where { get; set; }
///
/// Gets or sets a list of properties of Data (or its realizations) that are used for sorting the Data objects in the
/// query response.The order of properties in the list governs the sorting order
///
+ [Property(lowerValue: 0, upperValue: int.MaxValue, isOrdered: true)]
public List OrderBy { get; set; } = [];
}
}
diff --git a/SysML2.NET/PIM/POCO/Tag.cs b/SysML2.NET/PIM/POCO/Tag.cs
index 746f35548..47940d448 100644
--- a/SysML2.NET/PIM/POCO/Tag.cs
+++ b/SysML2.NET/PIM/POCO/Tag.cs
@@ -22,6 +22,8 @@ namespace SysML2.NET.PIM.POCO
{
using System;
+ using SysML2.NET.Decorators;
+
///
/// a is used for annotating specific commits-of-interest during development,
/// such as for representing milestones, releases, baselines, or snapshots. A
@@ -33,6 +35,7 @@ public class Tag : CommitReference
/// Gets or sets a reference to the which the Tag is pointing. It represents a
/// -of-interest in the owning .
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Commit TaggedCommit { get; set; }
}
}
diff --git a/SysML2.NET/PIM/Record.cs b/SysML2.NET/PIM/Record.cs
index 295e4a6a2..caf6522a4 100644
--- a/SysML2.NET/PIM/Record.cs
+++ b/SysML2.NET/PIM/Record.cs
@@ -1,20 +1,20 @@
// -------------------------------------------------------------------------------------------------
//
-//
+//
// Copyright 2022-2025 Starion Group S.A.
-//
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
-//
+//
//
// ------------------------------------------------------------------------------------------------
@@ -24,6 +24,7 @@ namespace SysML2.NET.PIM
using System.Collections.Generic;
using SysML2.NET.Common;
+ using SysML2.NET.Decorators;
///
/// A Record represents any data that is consumed (input) or produced (output) by the Systems Modeling API
@@ -42,28 +43,34 @@ protected Record()
///
/// Gets or sets the unique identifier of the
///
+ [Property(lowerValue: 1, upperValue: 1)]
public Guid Id { get; set; }
///
/// Gets or sets string representation of the IRI for the
///
+ [Property(lowerValue: 0, upperValue: 1)]
public string ResourceIdentifier { get; set; }
///
/// Gets or sets a collection of other identifiers for this record, especially if the record was created or represented
/// in other software applications and systems
///
+ [Property(lowerValue: 0, upperValue: int.MaxValue)]
public List Alias { get; set; }
///
/// Gets or sets a statement that provides details about the .
///
+ [Property(lowerValue: 1, upperValue: 1)]
public string Description { get; set; }
///
/// Gets or sets an optional human-friendly identifier for a record. The value assigned to the name for a given
/// record must be in the set of values assigned to alias for that record
///
+ [Property(lowerValue: 0, upperValue: 1)]
+ [SubsettedProperty(propertyName: "Record.Alias")]
public string Name { get; set; }
}
}
diff --git a/SysML2.NET/PSM/DTO/ConstraintMapper.cs b/SysML2.NET/PSM/DTO/ConstraintMapper.cs
new file mode 100644
index 000000000..f35f0770d
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/ConstraintMapper.cs
@@ -0,0 +1,294 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright (C) 2022-2026 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+ using System.Globalization;
+
+ using SysML2.NET.PIM;
+ using SysML2.NET.PIM.DTO;
+ using SysML2.NET.PSM.Enumerations;
+
+ ///
+ /// Maps the query condition tree between the Platform Independent Model and the REST/HTTP PSM
+ ///
+ ///
+ /// The condition alternatives are reached through and ,
+ /// which carry no Platform Independent Model counterpart of their own, so the dispatch lives here.
+ ///
+ public static class ConstraintMapper
+ {
+ ///
+ /// Maps a REST/HTTP PSM query condition onto its Platform Independent Model counterpart
+ ///
+ /// The condition to map.
+ /// The Platform Independent Model condition, or null when the condition is null.
+ /// Thrown when the condition is of an alternative the Platform Independent Model does not model.
+ public static Constraint ToPim(IConstraint constraint)
+ {
+ return constraint switch
+ {
+ null => null,
+ PrimitiveConstraint primitive => primitive.ToPim(),
+ CompositeConstraint composite => composite.ToPim(),
+ _ => throw new NotSupportedException($"A {constraint.GetType().Name} has no Platform Independent Model counterpart.")
+ };
+ }
+
+ ///
+ /// Maps a REST/HTTP PSM query condition request onto its Platform Independent Model counterpart
+ ///
+ /// The condition to map.
+ /// The Platform Independent Model condition, or null when the condition is null.
+ /// Thrown when the condition is of an alternative the Platform Independent Model does not model.
+ public static Constraint ToPim(IConstraintRequest request)
+ {
+ return request switch
+ {
+ null => null,
+ PrimitiveConstraintRequest primitive => primitive.ToPim(),
+ CompositeConstraintRequest composite => composite.ToPim(),
+ _ => throw new NotSupportedException($"A {request.GetType().Name} has no Platform Independent Model counterpart.")
+ };
+ }
+
+ ///
+ /// Maps a REST/HTTP PSM comparison operator onto its Platform Independent Model literal
+ ///
+ /// The operator to map.
+ /// The Platform Independent Model literal denoting the same comparison.
+ /// Thrown when the operator has no Platform Independent Model literal.
+ internal static Operator ToPim(PrimitiveConstraintOperator comparisonOperator)
+ {
+ return comparisonOperator switch
+ {
+ PrimitiveConstraintOperator.instanceOf => Operator.instanceOf,
+ PrimitiveConstraintOperator.equalto => Operator.equalto,
+ PrimitiveConstraintOperator.lessthan => Operator.lessthan,
+ PrimitiveConstraintOperator.lessthanorequalto => Operator.lessthanorequalto,
+ PrimitiveConstraintOperator.greaterthan => Operator.greaterthan,
+ PrimitiveConstraintOperator.greaterthanorequalto => Operator.greaterthanorequalto,
+ PrimitiveConstraintOperator.@in => Operator.@in,
+ _ => throw new NotSupportedException($"The {comparisonOperator} operator has no Platform Independent Model literal.")
+ };
+ }
+
+ ///
+ /// Maps a REST/HTTP PSM comparison operator request onto its Platform Independent Model literal
+ ///
+ /// The operator to map.
+ /// The Platform Independent Model literal denoting the same comparison.
+ /// Thrown when the operator has no Platform Independent Model literal.
+ internal static Operator ToPim(PrimitiveConstraintRequestOperator comparisonOperator)
+ {
+ return comparisonOperator switch
+ {
+ PrimitiveConstraintRequestOperator.instanceOf => Operator.instanceOf,
+ PrimitiveConstraintRequestOperator.equalto => Operator.equalto,
+ PrimitiveConstraintRequestOperator.lessthan => Operator.lessthan,
+ PrimitiveConstraintRequestOperator.lessthanorequalto => Operator.lessthanorequalto,
+ PrimitiveConstraintRequestOperator.greaterthan => Operator.greaterthan,
+ PrimitiveConstraintRequestOperator.greaterthanorequalto => Operator.greaterthanorequalto,
+ PrimitiveConstraintRequestOperator.@in => Operator.@in,
+ _ => throw new NotSupportedException($"The {comparisonOperator} operator has no Platform Independent Model literal.")
+ };
+ }
+
+ ///
+ /// Maps a REST/HTTP PSM join operator onto its Platform Independent Model literal
+ ///
+ /// The operator to map.
+ /// The Platform Independent Model literal denoting the same join.
+ /// Thrown when the operator has no Platform Independent Model literal.
+ internal static JoinOperator ToPim(CompositeConstraintOperator joinOperator)
+ {
+ return joinOperator switch
+ {
+ CompositeConstraintOperator.and => JoinOperator.AND,
+ CompositeConstraintOperator.or => JoinOperator.OR,
+ _ => throw new NotSupportedException($"The {joinOperator} join operator has no Platform Independent Model literal.")
+ };
+ }
+
+ ///
+ /// Maps a REST/HTTP PSM join operator request onto its Platform Independent Model literal
+ ///
+ /// The operator to map.
+ /// The Platform Independent Model literal denoting the same join.
+ /// Thrown when the operator has no Platform Independent Model literal.
+ internal static JoinOperator ToPim(CompositeConstraintRequestOperator joinOperator)
+ {
+ return joinOperator switch
+ {
+ CompositeConstraintRequestOperator.and => JoinOperator.AND,
+ CompositeConstraintRequestOperator.or => JoinOperator.OR,
+ _ => throw new NotSupportedException($"The {joinOperator} join operator has no Platform Independent Model literal.")
+ };
+ }
+
+ ///
+ /// Maps a Platform Independent Model query condition onto its REST/HTTP PSM response alternative
+ ///
+ /// The condition to map.
+ /// The response condition, or null when the condition is null.
+ /// Thrown when the condition is of a type the REST/HTTP PSM does not model.
+ public static IConstraint ToResponse(Constraint constraint)
+ {
+ return constraint switch
+ {
+ null => null,
+ PIM.DTO.PrimitiveConstraint primitive => PimMapper.Map(primitive),
+ PIM.DTO.CompositeConstraint composite => PimMapper.Map(composite),
+ _ => throw new NotSupportedException($"A {constraint.GetType().Name} has no REST/HTTP PSM counterpart.")
+ };
+ }
+
+ ///
+ /// Maps a Platform Independent Model comparison operator onto its REST/HTTP PSM response literal
+ ///
+ /// The operator to map.
+ /// The response literal denoting the same comparison.
+ /// Thrown when the operator has no REST/HTTP PSM literal.
+ internal static PrimitiveConstraintOperator ToResponse(Operator comparisonOperator)
+ {
+ return comparisonOperator switch
+ {
+ Operator.instanceOf => PrimitiveConstraintOperator.instanceOf,
+ Operator.equalto => PrimitiveConstraintOperator.equalto,
+ Operator.lessthan => PrimitiveConstraintOperator.lessthan,
+ Operator.lessthanorequalto => PrimitiveConstraintOperator.lessthanorequalto,
+ Operator.greaterthan => PrimitiveConstraintOperator.greaterthan,
+ Operator.greaterthanorequalto => PrimitiveConstraintOperator.greaterthanorequalto,
+ Operator.@in => PrimitiveConstraintOperator.@in,
+ _ => throw new NotSupportedException($"The {comparisonOperator} operator has no REST/HTTP PSM literal.")
+ };
+ }
+
+ ///
+ /// Maps a Platform Independent Model join operator onto its REST/HTTP PSM response literal
+ ///
+ /// The operator to map.
+ /// The response literal denoting the same join.
+ /// Thrown when the operator has no REST/HTTP PSM literal.
+ internal static CompositeConstraintOperator ToResponse(JoinOperator joinOperator)
+ {
+ return joinOperator switch
+ {
+ JoinOperator.AND => CompositeConstraintOperator.and,
+ JoinOperator.OR => CompositeConstraintOperator.or,
+ _ => throw new NotSupportedException($"The {joinOperator} join operator has no REST/HTTP PSM literal.")
+ };
+ }
+
+ ///
+ /// Maps a Platform Independent Model query condition onto its REST/HTTP PSM request alternative
+ ///
+ /// The condition to map.
+ /// The request condition, or null when the condition is null.
+ /// Thrown when the condition is of a type the REST/HTTP PSM does not model.
+ public static IConstraintRequest ToRequest(Constraint constraint)
+ {
+ return constraint switch
+ {
+ null => null,
+ PIM.DTO.PrimitiveConstraint primitive => PimMapper.Map(primitive),
+ PIM.DTO.CompositeConstraint composite => PimMapper.Map(composite),
+ _ => throw new NotSupportedException($"A {constraint.GetType().Name} has no REST/HTTP PSM counterpart.")
+ };
+ }
+
+ ///
+ /// Maps a Platform Independent Model comparison operator onto its REST/HTTP PSM request literal
+ ///
+ /// The operator to map.
+ /// The request literal denoting the same comparison.
+ /// Thrown when the operator has no REST/HTTP PSM literal.
+ internal static PrimitiveConstraintRequestOperator ToRequest(Operator comparisonOperator)
+ {
+ return comparisonOperator switch
+ {
+ Operator.instanceOf => PrimitiveConstraintRequestOperator.instanceOf,
+ Operator.equalto => PrimitiveConstraintRequestOperator.equalto,
+ Operator.lessthan => PrimitiveConstraintRequestOperator.lessthan,
+ Operator.lessthanorequalto => PrimitiveConstraintRequestOperator.lessthanorequalto,
+ Operator.greaterthan => PrimitiveConstraintRequestOperator.greaterthan,
+ Operator.greaterthanorequalto => PrimitiveConstraintRequestOperator.greaterthanorequalto,
+ Operator.@in => PrimitiveConstraintRequestOperator.@in,
+ _ => throw new NotSupportedException($"The {comparisonOperator} operator has no REST/HTTP PSM literal.")
+ };
+ }
+
+ ///
+ /// Maps a Platform Independent Model join operator onto its REST/HTTP PSM request literal
+ ///
+ /// The operator to map.
+ /// The request literal denoting the same join.
+ /// Thrown when the operator has no REST/HTTP PSM literal.
+ internal static CompositeConstraintRequestOperator ToRequest(JoinOperator joinOperator)
+ {
+ return joinOperator switch
+ {
+ JoinOperator.AND => CompositeConstraintRequestOperator.and,
+ JoinOperator.OR => CompositeConstraintRequestOperator.or,
+ _ => throw new NotSupportedException($"The {joinOperator} join operator has no REST/HTTP PSM literal.")
+ };
+ }
+
+ ///
+ /// Renders a REST/HTTP PSM condition value as the string that the Platform Independent Model carries
+ ///
+ /// The value to render.
+ /// The rendered value, or null when the value is the null alternative.
+ ///
+ /// Systems Modeling API and Services, Clause 7.1.4 assigns no explicit type to PrimitiveConstraint::value,
+ /// whereas the Platform Independent Model types it String, so the alternative is not recoverable.
+ ///
+ internal static string ToPimValue(ConstraintValue value)
+ {
+ if (value.TryGetString(out var stringValue))
+ {
+ return stringValue;
+ }
+
+ if (value.TryGetBoolean(out var booleanValue))
+ {
+ return booleanValue ? "true" : "false";
+ }
+
+ if (value.TryGetNumber(out var numberValue))
+ {
+ return numberValue.ToString(CultureInfo.InvariantCulture);
+ }
+
+ return value.TryGetGuid(out var guidValue) ? guidValue.ToString() : null;
+ }
+
+ ///
+ /// Wraps the string that the Platform Independent Model carries as a REST/HTTP PSM condition value
+ ///
+ /// The value to wrap.
+ /// The wrapped value, which is the null alternative when the value is null.
+ internal static ConstraintValue ToPsmValue(string value)
+ {
+ return ConstraintValue.From(value);
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/IPimMappable.cs b/SysML2.NET/PSM/DTO/IPimMappable.cs
new file mode 100644
index 000000000..c94e5a432
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/IPimMappable.cs
@@ -0,0 +1,47 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ ///
+ /// Declares the correspondence between a REST/HTTP PSM model and its Platform Independent Model record
+ ///
+ ///
+ /// The Platform Independent Model type that this model corresponds to, per Systems Modeling API and Services, Table 9.
+ ///
+ ///
+ /// is an instance mutator because static abstract interface members are unavailable on netstandard2.1.
+ ///
+ public interface IPimMappable
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ TRecord ToPim();
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ void FromPim(TRecord record);
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/IRequestOfTRecord.cs b/SysML2.NET/PSM/DTO/IRequestOfTRecord.cs
new file mode 100644
index 000000000..a92f91377
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/IRequestOfTRecord.cs
@@ -0,0 +1,35 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ ///
+ /// Marker interface implemented by the request models that declare a Platform Independent Model counterpart
+ ///
+ ///
+ /// The Platform Independent Model type that this request model corresponds to.
+ ///
+ ///
+ /// Requests whose payload the Platform Independent Model cannot carry implement the non generic only.
+ ///
+ public interface IRequest : IRequest, IPimMappable
+ {
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/IResponseOfTRecord.cs b/SysML2.NET/PSM/DTO/IResponseOfTRecord.cs
new file mode 100644
index 000000000..16fe49d5c
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/IResponseOfTRecord.cs
@@ -0,0 +1,35 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ ///
+ /// Marker interface implemented by the response models that declare a Platform Independent Model counterpart
+ ///
+ ///
+ /// The Platform Independent Model type that this response model corresponds to.
+ ///
+ ///
+ /// Responses without a counterpart, such as , implement the non generic only.
+ ///
+ public interface IResponse : IResponse, IPimMappable
+ {
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/Branch.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/Branch.Mapping.cs
new file mode 100644
index 000000000..544df6dc1
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/Branch.Mapping.cs
@@ -0,0 +1,76 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the Branch response model
+ ///
+ ///
+ /// Systems Modeling API and Services, Clause 7.1.2 declares head as redefining referencedCommit,
+ /// so the one Platform Independent Model member supplies both REST/HTTP PSM members.
+ ///
+ public partial class Branch : IResponse
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.Branch ToPim()
+ {
+ return new PIM.DTO.Branch
+ {
+ Id = this.Id,
+ Alias = [.. this.Alias ?? []],
+ Created = this.Created,
+ Deleted = this.Deleted ?? default,
+ Description = this.Description,
+ Head = this.Head ?? this.ReferencedCommit,
+ Name = this.Name,
+ OwningProject = this.OwningProject
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.Branch record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+ this.Alias = [.. record.Alias ?? []];
+ this.Created = record.Created;
+ this.Deleted = record.Deleted;
+ this.Description = record.Description;
+ this.Head = record.Head;
+ this.Name = record.Name;
+ this.OwningProject = record.OwningProject;
+ this.ReferencedCommit = record.Head;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/BranchRequest.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/BranchRequest.Mapping.cs
new file mode 100644
index 000000000..381e625a8
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/BranchRequest.Mapping.cs
@@ -0,0 +1,66 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the Branch request model
+ ///
+ ///
+ /// The request carries no referencedCommit; Clause 7.1.2 declares head as redefining it.
+ ///
+ public partial class BranchRequest : IRequest
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.Branch ToPim()
+ {
+ return new PIM.DTO.Branch
+ {
+ Alias = [.. this.Alias ?? []],
+ Description = this.Description,
+ Head = this.Head ?? Guid.Empty,
+ Name = this.Name
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.Branch record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Alias = [.. record.Alias ?? []];
+ this.Description = record.Description;
+ this.Head = record.Head;
+ this.Name = record.Name;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/Commit.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/Commit.Mapping.cs
new file mode 100644
index 000000000..777b76ed5
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/Commit.Mapping.cs
@@ -0,0 +1,73 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the Commit response model
+ ///
+ ///
+ /// The REST/HTTP PSM commit response models no change or versionedData member; change is
+ /// carried by the commit request, and the versioned data is reached through its own endpoint.
+ ///
+ public partial class Commit : IResponse
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.Commit ToPim()
+ {
+ return new PIM.DTO.Commit
+ {
+ Id = this.Id,
+ Alias = [.. this.Alias ?? []],
+ Created = this.Created,
+ Description = this.Description,
+ Name = this.Name,
+ OwningProject = this.OwningProject,
+ PreviousCommits = [.. this.PreviousCommit ?? []]
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.Commit record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+ this.Alias = [.. record.Alias ?? []];
+ this.Created = record.Created;
+ this.Description = record.Description;
+ this.Name = record.Name;
+ this.OwningProject = record.OwningProject;
+ this.PreviousCommit = [.. record.PreviousCommits ?? []];
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/CompositeConstraint.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/CompositeConstraint.Mapping.cs
new file mode 100644
index 000000000..b6175805a
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/CompositeConstraint.Mapping.cs
@@ -0,0 +1,62 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+ using System.Linq;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the CompositeConstraint response model
+ ///
+ public partial class CompositeConstraint : IResponse
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ /// Thrown when a composed condition has no Platform Independent Model counterpart.
+ public PIM.DTO.CompositeConstraint ToPim()
+ {
+ return new PIM.DTO.CompositeConstraint
+ {
+ Operator = ConstraintMapper.ToPim(this.Operator),
+ Constraint = [.. (this.Constraint ?? []).Select(ConstraintMapper.ToPim)]
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ /// Thrown when a composed condition has no REST/HTTP PSM counterpart.
+ public void FromPim(PIM.DTO.CompositeConstraint record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Operator = ConstraintMapper.ToResponse(record.Operator);
+ this.Constraint = [.. (record.Constraint ?? []).Select(ConstraintMapper.ToResponse)];
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/CompositeConstraintRequest.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/CompositeConstraintRequest.Mapping.cs
new file mode 100644
index 000000000..aed3d665d
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/CompositeConstraintRequest.Mapping.cs
@@ -0,0 +1,66 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+ using System.Linq;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the CompositeConstraint request model
+ ///
+ ///
+ /// The composed conditions are typed by the response family rather than by
+ /// , so the recursion crosses families.
+ ///
+ public partial class CompositeConstraintRequest : IRequest
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ /// Thrown when a composed condition has no Platform Independent Model counterpart.
+ public PIM.DTO.CompositeConstraint ToPim()
+ {
+ return new PIM.DTO.CompositeConstraint
+ {
+ Operator = ConstraintMapper.ToPim(this.Operator),
+ Constraint = [.. (this.Constraint ?? []).Select(ConstraintMapper.ToPim)]
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ /// Thrown when a composed condition has no REST/HTTP PSM counterpart.
+ public void FromPim(PIM.DTO.CompositeConstraint record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Operator = ConstraintMapper.ToRequest(record.Operator);
+ this.Constraint = [.. (record.Constraint ?? []).Select(ConstraintMapper.ToResponse)];
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/DataDifference.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/DataDifference.Mapping.cs
new file mode 100644
index 000000000..ee7df5d5e
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/DataDifference.Mapping.cs
@@ -0,0 +1,63 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the DataDifference response model
+ ///
+ ///
+ /// The REST/HTTP PSM carries whole data versions where the Platform Independent Model carries their identifiers,
+ /// so a version reconstructed from a record holds its identifier alone.
+ ///
+ public partial class DataDifference : IResponse
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.DataDifference ToPim()
+ {
+ return new PIM.DTO.DataDifference
+ {
+ BaseData = this.BaseData?.Id,
+ CompareData = this.CompareData?.Id
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.DataDifference record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.BaseData = record.BaseData.HasValue ? new DataVersion { Id = record.BaseData.Value } : null;
+ this.CompareData = record.CompareData.HasValue ? new DataVersion { Id = record.CompareData.Value } : null;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/DataIdentity.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/DataIdentity.Mapping.cs
new file mode 100644
index 000000000..1a101f8f9
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/DataIdentity.Mapping.cs
@@ -0,0 +1,63 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the DataIdentity response model
+ ///
+ public partial class DataIdentity : IResponse
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.DataIdentity ToPim()
+ {
+ return new PIM.DTO.DataIdentity
+ {
+ Id = this.Id,
+ Alias = [.. this.Alias ?? []],
+ Description = this.Description,
+ Name = this.Name
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.DataIdentity record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+ this.Alias = [.. record.Alias ?? []];
+ this.Description = record.Description;
+ this.Name = record.Name;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/DataIdentityRequest.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/DataIdentityRequest.Mapping.cs
new file mode 100644
index 000000000..963f93595
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/DataIdentityRequest.Mapping.cs
@@ -0,0 +1,63 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the DataIdentity request model
+ ///
+ public partial class DataIdentityRequest : IRequest
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.DataIdentity ToPim()
+ {
+ return new PIM.DTO.DataIdentity
+ {
+ Id = this.Id,
+ Alias = [.. this.Alias ?? []],
+ Description = this.Description,
+ Name = this.Name
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.DataIdentity record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+ this.Alias = [.. record.Alias ?? []];
+ this.Description = record.Description;
+ this.Name = record.Name;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/DataVersion.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/DataVersion.Mapping.cs
new file mode 100644
index 000000000..260c5e1fd
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/DataVersion.Mapping.cs
@@ -0,0 +1,71 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the DataVersion response model
+ ///
+ ///
+ /// The REST/HTTP PSM models no commit member, so the mandatory Platform Independent Model
+ /// DataVersion::commit and the derived project are supplied by the route the version was reached through.
+ ///
+ public partial class DataVersion : IResponse
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.DataVersion ToPim()
+ {
+ return new PIM.DTO.DataVersion
+ {
+ Id = this.Id,
+ Alias = [.. this.Alias ?? []],
+ Description = this.Description,
+ Identity = this.Identity?.ToPim(),
+ Name = this.Name,
+ Payload = this.Payload
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.DataVersion record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+ this.Alias = [.. record.Alias ?? []];
+ this.Description = record.Description;
+ this.Identity = PimMapper.Map(record.Identity);
+ this.Name = record.Name;
+ this.Payload = record.Payload;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/ExternalData.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/ExternalData.Mapping.cs
new file mode 100644
index 000000000..259ce4075
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/ExternalData.Mapping.cs
@@ -0,0 +1,62 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the ExternalData response model
+ ///
+ public partial class ExternalData : IResponse
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.ExternalData ToPim()
+ {
+ return new PIM.DTO.ExternalData
+ {
+ Id = this.Id,
+ ResourceIdentifier = this.ResourceIdentifier?.OriginalString
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.ExternalData record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+
+ this.ResourceIdentifier = Uri.TryCreate(record.ResourceIdentifier, UriKind.RelativeOrAbsolute, out var resourceIdentifier)
+ ? resourceIdentifier
+ : null;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/ExternalDataRequest.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/ExternalDataRequest.Mapping.cs
new file mode 100644
index 000000000..0efc749b5
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/ExternalDataRequest.Mapping.cs
@@ -0,0 +1,62 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the ExternalData request model
+ ///
+ public partial class ExternalDataRequest : IRequest
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.ExternalData ToPim()
+ {
+ return new PIM.DTO.ExternalData
+ {
+ Id = this.Id ?? Guid.Empty,
+ ResourceIdentifier = this.ResourceIdentifier?.OriginalString
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.ExternalData record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+
+ this.ResourceIdentifier = Uri.TryCreate(record.ResourceIdentifier, UriKind.RelativeOrAbsolute, out var resourceIdentifier)
+ ? resourceIdentifier
+ : null;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/ExternalRelationship.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/ExternalRelationship.Mapping.cs
new file mode 100644
index 000000000..6dbb9308f
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/ExternalRelationship.Mapping.cs
@@ -0,0 +1,65 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the ExternalRelationship response model
+ ///
+ public partial class ExternalRelationship : IResponse
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.ExternalRelationship ToPim()
+ {
+ return new PIM.DTO.ExternalRelationship
+ {
+ Id = this.Id,
+ ElementEnd = this.ElementEnd,
+ ExternalDataEnd = this.ExternalDataEnd,
+ Language = this.Language,
+ Specification = this.Specification
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.ExternalRelationship record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+ this.ElementEnd = record.ElementEnd;
+ this.ExternalDataEnd = record.ExternalDataEnd;
+ this.Language = record.Language;
+ this.Specification = record.Specification;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/ExternalRelationshipRequest.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/ExternalRelationshipRequest.Mapping.cs
new file mode 100644
index 000000000..30d40f33c
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/ExternalRelationshipRequest.Mapping.cs
@@ -0,0 +1,65 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the ExternalRelationship request model
+ ///
+ public partial class ExternalRelationshipRequest : IRequest
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.ExternalRelationship ToPim()
+ {
+ return new PIM.DTO.ExternalRelationship
+ {
+ Id = this.Id ?? Guid.Empty,
+ ElementEnd = this.ElementEnd ?? Guid.Empty,
+ ExternalDataEnd = this.ExternalDataEnd ?? Guid.Empty,
+ Language = this.Language,
+ Specification = this.Specification
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.ExternalRelationship record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+ this.ElementEnd = record.ElementEnd;
+ this.ExternalDataEnd = record.ExternalDataEnd;
+ this.Language = record.Language;
+ this.Specification = record.Specification;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/PrimitiveConstraint.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/PrimitiveConstraint.Mapping.cs
new file mode 100644
index 000000000..1891306f0
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/PrimitiveConstraint.Mapping.cs
@@ -0,0 +1,64 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+ using System.Linq;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the PrimitiveConstraint response model
+ ///
+ public partial class PrimitiveConstraint : IResponse
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.PrimitiveConstraint ToPim()
+ {
+ return new PIM.DTO.PrimitiveConstraint
+ {
+ Property = this.Property,
+ Operator = ConstraintMapper.ToPim(this.Operator),
+ Inverse = this.Inverse,
+ Value = [.. (this.Value ?? []).Select(ConstraintMapper.ToPimValue)]
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.PrimitiveConstraint record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Property = record.Property;
+ this.Operator = ConstraintMapper.ToResponse(record.Operator);
+ this.Inverse = record.Inverse;
+ this.Value = [.. (record.Value ?? []).Select(ConstraintMapper.ToPsmValue)];
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/PrimitiveConstraintRequest.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/PrimitiveConstraintRequest.Mapping.cs
new file mode 100644
index 000000000..3a0956b7b
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/PrimitiveConstraintRequest.Mapping.cs
@@ -0,0 +1,64 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+ using System.Linq;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the PrimitiveConstraint request model
+ ///
+ public partial class PrimitiveConstraintRequest : IRequest
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.PrimitiveConstraint ToPim()
+ {
+ return new PIM.DTO.PrimitiveConstraint
+ {
+ Property = this.Property,
+ Operator = ConstraintMapper.ToPim(this.Operator),
+ Inverse = this.Inverse ?? false,
+ Value = [.. (this.Value ?? []).Select(ConstraintMapper.ToPimValue)]
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.PrimitiveConstraint record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Property = record.Property;
+ this.Operator = ConstraintMapper.ToRequest(record.Operator);
+ this.Inverse = record.Inverse;
+ this.Value = [.. (record.Value ?? []).Select(ConstraintMapper.ToPsmValue)];
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/Project.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/Project.Mapping.cs
new file mode 100644
index 000000000..1c617c201
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/Project.Mapping.cs
@@ -0,0 +1,71 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the Project response model
+ ///
+ ///
+ /// The REST/HTTP PSM models no project member for commits, queries, commitReferences,
+ /// branches or tags; a client reaches those through their own endpoints, so they are not carried.
+ ///
+ public partial class Project : IResponse
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.Project ToPim()
+ {
+ return new PIM.DTO.Project
+ {
+ Id = this.Id,
+ Alias = [.. this.Alias ?? []],
+ Created = this.Created,
+ DefaultBranch = this.DefaultBranch,
+ Description = this.Description,
+ Name = this.Name
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.Project record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+ this.Alias = [.. record.Alias ?? []];
+ this.Created = record.Created;
+ this.DefaultBranch = record.DefaultBranch;
+ this.Description = record.Description;
+ this.Name = record.Name;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/ProjectRequest.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/ProjectRequest.Mapping.cs
new file mode 100644
index 000000000..e943a8d90
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/ProjectRequest.Mapping.cs
@@ -0,0 +1,63 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the Project request model
+ ///
+ public partial class ProjectRequest : IRequest
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.Project ToPim()
+ {
+ return new PIM.DTO.Project
+ {
+ Alias = [.. this.Alias ?? []],
+ DefaultBranch = this.DefaultBranch ?? Guid.Empty,
+ Description = this.Description,
+ Name = this.Name
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.Project record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Alias = [.. record.Alias ?? []];
+ this.DefaultBranch = record.DefaultBranch;
+ this.Description = record.Description;
+ this.Name = record.Name;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/ProjectUsage.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/ProjectUsage.Mapping.cs
new file mode 100644
index 000000000..ace0f6c72
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/ProjectUsage.Mapping.cs
@@ -0,0 +1,61 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the ProjectUsage response model
+ ///
+ public partial class ProjectUsage : IResponse
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.ProjectUsage ToPim()
+ {
+ return new PIM.DTO.ProjectUsage
+ {
+ Id = this.Id,
+ UsedCommit = this.UsedCommit,
+ UsedProject = this.UsedProject
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.ProjectUsage record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+ this.UsedCommit = record.UsedCommit;
+ this.UsedProject = record.UsedProject;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/ProjectUsageRequest.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/ProjectUsageRequest.Mapping.cs
new file mode 100644
index 000000000..0798921d4
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/ProjectUsageRequest.Mapping.cs
@@ -0,0 +1,61 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the ProjectUsage request model
+ ///
+ public partial class ProjectUsageRequest : IRequest
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.ProjectUsage ToPim()
+ {
+ return new PIM.DTO.ProjectUsage
+ {
+ Id = this.Id ?? Guid.Empty,
+ UsedCommit = this.UsedCommit ?? Guid.Empty,
+ UsedProject = this.UsedProject ?? Guid.Empty
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.ProjectUsage record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+ this.UsedCommit = record.UsedCommit;
+ this.UsedProject = record.UsedProject;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/Query.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/Query.Mapping.cs
new file mode 100644
index 000000000..75cefa3ac
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/Query.Mapping.cs
@@ -0,0 +1,75 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the Query response model
+ ///
+ ///
+ /// The REST/HTTP PSM names the owning project owningProject where the Platform Independent Model names it
+ /// project, and models no member for scope or orderBy, so those are not carried.
+ ///
+ public partial class Query : IResponse
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ /// Thrown when the condition has no Platform Independent Model counterpart.
+ public PIM.DTO.Query ToPim()
+ {
+ return new PIM.DTO.Query
+ {
+ Id = this.Id,
+ Alias = [.. this.Alias ?? []],
+ Description = this.Description,
+ Name = this.Name,
+ Project = this.OwningProject,
+ Select = [.. this.Select ?? []],
+ Where = ConstraintMapper.ToPim(this.Where)
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ /// Thrown when the condition has no REST/HTTP PSM counterpart.
+ public void FromPim(PIM.DTO.Query record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+ this.Alias = [.. record.Alias ?? []];
+ this.Description = record.Description;
+ this.Name = record.Name;
+ this.OwningProject = record.Project;
+ this.Select = [.. record.Select ?? []];
+ this.Where = ConstraintMapper.ToResponse(record.Where);
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/QueryRequest.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/QueryRequest.Mapping.cs
new file mode 100644
index 000000000..0adc6d634
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/QueryRequest.Mapping.cs
@@ -0,0 +1,70 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the Query request model
+ ///
+ ///
+ /// The request models no member for project, scope or orderBy, so those are not carried.
+ ///
+ public partial class QueryRequest : IRequest
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ /// Thrown when the condition has no Platform Independent Model counterpart.
+ public PIM.DTO.Query ToPim()
+ {
+ return new PIM.DTO.Query
+ {
+ Alias = [.. this.Alias ?? []],
+ Description = this.Description,
+ Name = this.Name,
+ Select = [.. this.Select ?? []],
+ Where = ConstraintMapper.ToPim(this.Where)
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ /// Thrown when the condition has no REST/HTTP PSM counterpart.
+ public void FromPim(PIM.DTO.Query record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Alias = [.. record.Alias ?? []];
+ this.Description = record.Description;
+ this.Name = record.Name;
+ this.Select = [.. record.Select ?? []];
+ this.Where = ConstraintMapper.ToRequest(record.Where);
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/Tag.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/Tag.Mapping.cs
new file mode 100644
index 000000000..dd5f345db
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/Tag.Mapping.cs
@@ -0,0 +1,76 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the Tag response model
+ ///
+ ///
+ /// Systems Modeling API and Services, Clause 7.1.2 declares taggedCommit as redefining
+ /// referencedCommit, so the one Platform Independent Model member supplies both REST/HTTP PSM members.
+ ///
+ public partial class Tag : IResponse
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.Tag ToPim()
+ {
+ return new PIM.DTO.Tag
+ {
+ Id = this.Id,
+ Alias = [.. this.Alias ?? []],
+ Created = this.Created,
+ Deleted = this.Deleted ?? default,
+ Description = this.Description,
+ Name = this.Name,
+ OwningProject = this.OwningProject,
+ TaggedCommit = this.TaggedCommit
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.Tag record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Id = record.Id;
+ this.Alias = [.. record.Alias ?? []];
+ this.Created = record.Created;
+ this.Deleted = record.Deleted;
+ this.Description = record.Description;
+ this.Name = record.Name;
+ this.OwningProject = record.OwningProject;
+ this.ReferencedCommit = record.TaggedCommit;
+ this.TaggedCommit = record.TaggedCommit;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/Mapping/TagRequest.Mapping.cs b/SysML2.NET/PSM/DTO/Mapping/TagRequest.Mapping.cs
new file mode 100644
index 000000000..8b3b7c880
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/Mapping/TagRequest.Mapping.cs
@@ -0,0 +1,63 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+
+ ///
+ /// Declares the Platform Independent Model counterpart of the Tag request model
+ ///
+ public partial class TagRequest : IRequest
+ {
+ ///
+ /// Converts this model into its Platform Independent Model record
+ ///
+ /// The record carrying the members that the REST/HTTP PSM models.
+ public PIM.DTO.Tag ToPim()
+ {
+ return new PIM.DTO.Tag
+ {
+ Alias = [.. this.Alias ?? []],
+ Description = this.Description,
+ Name = this.Name,
+ TaggedCommit = this.TaggedCommit
+ };
+ }
+
+ ///
+ /// Populates this model from its Platform Independent Model record
+ ///
+ /// The record to read from.
+ /// Thrown when the record is null.
+ public void FromPim(PIM.DTO.Tag record)
+ {
+ if (record == null)
+ {
+ throw new ArgumentNullException(nameof(record));
+ }
+
+ this.Alias = [.. record.Alias ?? []];
+ this.Description = record.Description;
+ this.Name = record.Name;
+ this.TaggedCommit = record.TaggedCommit;
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/MergeOutcome.cs b/SysML2.NET/PSM/DTO/MergeOutcome.cs
new file mode 100644
index 000000000..7078712a7
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/MergeOutcome.cs
@@ -0,0 +1,152 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+
+ ///
+ /// The outcome of a merge, which is either the resulting commit or the data identities that conflict
+ ///
+ ///
+ /// Systems Modeling API and Services, Clause 7.2.3 requires exactly one of the two alternatives, and Table 9
+ /// maps each onto a REST/HTTP PSM model of its own, so no single PSM model corresponds to MergeResult.
+ ///
+ public sealed class MergeOutcome
+ {
+ ///
+ /// The commit that is held when is
+ ///
+ private readonly Commit mergeCommit;
+
+ ///
+ /// The data identities that are held when is
+ ///
+ private readonly IReadOnlyList conflict;
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The alternative that is held.
+ /// The commit that is held.
+ /// The data identities that are held.
+ private MergeOutcome(MergeOutcomeKind kind, Commit mergeCommit, IReadOnlyList conflict)
+ {
+ this.Kind = kind;
+ this.mergeCommit = mergeCommit;
+ this.conflict = conflict;
+ }
+
+ ///
+ /// Gets the alternative that is held
+ ///
+ public MergeOutcomeKind Kind { get; }
+
+ ///
+ /// Gets a value indicating whether the merge succeeded
+ ///
+ public bool IsMerged => this.Kind == MergeOutcomeKind.Merged;
+
+ ///
+ /// Creates a that holds the commit of a successful merge
+ ///
+ /// The commit to hold.
+ /// The created .
+ /// Thrown when the commit is null.
+ public static MergeOutcome Merged(Commit mergeCommit)
+ {
+ return mergeCommit == null
+ ? throw new ArgumentNullException(nameof(mergeCommit))
+ : new MergeOutcome(MergeOutcomeKind.Merged, mergeCommit, []);
+ }
+
+ ///
+ /// Creates a that holds the data identities of an unsuccessful merge
+ ///
+ /// The conflicting data identities to hold.
+ /// The created .
+ /// Thrown when the sequence is null.
+ /// Thrown when the sequence is empty, which denotes no conflict.
+ public static MergeOutcome Conflicted(IEnumerable conflict)
+ {
+ if (conflict == null)
+ {
+ throw new ArgumentNullException(nameof(conflict));
+ }
+
+ IReadOnlyList conflicting = [.. conflict];
+
+ return conflicting.Count == 0
+ ? throw new ArgumentException("An unsuccessful merge holds at least one conflicting data identity.", nameof(conflict))
+ : new MergeOutcome(MergeOutcomeKind.Conflicted, null, conflicting);
+ }
+
+ ///
+ /// Queries the commit of a successful merge
+ ///
+ /// The commit that is held, which is null when the merge was unsuccessful.
+ /// True when the merge succeeded.
+ public bool TryGetMergeCommit(out Commit outMergeCommit)
+ {
+ outMergeCommit = this.mergeCommit;
+
+ return this.Kind == MergeOutcomeKind.Merged;
+ }
+
+ ///
+ /// Queries the conflicting data identities of an unsuccessful merge
+ ///
+ /// The data identities that are held, which is empty when the merge succeeded.
+ /// True when the merge was unsuccessful.
+ public bool TryGetConflict(out IReadOnlyList conflicts)
+ {
+ conflicts = this.conflict;
+
+ return this.Kind == MergeOutcomeKind.Conflicted;
+ }
+
+ ///
+ /// Applies the function that corresponds to the alternative that is held
+ ///
+ /// The type that the functions return.
+ /// The function applied to the commit of a successful merge.
+ /// The function applied to the data identities of an unsuccessful merge.
+ /// The result of the applied function.
+ /// Thrown when either of the functions is null.
+ public T Match(Func onMerged, Func, T> onConflicted)
+ {
+ if (onMerged == null)
+ {
+ throw new ArgumentNullException(nameof(onMerged));
+ }
+
+ if (onConflicted == null)
+ {
+ throw new ArgumentNullException(nameof(onConflicted));
+ }
+
+ return this.Kind == MergeOutcomeKind.Merged
+ ? onMerged(this.mergeCommit)
+ : onConflicted(this.conflict);
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/MergeOutcomeKind.cs b/SysML2.NET/PSM/DTO/MergeOutcomeKind.cs
new file mode 100644
index 000000000..b6a0d31b7
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/MergeOutcomeKind.cs
@@ -0,0 +1,38 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ ///
+ /// Enumeration of the alternatives that a may hold
+ ///
+ public enum MergeOutcomeKind
+ {
+ ///
+ /// The merge succeeded and the outcome holds the resulting commit
+ ///
+ Merged,
+
+ ///
+ /// The merge failed and the outcome holds the data identities that conflict
+ ///
+ Conflicted
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/MergeResultMapper.cs b/SysML2.NET/PSM/DTO/MergeResultMapper.cs
new file mode 100644
index 000000000..fea5bab7f
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/MergeResultMapper.cs
@@ -0,0 +1,77 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+ using System.Linq;
+
+ using SysML2.NET.Exceptions;
+
+ ///
+ /// Maps the outcome of a merge between the Platform Independent Model and the REST/HTTP PSM
+ ///
+ ///
+ /// Systems Modeling API and Services, Table 9 maps MergeResult.mergeCommit onto Commit and
+ /// MergeResult.conflict onto DataIdentity [0..*], so the one record spans two REST/HTTP PSM models
+ /// and cannot declare a counterpart through .
+ ///
+ public static class MergeResultMapper
+ {
+ ///
+ /// Maps a Platform Independent Model merge result onto its REST/HTTP PSM outcome
+ ///
+ /// The record to map.
+ /// The outcome, or null when the record is null.
+ /// Thrown when the record holds neither alternative.
+ ///
+ /// A record holding conflicts is read as unsuccessful even when it also names a commit, because Clause 7.2.3
+ /// admits conflicts only for an unsuccessful merge.
+ ///
+ public static MergeOutcome ToPsm(PIM.DTO.MergeResult record)
+ {
+ if (record == null)
+ {
+ return null;
+ }
+
+ if (record.Conflict != null && record.Conflict.Count > 0)
+ {
+ return MergeOutcome.Conflicted(record.Conflict.Select(identity => new DataIdentity { Id = identity }));
+ }
+
+ return record.MergeCommit == Guid.Empty
+ ? throw new IncompleteModelException("A MergeResult holds either the merge commit or the conflicting data identities.")
+ : MergeOutcome.Merged(new Commit { Id = record.MergeCommit });
+ }
+
+ ///
+ /// Maps a REST/HTTP PSM merge outcome onto its Platform Independent Model record
+ ///
+ /// The outcome to map.
+ /// The record, or null when the outcome is null.
+ public static PIM.DTO.MergeResult ToPim(MergeOutcome outcome)
+ {
+ return outcome?.Match(
+ mergeCommit => new PIM.DTO.MergeResult { MergeCommit = mergeCommit.Id },
+ conflict => new PIM.DTO.MergeResult { Conflict = [.. conflict.Select(identity => identity.Id)] });
+ }
+ }
+}
diff --git a/SysML2.NET/PSM/DTO/PimMapper.cs b/SysML2.NET/PSM/DTO/PimMapper.cs
new file mode 100644
index 000000000..71b7971f5
--- /dev/null
+++ b/SysML2.NET/PSM/DTO/PimMapper.cs
@@ -0,0 +1,71 @@
+// -------------------------------------------------------------------------------------------------
+//
+//
+// Copyright 2022-2025 Starion Group S.A.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//
+// ------------------------------------------------------------------------------------------------
+
+namespace SysML2.NET.PSM.DTO
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+
+ ///
+ /// Maps Platform Independent Model records onto the REST/HTTP PSM models that declare them
+ ///
+ public static class PimMapper
+ {
+ ///
+ /// Maps a Platform Independent Model record onto the REST/HTTP PSM model that declares it
+ ///
+ /// The PSM model to create.
+ /// The Platform Independent Model type that declares.
+ /// The record to map.
+ /// The mapped model, or null when the record is null.
+ public static TPsm Map(TRecord record)
+ where TPsm : class, IPimMappable, new()
+ where TRecord : class
+ {
+ if (record == null)
+ {
+ return null;
+ }
+
+ var model = new TPsm();
+ model.FromPim(record);
+
+ return model;
+ }
+
+ ///
+ /// Maps a sequence of Platform Independent Model records onto the REST/HTTP PSM models that declare them
+ ///
+ /// The PSM model to create.
+ /// The Platform Independent Model type that declares.
+ /// The records to map.
+ /// The mapped models, in the order of the source sequence.
+ /// Thrown when the sequence is null.
+ public static IReadOnlyList MapAll(IEnumerable records)
+ where TPsm : class, IPimMappable, new()
+ where TRecord : class
+ {
+ return records == null
+ ? throw new ArgumentNullException(nameof(records))
+ : [.. records.Select(Map)];
+ }
+ }
+}