Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
9b5b5b1
Add todo
juliannguyen4 Mar 23, 2026
66c6a6f
Add test cases for query bin projection. Do some refactoring for test…
juliannguyen4 Mar 23, 2026
3472c9d
Update C client to use Varun's branch for now.
juliannguyen4 Mar 23, 2026
b3fa999
Fix potential memory leak in Query.add_ops() from the list of operati…
juliannguyen4 Mar 23, 2026
3286a22
Fix c client failing to compile because we are using internal impleme…
juliannguyen4 Mar 23, 2026
45e9e58
Fix import error
juliannguyen4 Mar 23, 2026
8714f7e
fix test
juliannguyen4 Mar 23, 2026
714b536
Fixtures from conftest.py should be available automatically without n…
juliannguyen4 Mar 23, 2026
6bcab07
Since clean_test_background already depends on as_connection, we can …
juliannguyen4 Mar 23, 2026
45cf7a2
Fix test syntax. pytest error wasn't helpful here..
juliannguyen4 Mar 23, 2026
f9e7484
add this todo
juliannguyen4 Mar 23, 2026
c795ea0
Fix test syntax. Tests shouldn't expect records to be returned in the…
juliannguyen4 Mar 23, 2026
46d38e4
We only care about the bin values, not the entire record tuple
juliannguyen4 Mar 23, 2026
f897182
Update documentation
juliannguyen4 Mar 23, 2026
9a7b2b1
fix..
juliannguyen4 Mar 23, 2026
5489e71
Fix bad formatting.
juliannguyen4 Mar 24, 2026
6e95ac0
Clean up query.rst to more easily document bin projection. Add missin…
juliannguyen4 Mar 24, 2026
197cfa4
Fix formatting warning.
juliannguyen4 Mar 24, 2026
3feaa18
Fix broken cross ref
juliannguyen4 Mar 24, 2026
3ba8401
Move test case for execute_background to a better location
juliannguyen4 Mar 24, 2026
7f4d0a2
Add mixed read and write ops test cases for execute_background() and …
juliannguyen4 Mar 24, 2026
617105b
Update ConfigProvider default to 5000 per c client changes
juliannguyen4 Mar 24, 2026
f4df01f
Fix test case. TODO - Maybe worth moving query fixture to conftest
juliannguyen4 Mar 24, 2026
ca01e1d
Add DeprecationWarning if bins are selected and operations are added …
juliannguyen4 Mar 25, 2026
43d3371
Merge remote-tracking branch 'origin/dev' into CLIENT-4000-query-read…
juliannguyen4 Mar 25, 2026
7eaea6d
Fix segv because self->query.ops is set to NULL by default. This isn'…
juliannguyen4 Mar 25, 2026
c257804
Add warning for breaking change in next major release for Query.add_ops
juliannguyen4 Mar 26, 2026
6f872c1
Verify behavior that operations are ignored in a foreground query whe…
juliannguyen4 Mar 26, 2026
53bc1cf
Point to Sam's new feature branch for this feature.
juliannguyen4 Mar 27, 2026
1051e4a
Fix one test case. Another test case still failing
juliannguyen4 Mar 27, 2026
3aa9207
Update c client to fix remaining test case failure.
juliannguyen4 Mar 27, 2026
673ca85
Update c client to fix remaining test case failure.
juliannguyen4 Mar 27, 2026
5d8fc3b
Update c client again
juliannguyen4 Mar 30, 2026
c915a01
Improve warning handling.
juliannguyen4 Mar 30, 2026
2d7ddd7
The C/Python client already raises an exception if a foreground or ba…
juliannguyen4 Mar 30, 2026
b888507
Add test cases for both foreground and background queries that check …
juliannguyen4 Mar 30, 2026
1862c36
This should be optimized assuming conftest.py is imported once per te…
juliannguyen4 Mar 30, 2026
4709c80
Add query fixture to conftest.py to be shared. Fix missing import.
juliannguyen4 Mar 30, 2026
15e978e
Not sure if as_connection is invoked twice or we are accessing it ind…
juliannguyen4 Mar 30, 2026
f151440
Fix execute background tests
juliannguyen4 Mar 30, 2026
e7c6c15
Fix test..
juliannguyen4 Mar 30, 2026
742c072
Rm this failing test. We already have test_select_bins_then_add_ops_t…
juliannguyen4 Mar 31, 2026
53855c1
Finish up docs
juliannguyen4 Mar 31, 2026
d88eac2
Fix formatting
juliannguyen4 Mar 31, 2026
f85a891
Change to warnings because deprecation implies removing the APIs
juliannguyen4 Mar 31, 2026
0b4bdc4
Clear up docs
juliannguyen4 Mar 31, 2026
7fe1fe9
Fix broken cross reference.
juliannguyen4 Mar 31, 2026
7c2bc10
Add top level section for foreground queries, since background querie…
juliannguyen4 Mar 31, 2026
a6a0ef8
Rm TODO. I think this is ok since there's no spaces inside the quoted…
juliannguyen4 Mar 31, 2026
b992eee
Move index creation for index named test_background_number_idx from c…
juliannguyen4 Mar 31, 2026
b790e66
Rm unused import
juliannguyen4 Mar 31, 2026
bef513e
Review and revise tests
juliannguyen4 Mar 31, 2026
3e885a8
Use helper function that Sam made
juliannguyen4 Mar 31, 2026
c3e4344
Fix nonsense logic
juliannguyen4 Mar 31, 2026
5f320aa
fix test syntax.
juliannguyen4 Mar 31, 2026
e1e73c1
Fix test..
juliannguyen4 Mar 31, 2026
0775a2d
artifact.aerospike.io may not need credentials
juliannguyen4 Apr 1, 2026
94efe7d
Add input for all test workflows on whether to log in with credential…
juliannguyen4 Apr 1, 2026
c346403
Make tests compatible with server versions < 8.1.2
juliannguyen4 Apr 1, 2026
4cebbc8
have to import requires_server_version since it's not a fixture. TODO…
juliannguyen4 Apr 1, 2026
c8c53b8
require_server_version is a fixture. Also don't need to decorate indi…
juliannguyen4 Apr 1, 2026
22d538d
Move away from deprecated behavior in pytest 9+ of marking fixtures w…
juliannguyen4 Apr 1, 2026
a10545d
Update C client again to see if that fixes test failures
juliannguyen4 Apr 1, 2026
4719b2a
Set up tests to also run with Scan object. TODO currently have failures
juliannguyen4 Apr 1, 2026
1d3313c
For test cases outside of bin projection that don't provide the metho…
juliannguyen4 Apr 1, 2026
dc3a183
Update C client again
juliannguyen4 Apr 1, 2026
84e9d93
Fix ci/cd not deploying the server from the correct registry / image …
juliannguyen4 Apr 1, 2026
c484b6d
Merge remote-tracking branch 'origin/dev' into CLIENT-4000-query-read…
juliannguyen4 Apr 2, 2026
e58faab
Merge remote-tracking branch 'origin/dev' into CLIENT-4000-query-read…
juliannguyen4 Apr 2, 2026
f8f1b47
Create a custom fixture that expects a ClientError if running bin pro…
juliannguyen4 Apr 3, 2026
67ef207
Add support for pulling server RC images from JFrog across the pipeline
juliannguyen4 Apr 3, 2026
cbece27
Copy permissions from CLIENT-4436 ft branch. TODO Also need to do wit…
juliannguyen4 Apr 3, 2026
e436160
Update C client again. Align warnings with PRD
juliannguyen4 Apr 3, 2026
52a7351
Update c client to fix compile error
juliannguyen4 Apr 3, 2026
94a9701
Sync ci/cd changes with other 8.1.2 related branch
juliannguyen4 Apr 6, 2026
52f1c07
Just revert since server 7.1 causes a bunch of ServerErrors with mess…
juliannguyen4 Apr 6, 2026
996c750
Fix tests and clear up in docs to allow basic read operations
juliannguyen4 Apr 7, 2026
3702c10
Forgot to update remaining tests that take in a basic read operation.
juliannguyen4 Apr 7, 2026
3cfd3ea
Cherry pick ci/cd changes from CLIENT-4436 branch to run dev tests
juliannguyen4 Apr 7, 2026
0cf5750
Add test case for increased code coverage
juliannguyen4 Apr 7, 2026
bc99d2d
Fix. query and scan add_ops() take in a generic pyobject that is vali…
juliannguyen4 Apr 7, 2026
fcd9767
Align warning messages with PRD
juliannguyen4 Apr 8, 2026
fdaaeb0
Also add the same test cases from query in scan's execute_background …
juliannguyen4 Apr 8, 2026
8c0361e
pull latest c client
juliannguyen4 Apr 8, 2026
e453f20
Point C client back to stage now that it has the bin projection feature
juliannguyen4 Apr 8, 2026
dd04205
Currently mypy complains when we pass static members of _ExprOp whene…
juliannguyen4 Apr 8, 2026
3932b87
Fix tests related to warnings
juliannguyen4 Apr 8, 2026
347963a
Fix test syntax
juliannguyen4 Apr 8, 2026
f087fd7
Fix test cases where as_connection.scan is somehow recursively callin…
juliannguyen4 Apr 8, 2026
f8c306f
Revert "Currently mypy complains when we pass static members of _Expr…
juliannguyen4 Apr 8, 2026
ee189b3
Cherrypick cicd stuff from CLIENT-4436
juliannguyen4 Apr 8, 2026
6bde8e2
Fix wording, this makes it seem like a breaking change.
juliannguyen4 Apr 8, 2026
424fa8b
Fix
juliannguyen4 Apr 8, 2026
9839fde
Rename set since background tests are using these fixtures/helpers
juliannguyen4 Apr 8, 2026
3c54fb4
Rm unused fixture
juliannguyen4 Apr 8, 2026
5153ea4
Rm comment copied from conftest py fixture
juliannguyen4 Apr 8, 2026
0459aee
Clear up comments in bin projection tests. Remove importing fixtures …
juliannguyen4 Apr 8, 2026
a53abc3
Remove inaccurate comment, there's 2 bins in each record
juliannguyen4 Apr 8, 2026
b180caa
Show logs after test fails. Was unable to reproduce locally with CE n…
juliannguyen4 Apr 8, 2026
89cba77
print job id in case the server shows what happened with this query job
juliannguyen4 Apr 8, 2026
9d74084
Merge remote-tracking branch 'origin/dev' into CLIENT-4000-query-read…
juliannguyen4 Apr 10, 2026
8c1f471
Revert ci/cd pipeline back to known working state that can use qe builds
juliannguyen4 Apr 10, 2026
9bdd921
Mark test regression. TODO - needs jira ticket
juliannguyen4 Apr 10, 2026
36927ea
Fix test
juliannguyen4 Apr 10, 2026
d3dee16
Merge remote-tracking branch 'origin/dev' into CLIENT-4000-query-read…
juliannguyen4 Apr 10, 2026
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
62 changes: 46 additions & 16 deletions doc/query.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,45 @@ Overview
Constructing A Query
--------------------

