# Generated by the protocol buffer compiler.  DO NOT EDIT!
# sources: oxia/internal/proto/client.proto
# plugin: python-betterproto2
# This file has been @generated

__all__ = (
    "CloseSessionRequest",
    "CloseSessionResponse",
    "CreateSessionRequest",
    "CreateSessionResponse",
    "DeleteRangeRequest",
    "DeleteRangeResponse",
    "DeleteRequest",
    "DeleteResponse",
    "GetRequest",
    "GetResponse",
    "GetSequenceUpdatesRequest",
    "GetSequenceUpdatesResponse",
    "Int32HashRange",
    "KeepAliveResponse",
    "KeyComparisonType",
    "ListRequest",
    "ListResponse",
    "NamespaceShardsAssignment",
    "Notification",
    "NotificationBatch",
    "NotificationType",
    "NotificationsRequest",
    "OxiaClientStub",
    "PutRequest",
    "PutResponse",
    "RangeScanRequest",
    "RangeScanResponse",
    "ReadRequest",
    "ReadResponse",
    "SecondaryIndex",
    "SessionHeartbeat",
    "ShardAssignment",
    "ShardAssignments",
    "ShardAssignmentsRequest",
    "ShardKeyRouter",
    "Status",
    "Version",
    "WriteRequest",
    "WriteResponse",
)

from collections.abc import Iterable, Iterator
from dataclasses import dataclass

import betterproto2
import grpc

from .....message_pool import default_message_pool

_COMPILER_VERSION = "0.9.0"
betterproto2.check_compiler_version(_COMPILER_VERSION)


class KeyComparisonType(betterproto2.Enum):
    """
    *
    The type of key comparison to apply in a get() request
    """

    EQUAL = 0
    """
    The stored key must be equal to the requested key
    """

    FLOOR = 1
    """
    Search for a key that is the highest key that is <= to the requested key
    """

    CEILING = 2
    """
    Search for a key that is the lowest key that is >= to the requested key
    """

    LOWER = 3
    """
    Search for a key that is the highest key that is < to the requested key
    """

    HIGHER = 4
    """
    Search for a key that is the lowest key that is > to the requested key
    """


class NotificationType(betterproto2.Enum):
    KEY_CREATED = 0

    KEY_MODIFIED = 1

    KEY_DELETED = 2

    KEY_RANGE_DELETED = 3


class ShardKeyRouter(betterproto2.Enum):
    UNKNOWN = 0

    XXHASH3 = 1


class Status(betterproto2.Enum):
    """
    *
    Represents all the possible status.
    """

    OK = 0
    """
    Operation was successful
    """

    KEY_NOT_FOUND = 1
    """
    The key was not found
    """

    UNEXPECTED_VERSION_ID = 2
    """
    The existing version does not match the expected version
    """

    SESSION_DOES_NOT_EXIST = 3
    """
    The session that the put request referred to is not alive
    """


@dataclass(eq=False, repr=False)
class CloseSessionRequest(betterproto2.Message):
    shard: "int" = betterproto2.field(1, betterproto2.TYPE_INT64)

    session_id: "int" = betterproto2.field(2, betterproto2.TYPE_INT64)


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "CloseSessionRequest", CloseSessionRequest
)


@dataclass(eq=False, repr=False)
class CloseSessionResponse(betterproto2.Message):
    pass


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "CloseSessionResponse", CloseSessionResponse
)


@dataclass(eq=False, repr=False)
class CreateSessionRequest(betterproto2.Message):
    shard: "int" = betterproto2.field(1, betterproto2.TYPE_INT64)

    session_timeout_ms: "int" = betterproto2.field(2, betterproto2.TYPE_UINT32)

    client_identity: "str" = betterproto2.field(3, betterproto2.TYPE_STRING)


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "CreateSessionRequest", CreateSessionRequest
)


@dataclass(eq=False, repr=False)
class CreateSessionResponse(betterproto2.Message):
    session_id: "int" = betterproto2.field(1, betterproto2.TYPE_INT64)


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "CreateSessionResponse", CreateSessionResponse
)


