diff --git a/csharp/Platform.Data.Doublets/Decorators/LinksItselfConstantToSelfReferenceResolver.cs b/csharp/Platform.Data.Doublets/Decorators/LinksItselfConstantToSelfReferenceResolver.cs index a1242c381..02cff53da 100644 --- a/csharp/Platform.Data.Doublets/Decorators/LinksItselfConstantToSelfReferenceResolver.cs +++ b/csharp/Platform.Data.Doublets/Decorators/LinksItselfConstantToSelfReferenceResolver.cs @@ -53,14 +53,133 @@ public override TLinkAddress Each(IList? restriction, ReadHandler< { var constants = _constants; var itselfConstant = constants.Itself; - if (constants.Any != itselfConstant && restriction.Contains(item: itselfConstant)) + if (constants.Any != itselfConstant && restriction != null && restriction.Contains(item: itselfConstant)) { - // Itself constant is not supported for Each method right now, skipping execution - return constants.Continue; + // Handle 'Itself' constant by filtering for self-referential links + return HandleEachWithItselfConstant(restriction, handler, itselfConstant); } return _links.Each(restriction: restriction, handler: handler); } + /// + /// + /// Handles Each operations when 'Itself' constant is present in the restriction. + /// + /// + /// + /// + /// The original restriction containing 'Itself' constants. + /// + /// + /// + /// The handler to execute for matching links. + /// + /// + /// + /// The 'Itself' constant value. + /// + /// + /// + /// The result of the Each operation. + /// + /// + [MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)] + private TLinkAddress HandleEachWithItselfConstant(IList restriction, ReadHandler? handler, TLinkAddress itselfConstant) + { + var constants = _constants; + + // Create a wrapper handler that filters for self-referential links + ReadHandler? filteringHandler = null; + if (handler != null) + { + filteringHandler = (link) => + { + var linkIndex = _links.GetIndex(link); + var linkSource = _links.GetSource(link); + var linkTarget = _links.GetTarget(link); + + // Check if this link matches the 'Itself' pattern in the restriction + if (MatchesItselfPattern(restriction, itselfConstant, linkIndex, linkSource, linkTarget)) + { + return handler(link); + } + + return constants.Continue; + }; + } + + // Get all links and let our filtering handler process them + return _links.Each(restriction: null, handler: filteringHandler); + } + + /// + /// + /// Checks if a link matches the pattern specified by the restriction with 'Itself' constants. + /// + /// + /// + /// + /// The restriction pattern. + /// + /// + /// + /// The 'Itself' constant value. + /// + /// + /// + /// The link's index. + /// + /// + /// + /// The link's source. + /// + /// + /// + /// The link's target. + /// + /// + /// + /// True if the link matches the pattern, false otherwise. + /// + /// + [MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)] + private bool MatchesItselfPattern(IList restriction, TLinkAddress itselfConstant, TLinkAddress linkIndex, TLinkAddress linkSource, TLinkAddress linkTarget) + { + var constants = _constants; + + // Check index (position 0) + if (restriction.Count > 0 && restriction[0] != constants.Any) + { + var expectedIndex = restriction[0] == itselfConstant ? linkIndex : restriction[0]; + if (linkIndex != expectedIndex) + { + return false; + } + } + + // Check source (position 1) + if (restriction.Count > 1 && restriction[1] != constants.Any) + { + var expectedSource = restriction[1] == itselfConstant ? linkIndex : restriction[1]; + if (linkSource != expectedSource) + { + return false; + } + } + + // Check target (position 2) + if (restriction.Count > 2 && restriction[2] != constants.Any) + { + var expectedTarget = restriction[2] == itselfConstant ? linkIndex : restriction[2]; + if (linkTarget != expectedTarget) + { + return false; + } + } + + return true; + } + /// /// /// Updates the restriction.