#                   GridGain Community Edition Licensing
#                   Copyright 2019 GridGain Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License") modified with Commons Clause
# Restriction; 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.
#
# Commons Clause Restriction
#
# The Software is provided to you by the Licensor under the License, as defined below, subject to
# the following condition.
#
# Without limiting other conditions in the License, the grant of rights under the License will not
# include, and the License does not grant to you, the right to Sell the Software.
# For purposes of the foregoing, “Sell” means practicing any or all of the rights granted to you
# under the License to provide to third parties, for a fee or other consideration (including without
# limitation fees for hosting or consulting/ support services related to the Software), a product or
# service whose value derives, entirely or substantially, from the functionality of the Software.
# Any license notice or attribution required by the License must also include this Commons Clause
# License Condition notice.
#
# For purposes of the clause above, the “Licensor” is Copyright 2019 GridGain Systems, Inc.,
# the “License” is the Apache License, Version 2.0, and the Software is the GridGain Community
# Edition software provided with this notice.

from typing import Iterable, Union

from pyignite.queries.op_codes import *
from pyignite.datatypes import (
    Map, Bool, Byte, Int, Long, AnyDataArray, AnyDataObject,
)
from pyignite.datatypes.key_value import PeekModes
from pyignite.queries import Query, Response
from pyignite.utils import cache_id


def cache_put(
    connection: 'Connection', cache: Union[str, int], key, value,
    key_hint=None, value_hint=None, binary=False, query_id=None,
) -> 'APIResult':
    """
    Puts a value with a given key to cache (overwriting existing value if any).

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param key: key for the cache entry. Can be of any supported type,
    :param value: value for the key,
    :param key_hint: (optional) Ignite data type, for which the given key
     should be converted,
    :param value_hint: (optional) Ignite data type, for which the given value
     should be converted.
    :param binary: (optional) pass True to keep the value in binary form.
     False by default,
    :param query_id: (optional) a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status if a value
     is written, non-zero status and an error description otherwise.
    """

    query_struct = Query(
        OP_CACHE_PUT,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('key', key_hint or AnyDataObject),
            ('value', value_hint or AnyDataObject),
        ],
        query_id=query_id,
    )
    return query_struct.perform(connection, {
        'hash_code': cache_id(cache),
        'flag': 1 if binary else 0,
        'key': key,
        'value': value,
    })


def cache_get(
    connection: 'Connection', cache: Union[str, int], key,
    key_hint=None, binary=False, query_id=None,
) -> 'APIResult':
    """
    Retrieves a value from cache by key.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param key: key for the cache entry. Can be of any supported type,
    :param key_hint: (optional) Ignite data type, for which the given key
     should be converted,
    :param binary: (optional) pass True to keep the value in binary form.
     False by default,
    :param query_id: (optional) a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status and a value
     retrieved on success, non-zero status and an error description on failure.
    """

    query_struct = Query(
        OP_CACHE_GET,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('key', key_hint or AnyDataObject),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'key': key,
        },
        response_config=[
           ('value', AnyDataObject),
        ],
    )
    if result.status != 0:
        return result
    result.value = result.value['value']
    return result


def cache_get_all(
    connection: 'Connection', cache: Union[str, int], keys: Iterable,
    binary=False, query_id=None,
) -> 'APIResult':
    """
    Retrieves multiple key-value pairs from cache.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param keys: list of keys or tuples of (key, key_hint),
    :param binary: (optional) pass True to keep the value in binary form.
     False by default,
    :param query_id: (optional) a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status and a dict, made of
     retrieved key-value pairs, non-zero status and an error description
     on failure.
    """

    query_struct = Query(
        OP_CACHE_GET_ALL,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('keys', AnyDataArray()),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'keys': keys,
        },
        response_config=[
            ('data', Map),
        ],
    )
    if result.status == 0:
        result.value = dict(result.value)['data']
    return result


def cache_put_all(
    connection: 'Connection', cache: Union[str, int], pairs: dict,
    binary=False, query_id=None,
) -> 'APIResult':
    """
    Puts multiple key-value pairs to cache (overwriting existing associations
    if any).

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param pairs: dictionary type parameters, contains key-value pairs to save.
     Each key or value can be an item of representable Python type or a tuple
     of (item, hint),
    :param binary: (optional) pass True to keep the value in binary form.
     False by default,
    :param query_id: (optional) a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status if key-value pairs
     are written, non-zero status and an error description otherwise.
    """

    query_struct = Query(
        OP_CACHE_PUT_ALL,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('data', Map),
        ],
        query_id=query_id,
    )
    return query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'data': pairs,
        },
    )


def cache_contains_key(
    connection: 'Connection', cache: Union[str, int], key,
    key_hint=None, binary=False, query_id=None,
) -> 'APIResult':
    """
    Returns a value indicating whether given key is present in cache.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param key: key for the cache entry. Can be of any supported type,
    :param key_hint: (optional) Ignite data type, for which the given key
     should be converted,
    :param binary: pass True to keep the value in binary form. False
     by default,
    :param query_id: a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status and a bool value
     retrieved on success: `True` when key is present, `False` otherwise,
     non-zero status and an error description on failure.
    """

    query_struct = Query(
        OP_CACHE_CONTAINS_KEY,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('key', key_hint or AnyDataObject),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
            query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'key': key,
        },
        response_config=[
            ('value', Bool),
        ],
    )
    if result.status == 0:
        result.value = result.value['value']
    return result


def cache_contains_keys(
    connection: 'Connection', cache: Union[str, int], keys: Iterable,
    binary=False, query_id=None,
) -> 'APIResult':
    """
    Returns a value indicating whether all given keys are present in cache.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param keys: a list of keys or (key, type hint) tuples,
    :param binary: pass True to keep the value in binary form. False
     by default,
    :param query_id: a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status and a bool value
     retrieved on success: `True` when all keys are present, `False` otherwise,
     non-zero status and an error description on failure.
    """

    query_struct = Query(
        OP_CACHE_CONTAINS_KEYS,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('keys', AnyDataArray()),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'keys': keys,
        },
        response_config=[
            ('value', Bool),
        ],
    )
    if result.status == 0:
        result.value = result.value['value']
    return result


def cache_get_and_put(
    connection: 'Connection', cache: Union[str, int], key, value,
    key_hint=None, value_hint=None, binary=False, query_id=None,
) -> 'APIResult':
    """
    Puts a value with a given key to cache, and returns the previous value
    for that key, or null value if there was not such key.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param key: key for the cache entry. Can be of any supported type,
    :param value: value for the key,
    :param key_hint: (optional) Ignite data type, for which the given key
     should be converted,
    :param value_hint: (optional) Ignite data type, for which the given value
     should be converted.
    :param binary: pass True to keep the value in binary form. False
     by default,
    :param query_id: a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status and an old value
     or None if a value is written, non-zero status and an error description
     in case of error.
    """

    query_struct = Query(
        OP_CACHE_GET_AND_PUT,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('key', key_hint or AnyDataObject),
            ('value', value_hint or AnyDataObject),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'key': key,
            'value': value,
        },
        response_config=[
            ('value', AnyDataObject),
        ],
    )
    if result.status == 0:
        result.value = result.value['value']
    return result


def cache_get_and_replace(
    connection: 'Connection', cache: Union[str, int], key, value,
    key_hint=None, value_hint=None, binary=False, query_id=None,
) -> 'APIResult':
    """
    Puts a value with a given key to cache, returning previous value
    for that key, if and only if there is a value currently mapped
    for that key.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param key: key for the cache entry. Can be of any supported type,
    :param value: value for the key,
    :param key_hint: (optional) Ignite data type, for which the given key
     should be converted,
    :param value_hint: (optional) Ignite data type, for which the given value
     should be converted.
    :param binary: pass True to keep the value in binary form. False
     by default,
    :param query_id: a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status and an old value
     or None on success, non-zero status and an error description otherwise.
    """

    query_struct = Query(
        OP_CACHE_GET_AND_REPLACE, [
            ('hash_code', Int),
            ('flag', Byte),
            ('key', key_hint or AnyDataObject),
            ('value', value_hint or AnyDataObject),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'key': key,
            'value': value,
        },
        response_config=[
            ('value', AnyDataObject),
        ],
    )
    if result.status == 0:
        result.value = result.value['value']
    return result


def cache_get_and_remove(
    connection: 'Connection', cache: Union[str, int], key,
    key_hint=None, binary=False, query_id=None,
) -> 'APIResult':
    """
    Removes the cache entry with specified key, returning the value.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param key: key for the cache entry. Can be of any supported type,
    :param key_hint: (optional) Ignite data type, for which the given key
     should be converted,
    :param binary: pass True to keep the value in binary form. False
     by default,
    :param query_id: a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status and an old value
     or None, non-zero status and an error description otherwise.
    """

    query_struct = Query(
        OP_CACHE_GET_AND_REMOVE, [
            ('hash_code', Int),
            ('flag', Byte),
            ('key', key_hint or AnyDataObject),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'key': key,
        },
        response_config=[
            ('value', AnyDataObject),
        ],
    )
    if result.status == 0:
        result.value = result.value['value']
    return result


def cache_put_if_absent(
    connection: 'Connection', cache: Union[str, int], key, value,
    key_hint=None, value_hint=None, binary=False, query_id=None,
) -> 'APIResult':
    """
    Puts a value with a given key to cache only if the key
    does not already exist.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param key: key for the cache entry. Can be of any supported type,
    :param value: value for the key,
    :param key_hint: (optional) Ignite data type, for which the given key
     should be converted,
    :param value_hint: (optional) Ignite data type, for which the given value
     should be converted.
    :param binary: (optional) pass True to keep the value in binary form. False
     by default,
    :param query_id: (optional) a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status on success,
     non-zero status and an error description otherwise.
    """

    query_struct = Query(
        OP_CACHE_PUT_IF_ABSENT,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('key', key_hint or AnyDataObject),
            ('value', value_hint or AnyDataObject),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'key': key,
            'value': value,
        },
        response_config=[
            ('success', Bool),
        ],
    )
    if result.status == 0:
        result.value = result.value['success']
    return result


def cache_get_and_put_if_absent(
    connection: 'Connection', cache: Union[str, int], key, value,
    key_hint=None, value_hint=None, binary=False, query_id=None,
) -> 'APIResult':
    """
    Puts a value with a given key to cache only if the key does not
    already exist.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param key: key for the cache entry. Can be of any supported type,
    :param value: value for the key,
    :param key_hint: (optional) Ignite data type, for which the given key
     should be converted,
    :param value_hint: (optional) Ignite data type, for which the given value
     should be converted.
    :param binary: (optional) pass True to keep the value in binary form. False
     by default,
    :param query_id: (optional) a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status and an old value
     or None on success, non-zero status and an error description otherwise.
    """

    query_struct = Query(
        OP_CACHE_GET_AND_PUT_IF_ABSENT,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('key', key_hint or AnyDataObject),
            ('value', value_hint or AnyDataObject),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'key': key,
            'value': value,
        },
        response_config=[
            ('value', AnyDataObject),
        ],
    )
    if result.status == 0:
        result.value = result.value['value']
    return result


def cache_replace(
    connection: 'Connection', cache: Union[str, int], key, value,
    key_hint=None, value_hint=None, binary=False, query_id=None,
) -> 'APIResult':
    """
    Puts a value with a given key to cache only if the key already exist.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param key: key for the cache entry. Can be of any supported type,
    :param value: value for the key,
    :param key_hint: (optional) Ignite data type, for which the given key
     should be converted,
    :param value_hint: (optional) Ignite data type, for which the given value
     should be converted.
    :param binary: pass True to keep the value in binary form. False
     by default,
    :param query_id: a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status and a boolean
     success code, or non-zero status and an error description if something
     has gone wrong.
    """

    query_struct = Query(
        OP_CACHE_REPLACE,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('key', key_hint or AnyDataObject),
            ('value', value_hint or AnyDataObject),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'key': key,
            'value': value,
        },
        response_config=[
            ('success', Bool),
        ],
    )
    if result.status == 0:
        result.value = result.value['success']
    return result


