import { ExecutionResult, IResolvers } from '@graphql-tools/utils';
import { GraphQLSchema } from 'graphql';
export type IMockFn = () => unknown;
export type IScalarMock = unknown | IMockFn;
export type ITypeMock = () => {
    [fieldName: string]: unknown | IMockFn;
} | {
    [fieldName: string]: IMockFn;
};
export type IMocks<TResolvers = IResolvers> = {
    [TTypeName in keyof TResolvers]?: {
        [TFieldName in keyof TResolvers[TTypeName]]: TResolvers[TTypeName][TFieldName] extends (args: any) => any ? () => ReturnType<TResolvers[TTypeName][TFieldName]> | ReturnType<TResolvers[TTypeName][TFieldName]> : TResolvers[TTypeName][TFieldName];
    };
} & {
    [typeOrScalarName: string]: IScalarMock | ITypeMock;
};
export type KeyTypeConstraints = string | number;
export type TypePolicy = {
    /**
     * The name of the field that should be used as store `key`.
     *
     * If `false`, no field will be used and `id` or `_id` will be used,
     * otherwise we'll generate a random string
     * as key.
     */
    keyFieldName?: string | false;
};
export type GetArgs<KeyT extends KeyTypeConstraints = string> = {
    typeName: string;
    key?: KeyT;
    fieldName?: string;
    /**
     * Optional arguments when querying the field.
     *
     * Querying the field with the same arguments will return
     * the same value. Deep equality is checked.
     *
     * ```ts
     * store.get('User', 1, 'friend', { id: 2 }) === store.get('User', 1, 'friend', { id: 2 })
     * store.get('User', 1, 'friend', { id: 2 }) !== store.get('User', 1, 'friend')
     * ```
     *
     * Args can be a record, just like `args` argument of field resolver or an
     * arbitrary string.
     */
    fieldArgs?: string | {
        [argName: string]: any;
    };
    /**
     * If no value found, insert the `defaultValue`.
     */
    defaultValue?: unknown | {
        [fieldName: string]: any;
    };
};
export type SetArgs<KeyT extends KeyTypeConstraints = string> = {
    typeName: string;
    key: KeyT;
    fieldName?: string;
    /**
     * Optional arguments when querying the field.
     *
     * @see GetArgs#fieldArgs
     */
    fieldArgs?: string | {
        [argName: string]: any;
    };
    value?: unknown | {
        [fieldName: string]: any;
    };
    /**
     * If the value for this field is already set, it won't
     * be overridden.
     *
     * Propagates down do nested `set`.
     */
    noOverride?: boolean;
};
export interface IMockStore {
    schema: GraphQLSchema;
    /**
     * Get a field value from the store for the given type, key and field
     * name — and optionally field arguments. If the field name is not given,
     * a reference to the type will be returned.
     *
     * If the the value for this field is not set, a value will be
     * generated according to field return type and mock functions.
     *
     * If the field's output type is a `ObjectType` (or list of `ObjectType`),
     * it will return a `Ref` (or array of `Ref`), ie a reference to an entity
     * in the store.
     *
     * Example:
     * ```ts
     * store.get('Query', 'ROOT', 'viewer');
     * > { $ref: { key: 'abc-737dh-djdjd', typeName: 'User' } }
     * store.get('User', 'abc-737dh-djdjd', 'name')
     * > "Hello World"
     * ```
     */
    get<KeyT extends KeyTypeConstraints = string, ReturnKeyT extends KeyTypeConstraints = string>(args: GetArgs<KeyT>): unknown | Ref<ReturnKeyT>;
    /**
     * Shorthand for `get({typeName, key, fieldName, fieldArgs})`.
     */
    get<KeyT extends KeyTypeConstraints = string, ReturnKeyT extends KeyTypeConstraints = string>(typeName: string, key: KeyT, fieldNameOrFieldNames: string | string[], fieldArgs?: string | {
        [argName: string]: any;
    }): unknown | Ref<ReturnKeyT>;
    /**
     * Get a reference to the type.
     */
    get<KeyT extends KeyTypeConstraints = string>(typeName: string, keyOrDefaultValue?: KeyT | {
        [fieldName: string]: any;
    }, defaultValue?: {
        [fieldName: string]: any;
    }): unknown | Ref<KeyT>;
    /**
     * Shorthand for `get({typeName: ref.$ref.typeName, key: ref.$ref.key, fieldName, fieldArgs})`
     * @param ref
     * @param fieldNameOrFieldNames
     * @param fieldArgs
     */
    get<KeyT extends KeyTypeConstraints = string, ReturnKeyT extends KeyTypeConstraints = string>(ref: Ref<KeyT>, fieldNameOrFieldNames: string | string[], fieldArgs?: string | {
        [argName: string]: any;
    }): unknown | Ref<ReturnKeyT>;
    /**
     * Set a field value in the store for the given type, key and field
     * name — and optionally field arguments.
     *
     * If the the field return type is an `ObjectType` or a list of
     * `ObjectType`, you can set references to other entity as value:
     *
     * ```ts
     * // set the viewer name
     * store.set('User', 1, 'name', 'Alexandre);
     * store.set('Query', 'ROOT', 'viewer', store.get('User', 1));
     *
     * // set the friends of viewer
     * store.set('User', 2, 'name', 'Emily');
     * store.set('User', 3, 'name', 'Caroline');
     * store.set('User', 1, 'friends', [store.get('User', 2), store.get('User', 3)]);
     * ```
     *
     * But it also supports nested set:
     *
     * ```ts
     * store.set('Query', 'ROOT', 'viewer', {
     *  name: 'Alexandre',
     *  friends: [
     *    { name: 'Emily' }
     *    { name: 'Caroline }
     *  ]
     * });
     * ```
     */
    set<KeyT extends KeyTypeConstraints = string>(args: SetArgs<KeyT>): void;
    /**
     * Shorthand for `set({typeName, key, fieldName, value})`.
     */
    set<KeyT extends KeyTypeConstraints = string>(typeName: string, key: KeyT, fieldName: string, value?: unknown): void;
    /**
     * Set the given field values to the type with key.
     */
    set<KeyT extends KeyTypeConstraints = string>(typeName: string, key: KeyT, values: {
        [fieldName: string]: any;
    }): void;
    /**
     * Shorthand for `set({ref.$ref.typeName, ref.$ref.key, fieldName, value})`.
     */
    set<KeyT extends KeyTypeConstraints = string>(ref: Ref<KeyT>, fieldName: string, value?: unknown): void;
    /**
     * Set the given field values to the type with ref.
     */
    set<KeyT extends KeyTypeConstraints = string>(ref: Ref<KeyT>, values: {
        [fieldName: string]: any;
    }): void;
    /**
     * Checks if a mock is present in the store for the given typeName and key.
     */
    has<KeyT extends KeyTypeConstraints = string>(typeName: string, key: KeyT): boolean;
    /**
     * Resets the mock store
     */
    reset(): void;
}
export type Ref<KeyT extends KeyTypeConstraints = string> = {
    $ref: {
        key: KeyT;
        typeName: string;
    };
};
export declare function isRef<KeyT extends KeyTypeConstraints = string>(maybeRef: unknown): maybeRef is Ref<KeyT>;
export declare function assertIsRef<KeyT extends KeyTypeConstraints = string>(maybeRef: unknown, message?: string): asserts maybeRef is Ref<KeyT>;
export declare function isRecord(obj: unknown): obj is {
    [key: string]: unknown;
};
export interface IMockServer {
    /**
     * Executes the provided query against the mocked schema.
     * @param query GraphQL query to execute
     * @param vars Variables
     */
    query: (query: string, vars?: Record<string, any>) => Promise<ExecutionResult>;
}
