import type { FragmentDefinitionNode, GraphQLField, GraphQLObjectType, GraphQLOutputType, GraphQLSchema, GraphQLUnionType, OperationDefinitionNode } from "graphql";
import { $$timeout, $$ts } from "../constants.ts";
import type { Constraint } from "../constraints.ts";
import type { ErrorBehavior, GrafastPlanJSON } from "../index.ts";
import { __ValueStep, Step } from "../index.ts";
import type { FieldPlanResolver, LocationDetails, TrackedArguments } from "../interfaces.ts";
import type { ApplyAfterModeArg } from "../operationPlan-input.ts";
import type { GrafastOperationOptions } from "../prepare.ts";
import type { LayerPlanReasonSubroutine } from "./LayerPlan.ts";
import { LayerPlan } from "./LayerPlan.ts";
import type { ProcessGroupedFieldSetDetails, StreamDetails } from "./OperationPlanTypes.ts";
import { OutputPlan } from "./OutputPlan.ts";
export declare const POLYMORPHIC_ROOT_PATH: null;
export declare const POLYMORPHIC_ROOT_PATHS: ReadonlySet<string> | null;
/** Beware: the list of phases may change over time... @experimental */
export type OperationPlanPhase = "init" | "plan" | "validate" | "optimize" | "finalize" | "ready";
export interface MetaByMetaKey {
    [metaKey: string | number | symbol]: Record<string, any>;
}
export declare class OperationPlan {
    readonly [$$timeout]: undefined;
    readonly [$$ts]: undefined;
    readonly queryType: GraphQLObjectType;
    readonly mutationType: GraphQLObjectType | null;
    readonly subscriptionType: GraphQLObjectType | null;
    readonly unionsContainingObjectType: {
        [objectTypeName: string]: ReadonlyArray<GraphQLUnionType>;
    };
    private operationType;
    /**
     * What state is the OpPlan in?
     *
     * 1. init
     * 2. plan
     * 3. validate
     * 5. optimize
     * 6. finalize
     * 7. ready
     *
     * Once in 'ready' state we can execute the plan.
     */
    phase: OperationPlanPhase;
    /**
     * Gets updated as we work our way through the plan, useful for making errors more helpful.
     */
    loc: string[] | null;
    /** Stores the actual value of rootValue. */
    readonly rootValueStep: __ValueStep<any>;
    /**
     * If true, then this operation doesn't use (custom) resolvers.
     */
    pure: boolean;
    private startTime;
    private previousLap;
    private laps;
    private optimizeMeta;
    private scalarPlanInfo;
    private frozenPlanningPaths;
    readonly schema: GraphQLSchema;
    readonly operation: OperationDefinitionNode;
    readonly fragments: {
        [fragmentName: string]: FragmentDefinitionNode;
    };
    readonly errorBehavior: ErrorBehavior;
    private readonly planningTimeout;
    private readonly maxPlanningDepth;
    constructor(schema: GraphQLSchema, operation: OperationDefinitionNode, fragments: {
        [fragmentName: string]: FragmentDefinitionNode;
    }, variableValuesConstraints: Constraint[], variableValues: {
        [key: string]: any;
    }, contextConstraints: Constraint[], context: {
        [key: string]: any;
    }, rootValueConstraints: Constraint[], rootValue: any, errorBehavior: ErrorBehavior, options: GrafastOperationOptions);
    private lap;
    private checkTimeout;
    private planOperation;
    /**
     * Plans a GraphQL query operation.
     */
    private planQuery;
    /**
     * Implements the `PlanOpPlanMutation` algorithm.
     */
    private planMutation;
    /**
     * Implements the `PlanOpPlanSubscription` algorithm.
     */
    private planSubscription;
    private getCombinedLayerPlanForLayerPlans;
    /**
     * Gets the item plan for a given parent list plan - this ensures we only
     * create one item plan per parent plan.
     */
    private itemStepForListStep;
    processGroupedFieldSet(details: ProcessGroupedFieldSetDetails): Generator<() => {
        haltTree: boolean;
        step: Step;
        latestSideEffectStep: Step | null;
    }, void, {
        step: Step<any>;
        haltTree: boolean;
        latestSideEffectStep: Step<any> | null;
    }>;
    /**
     *
     * @param details - planning details for this selection set. Includes the
     * output plan, path, parent step, position type, selections, and an
     * `isMutation` flag to enforce serial execution.
     */
    private planSelectionSet;
    private planningQueue;
    private planningQueueByPlanningPath;
    private queueNextLayer;
    private planPending;
    withLocLpSE(loc: string[] | null, layerPlan: LayerPlan, layerPlanLatestSideEffect: Step | null, cb: () => void): void;
    private mutateTodos;
    private internalDependency;
    private planFieldReturnType;
    private planIntoOutputPlan;
    handlePlanningError(details: {
        outputPlan: OutputPlan;
        layerPlan: LayerPlan;
        objectType: GraphQLObjectType | null;
        responseKey: string | null;
        positionType: GraphQLOutputType;
        locationDetails: LocationDetails;
        err: Error;
    }): void;
    private polymorphicPlanObjectType;
    planFieldBatch: PlanFieldBatch | null;
    private batchPlanField;
    private processPlanField;
    _realPlanField(planFieldDetails: PlanFieldDetails): {
        step: Step<unknown>;
        haltTree: boolean;
        latestSideEffectStep: Step<any> | null;
    } | {
        step: import("../index.ts").ErrorStep<any>;
        haltTree: boolean;
        latestSideEffectStep: Step<any> | null;
    };
    /**
     * A replacement for GraphQL's
     * `CoerceArgumentValues` that factors in tracked variables.
     *
     * @see https://spec.graphql.org/draft/#CoerceArgumentValues()
     */
    private getTrackedArguments;
    /**
     * Sets up tracking for the given value (variableValues, context, rootValue).
     */
    private track;
    /**
     * Checks that no step has a property on it whose value is another step. It
     * should addDependency instead.
     */
    private validateSteps;
    private replaceStep;
    private processStep;
    /**
     * Peers are steps of the same type (but not the same step!) that are in
     * compatible layers and have the same dependencies. Peers must not have side
     * effects. A step is not its own peer.
     */
    private getPeers;
    private isImmoveable;
    /**
     * Attempts to hoist the step into a higher layerPlan to maximize
     * deduplication.
     */
    private hoistStep;
    /**
     * Attempts to push the step into the lowest layerPlan to minimize the need
     * for copying between layer plans.
     */
    private pushDown;
    private _deduplicateInnerLogic;
    private deduplicateStep;
    private deduplicateStepsProcess;
    /**
     * Gives us a chance to replace nearly-duplicate plans with other existing
     * plans (and adding the necessary transforms); this means that by the time
     * we come to optimize the plan tree should already be simpler. For example
     * if you have two plans at the same level that both request row data from
     * the same database table with the same identifiers, `WHERE`, `LIMIT`,
     * `OFFSET` and `ORDER BY`, but different `SELECT`s we could merge the two
     * plans together by replacing the latter with the former and having the
     * former SELECT additional fields, then transform the results back to what
     * our child plans would be expecting.
     */
    private deduplicateSteps;
    private _deduplicateStepsInner;
    private hoistAndDeduplicate;
    private hoistSteps;
    private pushDownSteps;
    /**
     * Calls the 'optimize' method on a plan, which may cause the plan to
     * communicate with its (deep) dependencies, and even to replace itself with
     * a different plan.
     */
    private optimizeStep;
    /**
     * Note that we work through dependents first so we can make sure that we
     * know all our dependent's needs before we optimise ourself.
     */
    private optimizeSteps;
    private inlineSteps;
    /** Finalizes each step */
    private finalizeSteps;
    private finalizeLayerPlans;
    private finalize;
    /** Optimizes each output plan */
    private optimizeOutputPlans;
    /** Finalizes each output plan */
    private finalizeOutputPlans;
    private walkOutputPlans;
    generatePlanJSON(): GrafastPlanJSON;
    finishSubroutine(subroutineStep: Step, layerPlan: LayerPlan<LayerPlanReasonSubroutine>): void;
    getStepsByMetaKey(metaKey: string | number | symbol): Step[];
    getStepsByStepClass<TClass extends Step>(klass: {
        new (...args: any[]): TClass;
    }): TClass[];
    private _cacheStepStoreByActionKeyByLayerPlan;
    private _immutableCacheStepStoreAndActionKey;
    /**
     * Cache a generated step by a given identifier (cacheKey) such that we don't
     * need to regenerate it on future calls, significantly reducing the load on
     * deduplication later.
     *
     * @experimental
     */
    cacheStep<T extends Step>(ownerStep: Step, actionKey: string, cacheKey: symbol | string | number | boolean | null | undefined, cb: () => T): T;
    _cacheStep<T extends Step>(store: StepCache, ownerStep: Step, actionKey: string, cacheKey: any, cb: () => T): T;
    /**
     * Clears the cache, typically due to side effects having taken place. Called
     * from setting hasSideEffects on an ExecutableStep, among other places.
     */
    resetCache(): void;
    withRootLayerPlan<T>(cb: () => T): T;
}
type StepCache = Record<string, Map<any, any> | undefined>;
interface PlanFieldDetails {
    typeName: string;
    fieldName: string;
    layerPlan: LayerPlan;
    path: readonly string[];
    polymorphicPaths: ReadonlySet<string> | null;
    planningPath: string;
    planResolver: FieldPlanResolver;
    applyAfterMode: ApplyAfterModeArg;
    rawParentStep: Step;
    field: GraphQLField<any, any>;
    trackedArguments: TrackedArguments;
    streamDetails: StreamDetails | true | false | null;
}
type PlanFieldBatchResult = {
    error: Error;
} | {
    error?: never;
    haltTree: boolean;
    step: Step;
    latestSideEffectStep: Step | null;
};
interface PlanFieldBatch {
    complete: boolean;
    batch: Array<PlanFieldDetails>;
    results: Array<PlanFieldBatchResult>;
}
export {};
//# sourceMappingURL=OperationPlan.d.ts.map