def cache_replace_if_equals(
    connection: 'Connection', cache: Union[str, int], key, sample, value,
    key_hint=None, sample_hint=None, value_hint=None,
    binary=False, query_id=None,
) -> 'APIResult':
    """
    Puts a value with a given key to cache only if the key already exists
    and value equals provided sample.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param key:  key for the cache entry,
    :param sample: a sample to compare the stored value with,
    :param value: new value for the given key,
    :param key_hint: (optional) Ignite data type, for which the given key
     should be converted,
    :param sample_hint: (optional) Ignite data type, for whic
     the given sample should be converted
    :param value_hint: (optional) Ignite data type, for which the given value
     should be converted,
    :param binary: (optional) pass True to keep the value in binary form.
     False by default,
    :param query_id: (optional) a value generated by client and returned
     as-is in response.query_id. When the parameter is omitted, a random
     value is generated,
    :return: API result data object. Contains zero status and a boolean
     success code, or non-zero status and an error description if something
     has gone wrong.
    """

    query_struct = Query(
        OP_CACHE_REPLACE_IF_EQUALS,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('key', key_hint or AnyDataObject),
            ('sample', sample_hint or AnyDataObject),
            ('value', value_hint or AnyDataObject),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'key': key,
            'sample': sample,
            'value': value,
        },
        response_config=[
            ('success', Bool),
        ],
    )
    if result.status == 0:
        result.value = result.value['success']
    return result


def cache_clear(
    connection: 'Connection', cache: Union[str, int], binary=False,
    query_id=None,
) -> 'APIResult':
    """
    Clears the cache without notifying listeners or cache writers.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param binary: (optional) pass True to keep the value in binary form.
     False by default,
    :param query_id: (optional) a value generated by client and returned
     as-is in response.query_id. When the parameter is omitted, a random
     value is generated,
    :return: API result data object. Contains zero status on success,
     non-zero status and an error description otherwise.
    """

    query_struct = Query(
        OP_CACHE_CLEAR,
        [
            ('hash_code', Int),
            ('flag', Byte),
        ],
        query_id=query_id,
    )
    return query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
        },
    )


def cache_clear_key(
    connection: 'Connection', cache: Union[str, int], key,
    key_hint: object=None, binary=False, query_id=None,
) -> 'APIResult':
    """
    Clears the cache key without notifying listeners or cache writers.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param key:  key for the cache entry,
    :param key_hint: (optional) Ignite data type, for which the given key
     should be converted,
    :param binary: (optional) pass True to keep the value in binary form.
     False by default,
    :param query_id: (optional) a value generated by client and returned
     as-is in response.query_id. When the parameter is omitted, a random
     value is generated,
    :return: API result data object. Contains zero status on success,
     non-zero status and an error description otherwise.
    """

    query_struct = Query(
        OP_CACHE_CLEAR_KEY,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('key', key_hint or AnyDataObject),
        ],
        query_id=query_id,
    )
    return query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'key': key,
        },
    )


def cache_clear_keys(
    connection: 'Connection', cache: Union[str, int], keys: list,
    binary=False, query_id=None,
) -> 'APIResult':
    """
    Clears the cache keys without notifying listeners or cache writers.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param keys: list of keys or tuples of (key, key_hint),
    :param binary: (optional) pass True to keep the value in binary form.
     False by default,
    :param query_id: (optional) a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status on success,
     non-zero status and an error description otherwise.
    """

    query_struct = Query(
        OP_CACHE_CLEAR_KEYS,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('keys', AnyDataArray()),
        ],
        query_id=query_id,
    )
    return query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'keys': keys,
        },
    )


def cache_remove_key(
    connection: 'Connection', cache: Union[str, int], key,
    key_hint: object=None, binary=False, query_id=None,
) -> 'APIResult':
    """
    Clears the cache key without notifying listeners or cache writers.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param key:  key for the cache entry,
    :param key_hint: (optional) Ignite data type, for which the given key
     should be converted,
    :param binary: (optional) pass True to keep the value in binary form.
     False by default,
    :param query_id: (optional) a value generated by client and returned
     as-is in response.query_id. When the parameter is omitted, a random
     value is generated,
    :return: API result data object. Contains zero status and a boolean
     success code, or non-zero status and an error description if something
     has gone wrong.
    """

    query_struct = Query(
        OP_CACHE_REMOVE_KEY,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('key', key_hint or AnyDataObject),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'key': key,
        },
        response_config=[
            ('success', Bool),
        ],
    )
    if result.status == 0:
        result.value = result.value['success']
    return result