.. warning:: :meth:`aerospike.Query` should not be called directly to create a :class:`~aerospike.Query` object.

The query object is used for executing queries over a secondary index of a specified set.
It can be created by calling :meth:`aerospike.Client.query`.
It can be created by calling :meth:`aerospike.Client.query`. If the set is initialized to :py:obj:`None`,
then the query will only apply to records without a set.

.. warning:: :meth:`aerospike.Query` should not be called directly to create a :class:`~aerospike.Query` object.

A query without a secondary index filter will apply to all records in the namespace,
similar to a :class:`~aerospike.Scan`.

Otherwise, the query can optionally be assigned one of the secondary index filters in :mod:`aerospike.predicates`
Secondary Index Filters
-----------------------

The query can optionally be assigned one of the secondary index filters in :mod:`aerospike.predicates`
to filter out records using their bin values.
These secondary index filters are applied to the query using :meth:`~aerospike.Query.where`.
In this case, if the set is initialized to :py:obj:`None`, then the query will only apply to records without a set.

.. note::
The secondary index filters in :mod:`aerospike.predicates` are **not** the same as
the deprecated `predicate expressions`.
For more details, read this `guide <https://aerospike.com/docs/develop/learn/queries/secondary-index>`_.

Writing Using Query
-------------------
Filtering Bins
--------------

