From b8cd58ae8ac9c919f13cc83ce85b2f600f7b5704 Mon Sep 17 00:00:00 2001 From: juliannguyen4 <109386615+juliannguyen4@users.noreply.github.com> Date: Thu, 7 Sep 2023 12:49:46 -0700 Subject: [PATCH 01/42] Deprecate single value index creation methods --- doc/client.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/client.rst b/doc/client.rst index 0060c26048..e076cd4386 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -895,6 +895,8 @@ Index Operations :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. + .. deprecated:: 14.0.0 :meth:`index_single_value_create` should be used instead. + .. method:: index_integer_create(ns, set, bin, name[, policy]) Create an integer index with *name* on the *bin* in the specified \ @@ -907,6 +909,8 @@ Index Operations :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. + .. deprecated:: 14.0.0 :meth:`index_single_value_create` should be used instead. + .. method:: index_list_create(ns, set, bin, index_datatype, name[, policy: dict]) Create an index named *name* for numeric, string or GeoJSON values \ @@ -993,6 +997,7 @@ Index Operations client.index_geo2dsphere_create('test', 'pads', 'loc', 'pads_loc_geo') client.close() + .. deprecated:: 14.0.0 :meth:`index_single_value_create` should be used instead. .. method:: index_remove(ns: str, name: str[, policy: dict]) From b696c6108e6f0a1202fdde00b8564351a411e04f Mon Sep 17 00:00:00 2001 From: juliannguyen4 <109386615+juliannguyen4@users.noreply.github.com> Date: Thu, 7 Sep 2023 12:53:20 -0700 Subject: [PATCH 02/42] move deprecated index creation methods to the bottom of section --- doc/client.rst | 97 +++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/doc/client.rst b/doc/client.rst index e076cd4386..3164751ab8 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -883,34 +883,6 @@ Index Operations .. class:: Client :noindex: - .. method:: index_string_create(ns, set, bin, name[, policy: dict]) - - Create a string index with *index_name* on the *bin* in the specified \ - *ns*, *set*. - - :param str ns: the namespace in the aerospike cluster. - :param str set: the set name. - :param str bin: the name of bin the secondary index is built on. - :param str name: the name of the index. - :param dict policy: optional :ref:`aerospike_info_policies`. - :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - - .. deprecated:: 14.0.0 :meth:`index_single_value_create` should be used instead. - - .. method:: index_integer_create(ns, set, bin, name[, policy]) - - Create an integer index with *name* on the *bin* in the specified \ - *ns*, *set*. - - :param str ns: the namespace in the aerospike cluster. - :param str set: the set name. - :param str bin: the name of bin the secondary index is built on. - :param str name: the name of the index. - :param dict policy: optional :ref:`aerospike_info_policies`. - :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - - .. deprecated:: 14.0.0 :meth:`index_single_value_create` should be used instead. - .. method:: index_list_create(ns, set, bin, index_datatype, name[, policy: dict]) Create an index named *name* for numeric, string or GeoJSON values \ @@ -973,55 +945,82 @@ Index Operations client.index_map_values_create('test', 'demo', 'fav_movies', aerospike.INDEX_NUMERIC, 'demo_fav_movies_views_idx') client.close() - .. method:: index_geo2dsphere_create(ns, set, bin, name[, policy: dict]) + .. method:: index_remove(ns: str, name: str[, policy: dict]) - Create a geospatial 2D spherical index with *name* on the *bin* \ - in the specified *ns*, *set*. + Remove the index with *name* from the namespace. :param str ns: the namespace in the aerospike cluster. - :param str set: the set name. - :param str bin: the name of bin the secondary index is built on. :param str name: the name of the index. :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. seealso:: :class:`aerospike.GeoJSON`, :mod:`aerospike.predicates` + .. method:: get_cdtctx_base64(ctx: list) -> str - .. note:: Requires server version >= 3.7.0 + Get the base64 representation of aerospike CDT ctx. - .. code-block:: python + See :ref:`aerospike_operation_helpers.cdt_ctx` for more details on CDT context. - import aerospike + :param list ctx: Aerospike CDT context: generated by aerospike CDT ctx helper :mod:`aerospike_helpers`. + :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - client = aerospike.client({ 'hosts': [ ('127.0.0.1', 3000)]}) - client.index_geo2dsphere_create('test', 'pads', 'loc', 'pads_loc_geo') - client.close() + .. include:: examples/get_cdtctx_base64.py + :code: python + + .. versionchanged:: 7.1.1 + + .. method:: index_string_create(ns, set, bin, name[, policy: dict]) + + Create a string index with *index_name* on the *bin* in the specified \ + *ns*, *set*. + + :param str ns: the namespace in the aerospike cluster. + :param str set: the set name. + :param str bin: the name of bin the secondary index is built on. + :param str name: the name of the index. + :param dict policy: optional :ref:`aerospike_info_policies`. + :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. .. deprecated:: 14.0.0 :meth:`index_single_value_create` should be used instead. - .. method:: index_remove(ns: str, name: str[, policy: dict]) + .. method:: index_integer_create(ns, set, bin, name[, policy]) - Remove the index with *name* from the namespace. + Create an integer index with *name* on the *bin* in the specified \ + *ns*, *set*. :param str ns: the namespace in the aerospike cluster. + :param str set: the set name. + :param str bin: the name of bin the secondary index is built on. :param str name: the name of the index. :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. method:: get_cdtctx_base64(ctx: list) -> str + .. deprecated:: 14.0.0 :meth:`index_single_value_create` should be used instead. - Get the base64 representation of aerospike CDT ctx. + .. method:: index_geo2dsphere_create(ns, set, bin, name[, policy: dict]) - See :ref:`aerospike_operation_helpers.cdt_ctx` for more details on CDT context. + Create a geospatial 2D spherical index with *name* on the *bin* \ + in the specified *ns*, *set*. - :param list ctx: Aerospike CDT context: generated by aerospike CDT ctx helper :mod:`aerospike_helpers`. + :param str ns: the namespace in the aerospike cluster. + :param str set: the set name. + :param str bin: the name of bin the secondary index is built on. + :param str name: the name of the index. + :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. include:: examples/get_cdtctx_base64.py - :code: python + .. seealso:: :class:`aerospike.GeoJSON`, :mod:`aerospike.predicates` - .. versionchanged:: 7.1.1 + .. note:: Requires server version >= 3.7.0 + + .. code-block:: python + + import aerospike + + client = aerospike.client({ 'hosts': [ ('127.0.0.1', 3000)]}) + client.index_geo2dsphere_create('test', 'pads', 'loc', 'pads_loc_geo') + client.close() + .. deprecated:: 14.0.0 :meth:`index_single_value_create` should be used instead. .. index:: single: Admin Operations From 886b61e6ec7dbda8f46cc76096b7b3e0e5392383 Mon Sep 17 00:00:00 2001 From: juliannguyen4 <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 11 Sep 2023 11:18:10 -0700 Subject: [PATCH 03/42] WIP new API --- doc/client.rst | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/client.rst b/doc/client.rst index 3164751ab8..bbdf3ed775 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -883,7 +883,19 @@ Index Operations .. class:: Client :noindex: - .. method:: index_list_create(ns, set, bin, index_datatype, name[, policy: dict]) + .. method:: index_single_value_create(ns: str, set: str, bin: str, value_type: int, ctx: list = None, policy: dict = NOne) + + Create a secondary index on a single value with a given type. + + :param str index_name: the name of the index. + :param str ns: the namespace containing the value. + :param str set: the set containing the value. + :param str bin: the name of the bin containing the value. + :param str value_type: the type of the value being indexed. Possible values are ``aerospike.INDEX_STRING``, ``aerospike.INDEX_NUMERIC`` and ``aerospike.INDEX_GEO2DSPHERE``. + :param list ctx: a list of contexts to specify the location of a nested value in a collection data type. Defaults to :py:obj:`None`. + :param dict policy: a dictionary defined by :ref:`aerospike_info_policies`. Defaults to :py:obj:`None`. + + .. method:: index_list_create(ns, set, bin, index_datatype, name, policy: dict = None, ctx: list = None) Create an index named *name* for numeric, string or GeoJSON values \ (as defined by *index_datatype*) on records of the specified *ns*, *set* \ From 8a28fccbef75fffeb1cf470f44cd51d826eef3f7 Mon Sep 17 00:00:00 2001 From: juliannguyen4 <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:44:03 -0700 Subject: [PATCH 04/42] Add missing index_cdt_create method and deprecate it --- doc/client.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/doc/client.rst b/doc/client.rst index bbdf3ed775..a047e46da9 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -1034,6 +1034,24 @@ Index Operations .. deprecated:: 14.0.0 :meth:`index_single_value_create` should be used instead. +.. method:: index_cdt_create(ns: str, set: str, bin: str, index_type, index_datatype, index_name: str, ctx: dict[, policy: dict]) + + Create an collection data type (CDT) index named *index_name* for a scalar, list values, map keys, or map values (as defined by *index_type*) and for + numeric, string, or GeoJSON values (as defined by *index_datatype*) + on records of the specified *ns*, *set* whose bin is a list or map. + + :param str ns: the namespace in the aerospike cluster. + :param str set: the set name. + :param str bin: the name of bin the secondary index is built on. + :param index_type: whether we are querying a single scalar value or specific values of a CDT type. See :ref:`aerospike_index_types`. + :param index_datatype: the type of value being queried on. See :ref:`aerospike_index_data_types`. + :param str index_name: the name of the index. + :param dict ctx: a dictionary containing the ``"ctx"`` key mapping to a list of contexts. + :param dict policy: optional :ref:`aerospike_info_policies`. + :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. + + .. deprecated:: 14.0.0 Use the other non-deprecated index methods to create an index with a list of contexts. + .. index:: single: Admin Operations From 67b81e2e6024166fe95d0001369ba47483ec2336 Mon Sep 17 00:00:00 2001 From: juliannguyen4 <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:52:30 -0700 Subject: [PATCH 05/42] Organize index value type constants and link to them --- doc/aerospike.rst | 43 ++++++++++++++++++++++++++----------------- doc/client.rst | 10 +++++----- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/doc/aerospike.rst b/doc/aerospike.rst index 4cf6a242ba..67efc43ad2 100644 --- a/doc/aerospike.rst +++ b/doc/aerospike.rst @@ -1414,21 +1414,31 @@ Bin Types (int): 24 +.. _aerospike_index_types: -.. _aerospike_misc_constants: +Index Types +----------- -Miscellaneous -------------- +.. data:: INDEX_TYPE_DEFAULT -.. data:: __version__ + Index a single scalar value. - A :class:`str` containing the module's version. +.. data:: INDEX_TYPE_LIST - .. versionadded:: 1.0.54 + Index all of a list's values. -.. data:: UDF_TYPE_LUA +.. data:: INDEX_TYPE_MAPKEYS - UDF type is LUA (which is the only UDF type). + Index all of a map's keys. + +.. data:: INDEX_TYPE_MAPVALUES + + Index all of a map's values. + +.. _aerospike_index_data_types: + +Data Types +---------- .. data:: INDEX_STRING @@ -1444,21 +1454,20 @@ Miscellaneous .. seealso:: `Data Types `_. -.. data:: INDEX_TYPE_DEFAULT - - Index a bin that doesn't contain a complex data type. +.. _aerospike_misc_constants: -.. data:: INDEX_TYPE_LIST +Miscellaneous +------------- - Index a bin whose contents is an aerospike list. +.. data:: __version__ -.. data:: INDEX_TYPE_MAPKEYS + A :class:`str` containing the module's version. - Index the keys of a bin whose contents is an aerospike map. + .. versionadded:: 1.0.54 -.. data:: INDEX_TYPE_MAPVALUES +.. data:: UDF_TYPE_LUA - Index the values of a bin whose contents is an aerospike map. + UDF type is LUA (which is the only UDF type). .. _aerospike_log_levels: diff --git a/doc/client.rst b/doc/client.rst index a047e46da9..c61e225144 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -883,7 +883,7 @@ Index Operations .. class:: Client :noindex: - .. method:: index_single_value_create(ns: str, set: str, bin: str, value_type: int, ctx: list = None, policy: dict = NOne) + .. method:: index_single_value_create(ns: str, set: str, bin: str, value_type: int, ctx: list = None, policy: dict = None) Create a secondary index on a single value with a given type. @@ -891,7 +891,7 @@ Index Operations :param str ns: the namespace containing the value. :param str set: the set containing the value. :param str bin: the name of the bin containing the value. - :param str value_type: the type of the value being indexed. Possible values are ``aerospike.INDEX_STRING``, ``aerospike.INDEX_NUMERIC`` and ``aerospike.INDEX_GEO2DSPHERE``. + :param str value_type: the type of the value being indexed. See :ref:`aerospike_index_data_types`. :param list ctx: a list of contexts to specify the location of a nested value in a collection data type. Defaults to :py:obj:`None`. :param dict policy: a dictionary defined by :ref:`aerospike_info_policies`. Defaults to :py:obj:`None`. @@ -904,7 +904,7 @@ Index Operations :param str ns: the namespace in the aerospike cluster. :param str set: the set name. :param str bin: the name of bin the secondary index is built on. - :param index_datatype: Possible values are ``aerospike.INDEX_STRING``, ``aerospike.INDEX_NUMERIC`` and ``aerospike.INDEX_GEO2DSPHERE``. + :param index_datatype: the type of the values being indexed. See :ref:`aerospike_index_data_types`. :param str name: the name of the index. :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. @@ -920,7 +920,7 @@ Index Operations :param str ns: the namespace in the aerospike cluster. :param str set: the set name. :param str bin: the name of bin the secondary index is built on. - :param index_datatype: Possible values are ``aerospike.INDEX_STRING``, ``aerospike.INDEX_NUMERIC`` and ``aerospike.INDEX_GEO2DSPHERE``. + :param index_datatype: the type of the values being indexed. See :ref:`aerospike_index_data_types`. :param str name: the name of the index. :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. @@ -936,7 +936,7 @@ Index Operations :param str ns: the namespace in the aerospike cluster. :param str set: the set name. :param str bin: the name of bin the secondary index is built on. - :param index_datatype: Possible values are ``aerospike.INDEX_STRING``, ``aerospike.INDEX_NUMERIC`` and ``aerospike.INDEX_GEO2DSPHERE``. + :param index_datatype: the type of the values being indexed. See :ref:`aerospike_index_data_types`. :param str name: the name of the index. :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. From b0ac126964deb987ee8e2e0995a5d9f303602221 Mon Sep 17 00:00:00 2001 From: juliannguyen4 <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 13 Sep 2023 13:56:46 -0700 Subject: [PATCH 06/42] Update the rest of the API --- doc/client.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/doc/client.rst b/doc/client.rst index c61e225144..d5282045fa 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -883,7 +883,7 @@ Index Operations .. class:: Client :noindex: - .. method:: index_single_value_create(ns: str, set: str, bin: str, value_type: int, ctx: list = None, policy: dict = None) + .. method:: index_single_value_create(ns: str, set: str, bin: str, value_type: int, policy: dict = None, ctx: list = None) Create a secondary index on a single value with a given type. @@ -892,8 +892,9 @@ Index Operations :param str set: the set containing the value. :param str bin: the name of the bin containing the value. :param str value_type: the type of the value being indexed. See :ref:`aerospike_index_data_types`. - :param list ctx: a list of contexts to specify the location of a nested value in a collection data type. Defaults to :py:obj:`None`. :param dict policy: a dictionary defined by :ref:`aerospike_info_policies`. Defaults to :py:obj:`None`. + :param list ctx: a list of contexts to specify the location of a nested value in a collection data type. Defaults to :py:obj:`None`. + :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. .. method:: index_list_create(ns, set, bin, index_datatype, name, policy: dict = None, ctx: list = None) @@ -907,11 +908,12 @@ Index Operations :param index_datatype: the type of the values being indexed. See :ref:`aerospike_index_data_types`. :param str name: the name of the index. :param dict policy: optional :ref:`aerospike_info_policies`. + :param list ctx: a list of contexts to specify the location of a nested value in a collection data type. Defaults to :py:obj:`None`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. .. note:: Requires server version >= 3.8.0 - .. method:: index_map_keys_create(ns, set, bin, index_datatype, name[, policy: dict]) + .. method:: index_map_keys_create(ns, set, bin, index_datatype, name, policy: dict = None, ctx: list = None) Create an index named *name* for numeric, string or GeoJSON values \ (as defined by *index_datatype*) on records of the specified *ns*, *set* \ @@ -923,11 +925,12 @@ Index Operations :param index_datatype: the type of the values being indexed. See :ref:`aerospike_index_data_types`. :param str name: the name of the index. :param dict policy: optional :ref:`aerospike_info_policies`. + :param list ctx: a list of contexts to specify the location of a nested value in a collection data type. Defaults to :py:obj:`None`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. .. note:: Requires server version >= 3.8.0 - .. method:: index_map_values_create(ns, set, bin, index_datatype, name[, policy: dict]) + .. method:: index_map_values_create(ns, set, bin, index_datatype, name, policy: dict = None, ctx: list = None) Create an index named *name* for numeric, string or GeoJSON values \ (as defined by *index_datatype*) on records of the specified *ns*, *set* \ @@ -939,6 +942,7 @@ Index Operations :param index_datatype: the type of the values being indexed. See :ref:`aerospike_index_data_types`. :param str name: the name of the index. :param dict policy: optional :ref:`aerospike_info_policies`. + :param list ctx: a list of contexts to specify the location of a nested value in a collection data type. Defaults to :py:obj:`None`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. .. note:: Requires server version >= 3.8.0 From 8f3ec0d3dc974b2ac23d1b52a93f95c087ef200d Mon Sep 17 00:00:00 2001 From: juliannguyen4 <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 13 Sep 2023 14:11:20 -0700 Subject: [PATCH 07/42] Improve docstring for list create --- doc/client.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/client.rst b/doc/client.rst index d5282045fa..7a10486e23 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -898,9 +898,7 @@ Index Operations .. method:: index_list_create(ns, set, bin, index_datatype, name, policy: dict = None, ctx: list = None) - Create an index named *name* for numeric, string or GeoJSON values \ - (as defined by *index_datatype*) on records of the specified *ns*, *set* \ - whose *bin* is a list. + Create a secondary index for all of a list's values, where all the values are the same type. :param str ns: the namespace in the aerospike cluster. :param str set: the set name. From 7ff0d0f99887c9b3bf051934ef66d0c8013c0fde Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 26 Jan 2026 16:19:22 -0800 Subject: [PATCH 08/42] fix --- doc/client.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/client.rst b/doc/client.rst index 6197e0e4cd..477fa3dc88 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -846,7 +846,7 @@ Index Operations :param str ns: the namespace containing the value. :param str set: the set containing the value. :param str bin: the name of the bin containing the value. - :param str value_type: the type of the value being indexed. See :ref:`aerospike_index_data_types`. + :param str value_type: the type of the value being indexed. See :ref:`aerospike_index_datatypes`. :param dict policy: a dictionary defined by :ref:`aerospike_info_policies`. Defaults to :py:obj:`None`. :param list ctx: a list of contexts to specify the location of a nested value in a collection data type. Defaults to :py:obj:`None`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. @@ -858,7 +858,7 @@ Index Operations :param str ns: the namespace in the aerospike cluster. :param str set: the set name. :param str bin: the name of bin the secondary index is built on. - :param index_datatype: the type of the values being indexed. See :ref:`aerospike_index_data_types`. + :param index_datatype: the type of the values being indexed. See :ref:`aerospike_index_datatypes`. :param str name: the name of the index. :param dict policy: optional :ref:`aerospike_info_policies`. :param list ctx: a list of contexts to specify the location of a nested value in a collection data type. Defaults to :py:obj:`None`. @@ -1012,7 +1012,7 @@ Index Operations :param str set: the set name. :param str bin: the name of bin the secondary index is built on. :param index_type: whether we are querying a single scalar value or specific values of a CDT type. See :ref:`aerospike_index_types`. - :param index_datatype: the type of value being queried on. See :ref:`aerospike_index_data_types`. + :param index_datatype: the type of value being queried on. See :ref:`aerospike_index_datatypes`. :param str index_name: the name of the index. :param dict ctx: a dictionary containing the ``"ctx"`` key mapping to a list of contexts. :param dict policy: optional :ref:`aerospike_info_policies`. From 9ce7dcc818b54521a14176f593b8d558b37ec4a9 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 26 Jan 2026 16:21:36 -0800 Subject: [PATCH 09/42] fix bad merge --- doc/aerospike.rst | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/doc/aerospike.rst b/doc/aerospike.rst index ce0cb309c3..9f88a9f471 100644 --- a/doc/aerospike.rst +++ b/doc/aerospike.rst @@ -1631,21 +1631,6 @@ Index data types Miscellaneous ------------- -.. data:: __version__ - - A :class:`str` containing the module's version. - - .. versionadded:: 1.0.54 - -.. data:: UDF_TYPE_LUA - - UDF type is LUA (which is the only UDF type). - -.. _aerospike_misc_constants: - -Miscellaneous -------------- - .. data:: UDF_TYPE_LUA UDF type is LUA (which is the only UDF type). From d33892a6642be34a35346ade42444a2f9e0150c1 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 26 Jan 2026 16:30:22 -0800 Subject: [PATCH 10/42] move index type section back to original location --- doc/aerospike.rst | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/doc/aerospike.rst b/doc/aerospike.rst index 9f88a9f471..74c7fd039b 100644 --- a/doc/aerospike.rst +++ b/doc/aerospike.rst @@ -1583,26 +1583,6 @@ Bin Types (int): 24 -.. _aerospike_index_types: - -Index Types ------------ - -.. data:: INDEX_TYPE_DEFAULT - - Index a single scalar value. - -.. data:: INDEX_TYPE_LIST - - Index all of a list's values. - -.. data:: INDEX_TYPE_MAPKEYS - - Index all of a map's keys. - -.. data:: INDEX_TYPE_MAPVALUES - - Index all of a map's values. .. _aerospike_index_datatypes: @@ -1626,6 +1606,27 @@ Index data types .. seealso:: `Data Types `_. +.. _aerospike_index_types: + +Index Types +----------- + +.. data:: INDEX_TYPE_DEFAULT + + Index a single scalar value. + +.. data:: INDEX_TYPE_LIST + + Index all of a list's values. + +.. data:: INDEX_TYPE_MAPKEYS + + Index all of a map's keys. + +.. data:: INDEX_TYPE_MAPVALUES + + Index all of a map's values. + .. _aerospike_misc_constants: Miscellaneous From 761ac7890dc1815a538b5886c4b2f220d5e2bc74 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Tue, 27 Jan 2026 08:47:52 -0800 Subject: [PATCH 11/42] Move all index cdt create methods in one place --- doc/client.rst | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/client.rst b/doc/client.rst index 477fa3dc88..934d846f51 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -864,19 +864,6 @@ Index Operations :param list ctx: a list of contexts to specify the location of a nested value in a collection data type. Defaults to :py:obj:`None`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. method:: index_expr_create(ns, set, index_type, index_datatype, expressions, name[, policy: dict]) - - Create secondary index on an expression. - - :param str ns: The namespace to be indexed. - :param str set: The set to be indexed. - :param index_type: See :ref:`aerospike_index_types` for possible values. - :param index_datatype: See :ref:`aerospike_index_datatypes` for possible values. - :param list expressions: The compiled expression to be indexed. Produced from :ref:`aerospike_operation_helpers.expressions`. - :param str name: the name of the index. - :param dict policy: optional :ref:`aerospike_info_policies`. - :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. method:: index_map_keys_create(ns, set, bin, index_datatype, name, policy: dict = None, ctx: list = None) Create an index named *name* for numeric, string or GeoJSON values \ @@ -925,6 +912,19 @@ Index Operations client.index_map_values_create('test', 'demo', 'fav_movies', aerospike.INDEX_NUMERIC, 'demo_fav_movies_views_idx') client.close() + .. method:: index_expr_create(ns, set, index_type, index_datatype, expressions, name[, policy: dict]) + + Create secondary index on an expression. + + :param str ns: The namespace to be indexed. + :param str set: The set to be indexed. + :param index_type: See :ref:`aerospike_index_types` for possible values. + :param index_datatype: See :ref:`aerospike_index_datatypes` for possible values. + :param list expressions: The compiled expression to be indexed. Produced from :ref:`aerospike_operation_helpers.expressions`. + :param str name: the name of the index. + :param dict policy: optional :ref:`aerospike_info_policies`. + :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. + .. method:: index_remove(ns: str, name: str[, policy: dict]) Remove the index with *name* from the namespace. From 9e2ad3bf041fa94e93ea1932fddd3aceb4982c2d Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Tue, 27 Jan 2026 08:51:14 -0800 Subject: [PATCH 12/42] Add back index_blob_create. Update deprecated version notices --- doc/client.rst | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/doc/client.rst b/doc/client.rst index 934d846f51..9685735b1c 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -960,7 +960,7 @@ Index Operations :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. deprecated:: 14.0.0 :meth:`index_single_value_create` should be used instead. + .. deprecated:: 19.0.0 :meth:`index_single_value_create` should be used instead. .. method:: index_integer_create(ns, set, bin, name[, policy]) @@ -974,7 +974,21 @@ Index Operations :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. deprecated:: 14.0.0 :meth:`index_single_value_create` should be used instead. + .. deprecated:: 19.0.0 :meth:`index_single_value_create` should be used instead. + + .. method:: index_blob_create(ns, set, bin, name[, policy]) + + Create a blob index with *name* on the *bin* in the specified \ + *ns*, *set*. + + :param str ns: the namespace in the aerospike cluster. + :param str set: the set name. + :param str bin: the name of bin the secondary index is built on. + :param str name: the name of the index. + :param dict policy: optional :ref:`aerospike_info_policies`. + :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. + + .. deprecated:: 19.0.0 :meth:`index_single_value_create` should be used instead. .. method:: index_geo2dsphere_create(ns, set, bin, name[, policy: dict]) @@ -1000,7 +1014,7 @@ Index Operations client.index_geo2dsphere_create('test', 'pads', 'loc', 'pads_loc_geo') client.close() - .. deprecated:: 14.0.0 :meth:`index_single_value_create` should be used instead. + .. deprecated:: 19.0.0 :meth:`index_single_value_create` should be used instead. .. method:: index_cdt_create(ns: str, set: str, bin: str, index_type, index_datatype, index_name: str, ctx: dict[, policy: dict]) @@ -1018,7 +1032,7 @@ Index Operations :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. deprecated:: 14.0.0 Use the other non-deprecated index methods to create an index with a list of contexts. + .. deprecated:: 19.0.0 Use the other non-deprecated index methods to create an index with a list of contexts. .. index:: single: Admin Operations From f54af6130b14fd04044562bb34fd4da8f8c92f71 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Tue, 27 Jan 2026 08:53:01 -0800 Subject: [PATCH 13/42] Move deprecated notices to top of each method --- doc/client.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/client.rst b/doc/client.rst index 9685735b1c..4e7c92f27b 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -950,6 +950,8 @@ Index Operations .. method:: index_string_create(ns, set, bin, name[, policy: dict]) + .. deprecated:: 19.0.0 :meth:`index_single_value_create` should be used instead. + Create a string index with *index_name* on the *bin* in the specified \ *ns*, *set*. @@ -960,10 +962,10 @@ Index Operations :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. deprecated:: 19.0.0 :meth:`index_single_value_create` should be used instead. - .. method:: index_integer_create(ns, set, bin, name[, policy]) + .. deprecated:: 19.0.0 :meth:`index_single_value_create` should be used instead. + Create an integer index with *name* on the *bin* in the specified \ *ns*, *set*. @@ -974,10 +976,10 @@ Index Operations :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. deprecated:: 19.0.0 :meth:`index_single_value_create` should be used instead. - .. method:: index_blob_create(ns, set, bin, name[, policy]) + .. deprecated:: 19.0.0 :meth:`index_single_value_create` should be used instead. + Create a blob index with *name* on the *bin* in the specified \ *ns*, *set*. @@ -988,10 +990,10 @@ Index Operations :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. deprecated:: 19.0.0 :meth:`index_single_value_create` should be used instead. - .. method:: index_geo2dsphere_create(ns, set, bin, name[, policy: dict]) + .. deprecated:: 19.0.0 :meth:`index_single_value_create` should be used instead. + Create a geospatial 2D spherical index with *name* on the *bin* \ in the specified *ns*, *set*. @@ -1014,10 +1016,10 @@ Index Operations client.index_geo2dsphere_create('test', 'pads', 'loc', 'pads_loc_geo') client.close() - .. deprecated:: 19.0.0 :meth:`index_single_value_create` should be used instead. - .. method:: index_cdt_create(ns: str, set: str, bin: str, index_type, index_datatype, index_name: str, ctx: dict[, policy: dict]) + .. deprecated:: 19.0.0 Use the other non-deprecated index methods to create an index with a list of contexts. + Create an collection data type (CDT) index named *index_name* for a scalar, list values, map keys, or map values (as defined by *index_type*) and for numeric, string, or GeoJSON values (as defined by *index_datatype*) on records of the specified *ns*, *set* whose bin is a list or map. @@ -1032,8 +1034,6 @@ Index Operations :param dict policy: optional :ref:`aerospike_info_policies`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. - .. deprecated:: 19.0.0 Use the other non-deprecated index methods to create an index with a list of contexts. - .. index:: single: Admin Operations From eaa954c9c2166d1423f56bd636d67014a627fa42 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Tue, 27 Jan 2026 15:07:49 -0800 Subject: [PATCH 14/42] make consistent --- doc/client.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/client.rst b/doc/client.rst index 4e7c92f27b..c2ebb0ecc9 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -838,15 +838,15 @@ Index Operations .. class:: Client :noindex: - .. method:: index_single_value_create(ns: str, set: str, bin: str, value_type: int, policy: dict = None, ctx: list = None) + .. method:: index_single_value_create(ns: str, set: str, bin: str, value_type: int, name: str, policy: dict = None, ctx: list = None) Create a secondary index on a single value with a given type. - :param str index_name: the name of the index. :param str ns: the namespace containing the value. :param str set: the set containing the value. :param str bin: the name of the bin containing the value. :param str value_type: the type of the value being indexed. See :ref:`aerospike_index_datatypes`. + :param str name: the name of the index. :param dict policy: a dictionary defined by :ref:`aerospike_info_policies`. Defaults to :py:obj:`None`. :param list ctx: a list of contexts to specify the location of a nested value in a collection data type. Defaults to :py:obj:`None`. :raises: a subclass of :exc:`~aerospike.exception.AerospikeError`. From 5d8a7d285605b960abe98dd9f529e746376a335a Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Tue, 27 Jan 2026 15:42:58 -0800 Subject: [PATCH 15/42] make signature consistent --- doc/client.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/client.rst b/doc/client.rst index c2ebb0ecc9..a9497921fb 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -838,14 +838,14 @@ Index Operations .. class:: Client :noindex: - .. method:: index_single_value_create(ns: str, set: str, bin: str, value_type: int, name: str, policy: dict = None, ctx: list = None) + .. method:: index_single_value_create(ns, set, bin, index_datatype, name, policy: dict = None, ctx: list = None) Create a secondary index on a single value with a given type. :param str ns: the namespace containing the value. :param str set: the set containing the value. :param str bin: the name of the bin containing the value. - :param str value_type: the type of the value being indexed. See :ref:`aerospike_index_datatypes`. + :param str index_datatype: the type of the value being indexed. See :ref:`aerospike_index_datatypes`. :param str name: the name of the index. :param dict policy: a dictionary defined by :ref:`aerospike_info_policies`. Defaults to :py:obj:`None`. :param list ctx: a list of contexts to specify the location of a nested value in a collection data type. Defaults to :py:obj:`None`. From 9fc8f3a666c21ee2bb3eedb12b46bad481ed21e0 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 28 Jan 2026 09:36:05 -0800 Subject: [PATCH 16/42] Update outdated docstrings for index_map_keys_create and index_map_values_create --- doc/client.rst | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/doc/client.rst b/doc/client.rst index a9497921fb..7b264d80e8 100755 --- a/doc/client.rst +++ b/doc/client.rst @@ -866,9 +866,7 @@ Index Operations .. method:: index_map_keys_create(ns, set, bin, index_datatype, name, policy: dict = None, ctx: list = None) - Create an index named *name* for numeric, string or GeoJSON values \ - (as defined by *index_datatype*) on records of the specified *ns*, *set* \ - whose *bin* is a map. The index will include the keys of the map. + Create a secondary index on all of a map's keys, where all of the keys are the same type. :param str ns: the namespace in the aerospike cluster. :param str set: the set name. @@ -883,9 +881,7 @@ Index Operations .. method:: index_map_values_create(ns, set, bin, index_datatype, name, policy: dict = None, ctx: list = None) - Create an index named *name* for numeric, string or GeoJSON values \ - (as defined by *index_datatype*) on records of the specified *ns*, *set* \ - whose *bin* is a map. The index will include the values of the map. + Create a secondary index on all of a map's values, where all of the values are the same type. :param str ns: the namespace in the aerospike cluster. :param str set: the set name. From a6b83633c89016137c50abe4977e14e7348f800e Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 28 Jan 2026 09:46:15 -0800 Subject: [PATCH 17/42] Add deprecation warnings --- src/main/client/sec_index.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 1b22db2257..4574108096 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -44,6 +44,9 @@ static PyObject *createIndexWithDataAndCollectionType( as_index_type index_type, as_index_datatype data_type, as_cdt_ctx *ctx, as_exp *exp); +#define DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE \ + "%s() is deprecated. Please use index_single_value_create() instead" + /** ******************************************************************************************************* * Creates an integer index for a bin in the Aerospike DB. @@ -60,6 +63,10 @@ static PyObject *createIndexWithDataAndCollectionType( PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { + PyErr_WarnFormat(PyExc_DeprecationWarning, 2, + DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, + "index_integer_create"); + // Initialize error as_error err; as_error_init(&err); @@ -102,6 +109,10 @@ PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, PyObject *AerospikeClient_Index_String_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { + PyErr_WarnFormat(PyExc_DeprecationWarning, 2, + DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, + "index_string_create"); + // Initialize error as_error err; as_error_init(&err); @@ -131,6 +142,10 @@ PyObject *AerospikeClient_Index_String_Create(AerospikeClient *self, PyObject *AerospikeClient_Index_Blob_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { + PyErr_WarnFormat(PyExc_DeprecationWarning, 2, + DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, + "index_blob_create"); + // Python Function Arguments PyObject *py_policy = NULL; PyObject *py_ns = NULL; @@ -209,6 +224,10 @@ PyObject *AerospikeClient_Index_Expr_Create(AerospikeClient *self, PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { + PyErr_WarnEx(PyExc_DeprecationWarning, 2, + "index_cdt_create() is deprecated. Please use one of the " + "other non-deprecated index_*_create() methods instead"); + // Initialize error as_error err; as_error_init(&err); @@ -484,6 +503,10 @@ PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { + PyErr_WarnFormat(PyExc_DeprecationWarning, 2, + DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, + "index_geo2dsphere_create"); + // Initialize error as_error err; as_error_init(&err); From 546d205d656270f35ab31a5b5e5a7aa6ffbd43c2 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 28 Jan 2026 10:25:44 -0800 Subject: [PATCH 18/42] fix --- src/main/client/sec_index.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 4574108096..d63a5f074d 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -224,9 +224,10 @@ PyObject *AerospikeClient_Index_Expr_Create(AerospikeClient *self, PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - PyErr_WarnEx(PyExc_DeprecationWarning, 2, + PyErr_WarnEx(PyExc_DeprecationWarning, "index_cdt_create() is deprecated. Please use one of the " - "other non-deprecated index_*_create() methods instead"); + "other non-deprecated index_*_create() methods instead", + 2); // Initialize error as_error err; From 0925579c1238da2370e534c8014e7d5f07ebe7e6 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 28 Jan 2026 10:48:01 -0800 Subject: [PATCH 19/42] Add index_single_value_create and ctx parameter for 3 other index create methods --- src/include/client.h | 5 ++ src/main/client/sec_index.c | 140 +++++++++++++++++++++++------------- src/main/client/type.c | 3 + 3 files changed, 100 insertions(+), 48 deletions(-) diff --git a/src/include/client.h b/src/include/client.h index 800c4c64dc..e41ddcc5fd 100644 --- a/src/include/client.h +++ b/src/include/client.h @@ -391,6 +391,11 @@ PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, */ PyObject *AerospikeClient_Index_Remove(AerospikeClient *self, PyObject *args, PyObject *kwds); + +PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, + PyObject *args, + PyObject *kwds); + /** * Create secondary list index * diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index d63a5f074d..f3be5436ae 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -36,12 +36,12 @@ static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, static PyObject *createIndexWithCollectionType( AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, PyObject *py_set, PyObject *py_bin, PyObject *py_name, - PyObject *py_datatype, as_index_type index_type, as_cdt_ctx *ctx); + PyObject *py_datatype, as_index_type index_type, PyObject *py_ctx); static PyObject *createIndexWithDataAndCollectionType( AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, PyObject *py_set, PyObject *py_bin, PyObject *py_name, - as_index_type index_type, as_index_datatype data_type, as_cdt_ctx *ctx, + as_index_type index_type, as_index_datatype data_type, PyObject *py_ctx, as_exp *exp); #define DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE \ @@ -243,9 +243,6 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, PyObject *py_name = NULL; PyObject *py_ctx = NULL; - as_cdt_ctx ctx; - bool ctx_in_use = false; - PyObject *py_ctx_dict = NULL; PyObject *py_obj = NULL; as_index_datatype data_type; @@ -272,39 +269,15 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, goto CLEANUP; } - // TODO: this should be refactored by using a new helper function to parse a ctx list instead of get_cdt_ctx() - // which only parses a dictionary containing a ctx list - py_ctx_dict = PyDict_New(); - if (!py_ctx_dict) { - as_error_update(&err, AEROSPIKE_ERR_CLIENT, CTX_PARSE_ERROR_MESSAGE); - goto CLEANUP; - } - int retval = PyDict_SetItemString(py_ctx_dict, "ctx", py_ctx); - if (retval == -1) { - Py_DECREF(py_ctx_dict); - as_error_update(&err, AEROSPIKE_ERR_CLIENT, CTX_PARSE_ERROR_MESSAGE); - goto CLEANUP; - } - - as_static_pool static_pool; - memset(&static_pool, 0, sizeof(static_pool)); - - if (get_cdt_ctx(self, &err, &ctx, py_ctx_dict, &ctx_in_use, &static_pool, - SERIALIZER_PYTHON) != AEROSPIKE_OK) { - goto CLEANUP; - } - // Even if this call fails, it will raise its own exception // and the err object here will not be set. We don't raise an exception twice py_obj = createIndexWithDataAndCollectionType( self, py_policy, py_ns, py_set, py_bin, py_name, index_type, data_type, - &ctx, NULL); + py_ctx, NULL); - as_cdt_ctx_destroy(&ctx); + // as_cdt_ctx_destroy(&ctx); CLEANUP: - Py_XDECREF(py_ctx_dict); - if (err.code != AEROSPIKE_OK) { raise_exception_base(&err, Py_None, Py_None, Py_None, Py_None, py_name); return NULL; @@ -407,6 +380,41 @@ PyObject *AerospikeClient_Index_Remove(AerospikeClient *self, PyObject *args, return PyLong_FromLong(0); } +// TODO: combine all 4 methods into one since they ahve the same signature +PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, + PyObject *args, + PyObject *kwds) +{ + // Initialize error + as_error err; + as_error_init(&err); + + // Python Function Arguments + PyObject *py_policy = NULL; + PyObject *py_ns = NULL; + PyObject *py_set = NULL; + PyObject *py_bin = NULL; + PyObject *py_name = NULL; + PyObject *py_datatype = NULL; + PyObject *py_ctx = NULL; + + // Python Function Keyword Arguments + static char *kwlist[] = {"ns", "set", "bin", "index_datatype", + "name", "policy", "ctx", NULL}; + + // Python Function Argument Parsing + if (PyArg_ParseTupleAndKeywords(args, kwds, + "OOOOO|O:index_single_value_create", kwlist, + &py_ns, &py_set, &py_bin, &py_datatype, + &py_name, &py_policy, &py_ctx) == false) { + return NULL; + } + + return createIndexWithCollectionType(self, py_policy, py_ns, py_set, py_bin, + py_name, py_datatype, + AS_INDEX_TYPE_DEFAULT, py_ctx); +} + PyObject *AerospikeClient_Index_List_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { @@ -421,21 +429,22 @@ PyObject *AerospikeClient_Index_List_Create(AerospikeClient *self, PyObject *py_bin = NULL; PyObject *py_name = NULL; PyObject *py_datatype = NULL; + PyObject *py_ctx = NULL; // Python Function Keyword Arguments static char *kwlist[] = {"ns", "set", "bin", "index_datatype", - "name", "policy", NULL}; + "name", "policy", "ctx", NULL}; // Python Function Argument Parsing if (PyArg_ParseTupleAndKeywords( args, kwds, "OOOOO|O:index_list_create", kwlist, &py_ns, &py_set, - &py_bin, &py_datatype, &py_name, &py_policy) == false) { + &py_bin, &py_datatype, &py_name, &py_policy, &py_ctx) == false) { return NULL; } return createIndexWithCollectionType(self, py_policy, py_ns, py_set, py_bin, py_name, py_datatype, - AS_INDEX_TYPE_LIST, NULL); + AS_INDEX_TYPE_LIST, py_ctx); } PyObject *AerospikeClient_Index_Map_Keys_Create(AerospikeClient *self, @@ -452,21 +461,23 @@ PyObject *AerospikeClient_Index_Map_Keys_Create(AerospikeClient *self, PyObject *py_bin = NULL; PyObject *py_name = NULL; PyObject *py_datatype = NULL; + PyObject *py_ctx = NULL; // Python Function Keyword Arguments static char *kwlist[] = {"ns", "set", "bin", "index_datatype", - "name", "policy", NULL}; + "name", "policy", "ctx", NULL}; // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords( - args, kwds, "OOOOO|O:index_map_keys_create", kwlist, &py_ns, - &py_set, &py_bin, &py_datatype, &py_name, &py_policy) == false) { + if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOOO|O:index_map_keys_create", + kwlist, &py_ns, &py_set, &py_bin, + &py_datatype, &py_name, &py_policy, + &py_ctx) == false) { return NULL; } return createIndexWithCollectionType(self, py_policy, py_ns, py_set, py_bin, py_name, py_datatype, - AS_INDEX_TYPE_MAPKEYS, NULL); + AS_INDEX_TYPE_MAPKEYS, py_ctx); } PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, @@ -484,21 +495,23 @@ PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, PyObject *py_bin = NULL; PyObject *py_name = NULL; PyObject *py_datatype = NULL; + PyObject *py_ctx = NULL; // Python Function Keyword Arguments static char *kwlist[] = {"ns", "set", "bin", "index_datatype", - "name", "policy", NULL}; + "name", "policy", "ctx", NULL}; // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords( - args, kwds, "OOOOO|O:index_map_values_create", kwlist, &py_ns, - &py_set, &py_bin, &py_datatype, &py_name, &py_policy) == false) { + if (PyArg_ParseTupleAndKeywords(args, kwds, + "OOOOO|O:index_map_values_create", kwlist, + &py_ns, &py_set, &py_bin, &py_datatype, + &py_name, &py_policy, &py_ctx) == false) { return NULL; } return createIndexWithCollectionType(self, py_policy, py_ns, py_set, py_bin, py_name, py_datatype, - AS_INDEX_TYPE_MAPVALUES, NULL); + AS_INDEX_TYPE_MAPVALUES, py_ctx); } PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, @@ -574,7 +587,7 @@ static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, static PyObject *createIndexWithCollectionType( AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, PyObject *py_set, PyObject *py_bin, PyObject *py_name, - PyObject *py_datatype, as_index_type index_type, as_cdt_ctx *ctx) + PyObject *py_datatype, as_index_type index_type, PyObject *py_ctx) { as_index_datatype data_type = AS_INDEX_STRING; @@ -588,7 +601,7 @@ static PyObject *createIndexWithCollectionType( return createIndexWithDataAndCollectionType(self, py_policy, py_ns, py_set, py_bin, py_name, index_type, - data_type, ctx, NULL); + data_type, py_ctx, NULL); } /* @@ -601,7 +614,7 @@ static PyObject *createIndexWithCollectionType( static PyObject *createIndexWithDataAndCollectionType( AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, PyObject *py_set, PyObject *py_bin, PyObject *py_name, - as_index_type index_type, as_index_datatype data_type, as_cdt_ctx *ctx, + as_index_type index_type, as_index_datatype data_type, PyObject *py_ctx, as_exp *exp) { @@ -686,6 +699,30 @@ static PyObject *createIndexWithDataAndCollectionType( goto CLEANUP; } + // TODO: this should be refactored by using a new helper function to parse a ctx list instead of get_cdt_ctx() + // which only parses a dictionary containing a ctx list + as_cdt_ctx ctx; + bool ctx_in_use = false; + PyObject *py_ctx_dict = PyDict_New(); + if (!py_ctx_dict) { + as_error_update(&err, AEROSPIKE_ERR_CLIENT, CTX_PARSE_ERROR_MESSAGE); + goto CLEANUP; + } + int retval = PyDict_SetItemString(py_ctx_dict, "ctx", py_ctx); + if (retval == -1) { + as_error_update(&err, AEROSPIKE_ERR_CLIENT, CTX_PARSE_ERROR_MESSAGE); + goto CLEANUP2; + } + + as_static_pool static_pool; + memset(&static_pool, 0, sizeof(static_pool)); + + if (get_cdt_ctx(self, &err, &ctx, py_ctx_dict, &ctx_in_use, &static_pool, + SERIALIZER_PYTHON) != AEROSPIKE_OK) { + goto CLEANUP2; + } + as_cdt_ctx *ctx_ref = ctx_in_use ? &ctx : NULL; + // Invoke operation Py_BEGIN_ALLOW_THREADS if (exp) { @@ -696,7 +733,7 @@ static PyObject *createIndexWithDataAndCollectionType( else { aerospike_index_create_ctx(self->as, &err, &task, info_policy_p, namespace, set_ptr, bin_ptr, name, - index_type, data_type, ctx); + index_type, data_type, ctx_ref); } Py_END_ALLOW_THREADS if (err.code == AEROSPIKE_OK) { @@ -705,6 +742,13 @@ static PyObject *createIndexWithDataAndCollectionType( Py_END_ALLOW_THREADS } + if (ctx_ref) { + as_cdt_ctx_destroy(ctx_ref); + } + +CLEANUP2: + Py_DECREF(py_ctx_dict); + CLEANUP: if (py_ustr_set) { Py_DECREF(py_ustr_set); diff --git a/src/main/client/type.c b/src/main/client/type.c index d239b536ef..62dd1cf12e 100644 --- a/src/main/client/type.c +++ b/src/main/client/type.c @@ -481,6 +481,9 @@ static PyMethodDef AerospikeClient_Type_Methods[] = { {"index_map_values_create", (PyCFunction)AerospikeClient_Index_Map_Values_Create, METH_VARARGS | METH_KEYWORDS, index_map_values_create_doc}, + {"index_single_value_create", + (PyCFunction)AerospikeClient_Index_Single_Value_Create, + METH_VARARGS | METH_KEYWORDS, NULL}, {"index_geo2dsphere_create", (PyCFunction)AerospikeClient_Index_2dsphere_Create, METH_VARARGS | METH_KEYWORDS, index_geo2dsphere_create_doc}, From caf05cd7bd95f2d95436c6718207552d02594ab1 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 28 Jan 2026 12:43:25 -0800 Subject: [PATCH 20/42] Refactor other index create methods. Implement index_single_value_create() --- src/main/client/sec_index.c | 114 +++++++----------------------------- src/main/client/type.c | 8 ++- 2 files changed, 27 insertions(+), 95 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index f3be5436ae..c177841407 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -380,109 +380,40 @@ PyObject *AerospikeClient_Index_Remove(AerospikeClient *self, PyObject *args, return PyLong_FromLong(0); } -// TODO: combine all 4 methods into one since they ahve the same signature PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - // Initialize error - as_error err; - as_error_init(&err); - - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; - PyObject *py_datatype = NULL; - PyObject *py_ctx = NULL; - - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "index_datatype", - "name", "policy", "ctx", NULL}; - - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, - "OOOOO|O:index_single_value_create", kwlist, - &py_ns, &py_set, &py_bin, &py_datatype, - &py_name, &py_policy, &py_ctx) == false) { - return NULL; - } - - return createIndexWithCollectionType(self, py_policy, py_ns, py_set, py_bin, - py_name, py_datatype, - AS_INDEX_TYPE_DEFAULT, py_ctx); + return AerospikeClient_Index_Create(self, args, kwds, AS_INDEX_TYPE_DEFAULT, + "index_single_value_create"); } PyObject *AerospikeClient_Index_List_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - // Initialize error - as_error err; - as_error_init(&err); - - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; - PyObject *py_datatype = NULL; - PyObject *py_ctx = NULL; - - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "index_datatype", - "name", "policy", "ctx", NULL}; - - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords( - args, kwds, "OOOOO|O:index_list_create", kwlist, &py_ns, &py_set, - &py_bin, &py_datatype, &py_name, &py_policy, &py_ctx) == false) { - return NULL; - } - - return createIndexWithCollectionType(self, py_policy, py_ns, py_set, py_bin, - py_name, py_datatype, - AS_INDEX_TYPE_LIST, py_ctx); + return AerospikeClient_Index_Create(self, args, kwds, AS_INDEX_TYPE_LIST, + "index_list_create"); } PyObject *AerospikeClient_Index_Map_Keys_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - // Initialize error - as_error err; - as_error_init(&err); - - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; - PyObject *py_datatype = NULL; - PyObject *py_ctx = NULL; - - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "index_datatype", - "name", "policy", "ctx", NULL}; - - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOOO|O:index_map_keys_create", - kwlist, &py_ns, &py_set, &py_bin, - &py_datatype, &py_name, &py_policy, - &py_ctx) == false) { - return NULL; - } - - return createIndexWithCollectionType(self, py_policy, py_ns, py_set, py_bin, - py_name, py_datatype, - AS_INDEX_TYPE_MAPKEYS, py_ctx); + return AerospikeClient_Index_Create(self, args, kwds, AS_INDEX_TYPE_MAPKEYS, + "index_map_keys_create"); } PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) +{ + return AerospikeClient_Index_Create( + self, args, kwds, AS_INDEX_TYPE_MAPVALUES, "index_map_values_create"); +} + +// TODO: way to get method name dynamically for error message? +PyObject *AerospikeClient_Index_Create(AerospikeClient *self, PyObject *args, + PyObject *kwds, as_index_type index_type, + const char *ml_name) { // Initialize error as_error err; @@ -497,21 +428,20 @@ PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, PyObject *py_datatype = NULL; PyObject *py_ctx = NULL; - // Python Function Keyword Arguments static char *kwlist[] = {"ns", "set", "bin", "index_datatype", "name", "policy", "ctx", NULL}; - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, - "OOOOO|O:index_map_values_create", kwlist, - &py_ns, &py_set, &py_bin, &py_datatype, - &py_name, &py_policy, &py_ctx) == false) { + const char format[256]; + snprintf(format, 256, "OOOOO|O:%s", ml_name); + if (PyArg_ParseTupleAndKeywords(args, kwds, format, kwlist, &py_ns, &py_set, + &py_bin, &py_datatype, &py_name, &py_policy, + &py_ctx) == false) { return NULL; } return createIndexWithCollectionType(self, py_policy, py_ns, py_set, py_bin, - py_name, py_datatype, - AS_INDEX_TYPE_MAPVALUES, py_ctx); + py_name, py_datatype, index_type, + py_ctx); } PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, diff --git a/src/main/client/type.c b/src/main/client/type.c index 62dd1cf12e..a6f45508f1 100644 --- a/src/main/client/type.c +++ b/src/main/client/type.c @@ -473,6 +473,10 @@ static PyMethodDef AerospikeClient_Type_Methods[] = { METH_VARARGS | METH_KEYWORDS, get_cdtctx_base64_doc}, {"index_remove", (PyCFunction)AerospikeClient_Index_Remove, METH_VARARGS | METH_KEYWORDS, index_remove_doc}, + + {"index_single_value_create", + (PyCFunction)AerospikeClient_Index_Single_Value_Create, + METH_VARARGS | METH_KEYWORDS, NULL}, {"index_list_create", (PyCFunction)AerospikeClient_Index_List_Create, METH_VARARGS | METH_KEYWORDS, index_list_create_doc}, {"index_map_keys_create", @@ -481,9 +485,7 @@ static PyMethodDef AerospikeClient_Type_Methods[] = { {"index_map_values_create", (PyCFunction)AerospikeClient_Index_Map_Values_Create, METH_VARARGS | METH_KEYWORDS, index_map_values_create_doc}, - {"index_single_value_create", - (PyCFunction)AerospikeClient_Index_Single_Value_Create, - METH_VARARGS | METH_KEYWORDS, NULL}, + {"index_geo2dsphere_create", (PyCFunction)AerospikeClient_Index_2dsphere_Create, METH_VARARGS | METH_KEYWORDS, index_geo2dsphere_create_doc}, From f372c5e23d42b5ee08ff984b25440e9a16d38a1e Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 28 Jan 2026 13:16:02 -0800 Subject: [PATCH 21/42] Move below definition --- src/main/client/sec_index.c | 68 +++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index c177841407..934da837e7 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -380,40 +380,12 @@ PyObject *AerospikeClient_Index_Remove(AerospikeClient *self, PyObject *args, return PyLong_FromLong(0); } -PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, - PyObject *args, - PyObject *kwds) -{ - return AerospikeClient_Index_Create(self, args, kwds, AS_INDEX_TYPE_DEFAULT, - "index_single_value_create"); -} - -PyObject *AerospikeClient_Index_List_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) -{ - return AerospikeClient_Index_Create(self, args, kwds, AS_INDEX_TYPE_LIST, - "index_list_create"); -} - -PyObject *AerospikeClient_Index_Map_Keys_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) -{ - return AerospikeClient_Index_Create(self, args, kwds, AS_INDEX_TYPE_MAPKEYS, - "index_map_keys_create"); -} - -PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, - PyObject *args, - PyObject *kwds) -{ - return AerospikeClient_Index_Create( - self, args, kwds, AS_INDEX_TYPE_MAPVALUES, "index_map_values_create"); -} - // TODO: way to get method name dynamically for error message? -PyObject *AerospikeClient_Index_Create(AerospikeClient *self, PyObject *args, - PyObject *kwds, as_index_type index_type, - const char *ml_name) +static inline PyObject *AerospikeClient_Index_Create(AerospikeClient *self, + PyObject *args, + PyObject *kwds, + as_index_type index_type, + const char *ml_name) { // Initialize error as_error err; @@ -444,6 +416,36 @@ PyObject *AerospikeClient_Index_Create(AerospikeClient *self, PyObject *args, py_ctx); } +PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, + PyObject *args, + PyObject *kwds) +{ + return AerospikeClient_Index_Create(self, args, kwds, AS_INDEX_TYPE_DEFAULT, + "index_single_value_create"); +} + +PyObject *AerospikeClient_Index_List_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) +{ + return AerospikeClient_Index_Create(self, args, kwds, AS_INDEX_TYPE_LIST, + "index_list_create"); +} + +PyObject *AerospikeClient_Index_Map_Keys_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) +{ + return AerospikeClient_Index_Create(self, args, kwds, AS_INDEX_TYPE_MAPKEYS, + "index_map_keys_create"); +} + +PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, + PyObject *args, + PyObject *kwds) +{ + return AerospikeClient_Index_Create( + self, args, kwds, AS_INDEX_TYPE_MAPVALUES, "index_map_values_create"); +} + PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { From e359beb9b22c7496a8e7185e7ac1d8f24900b97d Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 28 Jan 2026 16:41:21 -0800 Subject: [PATCH 22/42] char array must be mutable --- src/main/client/sec_index.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 934da837e7..3b38b59404 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -403,7 +403,7 @@ static inline PyObject *AerospikeClient_Index_Create(AerospikeClient *self, static char *kwlist[] = {"ns", "set", "bin", "index_datatype", "name", "policy", "ctx", NULL}; - const char format[256]; + char format[256]; snprintf(format, 256, "OOOOO|O:%s", ml_name); if (PyArg_ParseTupleAndKeywords(args, kwds, format, kwlist, &py_ns, &py_set, &py_bin, &py_datatype, &py_name, &py_policy, From 546f327442f6a7a1cdbe63ce6e40c3e85ad852bd Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 28 Jan 2026 17:42:21 -0800 Subject: [PATCH 23/42] fix seg fault --- src/main/client/sec_index.c | 38 +++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 3b38b59404..fd783a2198 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -635,24 +635,30 @@ static PyObject *createIndexWithDataAndCollectionType( // which only parses a dictionary containing a ctx list as_cdt_ctx ctx; bool ctx_in_use = false; - PyObject *py_ctx_dict = PyDict_New(); - if (!py_ctx_dict) { - as_error_update(&err, AEROSPIKE_ERR_CLIENT, CTX_PARSE_ERROR_MESSAGE); - goto CLEANUP; - } - int retval = PyDict_SetItemString(py_ctx_dict, "ctx", py_ctx); - if (retval == -1) { - as_error_update(&err, AEROSPIKE_ERR_CLIENT, CTX_PARSE_ERROR_MESSAGE); - goto CLEANUP2; - } + PyObject *py_ctx_dict = NULL; + if (py_ctx) { + py_ctx_dict = PyDict_New(); + if (!py_ctx_dict) { + as_error_update(&err, AEROSPIKE_ERR_CLIENT, + CTX_PARSE_ERROR_MESSAGE); + goto CLEANUP; + } + int retval = PyDict_SetItemString(py_ctx_dict, "ctx", py_ctx); + if (retval == -1) { + as_error_update(&err, AEROSPIKE_ERR_CLIENT, + CTX_PARSE_ERROR_MESSAGE); + goto CLEANUP2; + } - as_static_pool static_pool; - memset(&static_pool, 0, sizeof(static_pool)); + as_static_pool static_pool; + memset(&static_pool, 0, sizeof(static_pool)); - if (get_cdt_ctx(self, &err, &ctx, py_ctx_dict, &ctx_in_use, &static_pool, - SERIALIZER_PYTHON) != AEROSPIKE_OK) { - goto CLEANUP2; + if (get_cdt_ctx(self, &err, &ctx, py_ctx_dict, &ctx_in_use, + &static_pool, SERIALIZER_PYTHON) != AEROSPIKE_OK) { + goto CLEANUP2; + } } + as_cdt_ctx *ctx_ref = ctx_in_use ? &ctx : NULL; // Invoke operation @@ -679,7 +685,7 @@ static PyObject *createIndexWithDataAndCollectionType( } CLEANUP2: - Py_DECREF(py_ctx_dict); + Py_XDECREF(py_ctx_dict); CLEANUP: if (py_ustr_set) { From 1697c51a026ab426c6a8a861794444a702f5f8d0 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Wed, 28 Jan 2026 19:56:15 -0800 Subject: [PATCH 24/42] Fix --- src/main/client/sec_index.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index fd783a2198..ebdb41c02e 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -404,7 +404,7 @@ static inline PyObject *AerospikeClient_Index_Create(AerospikeClient *self, "name", "policy", "ctx", NULL}; char format[256]; - snprintf(format, 256, "OOOOO|O:%s", ml_name); + snprintf(format, 256, "OOOOO|OO:%s", ml_name); if (PyArg_ParseTupleAndKeywords(args, kwds, format, kwlist, &py_ns, &py_set, &py_bin, &py_datatype, &py_name, &py_policy, &py_ctx) == false) { From 91f8ed1ea4c55dd6cdaa9cb1f85d2a9daf5925e6 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Thu, 29 Jan 2026 08:43:24 -0800 Subject: [PATCH 25/42] Replace magic number --- src/main/client/sec_index.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index ebdb41c02e..92fa0e9560 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -47,6 +47,9 @@ static PyObject *createIndexWithDataAndCollectionType( #define DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE \ "%s() is deprecated. Please use index_single_value_create() instead" +// This allows people to see the function calling the Python client API that issues a warning +#define STACK_LEVEL 2 + /** ******************************************************************************************************* * Creates an integer index for a bin in the Aerospike DB. @@ -63,7 +66,7 @@ static PyObject *createIndexWithDataAndCollectionType( PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - PyErr_WarnFormat(PyExc_DeprecationWarning, 2, + PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, "index_integer_create"); @@ -109,7 +112,7 @@ PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, PyObject *AerospikeClient_Index_String_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - PyErr_WarnFormat(PyExc_DeprecationWarning, 2, + PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, "index_string_create"); @@ -142,7 +145,7 @@ PyObject *AerospikeClient_Index_String_Create(AerospikeClient *self, PyObject *AerospikeClient_Index_Blob_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - PyErr_WarnFormat(PyExc_DeprecationWarning, 2, + PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, "index_blob_create"); @@ -449,7 +452,7 @@ PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - PyErr_WarnFormat(PyExc_DeprecationWarning, 2, + PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, "index_geo2dsphere_create"); From ee906e77e1e2a5f273bdaa5a11a39509ccdd1166 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Thu, 29 Jan 2026 09:23:12 -0800 Subject: [PATCH 26/42] forgot --- src/main/client/sec_index.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 92fa0e9560..167c4c0ad1 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -230,7 +230,7 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, PyErr_WarnEx(PyExc_DeprecationWarning, "index_cdt_create() is deprecated. Please use one of the " "other non-deprecated index_*_create() methods instead", - 2); + STACK_LEVEL); // Initialize error as_error err; From b890dd4dcfb06475f854cda5da586d654a773968 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Thu, 29 Jan 2026 09:49:00 -0800 Subject: [PATCH 27/42] Consolidate helper method into new helper --- src/main/client/sec_index.c | 62 ++++++++++++------------------------- 1 file changed, 19 insertions(+), 43 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 167c4c0ad1..3c925efcf5 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -33,11 +33,6 @@ static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, as_error *err); -static PyObject *createIndexWithCollectionType( - AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, - PyObject *py_set, PyObject *py_bin, PyObject *py_name, - PyObject *py_datatype, as_index_type index_type, PyObject *py_ctx); - static PyObject *createIndexWithDataAndCollectionType( AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, PyObject *py_set, PyObject *py_bin, PyObject *py_name, @@ -384,11 +379,10 @@ PyObject *AerospikeClient_Index_Remove(AerospikeClient *self, PyObject *args, } // TODO: way to get method name dynamically for error message? -static inline PyObject *AerospikeClient_Index_Create(AerospikeClient *self, - PyObject *args, - PyObject *kwds, - as_index_type index_type, - const char *ml_name) +static inline PyObject * +create_index_with_known_index_type(AerospikeClient *self, PyObject *args, + PyObject *kwds, as_index_type index_type, + const char *ml_name) { // Initialize error as_error err; @@ -414,38 +408,43 @@ static inline PyObject *AerospikeClient_Index_Create(AerospikeClient *self, return NULL; } - return createIndexWithCollectionType(self, py_policy, py_ns, py_set, py_bin, - py_name, py_datatype, index_type, - py_ctx); + as_index_datatype index_datatype = AS_INDEX_STRING; + if (!getTypeFromPyObject(py_datatype, (int *)&index_datatype, &err)) { + return NULL; + } + + return createIndexWithDataAndCollectionType(self, py_policy, py_ns, py_set, + py_bin, py_name, index_type, + index_datatype, py_ctx, NULL); } PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - return AerospikeClient_Index_Create(self, args, kwds, AS_INDEX_TYPE_DEFAULT, - "index_single_value_create"); + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_DEFAULT, "index_single_value_create"); } PyObject *AerospikeClient_Index_List_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - return AerospikeClient_Index_Create(self, args, kwds, AS_INDEX_TYPE_LIST, - "index_list_create"); + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_LIST, "index_list_create"); } PyObject *AerospikeClient_Index_Map_Keys_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - return AerospikeClient_Index_Create(self, args, kwds, AS_INDEX_TYPE_MAPKEYS, - "index_map_keys_create"); + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_MAPKEYS, "index_map_keys_create"); } PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - return AerospikeClient_Index_Create( + return create_index_with_known_index_type( self, args, kwds, AS_INDEX_TYPE_MAPVALUES, "index_map_values_create"); } @@ -516,29 +515,6 @@ static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, return true; } -/* - * Figure out the data_type from a PyObject and call createIndexWithDataAndCollectionType. - */ -static PyObject *createIndexWithCollectionType( - AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, - PyObject *py_set, PyObject *py_bin, PyObject *py_name, - PyObject *py_datatype, as_index_type index_type, PyObject *py_ctx) -{ - - as_index_datatype data_type = AS_INDEX_STRING; - - as_error err; - as_error_init(&err); - - if (!getTypeFromPyObject(py_datatype, (int *)&data_type, &err)) { - return NULL; - } - - return createIndexWithDataAndCollectionType(self, py_policy, py_ns, py_set, - py_bin, py_name, index_type, - data_type, py_ctx, NULL); -} - /* * Create a complex index on the specified ns/set/bin with the given name and index and data_type. Return PyObject(0) on success * else return NULL with an error raised. From 9406bf3785fd6b5fc60b6dd81706e1f11aa006cc Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Thu, 29 Jan 2026 10:20:01 -0800 Subject: [PATCH 28/42] Make helper function permissive. index_cdt_create should be the only one checking for ctx=None --- src/main/client/sec_index.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 3c925efcf5..605ebe0040 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -33,7 +33,7 @@ static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, as_error *err); -static PyObject *createIndexWithDataAndCollectionType( +static PyObject *convert_python_args_to_c_and_create_index( AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, PyObject *py_set, PyObject *py_bin, PyObject *py_name, as_index_type index_type, as_index_datatype data_type, PyObject *py_ctx, @@ -86,7 +86,7 @@ PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, return NULL; } - return createIndexWithDataAndCollectionType( + return convert_python_args_to_c_and_create_index( self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, AS_INDEX_NUMERIC, NULL, NULL); } @@ -132,7 +132,7 @@ PyObject *AerospikeClient_Index_String_Create(AerospikeClient *self, return NULL; } - return createIndexWithDataAndCollectionType( + return convert_python_args_to_c_and_create_index( self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, AS_INDEX_STRING, NULL, NULL); } @@ -161,7 +161,7 @@ PyObject *AerospikeClient_Index_Blob_Create(AerospikeClient *self, return NULL; } - return createIndexWithDataAndCollectionType( + return convert_python_args_to_c_and_create_index( self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, AS_INDEX_BLOB, NULL, NULL); } @@ -199,9 +199,9 @@ PyObject *AerospikeClient_Index_Expr_Create(AerospikeClient *self, return NULL; } - return createIndexWithDataAndCollectionType(self, py_policy, py_ns, py_set, - NULL, py_name, index_type, - data_type, NULL, expr); + return convert_python_args_to_c_and_create_index( + self, py_policy, py_ns, py_set, NULL, py_name, index_type, data_type, + NULL, expr); } #define CTX_PARSE_ERROR_MESSAGE "Unable to parse ctx" @@ -267,9 +267,17 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, goto CLEANUP; } + // convert_python_args_to_c_and_create_index, which is called by the new index create method API's, + // accepts an optional value of None for ctx + // This API call is the only exception where a list of ctx's is required + if (Py_IsNone(py_ctx)) { + as_error_update(&err, AEROSPIKE_ERR_PARAM, "ctx cannot be None"); + goto CLEANUP; + } + // Even if this call fails, it will raise its own exception // and the err object here will not be set. We don't raise an exception twice - py_obj = createIndexWithDataAndCollectionType( + py_obj = convert_python_args_to_c_and_create_index( self, py_policy, py_ns, py_set, py_bin, py_name, index_type, data_type, py_ctx, NULL); @@ -413,9 +421,9 @@ create_index_with_known_index_type(AerospikeClient *self, PyObject *args, return NULL; } - return createIndexWithDataAndCollectionType(self, py_policy, py_ns, py_set, - py_bin, py_name, index_type, - index_datatype, py_ctx, NULL); + return convert_python_args_to_c_and_create_index( + self, py_policy, py_ns, py_set, py_bin, py_name, index_type, + index_datatype, py_ctx, NULL); } PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, @@ -476,7 +484,7 @@ PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, return NULL; } - return createIndexWithDataAndCollectionType( + return convert_python_args_to_c_and_create_index( self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, AS_INDEX_GEO2DSPHERE, NULL, NULL); } @@ -522,7 +530,8 @@ static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, // exp is optional and can be NULL. // If exp is non-NULL (i.e we are indexing an expression), py_bin should be NULL. -static PyObject *createIndexWithDataAndCollectionType( +// This is permissive and allows py_ctx to be None or NULL +static PyObject *convert_python_args_to_c_and_create_index( AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, PyObject *py_set, PyObject *py_bin, PyObject *py_name, as_index_type index_type, as_index_datatype data_type, PyObject *py_ctx, @@ -615,7 +624,7 @@ static PyObject *createIndexWithDataAndCollectionType( as_cdt_ctx ctx; bool ctx_in_use = false; PyObject *py_ctx_dict = NULL; - if (py_ctx) { + if (py_ctx && !Py_IsNone(py_ctx)) { py_ctx_dict = PyDict_New(); if (!py_ctx_dict) { as_error_update(&err, AEROSPIKE_ERR_CLIENT, From 3c8bbdcd0b82026e2e69171b6d5d360f9602e536 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Thu, 29 Jan 2026 12:09:23 -0800 Subject: [PATCH 29/42] Move all the deprecated API functions to the end --- src/main/client/sec_index.c | 702 ++++++++++++++++++------------------ 1 file changed, 346 insertions(+), 356 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 605ebe0040..127559a775 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -30,140 +30,178 @@ #include "exceptions.h" #include "policy.h" -static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, - as_error *err); +#define CTX_PARSE_ERROR_MESSAGE "Unable to parse ctx" +/* + * Create a complex index on the specified ns/set/bin with the given name and index and data_type. Return PyObject(0) on success + * else return NULL with an error raised. + */ +// exp is optional and can be NULL. +// If exp is non-NULL (i.e we are indexing an expression), py_bin should be NULL. +// This is permissive and allows py_ctx to be None or NULL static PyObject *convert_python_args_to_c_and_create_index( AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, PyObject *py_set, PyObject *py_bin, PyObject *py_name, as_index_type index_type, as_index_datatype data_type, PyObject *py_ctx, - as_exp *exp); - -#define DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE \ - "%s() is deprecated. Please use index_single_value_create() instead" - -// This allows people to see the function calling the Python client API that issues a warning -#define STACK_LEVEL 2 - -/** - ******************************************************************************************************* - * Creates an integer index for a bin in the Aerospike DB. - * - * @param self AerospikeClient object - * @param args The args is a tuple object containing an argument - * list passed from Python to a C function - * @param kwds Dictionary of keywords - * - * Returns an integer status. 0(Zero) is success value. - * In case of error,appropriate exceptions will be raised. - ******************************************************************************************************* - */ -PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) + as_exp *exp) { - PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, - DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_integer_create"); // Initialize error as_error err; as_error_init(&err); - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; + PyObject *py_ustr_set = NULL; + PyObject *py_ustr_bin = NULL; + PyObject *py_ustr_name = NULL; - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; + as_policy_info info_policy; + as_policy_info *info_policy_p = NULL; + as_index_task task; - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_integer_create", - kwlist, &py_ns, &py_set, &py_bin, &py_name, - &py_policy) == false) { - return NULL; + if (!self || !self->as) { + as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object"); + //raise_exception(&err, -2, "Invalid aerospike object"); + goto CLEANUP; } - return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_NUMERIC, NULL, NULL); -} + if (!self->is_conn_16) { + as_error_update(&err, AEROSPIKE_ERR_CLUSTER, + "No connection to aerospike cluster"); + goto CLEANUP; + } -/** - ******************************************************************************************************* - * Creates a string index for a bin in the Aerospike DB. - * - * @param self AerospikeClient object - * @param args The args is a tuple object containing an argument - * list passed from Python to a C function - * @param kwds Dictionary of keywords - * - * Returns an integer status. 0(Zero) is success value. - * In case of error,appropriate exceptions will be raised. - ******************************************************************************************************* - */ -PyObject *AerospikeClient_Index_String_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) -{ - PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, - DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_string_create"); + // Convert python object to policy_info + pyobject_to_policy_info(&err, py_policy, &info_policy, &info_policy_p, + &self->as->config.policies.info, + self->validate_keys, SECOND_AS_POLICY_NONE); + if (err.code != AEROSPIKE_OK) { + goto CLEANUP; + } - // Initialize error - as_error err; - as_error_init(&err); + // Convert python object into namespace string + if (!PyUnicode_Check(py_ns)) { + as_error_update(&err, AEROSPIKE_ERR_PARAM, + "Namespace should be a string"); + goto CLEANUP; + } + char *namespace = (char *)PyUnicode_AsUTF8(py_ns); - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; + // Convert python object into set string + char *set_ptr = NULL; + if (PyUnicode_Check(py_set)) { + py_ustr_set = PyUnicode_AsUTF8String(py_set); + set_ptr = PyBytes_AsString(py_ustr_set); + } + else if (py_set != Py_None) { + as_error_update(&err, AEROSPIKE_ERR_PARAM, + "Set should be string, unicode or None"); + goto CLEANUP; + } - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; + // Convert python object into bin string + char *bin_ptr = NULL; + if (py_bin) { + if (PyUnicode_Check(py_bin)) { + py_ustr_bin = PyUnicode_AsUTF8String(py_bin); + bin_ptr = PyBytes_AsString(py_ustr_bin); + } + else if (PyByteArray_Check(py_bin)) { + bin_ptr = PyByteArray_AsString(py_bin); + } + else { + as_error_update(&err, AEROSPIKE_ERR_PARAM, + "Bin should be a string"); + goto CLEANUP; + } + } - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_string_create", - kwlist, &py_ns, &py_set, &py_bin, &py_name, - &py_policy) == false) { - return NULL; + // Convert PyObject into the name of the index + char *name = NULL; + if (PyUnicode_Check(py_name)) { + py_ustr_name = PyUnicode_AsUTF8String(py_name); + name = PyBytes_AsString(py_ustr_name); + } + else { + as_error_update(&err, AEROSPIKE_ERR_PARAM, + "Index name should be string or unicode"); + goto CLEANUP; } - return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_STRING, NULL, NULL); -} + // TODO: this should be refactored by using a new helper function to parse a ctx list instead of get_cdt_ctx() + // which only parses a dictionary containing a ctx list + as_cdt_ctx ctx; + bool ctx_in_use = false; + PyObject *py_ctx_dict = NULL; + if (py_ctx && !Py_IsNone(py_ctx)) { + py_ctx_dict = PyDict_New(); + if (!py_ctx_dict) { + as_error_update(&err, AEROSPIKE_ERR_CLIENT, + CTX_PARSE_ERROR_MESSAGE); + goto CLEANUP; + } + int retval = PyDict_SetItemString(py_ctx_dict, "ctx", py_ctx); + if (retval == -1) { + as_error_update(&err, AEROSPIKE_ERR_CLIENT, + CTX_PARSE_ERROR_MESSAGE); + goto CLEANUP2; + } -PyObject *AerospikeClient_Index_Blob_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) -{ - PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, - DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_blob_create"); + as_static_pool static_pool; + memset(&static_pool, 0, sizeof(static_pool)); - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; + if (get_cdt_ctx(self, &err, &ctx, py_ctx_dict, &ctx_in_use, + &static_pool, SERIALIZER_PYTHON) != AEROSPIKE_OK) { + goto CLEANUP2; + } + } - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; + as_cdt_ctx *ctx_ref = ctx_in_use ? &ctx : NULL; - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_blob_create", - kwlist, &py_ns, &py_set, &py_bin, &py_name, - &py_policy) == false) { + // Invoke operation + Py_BEGIN_ALLOW_THREADS + if (exp) { + aerospike_index_create_exp(self->as, &err, &task, info_policy_p, + namespace, set_ptr, name, index_type, + data_type, exp); + } + else { + aerospike_index_create_ctx(self->as, &err, &task, info_policy_p, + namespace, set_ptr, bin_ptr, name, + index_type, data_type, ctx_ref); + } + Py_END_ALLOW_THREADS + if (err.code == AEROSPIKE_OK) { + Py_BEGIN_ALLOW_THREADS + aerospike_index_create_wait(&err, &task, 2000); + Py_END_ALLOW_THREADS + } + + if (ctx_ref) { + as_cdt_ctx_destroy(ctx_ref); + } + +CLEANUP2: + Py_XDECREF(py_ctx_dict); + +CLEANUP: + if (py_ustr_set) { + Py_DECREF(py_ustr_set); + } + if (py_ustr_bin) { + Py_DECREF(py_ustr_bin); + } + if (py_ustr_name) { + Py_DECREF(py_ustr_name); + } + if (exp) { + as_exp_destroy(exp); + } + if (err.code != AEROSPIKE_OK) { + raise_exception(&err); return NULL; } - return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_BLOB, NULL, NULL); + return PyLong_FromLong(0); } PyObject *AerospikeClient_Index_Expr_Create(AerospikeClient *self, @@ -204,11 +242,46 @@ PyObject *AerospikeClient_Index_Expr_Create(AerospikeClient *self, NULL, expr); } -#define CTX_PARSE_ERROR_MESSAGE "Unable to parse ctx" +/* + * Convert a PyObject into an as_index_datatype, return False if the conversion fails for any reason. + */ +static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, + as_error *err) +{ -/** - ******************************************************************************************************* - * Creates a cdt index for a bin in the Aerospike DB. + long type = 0; + if (PyLong_Check(py_datatype)) { + type = PyLong_AsLong(py_datatype); + if (type == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value exceeds sys.maxsize"); + goto CLEANUP; + } + } + } + else { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "Index type must be an integer"); + goto CLEANUP; + } + + *idx_datatype = type; + +CLEANUP: + if (err->code != AEROSPIKE_OK) { + raise_exception(err); + return false; + } + return true; +} + +// This allows people to see the function calling the Python client API that issues a warning +#define STACK_LEVEL 2 + +/** + ******************************************************************************************************* + * Creates a cdt index for a bin in the Aerospike DB. * * @param self AerospikeClient object * @param args The args is a tuple object containing an argument @@ -281,8 +354,6 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, self, py_policy, py_ns, py_set, py_bin, py_name, index_type, data_type, py_ctx, NULL); - // as_cdt_ctx_destroy(&ctx); - CLEANUP: if (err.code != AEROSPIKE_OK) { raise_exception_base(&err, Py_None, Py_None, Py_None, Py_None, py_name); @@ -291,6 +362,76 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, return py_obj; } +// TODO: way to get method name dynamically for error message? +static inline PyObject * +create_index_with_known_index_type(AerospikeClient *self, PyObject *args, + PyObject *kwds, as_index_type index_type, + const char *ml_name) +{ + // Initialize error + as_error err; + as_error_init(&err); + + // Python Function Arguments + PyObject *py_policy = NULL; + PyObject *py_ns = NULL; + PyObject *py_set = NULL; + PyObject *py_bin = NULL; + PyObject *py_name = NULL; + PyObject *py_datatype = NULL; + PyObject *py_ctx = NULL; + + static char *kwlist[] = {"ns", "set", "bin", "index_datatype", + "name", "policy", "ctx", NULL}; + + char format[256]; + snprintf(format, 256, "OOOOO|OO:%s", ml_name); + if (PyArg_ParseTupleAndKeywords(args, kwds, format, kwlist, &py_ns, &py_set, + &py_bin, &py_datatype, &py_name, &py_policy, + &py_ctx) == false) { + return NULL; + } + + as_index_datatype index_datatype = AS_INDEX_STRING; + if (!getTypeFromPyObject(py_datatype, (int *)&index_datatype, &err)) { + return NULL; + } + + return convert_python_args_to_c_and_create_index( + self, py_policy, py_ns, py_set, py_bin, py_name, index_type, + index_datatype, py_ctx, NULL); +} + +PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, + PyObject *args, + PyObject *kwds) +{ + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_DEFAULT, "index_single_value_create"); +} + +PyObject *AerospikeClient_Index_List_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) +{ + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_LIST, "index_list_create"); +} + +PyObject *AerospikeClient_Index_Map_Keys_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) +{ + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_MAPKEYS, "index_map_keys_create"); +} + +PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, + PyObject *args, + PyObject *kwds) +{ + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_MAPVALUES, "index_map_values_create"); +} + /** ******************************************************************************************************* * Removes an index in the Aerospike database. @@ -386,12 +527,31 @@ PyObject *AerospikeClient_Index_Remove(AerospikeClient *self, PyObject *args, return PyLong_FromLong(0); } -// TODO: way to get method name dynamically for error message? -static inline PyObject * -create_index_with_known_index_type(AerospikeClient *self, PyObject *args, - PyObject *kwds, as_index_type index_type, - const char *ml_name) +// Deprecated API's + +#define DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE \ + "%s() is deprecated. Please use index_single_value_create() instead" + +/** + ******************************************************************************************************* + * Creates an integer index for a bin in the Aerospike DB. + * + * @param self AerospikeClient object + * @param args The args is a tuple object containing an argument + * list passed from Python to a C function + * @param kwds Dictionary of keywords + * + * Returns an integer status. 0(Zero) is success value. + * In case of error,appropriate exceptions will be raised. + ******************************************************************************************************* + */ +PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) { + PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, + DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, + "index_integer_create"); + // Initialize error as_error err; as_error_init(&err); @@ -402,66 +562,41 @@ create_index_with_known_index_type(AerospikeClient *self, PyObject *args, PyObject *py_set = NULL; PyObject *py_bin = NULL; PyObject *py_name = NULL; - PyObject *py_datatype = NULL; - PyObject *py_ctx = NULL; - static char *kwlist[] = {"ns", "set", "bin", "index_datatype", - "name", "policy", "ctx", NULL}; - - char format[256]; - snprintf(format, 256, "OOOOO|OO:%s", ml_name); - if (PyArg_ParseTupleAndKeywords(args, kwds, format, kwlist, &py_ns, &py_set, - &py_bin, &py_datatype, &py_name, &py_policy, - &py_ctx) == false) { - return NULL; - } + // Python Function Keyword Arguments + static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; - as_index_datatype index_datatype = AS_INDEX_STRING; - if (!getTypeFromPyObject(py_datatype, (int *)&index_datatype, &err)) { + // Python Function Argument Parsing + if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_integer_create", + kwlist, &py_ns, &py_set, &py_bin, &py_name, + &py_policy) == false) { return NULL; } return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, index_type, - index_datatype, py_ctx, NULL); -} - -PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, - PyObject *args, - PyObject *kwds) -{ - return create_index_with_known_index_type( - self, args, kwds, AS_INDEX_TYPE_DEFAULT, "index_single_value_create"); -} - -PyObject *AerospikeClient_Index_List_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) -{ - return create_index_with_known_index_type( - self, args, kwds, AS_INDEX_TYPE_LIST, "index_list_create"); -} - -PyObject *AerospikeClient_Index_Map_Keys_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) -{ - return create_index_with_known_index_type( - self, args, kwds, AS_INDEX_TYPE_MAPKEYS, "index_map_keys_create"); -} - -PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, - PyObject *args, - PyObject *kwds) -{ - return create_index_with_known_index_type( - self, args, kwds, AS_INDEX_TYPE_MAPVALUES, "index_map_values_create"); + self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, + AS_INDEX_NUMERIC, NULL, NULL); } -PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) +/** + ******************************************************************************************************* + * Creates a string index for a bin in the Aerospike DB. + * + * @param self AerospikeClient object + * @param args The args is a tuple object containing an argument + * list passed from Python to a C function + * @param kwds Dictionary of keywords + * + * Returns an integer status. 0(Zero) is success value. + * In case of error,appropriate exceptions will be raised. + ******************************************************************************************************* + */ +PyObject *AerospikeClient_Index_String_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) { PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_geo2dsphere_create"); + "index_string_create"); // Initialize error as_error err; @@ -478,220 +613,75 @@ PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords( - args, kwds, "OOOO|O:index_geo2dsphere_create", kwlist, &py_ns, - &py_set, &py_bin, &py_name, &py_policy) == false) { + if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_string_create", + kwlist, &py_ns, &py_set, &py_bin, &py_name, + &py_policy) == false) { return NULL; } return convert_python_args_to_c_and_create_index( self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_GEO2DSPHERE, NULL, NULL); + AS_INDEX_STRING, NULL, NULL); } -/* - * Convert a PyObject into an as_index_datatype, return False if the conversion fails for any reason. - */ -static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, - as_error *err) +PyObject *AerospikeClient_Index_Blob_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) { + PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, + DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, + "index_blob_create"); - long type = 0; - if (PyLong_Check(py_datatype)) { - type = PyLong_AsLong(py_datatype); - if (type == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - as_error_update(err, AEROSPIKE_ERR_PARAM, - "integer value exceeds sys.maxsize"); - goto CLEANUP; - } - } - } - else { - as_error_update(err, AEROSPIKE_ERR_PARAM, - "Index type must be an integer"); - goto CLEANUP; - } + // Python Function Arguments + PyObject *py_policy = NULL; + PyObject *py_ns = NULL; + PyObject *py_set = NULL; + PyObject *py_bin = NULL; + PyObject *py_name = NULL; - *idx_datatype = type; + // Python Function Keyword Arguments + static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; -CLEANUP: - if (err->code != AEROSPIKE_OK) { - raise_exception(err); - return false; + // Python Function Argument Parsing + if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_blob_create", + kwlist, &py_ns, &py_set, &py_bin, &py_name, + &py_policy) == false) { + return NULL; } - return true; -} -/* - * Create a complex index on the specified ns/set/bin with the given name and index and data_type. Return PyObject(0) on success - * else return NULL with an error raised. - */ + return convert_python_args_to_c_and_create_index( + self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, + AS_INDEX_BLOB, NULL, NULL); +} -// exp is optional and can be NULL. -// If exp is non-NULL (i.e we are indexing an expression), py_bin should be NULL. -// This is permissive and allows py_ctx to be None or NULL -static PyObject *convert_python_args_to_c_and_create_index( - AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, - PyObject *py_set, PyObject *py_bin, PyObject *py_name, - as_index_type index_type, as_index_datatype data_type, PyObject *py_ctx, - as_exp *exp) +PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) { + PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, + DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, + "index_geo2dsphere_create"); // Initialize error as_error err; as_error_init(&err); - PyObject *py_ustr_set = NULL; - PyObject *py_ustr_bin = NULL; - PyObject *py_ustr_name = NULL; - - as_policy_info info_policy; - as_policy_info *info_policy_p = NULL; - as_index_task task; - - if (!self || !self->as) { - as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object"); - //raise_exception(&err, -2, "Invalid aerospike object"); - goto CLEANUP; - } - - if (!self->is_conn_16) { - as_error_update(&err, AEROSPIKE_ERR_CLUSTER, - "No connection to aerospike cluster"); - goto CLEANUP; - } - - // Convert python object to policy_info - pyobject_to_policy_info(&err, py_policy, &info_policy, &info_policy_p, - &self->as->config.policies.info, - self->validate_keys, SECOND_AS_POLICY_NONE); - if (err.code != AEROSPIKE_OK) { - goto CLEANUP; - } - - // Convert python object into namespace string - if (!PyUnicode_Check(py_ns)) { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Namespace should be a string"); - goto CLEANUP; - } - char *namespace = (char *)PyUnicode_AsUTF8(py_ns); - - // Convert python object into set string - char *set_ptr = NULL; - if (PyUnicode_Check(py_set)) { - py_ustr_set = PyUnicode_AsUTF8String(py_set); - set_ptr = PyBytes_AsString(py_ustr_set); - } - else if (py_set != Py_None) { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Set should be string, unicode or None"); - goto CLEANUP; - } - - // Convert python object into bin string - char *bin_ptr = NULL; - if (py_bin) { - if (PyUnicode_Check(py_bin)) { - py_ustr_bin = PyUnicode_AsUTF8String(py_bin); - bin_ptr = PyBytes_AsString(py_ustr_bin); - } - else if (PyByteArray_Check(py_bin)) { - bin_ptr = PyByteArray_AsString(py_bin); - } - else { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Bin should be a string"); - goto CLEANUP; - } - } - - // Convert PyObject into the name of the index - char *name = NULL; - if (PyUnicode_Check(py_name)) { - py_ustr_name = PyUnicode_AsUTF8String(py_name); - name = PyBytes_AsString(py_ustr_name); - } - else { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Index name should be string or unicode"); - goto CLEANUP; - } - - // TODO: this should be refactored by using a new helper function to parse a ctx list instead of get_cdt_ctx() - // which only parses a dictionary containing a ctx list - as_cdt_ctx ctx; - bool ctx_in_use = false; - PyObject *py_ctx_dict = NULL; - if (py_ctx && !Py_IsNone(py_ctx)) { - py_ctx_dict = PyDict_New(); - if (!py_ctx_dict) { - as_error_update(&err, AEROSPIKE_ERR_CLIENT, - CTX_PARSE_ERROR_MESSAGE); - goto CLEANUP; - } - int retval = PyDict_SetItemString(py_ctx_dict, "ctx", py_ctx); - if (retval == -1) { - as_error_update(&err, AEROSPIKE_ERR_CLIENT, - CTX_PARSE_ERROR_MESSAGE); - goto CLEANUP2; - } - - as_static_pool static_pool; - memset(&static_pool, 0, sizeof(static_pool)); - - if (get_cdt_ctx(self, &err, &ctx, py_ctx_dict, &ctx_in_use, - &static_pool, SERIALIZER_PYTHON) != AEROSPIKE_OK) { - goto CLEANUP2; - } - } - - as_cdt_ctx *ctx_ref = ctx_in_use ? &ctx : NULL; - - // Invoke operation - Py_BEGIN_ALLOW_THREADS - if (exp) { - aerospike_index_create_exp(self->as, &err, &task, info_policy_p, - namespace, set_ptr, name, index_type, - data_type, exp); - } - else { - aerospike_index_create_ctx(self->as, &err, &task, info_policy_p, - namespace, set_ptr, bin_ptr, name, - index_type, data_type, ctx_ref); - } - Py_END_ALLOW_THREADS - if (err.code == AEROSPIKE_OK) { - Py_BEGIN_ALLOW_THREADS - aerospike_index_create_wait(&err, &task, 2000); - Py_END_ALLOW_THREADS - } - - if (ctx_ref) { - as_cdt_ctx_destroy(ctx_ref); - } + // Python Function Arguments + PyObject *py_policy = NULL; + PyObject *py_ns = NULL; + PyObject *py_set = NULL; + PyObject *py_bin = NULL; + PyObject *py_name = NULL; -CLEANUP2: - Py_XDECREF(py_ctx_dict); + // Python Function Keyword Arguments + static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; -CLEANUP: - if (py_ustr_set) { - Py_DECREF(py_ustr_set); - } - if (py_ustr_bin) { - Py_DECREF(py_ustr_bin); - } - if (py_ustr_name) { - Py_DECREF(py_ustr_name); - } - if (exp) { - as_exp_destroy(exp); - } - if (err.code != AEROSPIKE_OK) { - raise_exception(&err); + // Python Function Argument Parsing + if (PyArg_ParseTupleAndKeywords( + args, kwds, "OOOO|O:index_geo2dsphere_create", kwlist, &py_ns, + &py_set, &py_bin, &py_name, &py_policy) == false) { return NULL; } - return PyLong_FromLong(0); + return convert_python_args_to_c_and_create_index( + self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, + AS_INDEX_GEO2DSPHERE, NULL, NULL); } From ac4646e9a01c94c78717934baefd265adc07a6cd Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Thu, 29 Jan 2026 12:20:17 -0800 Subject: [PATCH 30/42] Revert "Move all the deprecated API functions to the end" This reverts commit 3c8bbdcd0b82026e2e69171b6d5d360f9602e536. --- src/main/client/sec_index.c | 696 ++++++++++++++++++------------------ 1 file changed, 353 insertions(+), 343 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 127559a775..605ebe0040 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -30,178 +30,140 @@ #include "exceptions.h" #include "policy.h" -#define CTX_PARSE_ERROR_MESSAGE "Unable to parse ctx" +static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, + as_error *err); -/* - * Create a complex index on the specified ns/set/bin with the given name and index and data_type. Return PyObject(0) on success - * else return NULL with an error raised. - */ -// exp is optional and can be NULL. -// If exp is non-NULL (i.e we are indexing an expression), py_bin should be NULL. -// This is permissive and allows py_ctx to be None or NULL static PyObject *convert_python_args_to_c_and_create_index( AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, PyObject *py_set, PyObject *py_bin, PyObject *py_name, as_index_type index_type, as_index_datatype data_type, PyObject *py_ctx, - as_exp *exp) + as_exp *exp); + +#define DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE \ + "%s() is deprecated. Please use index_single_value_create() instead" + +// This allows people to see the function calling the Python client API that issues a warning +#define STACK_LEVEL 2 + +/** + ******************************************************************************************************* + * Creates an integer index for a bin in the Aerospike DB. + * + * @param self AerospikeClient object + * @param args The args is a tuple object containing an argument + * list passed from Python to a C function + * @param kwds Dictionary of keywords + * + * Returns an integer status. 0(Zero) is success value. + * In case of error,appropriate exceptions will be raised. + ******************************************************************************************************* + */ +PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) { + PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, + DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, + "index_integer_create"); // Initialize error as_error err; as_error_init(&err); - PyObject *py_ustr_set = NULL; - PyObject *py_ustr_bin = NULL; - PyObject *py_ustr_name = NULL; - - as_policy_info info_policy; - as_policy_info *info_policy_p = NULL; - as_index_task task; - - if (!self || !self->as) { - as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object"); - //raise_exception(&err, -2, "Invalid aerospike object"); - goto CLEANUP; - } - - if (!self->is_conn_16) { - as_error_update(&err, AEROSPIKE_ERR_CLUSTER, - "No connection to aerospike cluster"); - goto CLEANUP; - } + // Python Function Arguments + PyObject *py_policy = NULL; + PyObject *py_ns = NULL; + PyObject *py_set = NULL; + PyObject *py_bin = NULL; + PyObject *py_name = NULL; - // Convert python object to policy_info - pyobject_to_policy_info(&err, py_policy, &info_policy, &info_policy_p, - &self->as->config.policies.info, - self->validate_keys, SECOND_AS_POLICY_NONE); - if (err.code != AEROSPIKE_OK) { - goto CLEANUP; - } + // Python Function Keyword Arguments + static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; - // Convert python object into namespace string - if (!PyUnicode_Check(py_ns)) { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Namespace should be a string"); - goto CLEANUP; + // Python Function Argument Parsing + if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_integer_create", + kwlist, &py_ns, &py_set, &py_bin, &py_name, + &py_policy) == false) { + return NULL; } - char *namespace = (char *)PyUnicode_AsUTF8(py_ns); - // Convert python object into set string - char *set_ptr = NULL; - if (PyUnicode_Check(py_set)) { - py_ustr_set = PyUnicode_AsUTF8String(py_set); - set_ptr = PyBytes_AsString(py_ustr_set); - } - else if (py_set != Py_None) { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Set should be string, unicode or None"); - goto CLEANUP; - } + return convert_python_args_to_c_and_create_index( + self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, + AS_INDEX_NUMERIC, NULL, NULL); +} - // Convert python object into bin string - char *bin_ptr = NULL; - if (py_bin) { - if (PyUnicode_Check(py_bin)) { - py_ustr_bin = PyUnicode_AsUTF8String(py_bin); - bin_ptr = PyBytes_AsString(py_ustr_bin); - } - else if (PyByteArray_Check(py_bin)) { - bin_ptr = PyByteArray_AsString(py_bin); - } - else { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Bin should be a string"); - goto CLEANUP; - } - } +/** + ******************************************************************************************************* + * Creates a string index for a bin in the Aerospike DB. + * + * @param self AerospikeClient object + * @param args The args is a tuple object containing an argument + * list passed from Python to a C function + * @param kwds Dictionary of keywords + * + * Returns an integer status. 0(Zero) is success value. + * In case of error,appropriate exceptions will be raised. + ******************************************************************************************************* + */ +PyObject *AerospikeClient_Index_String_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) +{ + PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, + DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, + "index_string_create"); - // Convert PyObject into the name of the index - char *name = NULL; - if (PyUnicode_Check(py_name)) { - py_ustr_name = PyUnicode_AsUTF8String(py_name); - name = PyBytes_AsString(py_ustr_name); - } - else { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Index name should be string or unicode"); - goto CLEANUP; - } + // Initialize error + as_error err; + as_error_init(&err); - // TODO: this should be refactored by using a new helper function to parse a ctx list instead of get_cdt_ctx() - // which only parses a dictionary containing a ctx list - as_cdt_ctx ctx; - bool ctx_in_use = false; - PyObject *py_ctx_dict = NULL; - if (py_ctx && !Py_IsNone(py_ctx)) { - py_ctx_dict = PyDict_New(); - if (!py_ctx_dict) { - as_error_update(&err, AEROSPIKE_ERR_CLIENT, - CTX_PARSE_ERROR_MESSAGE); - goto CLEANUP; - } - int retval = PyDict_SetItemString(py_ctx_dict, "ctx", py_ctx); - if (retval == -1) { - as_error_update(&err, AEROSPIKE_ERR_CLIENT, - CTX_PARSE_ERROR_MESSAGE); - goto CLEANUP2; - } + // Python Function Arguments + PyObject *py_policy = NULL; + PyObject *py_ns = NULL; + PyObject *py_set = NULL; + PyObject *py_bin = NULL; + PyObject *py_name = NULL; - as_static_pool static_pool; - memset(&static_pool, 0, sizeof(static_pool)); + // Python Function Keyword Arguments + static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; - if (get_cdt_ctx(self, &err, &ctx, py_ctx_dict, &ctx_in_use, - &static_pool, SERIALIZER_PYTHON) != AEROSPIKE_OK) { - goto CLEANUP2; - } + // Python Function Argument Parsing + if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_string_create", + kwlist, &py_ns, &py_set, &py_bin, &py_name, + &py_policy) == false) { + return NULL; } - as_cdt_ctx *ctx_ref = ctx_in_use ? &ctx : NULL; + return convert_python_args_to_c_and_create_index( + self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, + AS_INDEX_STRING, NULL, NULL); +} - // Invoke operation - Py_BEGIN_ALLOW_THREADS - if (exp) { - aerospike_index_create_exp(self->as, &err, &task, info_policy_p, - namespace, set_ptr, name, index_type, - data_type, exp); - } - else { - aerospike_index_create_ctx(self->as, &err, &task, info_policy_p, - namespace, set_ptr, bin_ptr, name, - index_type, data_type, ctx_ref); - } - Py_END_ALLOW_THREADS - if (err.code == AEROSPIKE_OK) { - Py_BEGIN_ALLOW_THREADS - aerospike_index_create_wait(&err, &task, 2000); - Py_END_ALLOW_THREADS - } +PyObject *AerospikeClient_Index_Blob_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) +{ + PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, + DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, + "index_blob_create"); - if (ctx_ref) { - as_cdt_ctx_destroy(ctx_ref); - } + // Python Function Arguments + PyObject *py_policy = NULL; + PyObject *py_ns = NULL; + PyObject *py_set = NULL; + PyObject *py_bin = NULL; + PyObject *py_name = NULL; -CLEANUP2: - Py_XDECREF(py_ctx_dict); + // Python Function Keyword Arguments + static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; -CLEANUP: - if (py_ustr_set) { - Py_DECREF(py_ustr_set); - } - if (py_ustr_bin) { - Py_DECREF(py_ustr_bin); - } - if (py_ustr_name) { - Py_DECREF(py_ustr_name); - } - if (exp) { - as_exp_destroy(exp); - } - if (err.code != AEROSPIKE_OK) { - raise_exception(&err); + // Python Function Argument Parsing + if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_blob_create", + kwlist, &py_ns, &py_set, &py_bin, &py_name, + &py_policy) == false) { return NULL; } - return PyLong_FromLong(0); + return convert_python_args_to_c_and_create_index( + self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, + AS_INDEX_BLOB, NULL, NULL); } PyObject *AerospikeClient_Index_Expr_Create(AerospikeClient *self, @@ -242,42 +204,7 @@ PyObject *AerospikeClient_Index_Expr_Create(AerospikeClient *self, NULL, expr); } -/* - * Convert a PyObject into an as_index_datatype, return False if the conversion fails for any reason. - */ -static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, - as_error *err) -{ - - long type = 0; - if (PyLong_Check(py_datatype)) { - type = PyLong_AsLong(py_datatype); - if (type == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - as_error_update(err, AEROSPIKE_ERR_PARAM, - "integer value exceeds sys.maxsize"); - goto CLEANUP; - } - } - } - else { - as_error_update(err, AEROSPIKE_ERR_PARAM, - "Index type must be an integer"); - goto CLEANUP; - } - - *idx_datatype = type; - -CLEANUP: - if (err->code != AEROSPIKE_OK) { - raise_exception(err); - return false; - } - return true; -} - -// This allows people to see the function calling the Python client API that issues a warning -#define STACK_LEVEL 2 +#define CTX_PARSE_ERROR_MESSAGE "Unable to parse ctx" /** ******************************************************************************************************* @@ -354,6 +281,8 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, self, py_policy, py_ns, py_set, py_bin, py_name, index_type, data_type, py_ctx, NULL); + // as_cdt_ctx_destroy(&ctx); + CLEANUP: if (err.code != AEROSPIKE_OK) { raise_exception_base(&err, Py_None, Py_None, Py_None, Py_None, py_name); @@ -362,76 +291,6 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, return py_obj; } -// TODO: way to get method name dynamically for error message? -static inline PyObject * -create_index_with_known_index_type(AerospikeClient *self, PyObject *args, - PyObject *kwds, as_index_type index_type, - const char *ml_name) -{ - // Initialize error - as_error err; - as_error_init(&err); - - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; - PyObject *py_datatype = NULL; - PyObject *py_ctx = NULL; - - static char *kwlist[] = {"ns", "set", "bin", "index_datatype", - "name", "policy", "ctx", NULL}; - - char format[256]; - snprintf(format, 256, "OOOOO|OO:%s", ml_name); - if (PyArg_ParseTupleAndKeywords(args, kwds, format, kwlist, &py_ns, &py_set, - &py_bin, &py_datatype, &py_name, &py_policy, - &py_ctx) == false) { - return NULL; - } - - as_index_datatype index_datatype = AS_INDEX_STRING; - if (!getTypeFromPyObject(py_datatype, (int *)&index_datatype, &err)) { - return NULL; - } - - return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, index_type, - index_datatype, py_ctx, NULL); -} - -PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, - PyObject *args, - PyObject *kwds) -{ - return create_index_with_known_index_type( - self, args, kwds, AS_INDEX_TYPE_DEFAULT, "index_single_value_create"); -} - -PyObject *AerospikeClient_Index_List_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) -{ - return create_index_with_known_index_type( - self, args, kwds, AS_INDEX_TYPE_LIST, "index_list_create"); -} - -PyObject *AerospikeClient_Index_Map_Keys_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) -{ - return create_index_with_known_index_type( - self, args, kwds, AS_INDEX_TYPE_MAPKEYS, "index_map_keys_create"); -} - -PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, - PyObject *args, - PyObject *kwds) -{ - return create_index_with_known_index_type( - self, args, kwds, AS_INDEX_TYPE_MAPVALUES, "index_map_values_create"); -} - /** ******************************************************************************************************* * Removes an index in the Aerospike database. @@ -527,31 +386,12 @@ PyObject *AerospikeClient_Index_Remove(AerospikeClient *self, PyObject *args, return PyLong_FromLong(0); } -// Deprecated API's - -#define DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE \ - "%s() is deprecated. Please use index_single_value_create() instead" - -/** - ******************************************************************************************************* - * Creates an integer index for a bin in the Aerospike DB. - * - * @param self AerospikeClient object - * @param args The args is a tuple object containing an argument - * list passed from Python to a C function - * @param kwds Dictionary of keywords - * - * Returns an integer status. 0(Zero) is success value. - * In case of error,appropriate exceptions will be raised. - ******************************************************************************************************* - */ -PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) +// TODO: way to get method name dynamically for error message? +static inline PyObject * +create_index_with_known_index_type(AerospikeClient *self, PyObject *args, + PyObject *kwds, as_index_type index_type, + const char *ml_name) { - PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, - DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_integer_create"); - // Initialize error as_error err; as_error_init(&err); @@ -562,41 +402,66 @@ PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, PyObject *py_set = NULL; PyObject *py_bin = NULL; PyObject *py_name = NULL; + PyObject *py_datatype = NULL; + PyObject *py_ctx = NULL; - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; + static char *kwlist[] = {"ns", "set", "bin", "index_datatype", + "name", "policy", "ctx", NULL}; - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_integer_create", - kwlist, &py_ns, &py_set, &py_bin, &py_name, - &py_policy) == false) { + char format[256]; + snprintf(format, 256, "OOOOO|OO:%s", ml_name); + if (PyArg_ParseTupleAndKeywords(args, kwds, format, kwlist, &py_ns, &py_set, + &py_bin, &py_datatype, &py_name, &py_policy, + &py_ctx) == false) { + return NULL; + } + + as_index_datatype index_datatype = AS_INDEX_STRING; + if (!getTypeFromPyObject(py_datatype, (int *)&index_datatype, &err)) { return NULL; } return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_NUMERIC, NULL, NULL); + self, py_policy, py_ns, py_set, py_bin, py_name, index_type, + index_datatype, py_ctx, NULL); } -/** - ******************************************************************************************************* - * Creates a string index for a bin in the Aerospike DB. - * - * @param self AerospikeClient object - * @param args The args is a tuple object containing an argument - * list passed from Python to a C function - * @param kwds Dictionary of keywords - * - * Returns an integer status. 0(Zero) is success value. - * In case of error,appropriate exceptions will be raised. - ******************************************************************************************************* - */ -PyObject *AerospikeClient_Index_String_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) +PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, + PyObject *args, + PyObject *kwds) +{ + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_DEFAULT, "index_single_value_create"); +} + +PyObject *AerospikeClient_Index_List_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) +{ + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_LIST, "index_list_create"); +} + +PyObject *AerospikeClient_Index_Map_Keys_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) +{ + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_MAPKEYS, "index_map_keys_create"); +} + +PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, + PyObject *args, + PyObject *kwds) +{ + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_MAPVALUES, "index_map_values_create"); +} + +PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) { PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_string_create"); + "index_geo2dsphere_create"); // Initialize error as_error err; @@ -613,75 +478,220 @@ PyObject *AerospikeClient_Index_String_Create(AerospikeClient *self, static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_string_create", - kwlist, &py_ns, &py_set, &py_bin, &py_name, - &py_policy) == false) { + if (PyArg_ParseTupleAndKeywords( + args, kwds, "OOOO|O:index_geo2dsphere_create", kwlist, &py_ns, + &py_set, &py_bin, &py_name, &py_policy) == false) { return NULL; } return convert_python_args_to_c_and_create_index( self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_STRING, NULL, NULL); + AS_INDEX_GEO2DSPHERE, NULL, NULL); } -PyObject *AerospikeClient_Index_Blob_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) +/* + * Convert a PyObject into an as_index_datatype, return False if the conversion fails for any reason. + */ +static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, + as_error *err) { - PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, - DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_blob_create"); - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; + long type = 0; + if (PyLong_Check(py_datatype)) { + type = PyLong_AsLong(py_datatype); + if (type == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value exceeds sys.maxsize"); + goto CLEANUP; + } + } + } + else { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "Index type must be an integer"); + goto CLEANUP; + } - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; + *idx_datatype = type; - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_blob_create", - kwlist, &py_ns, &py_set, &py_bin, &py_name, - &py_policy) == false) { - return NULL; +CLEANUP: + if (err->code != AEROSPIKE_OK) { + raise_exception(err); + return false; } - - return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_BLOB, NULL, NULL); + return true; } -PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) +/* + * Create a complex index on the specified ns/set/bin with the given name and index and data_type. Return PyObject(0) on success + * else return NULL with an error raised. + */ + +// exp is optional and can be NULL. +// If exp is non-NULL (i.e we are indexing an expression), py_bin should be NULL. +// This is permissive and allows py_ctx to be None or NULL +static PyObject *convert_python_args_to_c_and_create_index( + AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, + PyObject *py_set, PyObject *py_bin, PyObject *py_name, + as_index_type index_type, as_index_datatype data_type, PyObject *py_ctx, + as_exp *exp) { - PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, - DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_geo2dsphere_create"); // Initialize error as_error err; as_error_init(&err); - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; + PyObject *py_ustr_set = NULL; + PyObject *py_ustr_bin = NULL; + PyObject *py_ustr_name = NULL; - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; + as_policy_info info_policy; + as_policy_info *info_policy_p = NULL; + as_index_task task; - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords( - args, kwds, "OOOO|O:index_geo2dsphere_create", kwlist, &py_ns, - &py_set, &py_bin, &py_name, &py_policy) == false) { + if (!self || !self->as) { + as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object"); + //raise_exception(&err, -2, "Invalid aerospike object"); + goto CLEANUP; + } + + if (!self->is_conn_16) { + as_error_update(&err, AEROSPIKE_ERR_CLUSTER, + "No connection to aerospike cluster"); + goto CLEANUP; + } + + // Convert python object to policy_info + pyobject_to_policy_info(&err, py_policy, &info_policy, &info_policy_p, + &self->as->config.policies.info, + self->validate_keys, SECOND_AS_POLICY_NONE); + if (err.code != AEROSPIKE_OK) { + goto CLEANUP; + } + + // Convert python object into namespace string + if (!PyUnicode_Check(py_ns)) { + as_error_update(&err, AEROSPIKE_ERR_PARAM, + "Namespace should be a string"); + goto CLEANUP; + } + char *namespace = (char *)PyUnicode_AsUTF8(py_ns); + + // Convert python object into set string + char *set_ptr = NULL; + if (PyUnicode_Check(py_set)) { + py_ustr_set = PyUnicode_AsUTF8String(py_set); + set_ptr = PyBytes_AsString(py_ustr_set); + } + else if (py_set != Py_None) { + as_error_update(&err, AEROSPIKE_ERR_PARAM, + "Set should be string, unicode or None"); + goto CLEANUP; + } + + // Convert python object into bin string + char *bin_ptr = NULL; + if (py_bin) { + if (PyUnicode_Check(py_bin)) { + py_ustr_bin = PyUnicode_AsUTF8String(py_bin); + bin_ptr = PyBytes_AsString(py_ustr_bin); + } + else if (PyByteArray_Check(py_bin)) { + bin_ptr = PyByteArray_AsString(py_bin); + } + else { + as_error_update(&err, AEROSPIKE_ERR_PARAM, + "Bin should be a string"); + goto CLEANUP; + } + } + + // Convert PyObject into the name of the index + char *name = NULL; + if (PyUnicode_Check(py_name)) { + py_ustr_name = PyUnicode_AsUTF8String(py_name); + name = PyBytes_AsString(py_ustr_name); + } + else { + as_error_update(&err, AEROSPIKE_ERR_PARAM, + "Index name should be string or unicode"); + goto CLEANUP; + } + + // TODO: this should be refactored by using a new helper function to parse a ctx list instead of get_cdt_ctx() + // which only parses a dictionary containing a ctx list + as_cdt_ctx ctx; + bool ctx_in_use = false; + PyObject *py_ctx_dict = NULL; + if (py_ctx && !Py_IsNone(py_ctx)) { + py_ctx_dict = PyDict_New(); + if (!py_ctx_dict) { + as_error_update(&err, AEROSPIKE_ERR_CLIENT, + CTX_PARSE_ERROR_MESSAGE); + goto CLEANUP; + } + int retval = PyDict_SetItemString(py_ctx_dict, "ctx", py_ctx); + if (retval == -1) { + as_error_update(&err, AEROSPIKE_ERR_CLIENT, + CTX_PARSE_ERROR_MESSAGE); + goto CLEANUP2; + } + + as_static_pool static_pool; + memset(&static_pool, 0, sizeof(static_pool)); + + if (get_cdt_ctx(self, &err, &ctx, py_ctx_dict, &ctx_in_use, + &static_pool, SERIALIZER_PYTHON) != AEROSPIKE_OK) { + goto CLEANUP2; + } + } + + as_cdt_ctx *ctx_ref = ctx_in_use ? &ctx : NULL; + + // Invoke operation + Py_BEGIN_ALLOW_THREADS + if (exp) { + aerospike_index_create_exp(self->as, &err, &task, info_policy_p, + namespace, set_ptr, name, index_type, + data_type, exp); + } + else { + aerospike_index_create_ctx(self->as, &err, &task, info_policy_p, + namespace, set_ptr, bin_ptr, name, + index_type, data_type, ctx_ref); + } + Py_END_ALLOW_THREADS + if (err.code == AEROSPIKE_OK) { + Py_BEGIN_ALLOW_THREADS + aerospike_index_create_wait(&err, &task, 2000); + Py_END_ALLOW_THREADS + } + + if (ctx_ref) { + as_cdt_ctx_destroy(ctx_ref); + } + +CLEANUP2: + Py_XDECREF(py_ctx_dict); + +CLEANUP: + if (py_ustr_set) { + Py_DECREF(py_ustr_set); + } + if (py_ustr_bin) { + Py_DECREF(py_ustr_bin); + } + if (py_ustr_name) { + Py_DECREF(py_ustr_name); + } + if (exp) { + as_exp_destroy(exp); + } + if (err.code != AEROSPIKE_OK) { + raise_exception(&err); return NULL; } - return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_GEO2DSPHERE, NULL, NULL); + return PyLong_FromLong(0); } From 94dd0a0278eb5a6c4294c1e7de91894b7751a860 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Thu, 29 Jan 2026 12:09:23 -0800 Subject: [PATCH 31/42] Move all the deprecated API functions to the end --- src/main/client/sec_index.c | 702 ++++++++++++++++++------------------ 1 file changed, 346 insertions(+), 356 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 605ebe0040..127559a775 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -30,140 +30,178 @@ #include "exceptions.h" #include "policy.h" -static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, - as_error *err); +#define CTX_PARSE_ERROR_MESSAGE "Unable to parse ctx" +/* + * Create a complex index on the specified ns/set/bin with the given name and index and data_type. Return PyObject(0) on success + * else return NULL with an error raised. + */ +// exp is optional and can be NULL. +// If exp is non-NULL (i.e we are indexing an expression), py_bin should be NULL. +// This is permissive and allows py_ctx to be None or NULL static PyObject *convert_python_args_to_c_and_create_index( AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, PyObject *py_set, PyObject *py_bin, PyObject *py_name, as_index_type index_type, as_index_datatype data_type, PyObject *py_ctx, - as_exp *exp); - -#define DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE \ - "%s() is deprecated. Please use index_single_value_create() instead" - -// This allows people to see the function calling the Python client API that issues a warning -#define STACK_LEVEL 2 - -/** - ******************************************************************************************************* - * Creates an integer index for a bin in the Aerospike DB. - * - * @param self AerospikeClient object - * @param args The args is a tuple object containing an argument - * list passed from Python to a C function - * @param kwds Dictionary of keywords - * - * Returns an integer status. 0(Zero) is success value. - * In case of error,appropriate exceptions will be raised. - ******************************************************************************************************* - */ -PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) + as_exp *exp) { - PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, - DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_integer_create"); // Initialize error as_error err; as_error_init(&err); - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; + PyObject *py_ustr_set = NULL; + PyObject *py_ustr_bin = NULL; + PyObject *py_ustr_name = NULL; - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; + as_policy_info info_policy; + as_policy_info *info_policy_p = NULL; + as_index_task task; - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_integer_create", - kwlist, &py_ns, &py_set, &py_bin, &py_name, - &py_policy) == false) { - return NULL; + if (!self || !self->as) { + as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object"); + //raise_exception(&err, -2, "Invalid aerospike object"); + goto CLEANUP; } - return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_NUMERIC, NULL, NULL); -} + if (!self->is_conn_16) { + as_error_update(&err, AEROSPIKE_ERR_CLUSTER, + "No connection to aerospike cluster"); + goto CLEANUP; + } -/** - ******************************************************************************************************* - * Creates a string index for a bin in the Aerospike DB. - * - * @param self AerospikeClient object - * @param args The args is a tuple object containing an argument - * list passed from Python to a C function - * @param kwds Dictionary of keywords - * - * Returns an integer status. 0(Zero) is success value. - * In case of error,appropriate exceptions will be raised. - ******************************************************************************************************* - */ -PyObject *AerospikeClient_Index_String_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) -{ - PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, - DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_string_create"); + // Convert python object to policy_info + pyobject_to_policy_info(&err, py_policy, &info_policy, &info_policy_p, + &self->as->config.policies.info, + self->validate_keys, SECOND_AS_POLICY_NONE); + if (err.code != AEROSPIKE_OK) { + goto CLEANUP; + } - // Initialize error - as_error err; - as_error_init(&err); + // Convert python object into namespace string + if (!PyUnicode_Check(py_ns)) { + as_error_update(&err, AEROSPIKE_ERR_PARAM, + "Namespace should be a string"); + goto CLEANUP; + } + char *namespace = (char *)PyUnicode_AsUTF8(py_ns); - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; + // Convert python object into set string + char *set_ptr = NULL; + if (PyUnicode_Check(py_set)) { + py_ustr_set = PyUnicode_AsUTF8String(py_set); + set_ptr = PyBytes_AsString(py_ustr_set); + } + else if (py_set != Py_None) { + as_error_update(&err, AEROSPIKE_ERR_PARAM, + "Set should be string, unicode or None"); + goto CLEANUP; + } - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; + // Convert python object into bin string + char *bin_ptr = NULL; + if (py_bin) { + if (PyUnicode_Check(py_bin)) { + py_ustr_bin = PyUnicode_AsUTF8String(py_bin); + bin_ptr = PyBytes_AsString(py_ustr_bin); + } + else if (PyByteArray_Check(py_bin)) { + bin_ptr = PyByteArray_AsString(py_bin); + } + else { + as_error_update(&err, AEROSPIKE_ERR_PARAM, + "Bin should be a string"); + goto CLEANUP; + } + } - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_string_create", - kwlist, &py_ns, &py_set, &py_bin, &py_name, - &py_policy) == false) { - return NULL; + // Convert PyObject into the name of the index + char *name = NULL; + if (PyUnicode_Check(py_name)) { + py_ustr_name = PyUnicode_AsUTF8String(py_name); + name = PyBytes_AsString(py_ustr_name); + } + else { + as_error_update(&err, AEROSPIKE_ERR_PARAM, + "Index name should be string or unicode"); + goto CLEANUP; } - return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_STRING, NULL, NULL); -} + // TODO: this should be refactored by using a new helper function to parse a ctx list instead of get_cdt_ctx() + // which only parses a dictionary containing a ctx list + as_cdt_ctx ctx; + bool ctx_in_use = false; + PyObject *py_ctx_dict = NULL; + if (py_ctx && !Py_IsNone(py_ctx)) { + py_ctx_dict = PyDict_New(); + if (!py_ctx_dict) { + as_error_update(&err, AEROSPIKE_ERR_CLIENT, + CTX_PARSE_ERROR_MESSAGE); + goto CLEANUP; + } + int retval = PyDict_SetItemString(py_ctx_dict, "ctx", py_ctx); + if (retval == -1) { + as_error_update(&err, AEROSPIKE_ERR_CLIENT, + CTX_PARSE_ERROR_MESSAGE); + goto CLEANUP2; + } -PyObject *AerospikeClient_Index_Blob_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) -{ - PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, - DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_blob_create"); + as_static_pool static_pool; + memset(&static_pool, 0, sizeof(static_pool)); - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; + if (get_cdt_ctx(self, &err, &ctx, py_ctx_dict, &ctx_in_use, + &static_pool, SERIALIZER_PYTHON) != AEROSPIKE_OK) { + goto CLEANUP2; + } + } - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; + as_cdt_ctx *ctx_ref = ctx_in_use ? &ctx : NULL; - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_blob_create", - kwlist, &py_ns, &py_set, &py_bin, &py_name, - &py_policy) == false) { + // Invoke operation + Py_BEGIN_ALLOW_THREADS + if (exp) { + aerospike_index_create_exp(self->as, &err, &task, info_policy_p, + namespace, set_ptr, name, index_type, + data_type, exp); + } + else { + aerospike_index_create_ctx(self->as, &err, &task, info_policy_p, + namespace, set_ptr, bin_ptr, name, + index_type, data_type, ctx_ref); + } + Py_END_ALLOW_THREADS + if (err.code == AEROSPIKE_OK) { + Py_BEGIN_ALLOW_THREADS + aerospike_index_create_wait(&err, &task, 2000); + Py_END_ALLOW_THREADS + } + + if (ctx_ref) { + as_cdt_ctx_destroy(ctx_ref); + } + +CLEANUP2: + Py_XDECREF(py_ctx_dict); + +CLEANUP: + if (py_ustr_set) { + Py_DECREF(py_ustr_set); + } + if (py_ustr_bin) { + Py_DECREF(py_ustr_bin); + } + if (py_ustr_name) { + Py_DECREF(py_ustr_name); + } + if (exp) { + as_exp_destroy(exp); + } + if (err.code != AEROSPIKE_OK) { + raise_exception(&err); return NULL; } - return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_BLOB, NULL, NULL); + return PyLong_FromLong(0); } PyObject *AerospikeClient_Index_Expr_Create(AerospikeClient *self, @@ -204,11 +242,46 @@ PyObject *AerospikeClient_Index_Expr_Create(AerospikeClient *self, NULL, expr); } -#define CTX_PARSE_ERROR_MESSAGE "Unable to parse ctx" +/* + * Convert a PyObject into an as_index_datatype, return False if the conversion fails for any reason. + */ +static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, + as_error *err) +{ -/** - ******************************************************************************************************* - * Creates a cdt index for a bin in the Aerospike DB. + long type = 0; + if (PyLong_Check(py_datatype)) { + type = PyLong_AsLong(py_datatype); + if (type == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_OverflowError)) { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "integer value exceeds sys.maxsize"); + goto CLEANUP; + } + } + } + else { + as_error_update(err, AEROSPIKE_ERR_PARAM, + "Index type must be an integer"); + goto CLEANUP; + } + + *idx_datatype = type; + +CLEANUP: + if (err->code != AEROSPIKE_OK) { + raise_exception(err); + return false; + } + return true; +} + +// This allows people to see the function calling the Python client API that issues a warning +#define STACK_LEVEL 2 + +/** + ******************************************************************************************************* + * Creates a cdt index for a bin in the Aerospike DB. * * @param self AerospikeClient object * @param args The args is a tuple object containing an argument @@ -281,8 +354,6 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, self, py_policy, py_ns, py_set, py_bin, py_name, index_type, data_type, py_ctx, NULL); - // as_cdt_ctx_destroy(&ctx); - CLEANUP: if (err.code != AEROSPIKE_OK) { raise_exception_base(&err, Py_None, Py_None, Py_None, Py_None, py_name); @@ -291,6 +362,76 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, return py_obj; } +// TODO: way to get method name dynamically for error message? +static inline PyObject * +create_index_with_known_index_type(AerospikeClient *self, PyObject *args, + PyObject *kwds, as_index_type index_type, + const char *ml_name) +{ + // Initialize error + as_error err; + as_error_init(&err); + + // Python Function Arguments + PyObject *py_policy = NULL; + PyObject *py_ns = NULL; + PyObject *py_set = NULL; + PyObject *py_bin = NULL; + PyObject *py_name = NULL; + PyObject *py_datatype = NULL; + PyObject *py_ctx = NULL; + + static char *kwlist[] = {"ns", "set", "bin", "index_datatype", + "name", "policy", "ctx", NULL}; + + char format[256]; + snprintf(format, 256, "OOOOO|OO:%s", ml_name); + if (PyArg_ParseTupleAndKeywords(args, kwds, format, kwlist, &py_ns, &py_set, + &py_bin, &py_datatype, &py_name, &py_policy, + &py_ctx) == false) { + return NULL; + } + + as_index_datatype index_datatype = AS_INDEX_STRING; + if (!getTypeFromPyObject(py_datatype, (int *)&index_datatype, &err)) { + return NULL; + } + + return convert_python_args_to_c_and_create_index( + self, py_policy, py_ns, py_set, py_bin, py_name, index_type, + index_datatype, py_ctx, NULL); +} + +PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, + PyObject *args, + PyObject *kwds) +{ + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_DEFAULT, "index_single_value_create"); +} + +PyObject *AerospikeClient_Index_List_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) +{ + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_LIST, "index_list_create"); +} + +PyObject *AerospikeClient_Index_Map_Keys_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) +{ + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_MAPKEYS, "index_map_keys_create"); +} + +PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, + PyObject *args, + PyObject *kwds) +{ + return create_index_with_known_index_type( + self, args, kwds, AS_INDEX_TYPE_MAPVALUES, "index_map_values_create"); +} + /** ******************************************************************************************************* * Removes an index in the Aerospike database. @@ -386,12 +527,31 @@ PyObject *AerospikeClient_Index_Remove(AerospikeClient *self, PyObject *args, return PyLong_FromLong(0); } -// TODO: way to get method name dynamically for error message? -static inline PyObject * -create_index_with_known_index_type(AerospikeClient *self, PyObject *args, - PyObject *kwds, as_index_type index_type, - const char *ml_name) +// Deprecated API's + +#define DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE \ + "%s() is deprecated. Please use index_single_value_create() instead" + +/** + ******************************************************************************************************* + * Creates an integer index for a bin in the Aerospike DB. + * + * @param self AerospikeClient object + * @param args The args is a tuple object containing an argument + * list passed from Python to a C function + * @param kwds Dictionary of keywords + * + * Returns an integer status. 0(Zero) is success value. + * In case of error,appropriate exceptions will be raised. + ******************************************************************************************************* + */ +PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) { + PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, + DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, + "index_integer_create"); + // Initialize error as_error err; as_error_init(&err); @@ -402,66 +562,41 @@ create_index_with_known_index_type(AerospikeClient *self, PyObject *args, PyObject *py_set = NULL; PyObject *py_bin = NULL; PyObject *py_name = NULL; - PyObject *py_datatype = NULL; - PyObject *py_ctx = NULL; - static char *kwlist[] = {"ns", "set", "bin", "index_datatype", - "name", "policy", "ctx", NULL}; - - char format[256]; - snprintf(format, 256, "OOOOO|OO:%s", ml_name); - if (PyArg_ParseTupleAndKeywords(args, kwds, format, kwlist, &py_ns, &py_set, - &py_bin, &py_datatype, &py_name, &py_policy, - &py_ctx) == false) { - return NULL; - } + // Python Function Keyword Arguments + static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; - as_index_datatype index_datatype = AS_INDEX_STRING; - if (!getTypeFromPyObject(py_datatype, (int *)&index_datatype, &err)) { + // Python Function Argument Parsing + if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_integer_create", + kwlist, &py_ns, &py_set, &py_bin, &py_name, + &py_policy) == false) { return NULL; } return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, index_type, - index_datatype, py_ctx, NULL); -} - -PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, - PyObject *args, - PyObject *kwds) -{ - return create_index_with_known_index_type( - self, args, kwds, AS_INDEX_TYPE_DEFAULT, "index_single_value_create"); -} - -PyObject *AerospikeClient_Index_List_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) -{ - return create_index_with_known_index_type( - self, args, kwds, AS_INDEX_TYPE_LIST, "index_list_create"); -} - -PyObject *AerospikeClient_Index_Map_Keys_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) -{ - return create_index_with_known_index_type( - self, args, kwds, AS_INDEX_TYPE_MAPKEYS, "index_map_keys_create"); -} - -PyObject *AerospikeClient_Index_Map_Values_Create(AerospikeClient *self, - PyObject *args, - PyObject *kwds) -{ - return create_index_with_known_index_type( - self, args, kwds, AS_INDEX_TYPE_MAPVALUES, "index_map_values_create"); + self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, + AS_INDEX_NUMERIC, NULL, NULL); } -PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) +/** + ******************************************************************************************************* + * Creates a string index for a bin in the Aerospike DB. + * + * @param self AerospikeClient object + * @param args The args is a tuple object containing an argument + * list passed from Python to a C function + * @param kwds Dictionary of keywords + * + * Returns an integer status. 0(Zero) is success value. + * In case of error,appropriate exceptions will be raised. + ******************************************************************************************************* + */ +PyObject *AerospikeClient_Index_String_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) { PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_geo2dsphere_create"); + "index_string_create"); // Initialize error as_error err; @@ -478,220 +613,75 @@ PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords( - args, kwds, "OOOO|O:index_geo2dsphere_create", kwlist, &py_ns, - &py_set, &py_bin, &py_name, &py_policy) == false) { + if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_string_create", + kwlist, &py_ns, &py_set, &py_bin, &py_name, + &py_policy) == false) { return NULL; } return convert_python_args_to_c_and_create_index( self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_GEO2DSPHERE, NULL, NULL); + AS_INDEX_STRING, NULL, NULL); } -/* - * Convert a PyObject into an as_index_datatype, return False if the conversion fails for any reason. - */ -static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, - as_error *err) +PyObject *AerospikeClient_Index_Blob_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) { + PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, + DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, + "index_blob_create"); - long type = 0; - if (PyLong_Check(py_datatype)) { - type = PyLong_AsLong(py_datatype); - if (type == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - as_error_update(err, AEROSPIKE_ERR_PARAM, - "integer value exceeds sys.maxsize"); - goto CLEANUP; - } - } - } - else { - as_error_update(err, AEROSPIKE_ERR_PARAM, - "Index type must be an integer"); - goto CLEANUP; - } + // Python Function Arguments + PyObject *py_policy = NULL; + PyObject *py_ns = NULL; + PyObject *py_set = NULL; + PyObject *py_bin = NULL; + PyObject *py_name = NULL; - *idx_datatype = type; + // Python Function Keyword Arguments + static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; -CLEANUP: - if (err->code != AEROSPIKE_OK) { - raise_exception(err); - return false; + // Python Function Argument Parsing + if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_blob_create", + kwlist, &py_ns, &py_set, &py_bin, &py_name, + &py_policy) == false) { + return NULL; } - return true; -} -/* - * Create a complex index on the specified ns/set/bin with the given name and index and data_type. Return PyObject(0) on success - * else return NULL with an error raised. - */ + return convert_python_args_to_c_and_create_index( + self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, + AS_INDEX_BLOB, NULL, NULL); +} -// exp is optional and can be NULL. -// If exp is non-NULL (i.e we are indexing an expression), py_bin should be NULL. -// This is permissive and allows py_ctx to be None or NULL -static PyObject *convert_python_args_to_c_and_create_index( - AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, - PyObject *py_set, PyObject *py_bin, PyObject *py_name, - as_index_type index_type, as_index_datatype data_type, PyObject *py_ctx, - as_exp *exp) +PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) { + PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, + DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, + "index_geo2dsphere_create"); // Initialize error as_error err; as_error_init(&err); - PyObject *py_ustr_set = NULL; - PyObject *py_ustr_bin = NULL; - PyObject *py_ustr_name = NULL; - - as_policy_info info_policy; - as_policy_info *info_policy_p = NULL; - as_index_task task; - - if (!self || !self->as) { - as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object"); - //raise_exception(&err, -2, "Invalid aerospike object"); - goto CLEANUP; - } - - if (!self->is_conn_16) { - as_error_update(&err, AEROSPIKE_ERR_CLUSTER, - "No connection to aerospike cluster"); - goto CLEANUP; - } - - // Convert python object to policy_info - pyobject_to_policy_info(&err, py_policy, &info_policy, &info_policy_p, - &self->as->config.policies.info, - self->validate_keys, SECOND_AS_POLICY_NONE); - if (err.code != AEROSPIKE_OK) { - goto CLEANUP; - } - - // Convert python object into namespace string - if (!PyUnicode_Check(py_ns)) { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Namespace should be a string"); - goto CLEANUP; - } - char *namespace = (char *)PyUnicode_AsUTF8(py_ns); - - // Convert python object into set string - char *set_ptr = NULL; - if (PyUnicode_Check(py_set)) { - py_ustr_set = PyUnicode_AsUTF8String(py_set); - set_ptr = PyBytes_AsString(py_ustr_set); - } - else if (py_set != Py_None) { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Set should be string, unicode or None"); - goto CLEANUP; - } - - // Convert python object into bin string - char *bin_ptr = NULL; - if (py_bin) { - if (PyUnicode_Check(py_bin)) { - py_ustr_bin = PyUnicode_AsUTF8String(py_bin); - bin_ptr = PyBytes_AsString(py_ustr_bin); - } - else if (PyByteArray_Check(py_bin)) { - bin_ptr = PyByteArray_AsString(py_bin); - } - else { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Bin should be a string"); - goto CLEANUP; - } - } - - // Convert PyObject into the name of the index - char *name = NULL; - if (PyUnicode_Check(py_name)) { - py_ustr_name = PyUnicode_AsUTF8String(py_name); - name = PyBytes_AsString(py_ustr_name); - } - else { - as_error_update(&err, AEROSPIKE_ERR_PARAM, - "Index name should be string or unicode"); - goto CLEANUP; - } - - // TODO: this should be refactored by using a new helper function to parse a ctx list instead of get_cdt_ctx() - // which only parses a dictionary containing a ctx list - as_cdt_ctx ctx; - bool ctx_in_use = false; - PyObject *py_ctx_dict = NULL; - if (py_ctx && !Py_IsNone(py_ctx)) { - py_ctx_dict = PyDict_New(); - if (!py_ctx_dict) { - as_error_update(&err, AEROSPIKE_ERR_CLIENT, - CTX_PARSE_ERROR_MESSAGE); - goto CLEANUP; - } - int retval = PyDict_SetItemString(py_ctx_dict, "ctx", py_ctx); - if (retval == -1) { - as_error_update(&err, AEROSPIKE_ERR_CLIENT, - CTX_PARSE_ERROR_MESSAGE); - goto CLEANUP2; - } - - as_static_pool static_pool; - memset(&static_pool, 0, sizeof(static_pool)); - - if (get_cdt_ctx(self, &err, &ctx, py_ctx_dict, &ctx_in_use, - &static_pool, SERIALIZER_PYTHON) != AEROSPIKE_OK) { - goto CLEANUP2; - } - } - - as_cdt_ctx *ctx_ref = ctx_in_use ? &ctx : NULL; - - // Invoke operation - Py_BEGIN_ALLOW_THREADS - if (exp) { - aerospike_index_create_exp(self->as, &err, &task, info_policy_p, - namespace, set_ptr, name, index_type, - data_type, exp); - } - else { - aerospike_index_create_ctx(self->as, &err, &task, info_policy_p, - namespace, set_ptr, bin_ptr, name, - index_type, data_type, ctx_ref); - } - Py_END_ALLOW_THREADS - if (err.code == AEROSPIKE_OK) { - Py_BEGIN_ALLOW_THREADS - aerospike_index_create_wait(&err, &task, 2000); - Py_END_ALLOW_THREADS - } - - if (ctx_ref) { - as_cdt_ctx_destroy(ctx_ref); - } + // Python Function Arguments + PyObject *py_policy = NULL; + PyObject *py_ns = NULL; + PyObject *py_set = NULL; + PyObject *py_bin = NULL; + PyObject *py_name = NULL; -CLEANUP2: - Py_XDECREF(py_ctx_dict); + // Python Function Keyword Arguments + static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; -CLEANUP: - if (py_ustr_set) { - Py_DECREF(py_ustr_set); - } - if (py_ustr_bin) { - Py_DECREF(py_ustr_bin); - } - if (py_ustr_name) { - Py_DECREF(py_ustr_name); - } - if (exp) { - as_exp_destroy(exp); - } - if (err.code != AEROSPIKE_OK) { - raise_exception(&err); + // Python Function Argument Parsing + if (PyArg_ParseTupleAndKeywords( + args, kwds, "OOOO|O:index_geo2dsphere_create", kwlist, &py_ns, + &py_set, &py_bin, &py_name, &py_policy) == false) { return NULL; } - return PyLong_FromLong(0); + return convert_python_args_to_c_and_create_index( + self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, + AS_INDEX_GEO2DSPHERE, NULL, NULL); } From 1483b8c63ef15f4b1802cfa7bf47b859cd5cf34a Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 2 Feb 2026 08:59:42 -0800 Subject: [PATCH 32/42] Review and finalize code changes. TODO tests --- src/main/client/sec_index.c | 103 +++++++++++++----------------------- 1 file changed, 38 insertions(+), 65 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 127559a775..957eb1c270 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -39,11 +39,17 @@ // exp is optional and can be NULL. // If exp is non-NULL (i.e we are indexing an expression), py_bin should be NULL. // This is permissive and allows py_ctx to be None or NULL +// +// NOTE: data_type and index_type are integers because some index creation methods i.e index_expr_create +// take in an C integer directly as an argument, but the rest of the index creation methods take in a PyObject +// that needs to be converted to a C integer on our end. +// To handle both cases, we just have each individual index creation method convert those parameters to C integers +// if needed. static PyObject *convert_python_args_to_c_and_create_index( AerospikeClient *self, PyObject *py_policy, PyObject *py_ns, PyObject *py_set, PyObject *py_bin, PyObject *py_name, as_index_type index_type, as_index_datatype data_type, PyObject *py_ctx, - as_exp *exp) + PyObject *py_expr) { // Initialize error @@ -60,7 +66,6 @@ static PyObject *convert_python_args_to_c_and_create_index( if (!self || !self->as) { as_error_update(&err, AEROSPIKE_ERR_PARAM, "Invalid aerospike object"); - //raise_exception(&err, -2, "Invalid aerospike object"); goto CLEANUP; } @@ -157,12 +162,18 @@ static PyObject *convert_python_args_to_c_and_create_index( as_cdt_ctx *ctx_ref = ctx_in_use ? &ctx : NULL; + as_exp *expr = NULL; + if (py_expr && as_exp_new_from_pyobject(self, py_expr, &expr, &err, + false) != AEROSPIKE_OK) { + goto CLEANUP3; + } + // Invoke operation Py_BEGIN_ALLOW_THREADS if (exp) { aerospike_index_create_exp(self->as, &err, &task, info_policy_p, namespace, set_ptr, name, index_type, - data_type, exp); + data_type, expr); } else { aerospike_index_create_ctx(self->as, &err, &task, info_policy_p, @@ -176,6 +187,11 @@ static PyObject *convert_python_args_to_c_and_create_index( Py_END_ALLOW_THREADS } + if (expr) { + as_exp_destroy(expr); + } + +CLEANUP3: if (ctx_ref) { as_cdt_ctx_destroy(ctx_ref); } @@ -193,9 +209,6 @@ static PyObject *convert_python_args_to_c_and_create_index( if (py_ustr_name) { Py_DECREF(py_ustr_name); } - if (exp) { - as_exp_destroy(exp); - } if (err.code != AEROSPIKE_OK) { raise_exception(&err); return NULL; @@ -213,7 +226,6 @@ PyObject *AerospikeClient_Index_Expr_Create(AerospikeClient *self, PyObject *py_expr = NULL; as_index_type index_type; as_index_datatype data_type; - as_exp *expr = NULL; PyObject *py_name = NULL; PyObject *py_policy = NULL; @@ -229,51 +241,9 @@ PyObject *AerospikeClient_Index_Expr_Create(AerospikeClient *self, return NULL; } - as_error err; - as_error_init(&err); - if (as_exp_new_from_pyobject(self, py_expr, &expr, &err, false) != - AEROSPIKE_OK) { - raise_exception(&err); - return NULL; - } - return convert_python_args_to_c_and_create_index( self, py_policy, py_ns, py_set, NULL, py_name, index_type, data_type, - NULL, expr); -} - -/* - * Convert a PyObject into an as_index_datatype, return False if the conversion fails for any reason. - */ -static bool getTypeFromPyObject(PyObject *py_datatype, int *idx_datatype, - as_error *err) -{ - - long type = 0; - if (PyLong_Check(py_datatype)) { - type = PyLong_AsLong(py_datatype); - if (type == -1 && PyErr_Occurred()) { - if (PyErr_ExceptionMatches(PyExc_OverflowError)) { - as_error_update(err, AEROSPIKE_ERR_PARAM, - "integer value exceeds sys.maxsize"); - goto CLEANUP; - } - } - } - else { - as_error_update(err, AEROSPIKE_ERR_PARAM, - "Index type must be an integer"); - goto CLEANUP; - } - - *idx_datatype = type; - -CLEANUP: - if (err->code != AEROSPIKE_OK) { - raise_exception(err); - return false; - } - return true; + NULL, py_expr); } // This allows people to see the function calling the Python client API that issues a warning @@ -315,7 +285,6 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, PyObject *py_ctx = NULL; - PyObject *py_obj = NULL; as_index_datatype data_type; as_index_type index_type; @@ -332,12 +301,14 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, return NULL; } - if (!getTypeFromPyObject(py_indextype, (int *)&index_type, &err)) { - goto CLEANUP; + if (!get_int_from_py_int(&err, py_indextype, (int *)&data_type, + "index_datatype")) { + goto CLEANUP_ON_ERROR; } - if (!getTypeFromPyObject(py_datatype, (int *)&data_type, &err)) { - goto CLEANUP; + if (!get_int_from_py_int(&err, py_datatype, (int *)&index_type, + "index_type")) { + goto CLEANUP_ON_ERROR; } // convert_python_args_to_c_and_create_index, which is called by the new index create method API's, @@ -345,21 +316,18 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, // This API call is the only exception where a list of ctx's is required if (Py_IsNone(py_ctx)) { as_error_update(&err, AEROSPIKE_ERR_PARAM, "ctx cannot be None"); - goto CLEANUP; + goto CLEANUP_ON_ERROR; } // Even if this call fails, it will raise its own exception // and the err object here will not be set. We don't raise an exception twice - py_obj = convert_python_args_to_c_and_create_index( + return convert_python_args_to_c_and_create_index( self, py_policy, py_ns, py_set, py_bin, py_name, index_type, data_type, py_ctx, NULL); -CLEANUP: - if (err.code != AEROSPIKE_OK) { - raise_exception_base(&err, Py_None, Py_None, Py_None, Py_None, py_name); - return NULL; - } - return py_obj; +CLEANUP_ON_ERROR: + raise_exception_base(&err, Py_None, Py_None, Py_None, Py_None, py_name); + return NULL; } // TODO: way to get method name dynamically for error message? @@ -393,13 +361,18 @@ create_index_with_known_index_type(AerospikeClient *self, PyObject *args, } as_index_datatype index_datatype = AS_INDEX_STRING; - if (!getTypeFromPyObject(py_datatype, (int *)&index_datatype, &err)) { - return NULL; + if (!get_int_from_py_int(&err, py_datatype, (int *)&index_datatype, + "index_datatype")) { + goto CLEANUP_ON_ERROR; } return convert_python_args_to_c_and_create_index( self, py_policy, py_ns, py_set, py_bin, py_name, index_type, index_datatype, py_ctx, NULL); + +CLEANUP_ON_ERROR: + raise_exception_base(&err, Py_None, Py_None, Py_None, Py_None, py_name); + return NULL; } PyObject *AerospikeClient_Index_Single_Value_Create(AerospikeClient *self, From 3c85c6aad78b57ed34a8234c46d1938064ea70ce Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 2 Feb 2026 09:07:17 -0800 Subject: [PATCH 33/42] fix --- src/main/client/sec_index.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 957eb1c270..63eb75b73e 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -36,8 +36,8 @@ * Create a complex index on the specified ns/set/bin with the given name and index and data_type. Return PyObject(0) on success * else return NULL with an error raised. */ -// exp is optional and can be NULL. -// If exp is non-NULL (i.e we are indexing an expression), py_bin should be NULL. +// expr is optional and can be NULL. +// If expr is non-NULL (i.e we are indexing an expression), py_bin should be NULL. // This is permissive and allows py_ctx to be None or NULL // // NOTE: data_type and index_type are integers because some index creation methods i.e index_expr_create @@ -170,7 +170,7 @@ static PyObject *convert_python_args_to_c_and_create_index( // Invoke operation Py_BEGIN_ALLOW_THREADS - if (exp) { + if (expr) { aerospike_index_create_exp(self->as, &err, &task, info_policy_p, namespace, set_ptr, name, index_type, data_type, expr); From 6cc6ff69be419bb2a305d943b40df149f0d53d84 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 2 Feb 2026 09:16:32 -0800 Subject: [PATCH 34/42] Fix get_int_from_py_int() assigning PyLong_AsLong()'s return value directly to an integer variable --- src/main/conversions.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/conversions.c b/src/main/conversions.c index 23065d51c7..e869275af0 100644 --- a/src/main/conversions.c +++ b/src/main/conversions.c @@ -2664,7 +2664,7 @@ as_status get_int_from_py_int(as_error *err, PyObject *py_long, "%s must be an integer.", py_object_name); } - int int_to_return = PyLong_AsLong(py_long); + long int_to_return = PyLong_AsLong(py_long); if (PyErr_Occurred()) { if (PyErr_ExceptionMatches(PyExc_OverflowError)) { return as_error_update(err, AEROSPIKE_ERR_PARAM, @@ -2680,7 +2680,7 @@ as_status get_int_from_py_int(as_error *err, PyObject *py_long, "%s too large for C int.", py_object_name); } - *int_pointer = int_to_return; + *int_pointer = (int)int_to_return; return AEROSPIKE_OK; } From 7e3e67bc90c61f743e9f064c567ebff6effbc131 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 2 Feb 2026 11:09:14 -0800 Subject: [PATCH 35/42] Fix since getTypeFromPyObject used to return a bool --- src/main/client/sec_index.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 63eb75b73e..f73db5695f 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -301,13 +301,13 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, return NULL; } - if (!get_int_from_py_int(&err, py_indextype, (int *)&data_type, - "index_datatype")) { + if (get_int_from_py_int(&err, py_indextype, (int *)&data_type, + "index_datatype") != AEROSPIKE_OK) { goto CLEANUP_ON_ERROR; } - if (!get_int_from_py_int(&err, py_datatype, (int *)&index_type, - "index_type")) { + if (get_int_from_py_int(&err, py_datatype, (int *)&index_type, + "index_type") != AEROSPIKE_OK) { goto CLEANUP_ON_ERROR; } @@ -361,8 +361,8 @@ create_index_with_known_index_type(AerospikeClient *self, PyObject *args, } as_index_datatype index_datatype = AS_INDEX_STRING; - if (!get_int_from_py_int(&err, py_datatype, (int *)&index_datatype, - "index_datatype")) { + if (get_int_from_py_int(&err, py_datatype, (int *)&index_datatype, + "index_datatype") != AEROSPIKE_OK) { goto CLEANUP_ON_ERROR; } From 93e2251e30b82076511daed5c8e670dcc04b9f1a Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 2 Feb 2026 12:36:41 -0800 Subject: [PATCH 36/42] Use helper method for deprecated index creation methods to avoid repetition --- src/main/client/sec_index.c | 133 +++++++++--------------------------- 1 file changed, 33 insertions(+), 100 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index f73db5695f..0cadf4b82e 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -505,38 +505,25 @@ PyObject *AerospikeClient_Index_Remove(AerospikeClient *self, PyObject *args, #define DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE \ "%s() is deprecated. Please use index_single_value_create() instead" -/** - ******************************************************************************************************* - * Creates an integer index for a bin in the Aerospike DB. - * - * @param self AerospikeClient object - * @param args The args is a tuple object containing an argument - * list passed from Python to a C function - * @param kwds Dictionary of keywords - * - * Returns an integer status. 0(Zero) is success value. - * In case of error,appropriate exceptions will be raised. - ******************************************************************************************************* - */ -PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, - PyObject *args, PyObject *kwds) +static PyObject * +deprecated_index_create_helper(AerospikeClient *self, PyObject *args, + PyObject *kwds, const char *ml_name, + as_index_datatype index_datatype) { PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_integer_create"); + ml_name); - // Initialize error as_error err; as_error_init(&err); // Python Function Arguments - PyObject *py_policy = NULL; PyObject *py_ns = NULL; PyObject *py_set = NULL; PyObject *py_bin = NULL; PyObject *py_name = NULL; + PyObject *py_policy = NULL; - // Python Function Keyword Arguments static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; // Python Function Argument Parsing @@ -548,7 +535,27 @@ PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, return convert_python_args_to_c_and_create_index( self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_NUMERIC, NULL, NULL); + index_datatype, NULL, NULL); +} + +/** + ******************************************************************************************************* + * Creates an integer index for a bin in the Aerospike DB. + * + * @param self AerospikeClient object + * @param args The args is a tuple object containing an argument + * list passed from Python to a C function + * @param kwds Dictionary of keywords + * + * Returns an integer status. 0(Zero) is success value. + * In case of error,appropriate exceptions will be raised. + ******************************************************************************************************* + */ +PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, + PyObject *args, PyObject *kwds) +{ + return deprecated_index_create_helper( + self, args, kwds, "index_integer_create", AS_INDEX_NUMERIC); } /** @@ -567,94 +574,20 @@ PyObject *AerospikeClient_Index_Integer_Create(AerospikeClient *self, PyObject *AerospikeClient_Index_String_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, - DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_string_create"); - - // Initialize error - as_error err; - as_error_init(&err); - - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; - - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; - - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_string_create", - kwlist, &py_ns, &py_set, &py_bin, &py_name, - &py_policy) == false) { - return NULL; - } - - return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_STRING, NULL, NULL); + return deprecated_index_create_helper( + self, args, kwds, "index_string_create", AS_INDEX_STRING); } PyObject *AerospikeClient_Index_Blob_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, - DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_blob_create"); - - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; - - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; - - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords(args, kwds, "OOOO|O:index_blob_create", - kwlist, &py_ns, &py_set, &py_bin, &py_name, - &py_policy) == false) { - return NULL; - } - - return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_BLOB, NULL, NULL); + return deprecated_index_create_helper(self, args, kwds, "index_blob_create", + AS_INDEX_BLOB); } PyObject *AerospikeClient_Index_2dsphere_Create(AerospikeClient *self, PyObject *args, PyObject *kwds) { - PyErr_WarnFormat(PyExc_DeprecationWarning, STACK_LEVEL, - DEPRECATION_NOTICE_TO_USE_INDEX_SINGLE_VALUE_CREATE, - "index_geo2dsphere_create"); - - // Initialize error - as_error err; - as_error_init(&err); - - // Python Function Arguments - PyObject *py_policy = NULL; - PyObject *py_ns = NULL; - PyObject *py_set = NULL; - PyObject *py_bin = NULL; - PyObject *py_name = NULL; - - // Python Function Keyword Arguments - static char *kwlist[] = {"ns", "set", "bin", "name", "policy", NULL}; - - // Python Function Argument Parsing - if (PyArg_ParseTupleAndKeywords( - args, kwds, "OOOO|O:index_geo2dsphere_create", kwlist, &py_ns, - &py_set, &py_bin, &py_name, &py_policy) == false) { - return NULL; - } - - return convert_python_args_to_c_and_create_index( - self, py_policy, py_ns, py_set, py_bin, py_name, AS_INDEX_TYPE_DEFAULT, - AS_INDEX_GEO2DSPHERE, NULL, NULL); + return deprecated_index_create_helper( + self, args, kwds, "index_geo2dsphere_create", AS_INDEX_GEO2DSPHERE); } From 3c2a4ce85fb6a6df1139c1dae9b711a868a33181 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:12:35 -0800 Subject: [PATCH 37/42] fix --- src/main/client/sec_index.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/client/sec_index.c b/src/main/client/sec_index.c index 0cadf4b82e..d95fbbd818 100644 --- a/src/main/client/sec_index.c +++ b/src/main/client/sec_index.c @@ -301,13 +301,13 @@ PyObject *AerospikeClient_Index_Cdt_Create(AerospikeClient *self, return NULL; } - if (get_int_from_py_int(&err, py_indextype, (int *)&data_type, - "index_datatype") != AEROSPIKE_OK) { + if (get_int_from_py_int(&err, py_indextype, (int *)&index_type, + "index_type") != AEROSPIKE_OK) { goto CLEANUP_ON_ERROR; } - if (get_int_from_py_int(&err, py_datatype, (int *)&index_type, - "index_type") != AEROSPIKE_OK) { + if (get_int_from_py_int(&err, py_datatype, (int *)&data_type, + "index_datatype") != AEROSPIKE_OK) { goto CLEANUP_ON_ERROR; } From 8f2864063250f7c5b514e47078e31e653f39a5f6 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:29:56 -0800 Subject: [PATCH 38/42] Fix test --- test/new_tests/test_mapkeys_index.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/new_tests/test_mapkeys_index.py b/test/new_tests/test_mapkeys_index.py index 3d1bc4147e..d280779a92 100644 --- a/test/new_tests/test_mapkeys_index.py +++ b/test/new_tests/test_mapkeys_index.py @@ -52,7 +52,7 @@ def test_mapkeysindex_with_extra_paramters(self): policy = {} with pytest.raises(TypeError): self.as_connection.index_map_keys_create( - "test", "demo", "string_map", aerospike.INDEX_STRING, "test_string_map_index", policy, 1 + "test", "demo", "string_map", aerospike.INDEX_STRING, "test_string_map_index", policy, None, 1 ) def test_mapkeysindex_with_correct_parameters(self): From 85220e7c0965e73c09e679c96bd47ad78d0e052a Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:33:03 -0800 Subject: [PATCH 39/42] update type stubs --- aerospike-stubs/aerospike.pyi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aerospike-stubs/aerospike.pyi b/aerospike-stubs/aerospike.pyi index 9fc53f6c6b..5d852c5718 100644 --- a/aerospike-stubs/aerospike.pyi +++ b/aerospike-stubs/aerospike.pyi @@ -394,11 +394,11 @@ class Client: def index_string_create(self, ns: str, set: str, bin: str, name: str, policy: dict = ...) -> None: ... def index_blob_create(self, ns: str, set: str, bin: str, name: str, policy: dict = ...) -> None: ... - # Index creation for root-level CDTs # We cannot use aerospike_helpers's TypeExpression type because mypy's stubtest will complain - def index_list_create(self, ns: str, set: str, bin: str, index_datatype, name: str, policy: dict = ...) -> None: ... - def index_map_keys_create(self, ns: str, set: str, bin: str, index_datatype, name: str, policy: dict = ...) -> None: ... - def index_map_values_create(self, ns: str, set: str, bin: str, index_datatype, name: str, policy: dict = ...) -> None: ... + def index_single_value_create(self, ns: str, set: str, bin: str, index_datatype, name: str, policy: dict = ..., ctx: Optional[list] = ...) -> None: ... + def index_list_create(self, ns: str, set: str, bin: str, index_datatype, name: str, policy: dict = ..., ctx: Optional[list] = ...) -> None: ... + def index_map_keys_create(self, ns: str, set: str, bin: str, index_datatype, name: str, policy: dict = ..., ctx: Optional[list] = ...) -> None: ... + def index_map_values_create(self, ns: str, set: str, bin: str, index_datatype, name: str, policy: dict = ..., ctx: Optional[list] = ...) -> None: ... def index_cdt_create(self, ns: str, set: str, bin: str, index_type: int, index_datatype: int, name: str, ctx: list, policy: dict = ...) -> int: ... def index_expr_create(self, ns: str, set: str, index_type: int, index_datatype: int, expressions: list, name: str, policy: dict = ...) -> None: ... From 75cd7e8709c40bb1dcc34aa3951f419581754ae5 Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:45:49 -0800 Subject: [PATCH 40/42] Replace index_integer_create() calls with index_single_value_create() in tests to prevent warnings --- test/new_tests/test_aggregate.py | 2 +- test/new_tests/test_apply.py | 4 +- test/new_tests/test_batch_apply.py | 4 +- test/new_tests/test_index.py | 46 +++++++++---------- test/new_tests/test_kv.py | 3 +- test/new_tests/test_query.py | 16 +++---- test/new_tests/test_query_apply.py | 4 +- .../test_query_execute_background.py | 2 +- 8 files changed, 41 insertions(+), 40 deletions(-) diff --git a/test/new_tests/test_aggregate.py b/test/new_tests/test_aggregate.py index 6109c0869c..e7255afc97 100644 --- a/test/new_tests/test_aggregate.py +++ b/test/new_tests/test_aggregate.py @@ -16,7 +16,7 @@ def remove_stream_udf(client): def add_required_index(client): - client.index_integer_create("test", "demo", "test_age", "age_index") + client.index_single_value_create("test", "demo", "test_age", aerospike.INDEX_NUMERIC, "age_index") def remove_index(client): diff --git a/test/new_tests/test_apply.py b/test/new_tests/test_apply.py index cb5ff0da82..7c54110228 100644 --- a/test/new_tests/test_apply.py +++ b/test/new_tests/test_apply.py @@ -53,11 +53,11 @@ def add_indexes_and_udfs(client): """ policy = {} try: - client.index_integer_create("test", "demo", "age", "age_index", policy) + client.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "age_index", policy) except e.IndexFoundError: pass try: - client.index_integer_create("test", "demo", "age1", "age_index1", policy) + client.index_single_value_create("test", "demo", "age1", aerospike.INDEX_NUMERIC, "age_index1", policy) except e.IndexFoundError: pass diff --git a/test/new_tests/test_batch_apply.py b/test/new_tests/test_batch_apply.py index 742c10d23c..bef6e9a5f8 100644 --- a/test/new_tests/test_batch_apply.py +++ b/test/new_tests/test_batch_apply.py @@ -18,11 +18,11 @@ def add_indexes_and_udfs(client): """ policy = {} try: - client.index_integer_create("test", "demo", "age", "age_index", policy) + client.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "age_index", policy) except e.IndexFoundError: pass try: - client.index_integer_create("test", "demo", "age1", "age_index1", policy) + client.index_single_value_create("test", "demo", "age1", aerospike.INDEX_NUMERIC, "age_index1", policy) except e.IndexFoundError: pass diff --git a/test/new_tests/test_index.py b/test/new_tests/test_index.py index 5d9a0e9628..b4c440c8ef 100644 --- a/test/new_tests/test_index.py +++ b/test/new_tests/test_index.py @@ -40,7 +40,7 @@ def test_create_indexes_with_no_parameters(self): assert "argument 'ns' (pos 1)" in str(typeError.value) with pytest.raises(TypeError) as typeError: - self.as_connection.index_integer_create() + self.as_connection.index_single_value_create() assert "argument 'ns' (pos 1)" in str(typeError.value) @@ -49,7 +49,7 @@ def test_create_integer_index_with_correct_parameters(self): Invoke createindex() with correct arguments """ policy = {} - retobj = self.as_connection.index_integer_create("test", "demo", "age", "age_index", policy) + retobj = self.as_connection.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "age_index", policy) assert retobj == AerospikeStatus.AEROSPIKE_OK self.as_connection.index_remove("test", "age_index", policy) @@ -61,7 +61,7 @@ def test_create_integer_index_with_set_name_too_long(self): policy = {} with pytest.raises(e.InvalidRequest) as err_info: - self.as_connection.index_integer_create("test", set_name, "age", "age_index", policy) + self.as_connection.index_single_value_create("test", set_name, "age", aerospike.INDEX_NUMERIC, "age_index", policy) err_code = err_info.value.code assert err_code is AerospikeStatus.AEROSPIKE_ERR_REQUEST_INVALID @@ -72,7 +72,7 @@ def test_create_integer_index_with_incorrect_namespace(self): """ policy = {} with pytest.raises(e.NamespaceNotFound) as err_info: - self.as_connection.index_integer_create("fake_namespace", "demo", "age", "age_index", policy) + self.as_connection.index_single_value_create("fake_namespace", "demo", "age", aerospike.INDEX_NUMERIC, "age_index", policy) err_code = err_info.value.code assert err_code is AerospikeStatus.AEROSPIKE_ERR_NAMESPACE_NOT_FOUND @@ -83,7 +83,7 @@ def test_create_integer_index_with_incorrect_set(self): It should succeed """ policy = {} - retobj = self.as_connection.index_integer_create("test", "demo1", "age", "age_index", policy) + retobj = self.as_connection.index_single_value_create("test", "demo1", "age", aerospike.INDEX_NUMERIC, "age_index", policy) assert retobj == AerospikeStatus.AEROSPIKE_OK self.as_connection.index_remove("test", "age_index", policy) @@ -94,7 +94,7 @@ def test_create_integer_index_with_incorrect_bin(self): Invoke createindex() with a nonexistent bin """ policy = {} - retobj = self.as_connection.index_integer_create("test", "demo", "fake_bin", "age_index", policy) + retobj = self.as_connection.index_single_value_create("test", "demo", "fake_bin", aerospike.INDEX_NUMERIC, "age_index", policy) assert retobj == AerospikeStatus.AEROSPIKE_OK self.as_connection.index_remove("test", "age_index", policy) @@ -106,7 +106,7 @@ def test_create_integer_index_with_namespace_is_none(self): """ policy = {} with pytest.raises(e.ParamError) as err_info: - self.as_connection.index_integer_create(None, "demo", "age", "age_index", policy) + self.as_connection.index_single_value_create(None, "demo", "age", aerospike.INDEX_NUMERIC, "age_index", policy) err_code = err_info.value.code assert err_code is AerospikeStatus.AEROSPIKE_ERR_PARAM @@ -115,7 +115,7 @@ def test_creat_integer_eindex_with_set_is_none(self): # Invoke createindex() with set is None policy = {} - retobj = self.as_connection.index_integer_create("test", None, "age", "age_index", policy) + retobj = self.as_connection.index_single_value_create("test", None, "age", aerospike.INDEX_NUMERIC, "age_index", policy) assert retobj == AerospikeStatus.AEROSPIKE_OK self.as_connection.index_remove("test", "age_index", policy) @@ -126,7 +126,7 @@ def test_create_integer_index_with_set_is_int(self): policy = {} with pytest.raises(e.ParamError) as err_info: - self.as_connection.index_integer_create("test", 1, "age", "age_index", policy) + self.as_connection.index_single_value_create("test", 1, "age", aerospike.INDEX_NUMERIC, "age_index", policy) err_code = err_info.value.code assert err_code is AerospikeStatus.AEROSPIKE_ERR_PARAM @@ -136,7 +136,7 @@ def test_create_integer_index_with_bin_is_none(self): """ policy = {} with pytest.raises(e.ParamError) as err_info: - self.as_connection.index_integer_create("test", "demo", None, "age_index", policy) + self.as_connection.index_single_value_create("test", "demo", None, aerospike.INDEX_NUMERIC, "age_index", policy) err_code = err_info.value.code assert err_code is AerospikeStatus.AEROSPIKE_ERR_PARAM @@ -147,7 +147,7 @@ def test_create_integer_index_with_index_is_none(self): """ policy = {} with pytest.raises(e.ParamError) as err_info: - self.as_connection.index_integer_create("test", "demo", "age", None, policy) + self.as_connection.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, None, policy) err_code = err_info.value.code assert err_code is AerospikeStatus.AEROSPIKE_ERR_PARAM @@ -159,10 +159,10 @@ def test_create_same_integer_index_multiple_times(self): """ policy = {} - retobj = self.as_connection.index_integer_create("test", "demo", "age", "age_index", policy) + retobj = self.as_connection.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "age_index", policy) assert retobj == AerospikeStatus.AEROSPIKE_OK try: - retobj = self.as_connection.index_integer_create("test", "demo", "age", "age_index", policy) + retobj = self.as_connection.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "age_index", policy) except e.IndexFoundError: assert self.server_version <= [6, 0] @@ -175,12 +175,12 @@ def test_create_same_integer_index_multiple_times_different_bin(self): multiple times on different bin names """ policy = {} - retobj = self.as_connection.index_integer_create("test", "demo", "age", "age_index", policy) + retobj = self.as_connection.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "age_index", policy) assert retobj == AerospikeStatus.AEROSPIKE_OK with pytest.raises(e.IndexFoundError): - retobj = self.as_connection.index_integer_create("test", "demo", "no", "age_index", policy) + retobj = self.as_connection.index_single_value_create("test", "demo", "no", aerospike.INDEX_NUMERIC, "age_index", policy) self.as_connection.index_remove("test", "age_index", policy) ensure_dropped_index(self.as_connection, "test", "age_index") @@ -191,10 +191,10 @@ def test_create_different_integer_index_multiple_times_same_bin(self): name """ policy = {} - retobj = self.as_connection.index_integer_create("test", "demo", "age", "age_index", policy) + retobj = self.as_connection.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "age_index", policy) assert retobj == AerospikeStatus.AEROSPIKE_OK try: - retobj = self.as_connection.index_integer_create("test", "demo", "age", "age_index1", policy) + retobj = self.as_connection.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "age_index1", policy) self.as_connection.index_remove("test", "age_index1", policy) except e.IndexFoundError: assert self.server_version <= [6, 0] @@ -206,7 +206,7 @@ def test_create_integer_index_with_policy(self): Invoke createindex() with policy """ policy = {"timeout": 180000} - retobj = self.as_connection.index_integer_create("test", "demo", "age", "age_index", policy) + retobj = self.as_connection.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "age_index", policy) ensure_dropped_index(self.as_connection, "test", "age_index") assert retobj == AerospikeStatus.AEROSPIKE_OK @@ -406,7 +406,7 @@ def test_drop_valid_index(self): Invoke drop valid index() """ policy = {} - self.as_connection.index_integer_create("test", "demo", "age", "age_index", policy) + self.as_connection.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "age_index", policy) retobj = self.as_connection.index_remove("test", "age_index", policy) ensure_dropped_index(self.as_connection, "test", "age_index") assert retobj == AerospikeStatus.AEROSPIKE_OK @@ -416,7 +416,7 @@ def test_drop_valid_index_policy(self): Invoke drop valid index() policy """ policy = {"timeout": 180000} - self.as_connection.index_integer_create("test", "demo", "age", "age_index", policy) + self.as_connection.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "age_index", policy) retobj = self.as_connection.index_remove("test", "age_index", policy) ensure_dropped_index(self.as_connection, "test", "age_index") assert retobj == AerospikeStatus.AEROSPIKE_OK @@ -425,7 +425,7 @@ def test_createindex_with_long_index_name(self): # Invoke createindex() with long index name policy = {} with pytest.raises(e.InvalidRequest): - self.as_connection.index_integer_create("test", "demo", "age", "index" * 100, policy) + self.as_connection.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "index" * 100, policy) def test_create_string_index_unicode_positive(self): """ @@ -443,7 +443,7 @@ def test_createindex_integer_unicode(self): Invoke createindex() with correct arguments """ policy = {} - retobj = self.as_connection.index_integer_create("test", "demo", "age", "uni_age_index", policy) + retobj = self.as_connection.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "uni_age_index", policy) assert retobj == AerospikeStatus.AEROSPIKE_OK self.as_connection.index_remove("test", "uni_age_index", policy) @@ -457,7 +457,7 @@ def test_createindex_with_correct_parameters_without_connection(self): client1.close() with pytest.raises(e.ClusterError) as err_info: - client1.index_integer_create("test", "demo", "age", "age_index", policy) + client1.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "age_index", policy) err_code = err_info.value.code assert err_code is AerospikeStatus.AEROSPIKE_CLUSTER_ERROR diff --git a/test/new_tests/test_kv.py b/test/new_tests/test_kv.py index 3a5bc1fd52..f1acf78a3c 100644 --- a/test/new_tests/test_kv.py +++ b/test/new_tests/test_kv.py @@ -1,5 +1,6 @@ import pytest from aerospike import exception as e +import aerospike def get_key_with_digest_only(key): @@ -200,7 +201,7 @@ def count_records_false(tuple): rec = {"name": "name%s" % (str(i)), "addr": "name%s" % (str(i)), "age": i, "no": i} self.as_connection.put(key, rec) - self.as_connection.index_integer_create("test", "unittest", "age", "age_index", {}) + self.as_connection.index_single_value_create("test", "unittest", "age", aerospike.INDEX_NUMERIC, "age_index", {}) query = self.as_connection.query("test", "unittest") diff --git a/test/new_tests/test_query.py b/test/new_tests/test_query.py index c65cbada91..ee73560df9 100644 --- a/test/new_tests/test_query.py +++ b/test/new_tests/test_query.py @@ -66,7 +66,7 @@ class TestQuery(TestBaseClass): @pytest.fixture(autouse=True, scope="class") def setupClass(self, as_connection): try: - as_connection.index_integer_create("test", "demo", "test_age", "age_index") + as_connection.index_single_value_create("test", "demo", "test_age", aerospike.INDEX_NUMERIC, "age_index") except e.IndexFoundError: pass @@ -76,7 +76,7 @@ def setupClass(self, as_connection): pass try: - as_connection.index_integer_create("test", "demo", "age1", "age_index1") + as_connection.index_single_value_create("test", "demo", "age1", aerospike.INDEX_NUMERIC, "age_index1") except e.IndexFoundError: pass @@ -115,12 +115,12 @@ def setupClass(self, as_connection): pass try: - as_connection.index_integer_create("test", None, "test_age_none", "age_index_none") + as_connection.index_single_value_create("test", None, "test_age_none", aerospike.INDEX_NUMERIC, "age_index_none") except e.IndexFoundError: pass try: - as_connection.index_integer_create("test", "demo", bytearray("sal\0kj", "utf-8"), "sal_index") + as_connection.index_single_value_create("test", "demo", bytearray("sal\0kj", "utf-8"), aerospike.INDEX_NUMERIC, "sal_index") except e.IndexFoundError: pass @@ -144,26 +144,26 @@ def setupClass(self, as_connection): pass try: - as_connection.index_cdt_create( + as_connection.index_single_value_create( "test", "demo", "numeric_list", - aerospike.INDEX_TYPE_DEFAULT, aerospike.INDEX_NUMERIC, "numeric_list_cdt_index", + None, ctx_list_index, ) except e.IndexFoundError: pass try: - as_connection.index_cdt_create( + as_connection.index_single_value_create( "test", "demo", "numeric_map", - aerospike.INDEX_TYPE_DEFAULT, aerospike.INDEX_NUMERIC, "numeric_map_cdt_index", + None, ctx_map_index, ) except e.IndexFoundError: diff --git a/test/new_tests/test_query_apply.py b/test/new_tests/test_query_apply.py index dc3ded8cbe..305e52e4c4 100644 --- a/test/new_tests/test_query_apply.py +++ b/test/new_tests/test_query_apply.py @@ -13,12 +13,12 @@ def add_indexes_to_client(client): try: - client.index_integer_create("test", "demo", "age", "test_demo_age_idx") + client.index_single_value_create("test", "demo", "age", aerospike.INDEX_NUMERIC, "test_demo_age_idx") except e.IndexFoundError: pass try: - client.index_integer_create("test", None, "age", "test_null_age_idx") + client.index_single_value_create("test", None, "age", aerospike.INDEX_NUMERIC, "test_null_age_idx") except e.IndexFoundError: pass diff --git a/test/new_tests/test_query_execute_background.py b/test/new_tests/test_query_execute_background.py index 9aa30f5a71..07b167ca54 100644 --- a/test/new_tests/test_query_execute_background.py +++ b/test/new_tests/test_query_execute_background.py @@ -20,7 +20,7 @@ def add_indexes_to_client(client): try: - client.index_integer_create(TEST_NS, TEST_SET, "number", "test_background_number_idx") + client.index_single_value_create(TEST_NS, TEST_SET, "number", aerospike.INDEX_NUMERIC, "test_background_number_idx") except exception.IndexFoundError: pass From c98dc66beb6829183dcc4c9d6eff7eeb126c9e9d Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:49:22 -0800 Subject: [PATCH 41/42] Replace the rest of the deprecated index creation methods --- test/new_tests/test_geospatial.py | 14 +++++----- test/new_tests/test_index.py | 38 +++++++++++++------------- test/new_tests/test_query.py | 4 +-- test/new_tests/test_query_partition.py | 2 +- 4 files changed, 29 insertions(+), 29 deletions(-) diff --git a/test/new_tests/test_geospatial.py b/test/new_tests/test_geospatial.py index 5e010ebc53..a9a173a065 100644 --- a/test/new_tests/test_geospatial.py +++ b/test/new_tests/test_geospatial.py @@ -31,17 +31,17 @@ def get_geo_object(): def add_geo_indexes(connection): try: - connection.index_geo2dsphere_create("test", "demo", "loc", "loc_index") + connection.index_geo2dsphere_create("test", "demo", "loc", aerospike.INDEX_GEO2DSPHERE, "loc_index") except (e.IndexFoundError): pass try: - connection.index_geo2dsphere_create("test", "demo", "loc_polygon", "loc_polygon_index") + connection.index_geo2dsphere_create("test", "demo", "loc_polygon", aerospike.INDEX_GEO2DSPHERE, "loc_polygon_index") except (e.IndexFoundError): pass try: - connection.index_geo2dsphere_create("test", "demo", "loc_circle", "loc_circle_index") + connection.index_geo2dsphere_create("test", "demo", "loc_circle", aerospike.INDEX_GEO2DSPHERE, "loc_circle_index") except (e.IndexFoundError): pass @@ -343,7 +343,7 @@ def test_geospatial_positive_query_without_set(self): keys.append(key) try: - self.as_connection.index_geo2dsphere_create("test", None, "loc", "loc_index_no_set") + self.as_connection.index_geo2dsphere_create("test", None, "loc", aerospike.INDEX_GEO2DSPHERE, "loc_index_no_set") except (e.IndexFoundError): pass @@ -780,7 +780,7 @@ def test_geospatial_2dindex_positive(self): except Exception: pass - status = self.as_connection.index_geo2dsphere_create("test", "demo", "loc", "loc_index") + status = self.as_connection.index_geo2dsphere_create("test", "demo", "loc", aerospike.INDEX_GEO2DSPHERE, "loc_index") assert status == 0 @@ -794,7 +794,7 @@ def test_geospatial_2dindex_positive_with_policy(self): except Exception: pass - status = self.as_connection.index_geo2dsphere_create("test", "demo", "loc", "loc_index", {"timeout": 180000}) + status = self.as_connection.index_geo2dsphere_create("test", "demo", "loc", aerospike.INDEX_GEO2DSPHERE, "loc_index", {"timeout": 180000}) assert status == 0 @@ -1154,7 +1154,7 @@ def test_geospatial_2dindex_set_length_extra(self): set_name = "a" * 100 with pytest.raises(e.InvalidRequest) as err_info: - self.as_connection.index_geo2dsphere_create("test", set_name, "loc", "loc_index_creation_should_fail") + self.as_connection.index_geo2dsphere_create("test", set_name, "loc", aerospike.INDEX_GEO2DSPHERE, "loc_index_creation_should_fail") err_code = err_info.value.code assert err_code == AerospikeStatus.AEROSPIKE_ERR_REQUEST_INVALID diff --git a/test/new_tests/test_index.py b/test/new_tests/test_index.py index b4c440c8ef..1ff93fae78 100644 --- a/test/new_tests/test_index.py +++ b/test/new_tests/test_index.py @@ -215,7 +215,7 @@ def test_create_blob_index(self): if self.server_version < [7, 0]: pytest.skip("Blob secondary indexes are only supported in server 7.0+") - self.as_connection.index_blob_create(ns="test", set="demo", bin="bytes", name="bytes_index", policy={}) + self.as_connection.index_single_value_create(ns="test", set="demo", bin="bytes", index_datatype=aerospike.INDEX_BLOB, name="bytes_index", policy={}) ensure_dropped_index(self.as_connection, "test", "bytes_index") @@ -224,7 +224,7 @@ def test_create_string_index_positive(self): Invoke create string index() with correct arguments """ policy = {} - retobj = self.as_connection.index_string_create("test", "demo", "name", "name_index", policy) + retobj = self.as_connection.index_string_create("test", "demo", "name", aerospike.INDEX_STRING, "name_index", policy) self.as_connection.index_remove("test", "name_index", policy) ensure_dropped_index(self.as_connection, "test", "name_index") @@ -237,7 +237,7 @@ def test_create_string_index_with_set_length_too_long(self): policy = {} with pytest.raises(e.InvalidRequest) as err_info: - self.as_connection.index_string_create("test", set_name, "name", "name_index", policy) + self.as_connection.index_string_create("test", set_name, "name", aerospike.INDEX_STRING, "name_index", policy) err_code = err_info.value.code assert err_code is AerospikeStatus.AEROSPIKE_ERR_REQUEST_INVALID @@ -247,7 +247,7 @@ def test_create_string_index_with_correct_parameters_ns_length_extra(self): policy = {} with pytest.raises((e.InvalidRequest, e.NamespaceNotFound)) as err_info: - self.as_connection.index_string_create(ns_name, "demo", "name", "name_index", policy) + self.as_connection.index_string_create(ns_name, "demo", "name", aerospike.INDEX_STRING, "name_index", policy) err_code = err_info.value.code if (TestBaseClass.major_ver, TestBaseClass.minor_ver) >= (7, 2): @@ -262,7 +262,7 @@ def test_create_string_index_with_incorrect_namespace(self): policy = {} with pytest.raises(e.NamespaceNotFound) as err_info: - self.as_connection.index_string_create("fake_namespace", "demo", "name", "name_index", policy) + self.as_connection.index_string_create("fake_namespace", "demo", "name", aerospike.INDEX_STRING, "name_index", policy) err_code = err_info.value.code assert err_code is AerospikeStatus.AEROSPIKE_ERR_NAMESPACE_NOT_FOUND @@ -272,7 +272,7 @@ def test_create_string_index_with_incorrect_set(self): Invoke create string index() with incorrect set """ policy = {} - retobj = self.as_connection.index_string_create("test", "demo1", "name", "name_index", policy) + retobj = self.as_connection.index_string_create("test", "demo1", "name", aerospike.INDEX_STRING, "name_index", policy) self.as_connection.index_remove("test", "name_index", policy) ensure_dropped_index(self.as_connection, "test", "name_index") @@ -283,7 +283,7 @@ def test_create_string_index_with_incorrect_bin(self): Invoke create string index() with incorrect bin """ policy = {} - retobj = self.as_connection.index_string_create("test", "demo", "name1", "name_index", policy) + retobj = self.as_connection.index_string_create("test", "demo", "name1", aerospike.INDEX_STRING, "name_index", policy) self.as_connection.index_remove("test", "name_index", policy) ensure_dropped_index(self.as_connection, "test", "name_index") @@ -295,7 +295,7 @@ def test_create_string_index_with_namespace_is_none(self): """ policy = {} with pytest.raises(e.ParamError) as err_info: - self.as_connection.index_string_create(None, "demo", "name", "name_index", policy) + self.as_connection.index_string_create(None, "demo", "name", aerospike.INDEX_STRING, "name_index", policy) err_code = err_info.value.code assert err_code is AerospikeStatus.AEROSPIKE_ERR_PARAM @@ -303,7 +303,7 @@ def test_create_string_index_with_namespace_is_none(self): def test_create_string_index_with_set_is_none(self): # Invoke create string index() with set is None policy = {} - retobj = self.as_connection.index_string_create("test", None, "name", "name_index", policy) + retobj = self.as_connection.index_string_create("test", None, "name", aerospike.INDEX_STRING, "name_index", policy) self.as_connection.index_remove("test", "name_index", policy) ensure_dropped_index(self.as_connection, "test", "name_index") @@ -315,7 +315,7 @@ def test_create_string_index_with_bin_is_none(self): """ policy = {} with pytest.raises(e.ParamError) as err_info: - self.as_connection.index_string_create("test", "demo", None, "name_index", policy) + self.as_connection.index_string_create("test", "demo", None, aerospike.INDEX_STRING, "name_index", policy) err_code = err_info.value.code assert err_code is AerospikeStatus.AEROSPIKE_ERR_PARAM @@ -326,7 +326,7 @@ def test_create_string_index_with_index_is_none(self): """ policy = {} with pytest.raises(e.ParamError) as err_info: - self.as_connection.index_string_create("test", "demo", "name", None, policy) + self.as_connection.index_string_create("test", "demo", "name", aerospike.INDEX_STRING, None, policy) err_code = err_info.value.code assert err_code is AerospikeStatus.AEROSPIKE_ERR_PARAM @@ -336,10 +336,10 @@ def test_create_same_string_index_multiple_times(self): Invoke create string index() with multiple times on same bin """ policy = {} - retobj = self.as_connection.index_string_create("test", "demo", "name", "name_index", policy) + retobj = self.as_connection.index_string_create("test", "demo", "name", aerospike.INDEX_STRING, "name_index", policy) assert retobj == AerospikeStatus.AEROSPIKE_OK try: - retobj = self.as_connection.index_string_create("test", "demo", "name", "name_index", policy) + retobj = self.as_connection.index_string_create("test", "demo", "name", aerospike.INDEX_STRING, "name_index", policy) except e.IndexFoundError: assert self.server_version <= [6, 0] @@ -351,11 +351,11 @@ def test_create_same_string_index_multiple_times_different_bin(self): Invoke create string index() with multiple times on different bin """ policy = {} - retobj = self.as_connection.index_string_create("test", "demo", "name", "name_index", policy) + retobj = self.as_connection.index_string_create("test", "demo", "name", aerospike.INDEX_STRING, "name_index", policy) assert retobj == AerospikeStatus.AEROSPIKE_OK with pytest.raises(e.IndexFoundError): - retobj = self.as_connection.index_string_create("test", "demo", "addr", "name_index", policy) + retobj = self.as_connection.index_string_create("test", "demo", "addr", aerospike.INDEX_STRING, "name_index", policy) self.as_connection.index_remove("test", "name_index", policy) ensure_dropped_index(self.as_connection, "test", "name_index") @@ -370,10 +370,10 @@ def test_create_different_string_index_multiple_times_same_bin(self): bin with different name """ policy = {} - retobj = self.as_connection.index_string_create("test", "demo", "name", "name_index", policy) + retobj = self.as_connection.index_string_create("test", "demo", "name", aerospike.INDEX_STRING, "name_index", policy) assert retobj == AerospikeStatus.AEROSPIKE_OK try: - retobj = self.as_connection.index_string_create("test", "demo", "name", "name_index1", policy) + retobj = self.as_connection.index_string_create("test", "demo", "name", aerospike.INDEX_STRING, "name_index1", policy) self.as_connection.index_remove("test", "name_index1", policy) except e.IndexFoundError: assert self.server_version <= [6, 0] @@ -385,7 +385,7 @@ def test_create_string_index_with_policy(self): Invoke create string index() with policy """ policy = {"timeout": 180000} - retobj = self.as_connection.index_string_create("test", "demo", "name", "name_index", policy) + retobj = self.as_connection.index_string_create("test", "demo", "name", aerospike.INDEX_STRING, "name_index", policy) assert retobj == AerospikeStatus.AEROSPIKE_OK self.as_connection.index_remove("test", "name_index", policy) @@ -432,7 +432,7 @@ def test_create_string_index_unicode_positive(self): Invoke create string index() with correct arguments """ policy = {} - retobj = self.as_connection.index_string_create("test", "demo", "name", "uni_name_index", policy) + retobj = self.as_connection.index_string_create("test", "demo", "name", aerospike.INDEX_STRING, "uni_name_index", policy) self.as_connection.index_remove("test", "uni_name_index", policy) ensure_dropped_index(self.as_connection, "test", "uni_name_index") diff --git a/test/new_tests/test_query.py b/test/new_tests/test_query.py index ee73560df9..6c6f6cc7fa 100644 --- a/test/new_tests/test_query.py +++ b/test/new_tests/test_query.py @@ -71,7 +71,7 @@ def setupClass(self, as_connection): pass try: - as_connection.index_string_create("test", "demo", "addr", "addr_index") + as_connection.index_string_create("test", "demo", "addr", aerospike.INDEX_STRING, "addr_index") except e.IndexFoundError: pass @@ -1129,7 +1129,7 @@ def test_query_blob_bin_equal(self): if (TestBaseClass.major_ver, TestBaseClass.minor_ver) < (7, 0): pytest.skip("Blob indexes are only supported in server 7.0+") - self.as_connection.index_blob_create("test", "demo", "blob", "blob_index") + self.as_connection.index_single_value_create("test", "demo", "blob", aerospike.INDEX_BLOB, "blob_index") query = self.as_connection.query("test", "demo") blob_val = int.to_bytes(4, length=1, byteorder='big') diff --git a/test/new_tests/test_query_partition.py b/test/new_tests/test_query_partition.py index 05a5ffbe9a..a721fb8858 100644 --- a/test/new_tests/test_query_partition.py +++ b/test/new_tests/test_query_partition.py @@ -17,7 +17,7 @@ def add_sindex(client): Load the sindex used in the tests """ try: - client.index_string_create("test", "demo", "s", "string") + client.index_string_create("test", "demo", "s", aerospike.INDEX_STRING, "string") except e.IndexFoundError: pass From 59fe5f9e82b3a6425a9eb4ea2aaec732bfedad3a Mon Sep 17 00:00:00 2001 From: Julian Nguyen <109386615+juliannguyen4@users.noreply.github.com> Date: Mon, 2 Feb 2026 16:00:34 -0800 Subject: [PATCH 42/42] Add test for deprecated index creation method warnings --- test/new_tests/test_index_deprecated.py | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 test/new_tests/test_index_deprecated.py diff --git a/test/new_tests/test_index_deprecated.py b/test/new_tests/test_index_deprecated.py new file mode 100644 index 0000000000..f5f3a73077 --- /dev/null +++ b/test/new_tests/test_index_deprecated.py @@ -0,0 +1,29 @@ +import pytest +import aerospike +from aerospike import exception as e +import warnings + +INDEX_NAME = "deprecated_index" + +@pytest.mark.usefixtures("as_connection") +class TestDeprecatedIndexCreationMethods: + @pytest.fixture(autouse=True) + def setup(self): + yield + self.as_connection.index_remove("test", INDEX_NAME) + + @pytest.mark.parametrize( + "index_create_method", + [ + aerospike.Client.index_blob_create, + aerospike.Client.index_integer_create, + aerospike.Client.index_string_create, + aerospike.Client.index_geo2dsphere_create, + ] + ) + def test_deprecated_index_creation_methods(self, index_create_method): + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter(action="always", category=DeprecationWarning) + with pytest.raises(e.ParamError): + index_create_method(self.as_connection, 1, "demo", "bin_name", INDEX_NAME) + assert len(w) == 1