Source code for aerospike_sdk.aio.operations.index
# Copyright 2025-2026 Aerospike, Inc.
#
# Portions may be licensed to Aerospike, Inc. under one or more contributor
# license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
#
# 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.
"""Builder for creating and dropping secondary indexes."""
from __future__ import annotations
from typing import List, Optional
from aerospike_async import (
CTX,
Client,
CollectionIndexType,
IndexType,
)
from aerospike_sdk.exceptions import _convert_pac_exception
[docs]
class IndexBuilder:
"""Configure a secondary index, then :meth:`create` or :meth:`drop` it.
Typical chain for a new index: :meth:`on_bin` → :meth:`named` →
:meth:`numeric` or :meth:`string` → optional :meth:`collection` or
:meth:`context` → ``await`` :meth:`create`.
For removal, only :meth:`named` (and namespace/set from construction) is
required before ``await`` :meth:`drop`.
Example::
await (
client.index(namespace="test", set_name="users")
.on_bin("email")
.named("email_idx")
.string()
.create()
)
See Also:
:meth:`~aerospike_sdk.aio.client.Client.index`
"""
[docs]
def __init__(
self,
client: Client,
namespace: str,
set_name: str,
) -> None:
"""
Args:
client: Connected async cluster client used for admin calls.
namespace: Namespace containing the set to index.
set_name: Set name within the namespace.
"""
self._client = client
self._namespace = namespace
self._set_name = set_name
self._bin_name: Optional[str] = None
self._index_name: Optional[str] = None
self._index_type: Optional[IndexType] = None
self._collection_index_type: Optional[CollectionIndexType] = None
self._ctx: Optional[List[CTX]] = None
[docs]
def on_bin(self, bin_name: str) -> IndexBuilder:
"""Set which bin this secondary index covers (required before :meth:`create`).
Args:
bin_name: Name of the bin to index.
Returns:
``self`` for method chaining.
"""
self._bin_name = bin_name
return self
[docs]
def named(self, index_name: str) -> IndexBuilder:
"""Set the secondary index name the cluster stores (required for create and drop).
Args:
index_name: Name passed to create/drop admin calls; must match when dropping.
Returns:
``self`` for method chaining.
"""
self._index_name = index_name
return self
[docs]
def numeric(self) -> IndexBuilder:
"""Set the secondary index type to numeric (for numeric bin values).
Call this or :meth:`string` before :meth:`create`, matching how the bin is
stored. If both are called on the same builder, the last call wins.
Returns:
``self`` for method chaining.
"""
self._index_type = IndexType.NUMERIC
return self
[docs]
def string(self) -> IndexBuilder:
"""Set the secondary index type to string (for string bin values).
Call this or :meth:`numeric` before :meth:`create`. If both are called,
the last call wins (see :meth:`numeric`).
Returns:
``self`` for method chaining.
"""
self._index_type = IndexType.STRING
return self
[docs]
def collection(
self, collection_index_type: CollectionIndexType
) -> IndexBuilder:
"""Set the collection index variant for map or list bins (optional).
Use together with :meth:`numeric` or :meth:`string` when indexing into
collection data types.
Args:
collection_index_type: ``CollectionIndexType`` constant from the
``aerospike_async`` package (map- vs list-style collection indexing).
Returns:
``self`` for method chaining.
"""
self._collection_index_type = collection_index_type
return self
[docs]
def context(self, ctx: List[CTX]) -> IndexBuilder:
"""Set a CDT context path for indexing a nested list or map element.
Args:
ctx: One or more ``CTX`` entries describing the path to the
nested element (e.g., ``[CTX.map_key("outer"), CTX.list_index(0)]``).
Returns:
``self`` for method chaining.
Example::
await (
client.index("test", "events")
.on_bin("payload")
.named("nested_ts_idx")
.numeric()
.context([CTX.map_key("meta"), CTX.map_key("timestamp")])
.create()
)
See Also:
:meth:`~aerospike_async.Filter.context`: Attach the same path when querying.
"""
self._ctx = ctx
return self
[docs]
async def create(self) -> None:
"""Create the index on the cluster.
Example::
await (
client.index(namespace="test", set_name="users")
.on_bin("email")
.named("email_idx")
.string()
.create()
)
Raises:
ValueError: If ``on_bin``, ``named``, or index type was not set.
AerospikeError: On server or transport failure (typed subclass when
the driver maps a result code).
See Also:
:meth:`drop`
"""
if not self._bin_name:
raise ValueError("bin_name is required. Call on_bin() first.")
if not self._index_name:
raise ValueError("index_name is required. Call named() first.")
if not self._index_type:
raise ValueError("index_type is required. Call numeric() or string() first.")
try:
await self._client.create_index(
self._namespace,
self._set_name,
self._bin_name,
self._index_name,
self._index_type,
self._collection_index_type,
self._ctx,
)
except Exception as e:
raise _convert_pac_exception(e) from e
[docs]
async def drop(self) -> None:
"""Drop a previously created index by name.
Example::
await (
client.index(namespace="test", set_name="users")
.named("email_idx")
.drop()
)
Raises:
ValueError: If :meth:`named` was not called.
AerospikeError: On server or transport failure.
Note:
Namespace and set come from the builder constructor, not from
:meth:`on_bin`.
"""
if not self._index_name:
raise ValueError("index_name is required. Call named() first.")
try:
await self._client.drop_index(
self._namespace, self._set_name, self._index_name
)
except Exception as e:
raise _convert_pac_exception(e) from e