The returned bins can be filtered by using :meth:`~aerospike.Query.select`.

Background Queries
------------------

If a list of write operations is added to the query with :meth:`~aerospike.Query.add_ops`, \
they will be applied to each record processed by the query. \
See available write operations at :mod:`aerospike_helpers.operations`.


Foreground Queries
------------------

Read operations can also be added in a foreground query using :meth:`~aerospike.Query.add_ops`.

Query Aggregations
------------------

Expand All @@ -47,13 +61,12 @@ records streaming back from the query.
Getting Results From Query
--------------------------

The returned bins can be filtered by using :meth:`select`.
For performing write operations or applying record UDF's, :meth:`~aerospike.Query.execute_background` must be used.

Finally, the query is invoked using one of these methods:
Otherwise, the query is invoked using one of these synchronous methods:

- :meth:`~aerospike.Query.foreach`
- :meth:`~aerospike.Query.results`
- :meth:`~aerospike.Query.execute_background`

.. seealso::
`Queries <https://aerospike.com/docs/develop/learn/queries/>`_ and \
Expand Down Expand Up @@ -107,12 +120,16 @@ Assume this boilerplate code is run before all examples below:

.. method:: select(bin1[, bin2[, bin3..]])

Set a filter on the record bins resulting from :meth:`results` or \
:meth:`foreach`.
.. warning:: In the next major client release, calling this method after :meth:`Query.add_ops` was called on the same Query object will raise a :py:exc:`~aerospike.exception.ParamError` exception.

