All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.neo4j.driver.internal.summary.InternalPlan Maven / Gradle / Ivy

There is a newer version: 5.27.0
Show newest version
/*
 * Copyright (c) 2002-2017 "Neo Technology,"
 * Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * This file is part of Neo4j.
 *
 * 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.
 */
package org.neo4j.driver.internal.summary;

import java.util.Collections;
import java.util.List;
import java.util.Map;

import org.neo4j.driver.v1.Value;
import org.neo4j.driver.v1.Values;
import org.neo4j.driver.v1.summary.Plan;
import org.neo4j.driver.v1.util.Function;

import static java.lang.String.format;
import static org.neo4j.driver.v1.Values.ofString;

public class InternalPlan implements Plan
{
    private final String operatorType;
    private final List identifiers;
    private final Map arguments;
    private final List children;

    // Only call when sub-classing, for constructing plans, use .plan instead
    protected InternalPlan(
            String operatorType,
            Map arguments,
            List identifiers,
            List children )
    {
        this.operatorType = operatorType;
        this.identifiers = identifiers;
        this.arguments = arguments;
        this.children = children;
    }

    @Override
    public String operatorType()
    {
        return operatorType;
    }

    @Override
    public List identifiers()
    {
        return identifiers;
    }

    @Override
    public Map arguments()
    {
        return arguments;
    }

    @Override
    public List children()
    {
        return children;
    }

    @Override
    public String toString()
    {
        return format(
            "SimplePlanTreeNode{operatorType='%s', arguments=%s, identifiers=%s, children=%s}",
            operatorType, arguments, identifiers, children
        );
    }

    @Override
    public boolean equals( Object o )
    {
        if ( this == o )
        {
            return true;
        }
        if ( o == null || getClass() != o.getClass() )
        {
            return false;
        }

        InternalPlan that = (InternalPlan) o;

        return operatorType.equals( that.operatorType )
            && arguments.equals( that.arguments )
            && identifiers.equals( that.identifiers )
            && children.equals( that.children );
    }

    @Override
    public int hashCode()
    {
        int result = operatorType.hashCode();
        result = 31 * result + identifiers.hashCode();
        result = 31 * result + arguments.hashCode();
        result = 31 * result + children.hashCode();
        return result;
    }

    public static Plan plan(
            String operatorType,
            Map arguments,
            List identifiers,
            List children )
    {
        return EXPLAIN_PLAN.create( operatorType, arguments, identifiers, children, null );
    }

    public static final PlanCreator EXPLAIN_PLAN = new PlanCreator()
    {
        @Override
        public Plan create( String operatorType, Map arguments, List identifiers, List children, Value originalPlanValue )
        {
            return new InternalPlan<>( operatorType, arguments, identifiers, children );
        }
    };

    /** Builds a regular plan without profiling information - eg. a plan that came as a result of an `EXPLAIN` statement */
    public static final Function EXPLAIN_PLAN_FROM_VALUE = new Converter<>(EXPLAIN_PLAN);

    /**
     * Since a plan with or without profiling looks almost the same, we just keep two impls. of this
     * around to contain the small difference, and share the rest of the code for building plan trees.
     * @param 
     */
    interface PlanCreator
    {
        T create( String operatorType,
                  Map arguments,
                  List identifiers,
                  List children,
                  Value originalPlanValue );
    }

    static class Converter implements Function
    {
        private final PlanCreator planCreator;

        public Converter( PlanCreator planCreator )
        {
            this.planCreator = planCreator;
        }

        @Override
        public T apply( Value plan )
        {
            final String operatorType = plan.get( "operatorType" ).asString();

            final Value argumentsValue = plan.get( "args" );
            final Map arguments = argumentsValue.isNull()
                    ? Collections.emptyMap()
                    : argumentsValue.asMap( Values.ofValue() );

            final Value identifiersValue = plan.get( "identifiers" );
            final List identifiers = identifiersValue.isNull()
                    ? Collections.emptyList()
                    : identifiersValue.asList( ofString() );

            final Value childrenValue = plan.get( "children" );
            final List children = childrenValue.isNull()
                    ? Collections.emptyList()
                    : childrenValue.asList( this );

            return planCreator.create( operatorType, arguments, identifiers, children, plan );
        }
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy