/// <inheritdoc/> public override bool TryHandleEnter( Neo4JProjectionVisitorContext context, ISelection selection, [NotNullWhen(true)] out ISelectionVisitorAction?action) { ++context.CurrentLevel; selection.Field.ContextData.TryGetValue( nameof(Neo4JRelationshipAttribute), out object?relationship); if (relationship is Neo4JRelationshipAttribute rel) { context.RelationshipTypes.Push(rel); } context.StartNodes.Push(Cypher.NamedNode(selection.DeclaringType.Name.Value)); if (context.RelationshipProjections.ContainsKey(context.CurrentLevel)) { context.RelationshipProjections[context.CurrentLevel] .Enqueue(selection.Field.GetName()); } else { Queue <object> queue = new(); queue.Enqueue(selection.Field.GetName()); context.RelationshipProjections.Add(context.CurrentLevel, queue); } action = SelectionVisitor.Continue; return(true); }
public static bool TryCreateRelationshipProjection( this Neo4JProjectionVisitorContext context, [NotNullWhen(true)] out PatternComprehension?patternComprehension) { patternComprehension = new PatternComprehension( context.Relationships.Peek(), context.EndNodes.Peek() .Project(context.RelationshipProjections[context.CurrentLevel].ToArray())); return(true); }
public static bool TryCreateQuery( this Neo4JProjectionVisitorContext context, [NotNullWhen(true)] out object[]?query) { query = null; if (context.Projections.Count == 0) { return(false); } query = context.Projections.ToArray(); return(true); }
/// <inheritdoc/> public override bool TryHandleEnter( Neo4JProjectionVisitorContext context, ISelection selection, out ISelectionVisitorAction action) { IObjectField field = selection.Field; action = SelectionVisitor.SkipAndLeave; if (!context.StartNodes.Any()) { context.Projections.Add(field.GetName()); return(true); } if (context.StartNodes.Count != context.EndNodes.Count) { context.EndNodes.Push(Cypher.NamedNode(selection.DeclaringType.Name.Value)); } if (context.StartNodes.Count != context.Relationships.Count) { Neo4JRelationshipAttribute rel = context.RelationshipTypes.Peek(); Node startNode = context.StartNodes.Peek(); Node endNode = context.EndNodes.Peek(); Relationship direction = rel.Direction switch { Incoming => startNode.RelationshipFrom(endNode, rel.Name), Outgoing => startNode.RelationshipTo(endNode, rel.Name), None => startNode.RelationshipBetween(endNode, rel.Name), _ => throw new InvalidOperationException( Neo4JResources.Projection_RelationshipDirectionNotSet) }; context.Relationships.Push(direction); } context .RelationshipProjections[context.CurrentLevel] .Enqueue(selection.Field.GetName()); return(true); } }
/// <inheritdoc/> public override FieldMiddleware CreateExecutor <TEntityType>() { return(next => context => ExecuteAsync(next, context)); async ValueTask ExecuteAsync( FieldDelegate next, IMiddlewareContext context) { // first we let the pipeline run and produce a result. await next(context).ConfigureAwait(false); if (context.Result is not null) { var visitorContext = new Neo4JProjectionVisitorContext(context, context.ObjectType); var visitor = new ProjectionVisitor <Neo4JProjectionVisitorContext>(); visitor.Visit(visitorContext); if (!visitorContext.TryCreateQuery(out object[]? projections) || visitorContext.Errors.Count > 0) { context.Result = Array.Empty <TEntityType>(); foreach (IError error in visitorContext.Errors) { context.ReportError(error.WithPath(context.Path)); } } else { context.LocalContextData = context.LocalContextData.SetItem("ProjectionDefinition", projections); await next(context).ConfigureAwait(false); if (context.Result is INeo4JExecutable executable) { context.Result = executable.WithProjection(projections); } } } }
/// <inheritdoc/> public override bool TryHandleLeave( Neo4JProjectionVisitorContext context, ISelection selection, [NotNullWhen(true)] out ISelectionVisitorAction?action) { if (context.StartNodes.Any()) { object field = context.RelationshipProjections[context.CurrentLevel].Dequeue(); context.TryCreateRelationshipProjection(out PatternComprehension? projections); switch (context.CurrentLevel) { case > 1: context.RelationshipProjections[context.CurrentLevel - 1].Enqueue(field); context.RelationshipProjections[context.CurrentLevel - 1] .Enqueue(projections); break; case 1: context.Projections.Push(field); context.Projections.Push(projections); break; } } --context.CurrentLevel; context.StartNodes.Pop(); context.EndNodes.Pop(); context.Relationships.Pop(); if (context.CurrentLevel == 0) { context.RelationshipProjections.Clear(); } action = SelectionVisitor.Continue; return(true); }