@dataclass(eq=False, repr=False)
class DeleteRangeRequest(betterproto2.Message):
    """
    *
    Input to a delete range request. Key ranges assume a UTF-8 byte sort order.
    """

    start_inclusive: "str" = betterproto2.field(1, betterproto2.TYPE_STRING)
    """
    The start of the range, inclusive
    """

    end_exclusive: "str" = betterproto2.field(2, betterproto2.TYPE_STRING)
    """
    The end of the range, exclusive
    """


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "DeleteRangeRequest", DeleteRangeRequest
)


@dataclass(eq=False, repr=False)
class DeleteRangeResponse(betterproto2.Message):
    """
    *
    The response for a delete range request.
    """

    status: "Status" = betterproto2.field(
        1, betterproto2.TYPE_ENUM, default_factory=lambda: Status(0)
    )
    """
    Includes the error or OK
    """


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "DeleteRangeResponse", DeleteRangeResponse
)


@dataclass(eq=False, repr=False)
class DeleteRequest(betterproto2.Message):
    """
    *
    A delete request. Deletes the specified key.
    """

    key: "str" = betterproto2.field(1, betterproto2.TYPE_STRING)
    """
    The key
    """

    expected_version_id: "int | None" = betterproto2.field(
        2, betterproto2.TYPE_INT64, optional=True
    )
    """
    An optional expected version_id. The delete will fail if the server's current version_id
    does not match
    """


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "DeleteRequest", DeleteRequest
)


@dataclass(eq=False, repr=False)
class DeleteResponse(betterproto2.Message):
    """
    *
    The response to a delete request or an item in a response to the
    delete range request.
    """

    status: "Status" = betterproto2.field(
        1, betterproto2.TYPE_ENUM, default_factory=lambda: Status(0)
    )
    """
    Includes the error or OK
    """


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "DeleteResponse", DeleteResponse
)


@dataclass(eq=False, repr=False)
class GetRequest(betterproto2.Message):
    """
    *
    A get request. Gets the stat and optionally the value for the specified
    key.
    """

    key: "str" = betterproto2.field(1, betterproto2.TYPE_STRING)
    """
    The key
    """

    include_value: "bool" = betterproto2.field(2, betterproto2.TYPE_BOOL)
    """
    Specifies whether the response should include the value
    """

    comparison_type: "KeyComparisonType" = betterproto2.field(
        3, betterproto2.TYPE_ENUM, default_factory=lambda: KeyComparisonType(0)
    )

    secondary_index_name: "str | None" = betterproto2.field(
        4, betterproto2.TYPE_STRING, optional=True
    )


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "GetRequest", GetRequest
)


@dataclass(eq=False, repr=False)
class GetResponse(betterproto2.Message):
    """
    *
    The response to a get request.
    """

    status: "Status" = betterproto2.field(
        1, betterproto2.TYPE_ENUM, default_factory=lambda: Status(0)
    )
    """
    Includes the error or OK
    """

    version: "Version | None" = betterproto2.field(
        2, betterproto2.TYPE_MESSAGE, optional=True
    )
    """
    The version of the record
    """

    value: "bytes | None" = betterproto2.field(
        3, betterproto2.TYPE_BYTES, optional=True
    )
    """
    The value, if it was requested and there was no error
    """

    key: "str | None" = betterproto2.field(4, betterproto2.TYPE_STRING, optional=True)
    """
    In case of non-exact queries (eg. floor, ceiling) the found key will be
    returned in the GetResponse.
    """

    secondary_index_key: "str | None" = betterproto2.field(
        5, betterproto2.TYPE_STRING, optional=True
    )


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "GetResponse", GetResponse
)


@dataclass(eq=False, repr=False)
class GetSequenceUpdatesRequest(betterproto2.Message):
    shard: "int" = betterproto2.field(1, betterproto2.TYPE_INT64)

    key: "str" = betterproto2.field(2, betterproto2.TYPE_STRING)


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "GetSequenceUpdatesRequest", GetSequenceUpdatesRequest
)