def cache_remove_if_equals(
    connection: 'Connection', cache: Union[str, int], key, sample,
    key_hint=None, sample_hint=None,
    binary=False, query_id=None,
) -> 'APIResult':
    """
    Removes an entry with a given key if provided value is equal to
    actual value, notifying listeners and cache writers.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param key:  key for the cache entry,
    :param sample: a sample to compare the stored value with,
    :param key_hint: (optional) Ignite data type, for which the given key
     should be converted,
    :param sample_hint: (optional) Ignite data type, for whic
     the given sample should be converted
    :param binary: (optional) pass True to keep the value in binary form.
     False by default,
    :param query_id: (optional) a value generated by client and returned
     as-is in response.query_id. When the parameter is omitted, a random
     value is generated,
    :return: API result data object. Contains zero status and a boolean
     success code, or non-zero status and an error description if something
     has gone wrong.
    """

    query_struct = Query(
        OP_CACHE_REMOVE_IF_EQUALS,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('key', key_hint or AnyDataObject),
            ('sample', sample_hint or AnyDataObject),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'key': key,
            'sample': sample,
        },
        response_config=[
            ('success', Bool),
        ],
    )
    if result.status == 0:
        result.value = result.value['success']
    return result


def cache_remove_keys(
    connection: 'Connection', cache: Union[str, int], keys: Iterable,
    binary=False, query_id=None,
) -> 'APIResult':
    """
    Removes entries with given keys, notifying listeners and cache writers.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param keys: list of keys or tuples of (key, key_hint),
    :param binary: (optional) pass True to keep the value in binary form.
     False by default,
    :param query_id: (optional) a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status on success,
     non-zero status and an error description otherwise.
    """

    query_struct = Query(
        OP_CACHE_REMOVE_KEYS,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('keys', AnyDataArray()),
        ],
        query_id=query_id,
    )
    return query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'keys': keys,
        },
    )


def cache_remove_all(
    connection: 'Connection', cache: Union[str, int], binary=False,
    query_id=None,
) -> 'APIResult':
    """
    Removes all entries from cache, notifying listeners and cache writers.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param binary: (optional) pass True to keep the value in binary form.
     False by default,
    :param query_id: (optional) a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status on success,
     non-zero status and an error description otherwise.
    """

    query_struct = Query(
        OP_CACHE_REMOVE_ALL,
        [
            ('hash_code', Int),
            ('flag', Byte),
        ],
        query_id=query_id,
    )
    return query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
        },
    )


def cache_get_size(
    connection: 'Connection', cache: Union[str, int], peek_modes=0,
    binary=False, query_id=None,
) -> 'APIResult':
    """
    Gets the number of entries in cache.

    :param connection: connection to Ignite server,
    :param cache: name or ID of the cache,
    :param peek_modes: (optional) limit count to near cache partition
     (PeekModes.NEAR), primary cache (PeekModes.PRIMARY), or backup cache
     (PeekModes.BACKUP). Defaults to all cache partitions (PeekModes.ALL),
    :param binary: (optional) pass True to keep the value in binary form.
     False by default,
    :param query_id: (optional) a value generated by client and returned as-is
     in response.query_id. When the parameter is omitted, a random value
     is generated,
    :return: API result data object. Contains zero status and a number of
     cache entries on success, non-zero status and an error description
     otherwise.
    """
    if not isinstance(peek_modes, (list, tuple)):
        if peek_modes == 0:
            peek_modes = []
        else:
            peek_modes = [peek_modes]

    query_struct = Query(
        OP_CACHE_GET_SIZE,
        [
            ('hash_code', Int),
            ('flag', Byte),
            ('peek_modes', PeekModes),
        ],
        query_id=query_id,
    )
    result = query_struct.perform(
        connection,
        query_params={
            'hash_code': cache_id(cache),
            'flag': 1 if binary else 0,
            'peek_modes': peek_modes,
        },
        response_config=[
            ('count', Long),
        ],
    )
    if result.status == 0:
        result.value = result.value['count']
    return result