Set a filter on the record bins resulting from :meth:`results` or :meth:`foreach`.

If this method is called more than once on the same query instance, a :py:exc:`~aerospike.exception.ClientError` exception will be raised.

If a selected bin does not exist in a record it will not appear in the *bins* portion of that record tuple.
If a selected bin does not exist in a record, it will not appear in the *bins* portion of that record tuple.

If this method is called after :meth:`Query.add_ops` was called on the same Query object, the selected bins in
this call will be ignored during the query.

.. method:: where(predicate[, ctx])

Expand Down Expand Up @@ -250,6 +267,8 @@ Assume this boilerplate code is run before all examples below:
predicate is attached to the :class:`~aerospike.Query` the stream UDF \
will aggregate over all the records in the specified set.

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

: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 @@ -280,11 +299,22 @@ Assume this boilerplate code is run before all examples below:

.. method:: add_ops(ops)

Add a list of write ops to the query.
When used with :meth:`Query.execute_background` the query will perform the write ops on any records found.
.. warning:: In the next major client release, if this is called after :meth:`~Query.select` was called on the same object, an :exc:`~aerospike.exception.ParamError` will be raised.

Add a list of operations to the query.

For background queries, only write operations are allowed.
For foreground queries, only read operations are allowed.

For server versions < 8.1.2, basic read operations are allowed in foreground queries. Otherwise with this
server version, using a non-basic read operation will raise a :exc:`~aerospike.exception.ParamError`.

If no predicate is attached to the Query it will apply ops to all the records in the specified set.

:param ops: `list` A list of write operations generated by the aerospike_helpers e.g. list_operations, map_operations, etc.
If there are selected bins in this Query object via :meth:`~Query.select`, those selected bins will be ignored
during the query.

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

.. note::
Requires server version >= 4.7.0.
Expand Down
5 changes: 5 additions & 0 deletions src/include/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -586,3 +586,8 @@ PyObject *AerospikeClient_Commit(AerospikeClient *self, PyObject *args,
PyObject *kwds);
PyObject *AerospikeClient_Abort(AerospikeClient *self, PyObject *args,
PyObject *kwds);

