Skip to content

Commit a60d3d9

Browse files
[CLIENT-3961] Add missing LoopVarHLL and unhide documentation for path expressions (#899)
Fix modify_by_path operation and ModifyByPath expression docstring
1 parent 6f998bf commit a60d3d9

File tree

10 files changed

+108
-66
lines changed

10 files changed

+108
-66
lines changed

aerospike_helpers/expressions/base.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,11 +1120,6 @@ class LoopVarBool(LoopVar):
11201120
_op = aerospike._AS_EXP_LOOPVAR_BOOL
11211121

11221122

1123-
# TODO: remove?
1124-
# class LoopVarInfinity(LoopVar):
1125-
# _op = aerospike._AS_EXP_LOOPVAR_INF
1126-
1127-
11281123
class LoopVarNil(LoopVar):
11291124
_op = aerospike._AS_EXP_LOOPVAR_NIL
11301125

@@ -1133,9 +1128,13 @@ class LoopVarGeoJson(LoopVar):
11331128
_op = aerospike._AS_EXP_LOOPVAR_GEOJSON
11341129

11351130

1131+
class LoopVarHLL(LoopVar):
1132+
_op = aerospike._AS_EXP_LOOPVAR_HLL
1133+
1134+
11361135
class ResultRemove(_BaseExpr):
11371136
"""
1138-
Indicates entry deletion for modify_by_path.
1137+
Indicates entry deletion for :py:class:`ModifyByPath`.
11391138
"""
11401139
_op = aerospike._AS_EXP_CODE_RESULT_REMOVE
11411140

@@ -1176,7 +1175,7 @@ class ModifyByPath(_BaseExpr):
11761175
Constructs an apply by path operation.
11771176
11781177
The results of the evaluation of the modifying expression will replace the
1179-
selected map, and the changes are written back to storage.
1178+
selected element, and the changes are written back to storage.
11801179
"""
11811180
_op = aerospike._AS_EXP_CODE_CALL_APPLY
11821181

aerospike_helpers/operations/operations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ def modify_by_path(bin_name: str, ctx: list[_cdt_ctx], expr, flags: int):
156156
Create path expression modification operation.
157157
158158
The results of the evaluation of the modifying expression will replace the
159-
selected map, and the changes are written back to storage.
159+
selected element, and the changes are written back to storage.
160160
161161
Args:
162162
bin_name: Name of bin that this modify operation is performed against

doc/aerospike.rst

Lines changed: 45 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1810,76 +1810,77 @@ Transaction State
18101810

18111811
.. data:: TXN_STATE_ABORTED
18121812

1813-
..
1814-
Path Expression Flags
1815-
---------------------
1813+
.. _exp_path_select_flags:
18161814

1817-
.. data:: EXP_PATH_SELECT_MATCHING_TREE
1815+
Path Expression Select Flags
1816+
----------------------------
18181817

1819-
Return a tree from the root (bin) level to the bottom of the tree, with only non-filtered out nodes.
1818+
.. data:: EXP_PATH_SELECT_MATCHING_TREE
18201819

1821-
.. data:: EXP_PATH_SELECT_VALUE
1820+
Return a tree from the root (bin) level to the bottom of the tree, with only non-filtered out nodes.
18221821

1823-
Return the list of the values of the nodes finally selected by the context.
1822+
.. data:: EXP_PATH_SELECT_VALUE
18241823

1825-
For maps, this returns the value of each (key, value) pair.
1824+
Return the list of the values of the nodes finally selected by the context.
18261825

1827-
.. data:: EXP_PATH_SELECT_LIST_VALUE
1826+
For maps, this returns the value of each (key, value) pair.
18281827

1829-
Return the list of the values of the nodes finally selected by the context.
1830-
This is a synonym for :data:`aerospike.EXP_PATH_SELECT_VALUE` to make it clear in your
1831-
source code that you're expecting a list.
1828+
.. data:: EXP_PATH_SELECT_LIST_VALUE
18321829

1833-
.. data:: EXP_PATH_SELECT_MAP_VALUE
1830+
Return the list of the values of the nodes finally selected by the context.
1831+
This is a synonym for :data:`aerospike.EXP_PATH_SELECT_VALUE` to make it clear in your
1832+
source code that you're expecting a list.
18341833

1835-
Return the list of map values of the nodes finally selected by the context.
1836-
This is a synonym for :data:`aerospike.EXP_PATH_SELECT_VALUE` to make it clear in your
1837-
source code that you're expecting a map. See also :data:`aerospike.EXP_PATH_SELECT_MAP_KEY_VALUE`.
1834+
.. data:: EXP_PATH_SELECT_MAP_VALUE
18381835

1839-
.. data:: EXP_PATH_SELECT_MAP_KEYS
1836+
Return the list of map values of the nodes finally selected by the context.
1837+
This is a synonym for :data:`aerospike.EXP_PATH_SELECT_VALUE` to make it clear in your
1838+
source code that you're expecting a map. See also :data:`aerospike.EXP_PATH_SELECT_MAP_KEY_VALUE`.
18401839

1841-
Return the list of map keys of the nodes finally selected by the context.
1840+
.. data:: EXP_PATH_SELECT_MAP_KEYS
18421841

1843-
.. data:: EXP_PATH_SELECT_MAP_KEY_VALUE
1842+
Return the list of map keys of the nodes finally selected by the context.
18441843

1845-
Returns the list of map (key, value) pairs of the nodes finally selected
1846-
by the context. This is a synonym for setting both
1847-
:data:`aerospike.EXP_PATH_SELECT_MAP_KEY` and :data:`aerospike.EXP_PATH_SELECT_MAP_VALUE`` bits together.
1848-
The list is formatted as ``[key0, value0, key1, value1...]``.
1844+
.. data:: EXP_PATH_SELECT_MAP_KEY_VALUE
18491845

1850-
.. data:: EXP_PATH_SELECT_NO_FAIL
1846+
Returns the list of map (key, value) pairs of the nodes finally selected
1847+
by the context. This is a synonym for setting both
1848+
:data:`aerospike.EXP_PATH_SELECT_MAP_KEY` and :data:`aerospike.EXP_PATH_SELECT_MAP_VALUE` bits together.
1849+
The list is formatted as ``[key0, value0, key1, value1...]``.
18511850

1852-
If the expression in the context hits an invalid type (e.g selects as an integer when the value is a string),
1853-
do not fail the operation; just ignore those elements. Interpret UNKNOWN as false instead.
1851+
.. data:: EXP_PATH_SELECT_NO_FAIL
18541852

1855-
.. _exp_path_modify_flags:
1853+
If the expression in the context hits an invalid type (e.g selects as an integer when the value is a string),
1854+
do not fail the operation; just ignore those elements. Interpret UNKNOWN as false instead.
18561855

1857-
CDT Modify Flags
1858-
----------------
1856+
.. _exp_path_modify_flags:
18591857

1860-
.. data:: EXP_PATH_MODIFY_DEFAULT
1858+
Path Expression Modify Flags
1859+
----------------------------
18611860

1862-
If the expression in the context hits an invalid type, the operation
1863-
will fail. This is the default behavior.
1861+
.. data:: EXP_PATH_MODIFY_DEFAULT
18641862

1865-
.. data:: EXP_PATH_MODIFY_NO_FAIL
1863+
If the expression in the context hits an invalid type, the operation
1864+
will fail. This is the default behavior.
18661865

1867-
If the expression in the context hits an invalid type (e.g., selects as an integer when the value is a string), do
1868-
not fail the operation; just ignore those elements. Interpret UNKNOWN as false instead.
1866+
.. data:: EXP_PATH_MODIFY_NO_FAIL
18691867

1870-
.. _exp_loopvar_metadata:
1868+
If the expression in the context hits an invalid type (e.g., selects as an integer when the value is a string), do
1869+
not fail the operation; just ignore those elements. Interpret UNKNOWN as false instead.
18711870

1872-
Expression Loop Variable Metadata
1873-
---------------------------------
1871+
.. _exp_loopvar_metadata:
18741872

1875-
.. data:: EXP_LOOPVAR_KEY
1873+
Path Expression Loop Variable Metadata
1874+
--------------------------------------
18761875

1877-
The key associated with this value if part of a key-value pair of a map.
1876+
.. data:: EXP_LOOPVAR_KEY
18781877

1879-
.. data:: EXP_LOOPVAR_VALUE
1878+
The key associated with this value if part of a key-value pair of a map.
18801879

1881-
List item, or value from a map key-value pair.
1880+
.. data:: EXP_LOOPVAR_VALUE
18821881

1883-
.. data:: EXP_LOOPVAR_INDEX
1882+
List item, or value from a map key-value pair.
18841883

1885-
The index if this element was part of a list.
1884+
.. data:: EXP_LOOPVAR_INDEX
1885+
1886+
The index if this element was part of a list.

doc/aerospike_helpers.cdt_ctx.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,5 @@ aerospike\_helpers\.cdt_ctx module
77

88
.. automodule:: aerospike_helpers.cdt_ctx
99
:members:
10-
:exclude-members: cdt_ctx_all_children, cdt_ctx_all_children_with_filter
1110
:undoc-members:
1211
:show-inheritance:

doc/aerospike_helpers.expressions.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@ aerospike\_helpers\.expressions\.base module
165165
---------------------------------------------
166166

167167
.. automodule:: aerospike_helpers.expressions.base
168-
:exclude-members: LoopVar, LoopVarMap, LoopVarList, LoopVarStr, LoopVarFloat, LoopVarInt, LoopVarBlob, LoopVarBool, LoopVarNil, LoopVarGeoJson, SelectByPath, ModifyByPath, ResultRemove
169168
:members:
170169
:special-members:
171170
:show-inheritance:

doc/aerospike_helpers.operations.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ aerospike\_helpers\.operations\.operations module
88

99
.. automodule:: aerospike_helpers.operations.operations
1010
:members:
11-
:exclude-members: select_by_path, modify_by_path
1211
:undoc-members:
1312
:show-inheritance:
1413

src/include/policy.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,9 @@ enum {
182182
_AS_EXP_LOOPVAR_STR,
183183
_AS_EXP_LOOPVAR_BLOB,
184184
_AS_EXP_LOOPVAR_BOOL,
185-
// _AS_EXP_LOOPVAR_INF,
186185
_AS_EXP_LOOPVAR_NIL,
187186
_AS_EXP_LOOPVAR_GEOJSON,
187+
_AS_EXP_LOOPVAR_HLL,
188188
_AS_EXP_CODE_CALL_SELECT,
189189
_AS_EXP_CODE_CALL_APPLY,
190190
};

src/main/aerospike.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,9 +586,9 @@ static struct module_constant_name_to_value module_constants[] = {
586586
EXPOSE_MACRO(_AS_EXP_LOOPVAR_STR),
587587
EXPOSE_MACRO(_AS_EXP_LOOPVAR_BLOB),
588588
EXPOSE_MACRO(_AS_EXP_LOOPVAR_BOOL),
589-
// EXPOSE_MACRO(_AS_EXP_LOOPVAR_INF),
590589
EXPOSE_MACRO(_AS_EXP_LOOPVAR_NIL),
591590
EXPOSE_MACRO(_AS_EXP_LOOPVAR_GEOJSON),
591+
EXPOSE_MACRO(_AS_EXP_LOOPVAR_HLL),
592592

593593
// C client uses the same expression code for these two expressions
594594
// so we define unique ones in the Python client code

src/main/convert_expressions.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ static as_status get_expr_size(int *size_to_alloc, int *intermediate_exprs_size,
222222
[_AS_EXP_LOOPVAR_BLOB] = EXP_SZ(as_exp_loopvar_blob(0)),
223223
[_AS_EXP_LOOPVAR_GEOJSON] = EXP_SZ(as_exp_loopvar_geojson(0)),
224224
[_AS_EXP_LOOPVAR_NIL] = EXP_SZ(as_exp_loopvar_nil(0)),
225-
// [_AS_EXP_LOOPVAR_INF] = EXP_SZ(as_exp_loopvar_infinity(0)),
225+
[_AS_EXP_LOOPVAR_HLL] = EXP_SZ(as_exp_loopvar_hll(0)),
226226
[VAL] = EXP_SZ(as_exp_val(
227227
NULL)), // NOTE if I don't count vals I don't need to subtract from other ops // MUST count these for expressions with var args.
228228
[EQ] = EXP_SZ(
@@ -661,6 +661,7 @@ add_expr_macros(AerospikeClient *self, as_static_pool *static_pool,
661661
case _AS_EXP_LOOPVAR_BOOL:
662662
case _AS_EXP_LOOPVAR_BLOB:
663663
case _AS_EXP_LOOPVAR_NIL:
664+
case _AS_EXP_LOOPVAR_HLL:
664665
case _AS_EXP_LOOPVAR_GEOJSON:
665666
if (get_int64_t(err, AS_PY_VAL_KEY, temp_expr->pydict, &lval1) !=
666667
AEROSPIKE_OK) {
@@ -695,6 +696,9 @@ add_expr_macros(AerospikeClient *self, as_static_pool *static_pool,
695696
case _AS_EXP_LOOPVAR_GEOJSON:
696697
APPEND_ARRAY(0, as_exp_loopvar_geojson(lval1));
697698
break;
699+
case _AS_EXP_LOOPVAR_HLL:
700+
APPEND_ARRAY(0, as_exp_loopvar_hll(lval1));
701+
break;
698702
}
699703

700704
break;

test/new_tests/test_path_expressions.py

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22

33
import aerospike
44
from aerospike_helpers.operations import operations
5+
from aerospike_helpers.operations import hll_operations as hll_ops
6+
from aerospike_helpers.operations import map_operations
57
from aerospike_helpers.expressions.resources import ResultType
6-
from aerospike_helpers.expressions.base import GE, Eq, LoopVarStr, LoopVarFloat, LoopVarInt, LoopVarMap, LoopVarList, ModifyByPath, SelectByPath, MapBin, LoopVarBool, LoopVarBlob, ResultRemove, LoopVarGeoJson, LoopVarNil, CmpGeo
7-
from aerospike_helpers.expressions.map import MapGetByKey
8+
from aerospike_helpers.expressions.base import GE, Eq, LoopVarStr, LoopVarFloat, LoopVarInt, LoopVarMap, LoopVarList, ModifyByPath, SelectByPath, MapBin, LoopVarBool, LoopVarBlob, ResultRemove, LoopVarGeoJson, LoopVarNil, CmpGeo, LoopVarHLL, HLLBin
9+
from aerospike_helpers.expressions.map import MapGetByKey, MapPut
810
from aerospike_helpers.expressions.list import ListSize
911
from aerospike_helpers.expressions.arithmetic import Sub
12+
from aerospike_helpers.expressions import hll
1013
from aerospike_helpers.operations import expression_operations as expr_ops
1114
from aerospike_helpers import cdt_ctx
1215
from aerospike import exception as e
@@ -30,7 +33,7 @@ class TestPathExprOperations:
3033
MAP_OF_NESTED_MAPS_BIN_NAME = "map_of_maps_bin"
3134
NESTED_LIST_BIN_NAME = "list_of_lists"
3235
MAP_WITH_GEOJSON_BIN_NAME = "map_w_geo_bin"
33-
36+
3437
GEOJSON_VALUE = aerospike.geojson('{"type": "Point", "coordinates": [-80.604333, 28.608389]}')
3538
RECORD_BINS = {
3639
MAP_BIN_NAME: {
@@ -165,7 +168,7 @@ def insert_record(self):
165168
)
166169
]
167170
)
168-
def test_exp_path_basic_functionality(self, op, expected_bins):
171+
def test_select_by_path_operation(self, op, expected_bins):
169172
ops = [
170173
op
171174
]
@@ -178,7 +181,7 @@ def test_exp_path_basic_functionality(self, op, expected_bins):
178181
20.0
179182
).compile()
180183

181-
def test_exp_path_with_filter(self):
184+
def test_select_by_path_operation_with_filter(self):
182185
ops = [
183186
operations.select_by_path(
184187
bin_name=self.MAP_OF_NESTED_MAPS_BIN_NAME,
@@ -296,6 +299,44 @@ def test_exp_loopvar_list(self):
296299
[4, 5]
297300
]
298301

302+
MAP_WITH_HLL_BIN_NAME = "map_w_hll_bin"
303+
304+
@pytest.fixture
305+
def setup_hll_bin(self):
306+
ops = [
307+
# Insert root level HLL bin
308+
# Using a second operation to move the hll value into a map doesn't work...
309+
hll_ops.hll_add(bin_name=self.MAP_WITH_HLL_BIN_NAME, values=[i for i in range(5000)], index_bit_count=4, mh_bit_count=4),
310+
]
311+
self.as_connection.operate(self.key, ops)
312+
313+
_, _, bins = self.as_connection.get(self.key)
314+
self.expected_hll_value = bins[self.MAP_WITH_HLL_BIN_NAME]
315+
316+
map_with_hll_value = {
317+
"a": bins[self.MAP_WITH_HLL_BIN_NAME]
318+
}
319+
self.as_connection.put(self.key, bins={self.MAP_WITH_HLL_BIN_NAME: map_with_hll_value})
320+
321+
yield
322+
323+
self.as_connection.remove_bin(self.key, list=[self.MAP_WITH_HLL_BIN_NAME])
324+
325+
def test_exp_loopvar_hll(self, setup_hll_bin):
326+
# HLL bin value should always be returned
327+
filter_expr = GE(hll.HLLGetCount(bin=LoopVarHLL(var_id=aerospike.EXP_LOOPVAR_VALUE)), 0).compile()
328+
ops = [
329+
operations.select_by_path(
330+
bin_name=self.MAP_WITH_HLL_BIN_NAME,
331+
ctx=[
332+
cdt_ctx.cdt_ctx_all_children_with_filter(filter_expr)
333+
],
334+
flags=aerospike.EXP_PATH_SELECT_VALUE
335+
)
336+
]
337+
with self.expected_context_for_pos_tests:
338+
_, _, bins = self.as_connection.operate(self.key, ops)
339+
assert bins[self.MAP_WITH_HLL_BIN_NAME] == [self.expected_hll_value]
299340

300341
SUBTRACT_FIVE_FROM_ITERATED_FLOAT_EXPR = Sub(LoopVarFloat(aerospike.EXP_LOOPVAR_VALUE), 5.0).compile()
301342
# Expected results
@@ -306,7 +347,7 @@ def test_exp_loopvar_list(self):
306347
aerospike.EXP_PATH_MODIFY_NO_FAIL,
307348
aerospike.EXP_PATH_MODIFY_DEFAULT,
308349
])
309-
def test_cdt_modify(self, flags):
350+
def test_modify_by_path_operation(self, flags):
310351
ops = [
311352
operations.modify_by_path(
312353
bin_name=self.MAP_OF_NESTED_MAPS_BIN_NAME,
@@ -332,7 +373,7 @@ def test_cdt_modify(self, flags):
332373
assert bins[self.MAP_OF_NESTED_MAPS_BIN_NAME] == self.SECOND_LEVEL_INTEGERS_MINUS_FIVE
333374

334375

335-
# Test path expression flags
376+
# Test path expression select flags
336377

337378
def test_exp_path_flag_matching_tree(self):
338379
ops = [
@@ -457,7 +498,7 @@ def test_neg_invalid_ctx(self, ctx_list, expected_context, op_method, op_kwargs)
457498
with expected_context:
458499
self.as_connection.operate(self.key, ops)
459500

460-
def test_exp_select_by_path(self):
501+
def test_select_by_path_expression(self):
461502
ctx=[
462503
cdt_ctx.cdt_ctx_all_children(),
463504
cdt_ctx.cdt_ctx_all_children()

0 commit comments

Comments
 (0)