@dataclass(eq=False, repr=False)
class GetSequenceUpdatesResponse(betterproto2.Message):
    highest_sequence_key: "str" = betterproto2.field(1, betterproto2.TYPE_STRING)


default_message_pool.register_message(
    "io.streamnative.oxia.proto",
    "GetSequenceUpdatesResponse",
    GetSequenceUpdatesResponse,
)


@dataclass(eq=False, repr=False)
class Int32HashRange(betterproto2.Message):
    """
    *
    Represents a range of hash values [min, max)
    """

    min_hash_inclusive: "int" = betterproto2.field(1, betterproto2.TYPE_FIXED32)
    """
    The minimum inclusive hash that the shard can contain
    """

    max_hash_inclusive: "int" = betterproto2.field(2, betterproto2.TYPE_FIXED32)
    """
    The maximum inclusive hash that the shard can contain
    """


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "Int32HashRange", Int32HashRange
)


@dataclass(eq=False, repr=False)
class KeepAliveResponse(betterproto2.Message):
    pass


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "KeepAliveResponse", KeepAliveResponse
)


@dataclass(eq=False, repr=False)
class ListRequest(betterproto2.Message):
    """
    *
    Input to a list request. Key ranges assume a UTF-8 byte sort order.
    """

    shard: "int | None" = betterproto2.field(1, betterproto2.TYPE_INT64, optional=True)
    """
    The shard id. This is optional allow for support for server-side hashing
    and proxying in the future.
    """

    start_inclusive: "str" = betterproto2.field(2, betterproto2.TYPE_STRING)
    """
    The start of the range, inclusive
    """

    end_exclusive: "str" = betterproto2.field(3, betterproto2.TYPE_STRING)
    """
    The end of the range, exclusive
    """

    secondary_index_name: "str | None" = betterproto2.field(
        4, betterproto2.TYPE_STRING, optional=True
    )


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "ListRequest", ListRequest
)


@dataclass(eq=False, repr=False)
class ListResponse(betterproto2.Message):
    """
    *
    The response to a list request.
    """

    keys: "list[str]" = betterproto2.field(1, betterproto2.TYPE_STRING, repeated=True)
    """
    A portion of the keys found within the specified range
    """


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "ListResponse", ListResponse
)


@dataclass(eq=False, repr=False)
class NamespaceShardsAssignment(betterproto2.Message):
    """
    *
    The shards assignments for a given namespace
    """

    assignments: "list[ShardAssignment]" = betterproto2.field(
        1, betterproto2.TYPE_MESSAGE, repeated=True
    )
    """
    All assignments in the response stream will contain all the
    assignments to bring the client up to date. For example, if a shard is
    split, the stream will return a single response containing all the new
    shard assignments as opposed to multiple stream responses, each containing
    a single shard assignment.
    """

    shard_key_router: "ShardKeyRouter" = betterproto2.field(
        2, betterproto2.TYPE_ENUM, default_factory=lambda: ShardKeyRouter(0)
    )
    """
    Indicates the mechanism by which the keys are assigned to the individual
    shards.
    """


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "NamespaceShardsAssignment", NamespaceShardsAssignment
)


@dataclass(eq=False, repr=False)
class Notification(betterproto2.Message):
    type: "NotificationType" = betterproto2.field(
        1, betterproto2.TYPE_ENUM, default_factory=lambda: NotificationType(0)
    )

    version_id: "int | None" = betterproto2.field(
        2, betterproto2.TYPE_INT64, optional=True
    )

    key_range_last: "str | None" = betterproto2.field(
        3, betterproto2.TYPE_STRING, optional=True
    )


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "Notification", Notification
)


@dataclass(eq=False, repr=False)
class NotificationBatch(betterproto2.Message):
    shard: "int" = betterproto2.field(1, betterproto2.TYPE_INT64)

    offset: "int" = betterproto2.field(2, betterproto2.TYPE_INT64)

    timestamp: "int" = betterproto2.field(3, betterproto2.TYPE_FIXED64)

    notifications: "dict[str, Notification]" = betterproto2.field(
        4,
        betterproto2.TYPE_MAP,
        map_meta=betterproto2.map_meta(
            betterproto2.TYPE_STRING, betterproto2.TYPE_MESSAGE
        ),
    )


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "NotificationBatch", NotificationBatch
)