[(68, 'pyignite.queries.Query', 'Query', (['OP_CACHE_PUT', "[('hash_code', Int), ('flag', Byte), ('key', key_hint or AnyDataObject), (\n    'value', value_hint or AnyDataObject)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (107, 'pyignite.queries.Query', 'Query', (['OP_CACHE_GET', "[('hash_code', Int), ('flag', Byte), ('key', key_hint or AnyDataObject)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (200, 'pyignite.queries.Query', 'Query', (['OP_CACHE_PUT_ALL', "[('hash_code', Int), ('flag', Byte), ('data', Map)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (241, 'pyignite.queries.Query', 'Query', (['OP_CACHE_CONTAINS_KEY', "[('hash_code', Int), ('flag', Byte), ('key', key_hint or AnyDataObject)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (337, 'pyignite.queries.Query', 'Query', (['OP_CACHE_GET_AND_PUT', "[('hash_code', Int), ('flag', Byte), ('key', key_hint or AnyDataObject), (\n    'value', value_hint or AnyDataObject)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (390, 'pyignite.queries.Query', 'Query', (['OP_CACHE_GET_AND_REPLACE', "[('hash_code', Int), ('flag', Byte), ('key', key_hint or AnyDataObject), (\n    'value', value_hint or AnyDataObject)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (437, 'pyignite.queries.Query', 'Query', (['OP_CACHE_GET_AND_REMOVE', "[('hash_code', Int), ('flag', Byte), ('key', key_hint or AnyDataObject)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (486, 'pyignite.queries.Query', 'Query', (['OP_CACHE_PUT_IF_ABSENT', "[('hash_code', Int), ('flag', Byte), ('key', key_hint or AnyDataObject), (\n    'value', value_hint or AnyDataObject)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (538, 'pyignite.queries.Query', 'Query', (['OP_CACHE_GET_AND_PUT_IF_ABSENT', "[('hash_code', Int), ('flag', Byte), ('key', key_hint or AnyDataObject), (\n    'value', value_hint or AnyDataObject)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (590, 'pyignite.queries.Query', 'Query', (['OP_CACHE_REPLACE', "[('hash_code', Int), ('flag', Byte), ('key', key_hint or AnyDataObject), (\n    'value', value_hint or AnyDataObject)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (647, 'pyignite.queries.Query', 'Query', (['OP_CACHE_REPLACE_IF_EQUALS', "[('hash_code', Int), ('flag', Byte), ('key', key_hint or AnyDataObject), (\n    'sample', sample_hint or AnyDataObject), ('value', value_hint or\n    AnyDataObject)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (694, 'pyignite.queries.Query', 'Query', (['OP_CACHE_CLEAR', "[('hash_code', Int), ('flag', Byte)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (732, 'pyignite.queries.Query', 'Query', (['OP_CACHE_CLEAR_KEY', "[('hash_code', Int), ('flag', Byte), ('key', key_hint or AnyDataObject)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (811, 'pyignite.queries.Query', 'Query', (['OP_CACHE_REMOVE_KEY', "[('hash_code', Int), ('flag', Byte), ('key', key_hint or AnyDataObject)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (863, 'pyignite.queries.Query', 'Query', (['OP_CACHE_REMOVE_IF_EQUALS', "[('hash_code', Int), ('flag', Byte), ('key', key_hint or AnyDataObject), (\n    'sample', sample_hint or AnyDataObject)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (946, 'pyignite.queries.Query', 'Query', (['OP_CACHE_REMOVE_ALL', "[('hash_code', Int), ('flag', Byte)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (990, 'pyignite.queries.Query', 'Query', (['OP_CACHE_GET_SIZE', "[('hash_code', Int), ('flag', Byte), ('peek_modes', PeekModes)]"], {'query_id': 'query_id'}), False, 'from pyignite.queries import Query, Response\n'), (79, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (119, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (158, 'pyignite.datatypes.AnyDataArray', 'AnyDataArray', ([], {}), False, 'from pyignite.datatypes import Map, Bool, Byte, Int, Long, AnyDataArray, AnyDataObject\n'), (165, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (212, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (253, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (291, 'pyignite.datatypes.AnyDataArray', 'AnyDataArray', ([], {}), False, 'from pyignite.datatypes import Map, Bool, Byte, Int, Long, AnyDataArray, AnyDataObject\n'), (298, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (350, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (402, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (448, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (499, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (551, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (603, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (661, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (705, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (744, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (775, 'pyignite.datatypes.AnyDataArray', 'AnyDataArray', ([], {}), False, 'from pyignite.datatypes import Map, Bool, Byte, Int, Long, AnyDataArray, AnyDataObject\n'), (782, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (823, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (876, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (914, 'pyignite.datatypes.AnyDataArray', 'AnyDataArray', ([], {}), False, 'from pyignite.datatypes import Map, Bool, Byte, Int, Long, AnyDataArray, AnyDataObject\n'), (921, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (957, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n'), (1002, 'pyignite.utils.cache_id', 'cache_id', (['cache'], {}), False, 'from pyignite.utils import cache_id\n')]