Beispiel #1
0
        /// <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);
        }
    }
Beispiel #5
0
        /// <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);
                        }
                    }
                }
            }
Beispiel #6
0
        /// <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);
        }