@dataclass(eq=False, repr=False)
class NotificationsRequest(betterproto2.Message):
    shard: "int" = betterproto2.field(1, betterproto2.TYPE_INT64)

    start_offset_exclusive: "int | None" = betterproto2.field(
        2, betterproto2.TYPE_INT64, optional=True
    )


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "NotificationsRequest", NotificationsRequest
)


@dataclass(eq=False, repr=False)
class PutRequest(betterproto2.Message):
    """
    *
    A put request. Persists the specified key and value
    """

    key: "str" = betterproto2.field(1, betterproto2.TYPE_STRING)
    """
    The key
    """

    value: "bytes" = betterproto2.field(2, betterproto2.TYPE_BYTES)
    """
    The value
    """

    expected_version_id: "int | None" = betterproto2.field(
        3, betterproto2.TYPE_INT64, optional=True
    )
    """
    An optional expected version_id. The put will fail if the server's current version_id
    does not match
    """

    session_id: "int | None" = betterproto2.field(
        4, betterproto2.TYPE_INT64, optional=True
    )
    """
    Optional. Associate the new record with the session (i.e. ephemeral record).
    When the session expires or is explicitly closed, the record will be automatically
    removed
    """

    client_identity: "str | None" = betterproto2.field(
        5, betterproto2.TYPE_STRING, optional=True
    )
    """
    Client identifier used to track the client that last modified an
    ephemeral record.
    """

    partition_key: "str | None" = betterproto2.field(
        6, betterproto2.TYPE_STRING, optional=True
    )
    """
    If a partition key is present, it supersedes the regular record key in determining the routing of
    a record to a particular shard. It is passed to the server because it needs to be persisted as
    part of the record. We would need the partition_key if we're going to do a split of the shards.
    """

    sequence_key_delta: "list[int]" = betterproto2.field(
        7, betterproto2.TYPE_UINT64, repeated=True
    )
    """
    If one or more sequence key are specified. The key will get added suffixes
    based on adding the delta to the current highest key with the same prefix
    """

    secondary_indexes: "list[SecondaryIndex]" = betterproto2.field(
        8, betterproto2.TYPE_MESSAGE, repeated=True
    )


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "PutRequest", PutRequest
)


@dataclass(eq=False, repr=False)
class PutResponse(betterproto2.Message):
    """
    *
    The response to a put request.
    """

    status: "Status" = betterproto2.field(
        1, betterproto2.TYPE_ENUM, default_factory=lambda: Status(0)
    )
    """
    Includes the error or OK
    """

    version: "Version | None" = betterproto2.field(
        2, betterproto2.TYPE_MESSAGE, optional=True
    )
    """
    The version if the put was successful
    """

    key: "str | None" = betterproto2.field(3, betterproto2.TYPE_STRING, optional=True)
    """
    If the key was generated by Oxia, it will be returned as part
    of the response
    """


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "PutResponse", PutResponse
)


@dataclass(eq=False, repr=False)
class RangeScanRequest(betterproto2.Message):
    """
    *
    Input to a range-scan request
    """

    shard: "int | None" = betterproto2.field(1, betterproto2.TYPE_INT64, optional=True)
    """
    The shard id. This is optional allow for support for server-side hashing
    and proxying in the future.
    """

    start_inclusive: "str" = betterproto2.field(2, betterproto2.TYPE_STRING)
    """
    The start of the range, inclusive
    """

    end_exclusive: "str" = betterproto2.field(3, betterproto2.TYPE_STRING)
    """
    The end of the range, exclusive
    """

    secondary_index_name: "str | None" = betterproto2.field(
        4, betterproto2.TYPE_STRING, optional=True
    )


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "RangeScanRequest", RangeScanRequest
)