#define SELECT_AND_ADD_OPS_ARE_MUTUALLY_EXCLUSIVE_MESSAGE \
"Operations and bin names are mutually exclusive." \
"In the next major client release, when this %s object is executed, a " \
"ParamError will be raised."
13 changes: 11 additions & 2 deletions src/main/query/add_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@
AerospikeQuery *AerospikeQuery_Add_Ops(AerospikeQuery *self, PyObject *args,
PyObject *kwds)
{
if (self->query.select.size) {
// If select() was called on this Query object before.

int retval = PyErr_WarnFormat(
PyExc_DeprecationWarning, STACK_LEVEL,
SELECT_AND_ADD_OPS_ARE_MUTUALLY_EXCLUSIVE_MESSAGE, "Query");
if (retval == -1) {
return NULL;
}
}

// Python function arguments.
PyObject *py_ops = NULL;
// Python function keyword arguments.
Expand All @@ -40,8 +51,6 @@ AerospikeQuery *AerospikeQuery_Add_Ops(AerospikeQuery *self, PyObject *args,
return NULL;
}

Py_INCREF(py_ops);

// Aerospike API arguments.
long return_type = -1;
long operation;
Expand Down
10 changes: 10 additions & 0 deletions src/main/query/select.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ AerospikeQuery *AerospikeQuery_Select(AerospikeQuery *self, PyObject *args,
{
TRACE();

// If add_ops() was called on this Query object before.
if (as_operations_defined(self->query.ops)) {
int retval = PyErr_WarnFormat(
PyExc_DeprecationWarning, STACK_LEVEL,
SELECT_AND_ADD_OPS_ARE_MUTUALLY_EXCLUSIVE_MESSAGE, "Query");
if (retval == -1) {
return NULL;
}
}

int nbins = (int)PyTuple_Size(args);
char *bin = NULL;
PyObject *py_ubin = NULL;
Expand Down
11 changes: 11 additions & 0 deletions src/main/scan/add_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@
AerospikeScan *AerospikeScan_Add_Ops(AerospikeScan *self, PyObject *args,
PyObject *kwds)
{
if (self->scan.select.size) {
// If select() was called on this Scan object before.

int retval = PyErr_WarnFormat(
PyExc_DeprecationWarning, STACK_LEVEL,
SELECT_AND_ADD_OPS_ARE_MUTUALLY_EXCLUSIVE_MESSAGE, "Scan");
if (retval == -1) {
return NULL;
}
}

// Python function arguments.
PyObject *py_ops = NULL;
// Python function keyword arguments.
Expand Down
10 changes: 10 additions & 0 deletions src/main/scan/select.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ AerospikeScan *AerospikeScan_Select(AerospikeScan *self, PyObject *args,
{
TRACE();

// If add_ops() was called on this Scan object before.
if (as_operations_defined(self->scan.ops)) {
int retval = PyErr_WarnFormat(
PyExc_DeprecationWarning, STACK_LEVEL,
SELECT_AND_ADD_OPS_ARE_MUTUALLY_EXCLUSIVE_MESSAGE, "Scan");
if (retval == -1) {
return NULL;
}
}

char *bin = NULL;
PyObject *py_ustr = NULL;
as_error err;
Expand Down
53 changes: 53 additions & 0 deletions test/new_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import aerospike
from aerospike import exception as e
from aerospike_helpers.operations import operations
from aerospike_helpers.batch.records import BatchRecords, Write
from contextlib import nullcontext

# Comment this out because nowhere in the repository is using it
Expand Down Expand Up @@ -260,6 +262,57 @@ def wait_for_job_completion(as_connection, job_id, job_module: int = aerospike.J
break
time.sleep(0.1)

# Shared between bin projection and execute background tests

TEST_NS = "test"
TEST_SET = "demo"
BIN_NAME = "number"
MAP_BIN_NAME = "map"

# TODO: scale down tests maybe
KEYS = [(TEST_NS, TEST_SET, i) for i in range(500)]
expected_number_bin_values = set()

# Add records around the test
@pytest.fixture(scope="function")
def clean_test_background(as_connection):
batch_records = []
brs = BatchRecords(batch_records=batch_records)
for i, key in enumerate(KEYS):
ops = [
operations.write(BIN_NAME, i),
operations.write(MAP_BIN_NAME, {"a": i})
]
br = Write(key, ops=ops)
batch_records.append(br)
expected_number_bin_values.add(i)
as_connection.batch_write(brs)
yield
as_connection.batch_remove(KEYS)

BASIC_READ_BIN_OPS = [
operations.read(BIN_NAME)
]

READ_AND_WRITE_OPS = [
operations.read(BIN_NAME),
operations.write(BIN_NAME, 1)
]

WRITE_OPS = [
operations.write(BIN_NAME, 3)
]

NON_EXISTENT_BIN_NAME = "asdf"

@pytest.fixture()
def query(request, clean_test_background, as_connection):
if not hasattr(request, "param"):
query = as_connection.query(TEST_NS, TEST_SET)
else:
query = request.param(as_connection, TEST_NS, TEST_SET)
yield query

@pytest.fixture(scope="function")
def expect_earlier_than_server_version_to_fail(as_connection, request):
# Some requesting test cases may not set the param. Like if it is a negative client-side test case and there is no
Expand Down
113 changes: 113 additions & 0 deletions test/new_tests/test_query_bin_projection.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import pytest
from .conftest import BIN_NAME, BASIC_READ_BIN_OPS, READ_AND_WRITE_OPS, NON_EXISTENT_BIN_NAME, WRITE_OPS, MAP_BIN_NAME, expected_number_bin_values
import aerospike
from aerospike_helpers.operations import map_operations
from aerospike import Query
from aerospike import exception as e
from .test_base_class import TestBaseClass
from contextlib import nullcontext


class TestQueryBinProjection:
pytestmark = [
pytest.mark.parametrize(
"query",
[
aerospike.Client.scan,
aerospike.Client.query
],
indirect=True
)
]

def test_query_foreach(self, query):
bin_values = set()
def callback(record):
bin_values.add(record[2][BIN_NAME])

query.add_ops(BASIC_READ_BIN_OPS)
query.foreach(callback)

assert bin_values == expected_number_bin_values

def test_query_results(self, query):
query.add_ops(BASIC_READ_BIN_OPS)
records = query.results()

bin_values = [record[2][BIN_NAME] for record in records]
assert len(bin_values) == len(set(bin_values)) and set(bin_values) == expected_number_bin_values

MAP_GET_BY_KEY_OP = [
map_operations.map_get_by_key(MAP_BIN_NAME, "a", aerospike.MAP_RETURN_VALUE)
]

@pytest.fixture()
def client_should_fail_if_server_version_less_than_8_1_2(self, as_connection, request):
# For bin projection, the server can convert complex (e.g map) read operations into a regular bin read
# Since the server doesn't fail, the client has to check the server version and raise an error on its end.
if (TestBaseClass.major_ver, TestBaseClass.minor_ver, TestBaseClass.patch_ver) >= (8, 1, 2):
yield nullcontext()
else:
yield pytest.raises(e.ParamError)

def test_query_nested_results(self, query, client_should_fail_if_server_version_less_than_8_1_2):
query.add_ops(self.MAP_GET_BY_KEY_OP)
with client_should_fail_if_server_version_less_than_8_1_2:
records = query.results()

bin_values = [record[2][MAP_BIN_NAME] for record in records]
assert len(bin_values) == len(set(bin_values)) and set(bin_values) == expected_number_bin_values

# Negative tests

def noop_callback(record):
pass

@pytest.mark.parametrize(
"api_method, args",
[
("results", []),
("foreach", [noop_callback])
]
)
@pytest.mark.parametrize(
"ops",
[
READ_AND_WRITE_OPS,
WRITE_OPS
]
)
def test_add_write_ops_in_foreground_query(self, query, api_method, args, ops):
query.add_ops(ops)
with pytest.raises(e.ParamError) as excinfo:
getattr(query, api_method)(*args)
cls_name: str = query.__class__.__name__
assert excinfo.value.msg == f"{cls_name} operations must be read-only. Use background {cls_name.lower()} for write-only operations."

# The following 2 test cases should work for any server version. Not just 8.1.2

def test_select_bins_then_add_ops_then_foreground_query(self, query):
query.select(NON_EXISTENT_BIN_NAME)
with pytest.warns(DeprecationWarning):
query.add_ops(BASIC_READ_BIN_OPS)

records = query.results()

# The "filtered out" bin should still be returned
for _, _, bins in records:
assert BIN_NAME in bins

def test_add_ops_then_select_bins_then_foreground_query(self, query):
query.add_ops(BASIC_READ_BIN_OPS)
with pytest.warns(DeprecationWarning):
query.select(NON_EXISTENT_BIN_NAME)

records = query.results()

# The "filtered out" bin should still be returned
for _, _, bins in records:
assert BIN_NAME in bins

def test_add_ops_invalid_args(self, query):
with pytest.raises(TypeError):
query.add_ops()
Loading
Loading