Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions doc/query.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ A `stream UDF <https://aerospike.com/docs/database/advanced/udf/modules/stream/d
may be applied with :meth:`~aerospike.Query.apply`. It will aggregate results out of the \
records streaming back from the query.

.. note::
:meth:`~aerospike.Query.add_ops` and :meth:`~aerospike.Query.apply` cannot both be used on the same
:class:`~aerospike.Query` object. See :meth:`~aerospike.Query.execute_background`.

Getting Results From Query
--------------------------

Expand Down Expand Up @@ -408,6 +412,9 @@ Assume this boilerplate code is run before all examples below:

This function can also be used to apply a record UDF.

This method cannot be used together with :meth:`~aerospike.Query.add_ops` on the same :class:`~aerospike.Query`
object — see :meth:`~aerospike.Query.execute_background`.

:param str module: the name of the Lua module.
:param str function: the name of the Lua function within the *module*.
:param list arguments: optional arguments to pass to the *function*. NOTE: these arguments must be types supported by Aerospike See: `supported data types <https://aerospike.com/docs/develop/client/python/data-types/>`_.
Expand Down Expand Up @@ -496,6 +503,9 @@ Assume this boilerplate code is run before all examples below:
If there are selected bins in this Query object via :meth:`~Query.select`, those selected bins will be ignored
during the query.

This method cannot be used together with :meth:`~aerospike.Query.apply` on the same :class:`~aerospike.Query`
object — see :meth:`~aerospike.Query.execute_background`.

:param ops: `list` A list of operations generated from :ref:`aerospike_operation_helpers.operations`.

.. note::
Expand All @@ -506,6 +516,9 @@ Assume this boilerplate code is run before all examples below:
Execute a record UDF or write operations on records found by the query in the background. This method returns before the query has completed.
A UDF or a list of write operations must have been added to the query with :meth:`Query.apply` or :meth:`Query.add_ops` respectively.

:meth:`Query.apply` and :meth:`Query.add_ops` cannot both be used on the same :class:`~aerospike.Query` object.
Calling this method after both have been set will raise a :exc:`~aerospike.exception.ParamError`.

:param dict policy: optional :ref:`aerospike_write_policies`.

:return: a job ID that can be used with :meth:`~aerospike.Client.job_info` to track the status of the :py:data:`aerospike.JOB_QUERY` , as it runs in the background.
Expand Down
13 changes: 11 additions & 2 deletions doc/scan.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ Methods
If you need to use an unsupported type, (e.g. set or tuple) you must use your own serializer.
:return: one of the supported types, :class:`int`, :class:`str`, :class:`float` (double), :class:`list`, :class:`dict` (map), :class:`bytearray` (bytes), :class:`bool`.

This method cannot be used together with :meth:`~aerospike.Scan.add_ops` on the same :class:`~aerospike.Scan`
object — see :meth:`~aerospike.Scan.execute_background`.

.. seealso:: `Developing Record UDFs <https://aerospike.com/docs/database/advanced/udf/modules/record/develop>`_


Expand All @@ -84,6 +87,9 @@ Methods
For foreground scans, only read operations are allowed. :meth:`Scan.foreach` and :meth:`Scan.results` will
raise a :py:exc:`~aerospike.exception.ParamError` if a write operation has been set with :meth:`Scan.add_ops`.

This method cannot be used together with :meth:`~aerospike.Scan.apply` on the same :class:`~aerospike.Scan`
object — see :meth:`~aerospike.Scan.execute_background`.

:param ops: `list` A list of write operations generated by the aerospike_helpers e.g. list_operations, map_operations, etc.

.. note::
Expand Down Expand Up @@ -297,8 +303,11 @@ Methods

.. method:: execute_background([, policy])

Execute a record UDF on records found by the scan in the background. This method returns before the scan has completed.
A UDF can be added to the scan with :meth:`Scan.apply`.
Execute a record UDF or write operations on records found by the scan in the background. This method returns before the scan has completed.
A UDF or a list of write operations must have been added to the scan with :meth:`Scan.apply` or :meth:`Scan.add_ops` respectively.

:meth:`Scan.apply` and :meth:`Scan.add_ops` cannot both be used on the same :class:`~aerospike.Scan` object.
Calling this method after both have been set will raise a :exc:`~aerospike.exception.ParamError`.

:param dict policy: optional :ref:`aerospike_write_policies`.

Expand Down
18 changes: 18 additions & 0 deletions test/new_tests/test_query_execute_background.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,3 +378,21 @@ def test_add_ops_then_select_bins_then_bg_query(self, query):
records = query.results()
for _, _, bins in records:
assert bins[BIN_NAME] == 3

def test_add_ops_then_apply(self, query):
query.add_ops(WRITE_OPS)
test_bin = "tz"
query.apply(TEST_UDF_MODULE, TEST_UDF_FUNCTION, [test_bin])

with pytest.raises(exception.ParamError) as excinfo:
query.execute_background()
assert excinfo.value.msg == "Cannot combine query operations with aggregation"

@juliannguyen4 juliannguyen4 Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Long term TODO: I think "aggregation" should be replaced with "UDF" since stream UDF's are supposed to be performed using foreground queries. But since this error message is on the C client side, we can address this later

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes.


def test_apply_then_add_ops(self, query):
test_bin = "tz"
query.apply(TEST_UDF_MODULE, TEST_UDF_FUNCTION, [test_bin])
query.add_ops(WRITE_OPS)

with pytest.raises(exception.ParamError) as excinfo:
query.execute_background()
assert excinfo.value.msg == "Cannot combine query operations with aggregation"
18 changes: 18 additions & 0 deletions test/new_tests/test_scan_execute_background.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,3 +379,21 @@ def test_add_ops_then_select_bins_then_bg_query(self, scan_obj):
records = scan2.results()
for _, _, bins in records:
assert bins[BIN_NAME] == 3

def test_add_ops_then_apply(self, scan_obj):
scan_obj.add_ops(WRITE_OPS)
test_bin = "tz"
scan_obj.apply(TEST_UDF_MODULE, TEST_UDF_FUNCTION, [test_bin])

with pytest.raises(exception.ParamError) as excinfo:
scan_obj.execute_background()
assert excinfo.value.msg == "Cannot combine scan operations with a UDF"

def test_apply_then_add_ops(self, scan_obj):
test_bin = "tz"
scan_obj.apply(TEST_UDF_MODULE, TEST_UDF_FUNCTION, [test_bin])
scan_obj.add_ops(WRITE_OPS)

with pytest.raises(exception.ParamError) as excinfo:
scan_obj.execute_background()
assert excinfo.value.msg == "Cannot combine scan operations with a UDF"
Loading