@dataclass(eq=False, repr=False)
class RangeScanResponse(betterproto2.Message):
    """
    *
    The response to a range-scan request.
    """

    records: "list[GetResponse]" = betterproto2.field(
        1, betterproto2.TYPE_MESSAGE, repeated=True
    )
    """
    A portion of the records found within the specified range
    """


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "RangeScanResponse", RangeScanResponse
)


@dataclass(eq=False, repr=False)
class ReadRequest(betterproto2.Message):
    """
    *
    A batch read request. Applies the batches of requests.
    """

    shard: "int | None" = betterproto2.field(1, betterproto2.TYPE_INT64, optional=True)
    """
    The shard id. This is optional allow for support for server-side hashing
    and proxying in the future.
    """

    gets: "list[GetRequest]" = betterproto2.field(
        2, betterproto2.TYPE_MESSAGE, repeated=True
    )
    """
    The get requests
    """


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "ReadRequest", ReadRequest
)


@dataclass(eq=False, repr=False)
class ReadResponse(betterproto2.Message):
    """
    *
    The response to a batch read request. Responses of each type respect the
    order of the original requests.
    """

    gets: "list[GetResponse]" = betterproto2.field(
        1, betterproto2.TYPE_MESSAGE, repeated=True
    )
    """
    The get responses
    """


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "ReadResponse", ReadResponse
)


@dataclass(eq=False, repr=False)
class SecondaryIndex(betterproto2.Message):
    index_name: "str" = betterproto2.field(1, betterproto2.TYPE_STRING)

    secondary_key: "str" = betterproto2.field(2, betterproto2.TYPE_STRING)


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "SecondaryIndex", SecondaryIndex
)


@dataclass(eq=False, repr=False)
class SessionHeartbeat(betterproto2.Message):
    shard: "int" = betterproto2.field(1, betterproto2.TYPE_INT64)

    session_id: "int" = betterproto2.field(2, betterproto2.TYPE_INT64)


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "SessionHeartbeat", SessionHeartbeat
)


@dataclass(eq=False, repr=False)
class ShardAssignment(betterproto2.Message):
    """
    *
    The assignment of a shard to a server.

    Oneofs:
        - shard_boundaries: There could be multiple ways to describe the boundaries of a shard
    """

    shard: "int" = betterproto2.field(1, betterproto2.TYPE_INT64)
    """
    The shard id
    """

    leader: "str" = betterproto2.field(2, betterproto2.TYPE_STRING)
    """
    The shard leader, e.g. `host:port`
    """

    int32_hash_range: "Int32HashRange | None" = betterproto2.field(
        3, betterproto2.TYPE_MESSAGE, optional=True, group="shard_boundaries"
    )


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "ShardAssignment", ShardAssignment
)


@dataclass(eq=False, repr=False)
class ShardAssignments(betterproto2.Message):
    """
    *
    The response to a shard assignments request.
    """

    namespaces: "dict[str, NamespaceShardsAssignment]" = betterproto2.field(
        1,
        betterproto2.TYPE_MAP,
        map_meta=betterproto2.map_meta(
            betterproto2.TYPE_STRING, betterproto2.TYPE_MESSAGE
        ),
    )


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "ShardAssignments", ShardAssignments
)


@dataclass(eq=False, repr=False)
class ShardAssignmentsRequest(betterproto2.Message):
    """
    *
    A shard assignments request. Gets all shard-to-server assignments as a
    stream. Each set of assignments in the response stream will contain all the
    assignments to bring the client up to date. For example, if a shard is split,
    the stream will return a single response containing all the new shard
    assignments as opposed to multiple stream responses, each containing a single
    shard assignment.
    """

    namespace: "str" = betterproto2.field(1, betterproto2.TYPE_STRING)


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "ShardAssignmentsRequest", ShardAssignmentsRequest
)


