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)]; + } + } +}