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..25096ee4b --- /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.Null); + 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.Null); + } + } + } +} 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/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..2825c71a3 --- /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 == null + ? throw new IncompleteModelException("A MergeResult holds either the merge commit or the conflicting data identities.") + : MergeOutcome.Merged(new Commit { Id = record.MergeCommit.Value }); + } + + /// + /// 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)]; + } + } +}