@dataclass(eq=False, repr=False)
class Version(betterproto2.Message):
    """
    *
    Version contains info about the state of a record.
    """

    version_id: "int" = betterproto2.field(1, betterproto2.TYPE_INT64)
    """
    The version identifier of the record
    """

    modifications_count: "int" = betterproto2.field(2, betterproto2.TYPE_INT64)
    """
    The number of modifications made to the record since
    it was created
    """

    created_timestamp: "int" = betterproto2.field(3, betterproto2.TYPE_FIXED64)
    """
    The creation timestamp of the first version of the record
    """

    modified_timestamp: "int" = betterproto2.field(4, betterproto2.TYPE_FIXED64)
    """
    The modified timestamp of the current version of the record
    """

    session_id: "int | None" = betterproto2.field(
        5, betterproto2.TYPE_INT64, optional=True
    )
    """
    Identifier of the session if the record is ephemeral
    """

    client_identity: "str | None" = betterproto2.field(
        6, betterproto2.TYPE_STRING, optional=True
    )


default_message_pool.register_message("io.streamnative.oxia.proto", "Version", Version)


@dataclass(eq=False, repr=False)
class WriteRequest(betterproto2.Message):
    """
    *
    A batch write request. Applies the batches of requests. Requests are
    processed in positional order within batches and the batch types are
    processed in the following order: puts, deletes, delete_ranges.
    """

    shard: "int | None" = betterproto2.field(1, betterproto2.TYPE_INT64, optional=True)
    """
    The shard id. This is optional allow for support for server-side hashing
    and proxying in the future.
    """

    puts: "list[PutRequest]" = betterproto2.field(
        2, betterproto2.TYPE_MESSAGE, repeated=True
    )
    """
    The put requests
    """

    deletes: "list[DeleteRequest]" = betterproto2.field(
        3, betterproto2.TYPE_MESSAGE, repeated=True
    )
    """
    The delete requests
    """

    delete_ranges: "list[DeleteRangeRequest]" = betterproto2.field(
        4, betterproto2.TYPE_MESSAGE, repeated=True
    )
    """
    The delete range requests
    """


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "WriteRequest", WriteRequest
)


@dataclass(eq=False, repr=False)
class WriteResponse(betterproto2.Message):
    """
    *
    The response to a batch write request. Responses of each type respect the
    order of the original requests.
    """

    puts: "list[PutResponse]" = betterproto2.field(
        1, betterproto2.TYPE_MESSAGE, repeated=True
    )
    """
    The put responses
    """

    deletes: "list[DeleteResponse]" = betterproto2.field(
        2, betterproto2.TYPE_MESSAGE, repeated=True
    )
    """
    The delete responses
    """

    delete_ranges: "list[DeleteRangeResponse]" = betterproto2.field(
        3, betterproto2.TYPE_MESSAGE, repeated=True
    )
    """
    The delete range responses
    """


default_message_pool.register_message(
    "io.streamnative.oxia.proto", "WriteResponse", WriteResponse
)


class OxiaClientStub:
    """
    *
    Oxia service that allows clients to discover shard-to-server assignments and
    submit batches of requests.

    Clients should connect to a random server to discover the shard-to-server
    assignments and then send the actual batched requests to the appropriate
    shard leader. In the future, this may be handled server-side in a proxy
    layer to allows clients to not be concerned with sharding.
    """

    def __init__(self, channel: grpc.Channel):
        self._channel = channel

    def get_shard_assignments(
        self, message: "ShardAssignmentsRequest"
    ) -> "Iterator[ShardAssignments]":
        """
        *
        Gets all shard-to-server assignments as a stream. Each set of assignments
        in the response stream will contain all the assignments to bring the client
        up to date. For example, if a shard is split, the stream will return a
        single response containing all the new shard assignments as opposed to
        multiple stream responses, each containing a single shard assignment.

        Clients should connect to a single random server which will stream the
        assignments for all shards on all servers.
        """

        yield from self._channel.unary_stream(
            "/io.streamnative.oxia.proto.OxiaClient/GetShardAssignments",
            ShardAssignmentsRequest.SerializeToString,
            ShardAssignments.FromString,
        )(message)

    def write(self, message: "WriteRequest") -> "WriteResponse":
        """
        *
        Batches put, delete and delete_range requests.

        Clients should send this request to the shard leader. In the future,
        this may be handled server-side in a proxy layer.

        Deprecated
        """

        return self._channel.unary_unary(
            "/io.streamnative.oxia.proto.OxiaClient/Write",
            WriteRequest.SerializeToString,
            WriteResponse.FromString,
        )(message)

    def write_stream(
        self, messages: "Iterable[WriteRequest]"
    ) -> "Iterator[WriteResponse]":
        """
        *
        Batches put, delete and delete_range requests.

        Clients should send this request to the shard leader. In the future,
        this may be handled server-side in a proxy layer.
        """

        yield from self._channel.stream_stream(
            "/io.streamnative.oxia.proto.OxiaClient/WriteStream",
            WriteRequest.SerializeToString,
            WriteResponse.FromString,
        )(iter(messages))

    def read(self, message: "ReadRequest") -> "Iterator[ReadResponse]":
        """
        *
        Batches get requests.

        Clients should send this request to the shard leader. In the future,
        this may be handled server-side in a proxy layer.
        """

        yield from self._channel.unary_stream(
            "/io.streamnative.oxia.proto.OxiaClient/Read",
            ReadRequest.SerializeToString,
            ReadResponse.FromString,
        )(message)

    def list(self, message: "ListRequest") -> "Iterator[ListResponse]":
        """
        *
        Requests all the keys between a range of keys.

        Clients should send an equivalent request to all respective shards,
        unless a particular partition key was specified.
        """

        yield from self._channel.unary_stream(
            "/io.streamnative.oxia.proto.OxiaClient/List",
            ListRequest.SerializeToString,
            ListResponse.FromString,
        )(message)

    def range_scan(self, message: "RangeScanRequest") -> "Iterator[RangeScanResponse]":
        """
        *
        Requests all the records between a range of keys.

        Clients should send an equivalent request to all respective shards,
        unless a particular partition key was specified.
        """

        yield from self._channel.unary_stream(
            "/io.streamnative.oxia.proto.OxiaClient/RangeScan",
            RangeScanRequest.SerializeToString,
            RangeScanResponse.FromString,
        )(message)

    def get_sequence_updates(
        self, message: "GetSequenceUpdatesRequest"
    ) -> "Iterator[GetSequenceUpdatesResponse]":
        """
        *
        Requests all the records between a range of keys.
        """

        return self._channel.unary_stream(
            "/io.streamnative.oxia.proto.OxiaClient/GetSequenceUpdates",
            GetSequenceUpdatesRequest.SerializeToString,
            GetSequenceUpdatesResponse.FromString,
        )(message)

    def get_notifications(
        self, message: "NotificationsRequest"
    ) -> "Iterator[NotificationBatch]":
        return self._channel.unary_stream(
            "/io.streamnative.oxia.proto.OxiaClient/GetNotifications",
            NotificationsRequest.SerializeToString,
            NotificationBatch.FromString,
        )(message)

    def create_session(
        self, message: "CreateSessionRequest"
    ) -> "CreateSessionResponse":
        """

        Creates a new client session. Sessions are kept alive by regularly sending
        heartbeats via the KeepAlive rpc.
        """

        return self._channel.unary_unary(
            "/io.streamnative.oxia.proto.OxiaClient/CreateSession",
            CreateSessionRequest.SerializeToString,
            CreateSessionResponse.FromString,
        )(message)

    def keep_alive(self, message: "SessionHeartbeat") -> "KeepAliveResponse":
        """

        Sends a heartbeat to prevent the session from timing out.
        """

        return self._channel.unary_unary(
            "/io.streamnative.oxia.proto.OxiaClient/KeepAlive",
            SessionHeartbeat.SerializeToString,
            KeepAliveResponse.FromString,
        )(message)

    def close_session(self, message: "CloseSessionRequest") -> "CloseSessionResponse":
        """

        Closes a session and removes all ephemeral values associated with it.
        """

        return self._channel.unary_unary(
            "/io.streamnative.oxia.proto.OxiaClient/CloseSession",
            CloseSessionRequest.SerializeToString,
            CloseSessionResponse.FromString,
        )(message)
