From 8bf245370e6a9d8c27e1a86105b634bee493a485 Mon Sep 17 00:00:00 2001 From: Adrian Zawadzki Date: Thu, 2 Apr 2026 22:37:15 +0200 Subject: [PATCH 1/2] fix(filters): fixed len for filters --- python_tests/test_filter.py | 11 +++++++++++ src/dbzero/object_model/tags/ObjectIterable.cpp | 15 ++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/python_tests/test_filter.py b/python_tests/test_filter.py index 39586cf3..c52dd2f5 100644 --- a/python_tests/test_filter.py +++ b/python_tests/test_filter.py @@ -24,6 +24,17 @@ def test_split_filtered_query(db0_fixture, memo_enum_tags): assert counts[Colors.BLUE] == 2 +def test_len_on_filtered_query(db0_fixture, memo_tags): + query = db0.filter(lambda x: x.value == 1, db0.find("tag1")) + assert len(query) == 1 + + query_even = db0.filter(lambda x: x.value % 2 == 0, db0.find("tag1")) + assert len(query_even) == 5 + + query_none = db0.filter(lambda x: x.value > 100, db0.find("tag1")) + assert len(query_none) == 0 + + def test_sort_filtered_query(db0_fixture, memo_tags): ix_value = db0.index() for obj in db0.find(MemoTestClass, "tag1"): diff --git a/src/dbzero/object_model/tags/ObjectIterable.cpp b/src/dbzero/object_model/tags/ObjectIterable.cpp index 4adbb821..81c5bce0 100644 --- a/src/dbzero/object_model/tags/ObjectIterable.cpp +++ b/src/dbzero/object_model/tags/ObjectIterable.cpp @@ -362,6 +362,15 @@ namespace db0::object_model return 0; } + if (!m_filters.empty()) { + auto obj_iter = iter(); + std::size_t result = 0; + while (!!obj_iter->next()) { + ++result; + } + return result; + } + std::unique_ptr iter; if (m_factory) { iter = m_factory->createFTIterator(); @@ -412,7 +421,11 @@ namespace db0::object_model if (isNull()) { return true; } - + if (!m_filters.empty()) { + auto obj_iter = iter(); + return !obj_iter->next(); + } + std::unique_ptr iter; if (m_factory) { iter = m_factory->createFTIterator(); From 837eabbb6e90d524ea6e13faf23fb4b41742b771 Mon Sep 17 00:00:00 2001 From: Adrian Zawadzki Date: Tue, 14 Apr 2026 12:17:55 +0200 Subject: [PATCH 2/2] bufix(enums): fixed problems with different hashes for EnumValue and EnumValueRepr --- python_tests/test_enum_comparison.py | 380 +++++++++++++++++++++ src/dbzero/object_model/enum/EnumValue.cpp | 2 +- 2 files changed, 381 insertions(+), 1 deletion(-) create mode 100644 python_tests/test_enum_comparison.py diff --git a/python_tests/test_enum_comparison.py b/python_tests/test_enum_comparison.py new file mode 100644 index 00000000..7d81b935 --- /dev/null +++ b/python_tests/test_enum_comparison.py @@ -0,0 +1,380 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Copyright (c) 2025 DBZero Software sp. z o.o. + +import pytest +import dbzero as db0 + + +@db0.enum(values=["RED", "GREEN", "BLUE"]) +class ColorsEnum: + pass + + +@db0.enum(values=["RED", "GREEN", "BLUE"]) +class PaletteEnum: + pass + + +# capture EnumValueRepr before db0 is initialized (default param trick) +def _get_color_repr(color=ColorsEnum.RED): + return color + +def _get_color_green_repr(color=ColorsEnum.GREEN): + return color + +def _get_palette_repr(color=PaletteEnum.RED): + return color + + +# ---- EnumValue comparisons across different prefixes ---- + +def test_enum_value_equal_across_prefixes(db0_fixture): + val_1 = ColorsEnum.RED + db0.open("other-prefix", "rw") + val_2 = ColorsEnum.RED + assert db0.get_prefix_of(val_1) != db0.get_prefix_of(val_2) + assert val_1 == val_2 + assert not (val_1 != val_2) + + +def test_enum_value_not_equal_different_value_across_prefixes(db0_fixture): + val_1 = ColorsEnum.RED + db0.open("other-prefix", "rw") + val_2 = ColorsEnum.GREEN + assert db0.get_prefix_of(val_1) != db0.get_prefix_of(val_2) + assert val_1 != val_2 + assert not (val_1 == val_2) + + +# ---- EnumValueRepr comparisons across different prefixes ---- + +def test_enum_value_repr_equal_across_prefixes(db0_fixture): + """EnumValueRepr for the same enum and value should be equal regardless of prefix.""" + repr_1 = _get_color_repr() + db0.open("other-prefix", "rw") + repr_2 = _get_color_repr() + assert repr_1 == repr_2 + assert not (repr_1 != repr_2) + + +def test_enum_value_repr_not_equal_different_value(db0_fixture): + repr_red = _get_color_repr() + repr_green = _get_color_green_repr() + assert repr_red != repr_green + assert not (repr_red == repr_green) + + +def test_enum_value_repr_not_equal_different_enum(db0_fixture): + """Same value name but different enum types should not be equal.""" + repr_color = _get_color_repr() + repr_palette = _get_palette_repr() + assert repr_color != repr_palette + assert not (repr_color == repr_palette) + + +# ---- EnumValue vs EnumValueRepr on the same prefix ---- + +def test_enum_value_equals_enum_value_repr_same_prefix(db0_fixture): + enum_val = ColorsEnum.RED + repr_val = _get_color_repr() + assert enum_val == repr_val + assert repr_val == enum_val + assert not (enum_val != repr_val) + assert not (repr_val != enum_val) + + +def test_enum_value_not_equal_enum_value_repr_different_value_same_prefix(db0_fixture): + enum_val = ColorsEnum.RED + repr_val = _get_color_green_repr() + assert enum_val != repr_val + assert repr_val != enum_val + assert not (enum_val == repr_val) + assert not (repr_val == enum_val) + + +# ---- EnumValue vs EnumValueRepr on different prefixes ---- + +def test_enum_value_equals_enum_value_repr_different_prefix(db0_fixture): + repr_val = _get_color_repr() + db0.open("other-prefix", "rw") + enum_val = ColorsEnum.RED + assert db0.get_prefix_of(enum_val).name == "other-prefix" + assert enum_val == repr_val + assert repr_val == enum_val + assert not (enum_val != repr_val) + assert not (repr_val != enum_val) + + +def test_enum_value_not_equal_enum_value_repr_different_value_different_prefix(db0_fixture): + repr_val = _get_color_green_repr() + db0.open("other-prefix", "rw") + enum_val = ColorsEnum.RED + assert db0.get_prefix_of(enum_val).name == "other-prefix" + assert enum_val != repr_val + assert repr_val != enum_val + assert not (enum_val == repr_val) + assert not (repr_val == enum_val) + + +# ---- set/in lookup with EnumValue across different prefixes ---- + +def test_in_set_enum_value_across_prefixes(db0_fixture): + val_1 = ColorsEnum.RED + s = {val_1} + db0.open("other-prefix", "rw") + val_2 = ColorsEnum.RED + assert db0.get_prefix_of(val_1) != db0.get_prefix_of(val_2) + assert val_2 in s + + +def test_in_set_enum_value_different_value_across_prefixes(db0_fixture): + val_1 = ColorsEnum.RED + s = {val_1} + db0.open("other-prefix", "rw") + val_2 = ColorsEnum.GREEN + assert val_2 not in s + + +# ---- set/in lookup with EnumValueRepr across different prefixes ---- + +def test_in_set_enum_value_repr_across_prefixes(db0_fixture): + repr_1 = _get_color_repr() + s = {repr_1} + db0.open("other-prefix", "rw") + repr_2 = _get_color_repr() + assert repr_2 in s + + +def test_in_set_enum_value_repr_different_value(db0_fixture): + repr_red = _get_color_repr() + s = {repr_red} + repr_green = _get_color_green_repr() + assert repr_green not in s + + +# ---- set/in lookup between EnumValue and EnumValueRepr on same prefix ---- + +def test_in_set_enum_value_by_repr_same_prefix(db0_fixture): + enum_val = ColorsEnum.RED + s = {enum_val} + repr_val = _get_color_repr() + assert repr_val in s + + +def test_in_set_enum_repr_by_value_same_prefix(db0_fixture): + repr_val = _get_color_repr() + s = {repr_val} + enum_val = ColorsEnum.RED + assert enum_val in s + + +def test_in_set_enum_value_by_repr_different_value_same_prefix(db0_fixture): + enum_val = ColorsEnum.RED + s = {enum_val} + repr_green = _get_color_green_repr() + assert repr_green not in s + + +# ---- set/in lookup between EnumValue and EnumValueRepr on different prefixes ---- + +def test_in_set_enum_value_by_repr_different_prefix(db0_fixture): + repr_val = _get_color_repr() + s = {repr_val} + db0.open("other-prefix", "rw") + enum_val = ColorsEnum.RED + assert db0.get_prefix_of(enum_val).name == "other-prefix" + assert enum_val in s + + +def test_in_set_enum_repr_by_value_different_prefix(db0_fixture): + enum_val = ColorsEnum.RED + s = {enum_val} + db0.open("other-prefix", "rw") + repr_val = _get_color_repr() + assert repr_val in s + + +def test_in_set_enum_value_by_repr_different_value_different_prefix(db0_fixture): + enum_val = ColorsEnum.RED + s = {enum_val} + db0.open("other-prefix", "rw") + repr_green = _get_color_green_repr() + assert repr_green not in s + + +# ---- dict lookup with EnumValue across different prefixes ---- + +def test_in_dict_enum_value_across_prefixes(db0_fixture): + val_1 = ColorsEnum.RED + d = {val_1: "red"} + db0.open("other-prefix", "rw") + val_2 = ColorsEnum.RED + assert db0.get_prefix_of(val_1) != db0.get_prefix_of(val_2) + assert val_2 in d + assert d[val_2] == "red" + + +def test_in_dict_enum_value_different_value_across_prefixes(db0_fixture): + val_1 = ColorsEnum.RED + d = {val_1: "red"} + db0.open("other-prefix", "rw") + val_2 = ColorsEnum.GREEN + assert val_2 not in d + + +# ---- dict lookup with EnumValueRepr across different prefixes ---- + +def test_in_dict_enum_value_repr_across_prefixes(db0_fixture): + repr_1 = _get_color_repr() + d = {repr_1: "red"} + db0.open("other-prefix", "rw") + repr_2 = _get_color_repr() + assert repr_2 in d + assert d[repr_2] == "red" + + +def test_in_dict_enum_value_repr_different_value(db0_fixture): + repr_red = _get_color_repr() + d = {repr_red: "red"} + repr_green = _get_color_green_repr() + assert repr_green not in d + + +# ---- dict lookup between EnumValue and EnumValueRepr on same prefix ---- + +def test_in_dict_enum_value_by_repr_same_prefix(db0_fixture): + enum_val = ColorsEnum.RED + d = {enum_val: "red"} + repr_val = _get_color_repr() + assert repr_val in d + assert d[repr_val] == "red" + + +def test_in_dict_enum_repr_by_value_same_prefix(db0_fixture): + repr_val = _get_color_repr() + d = {repr_val: "red"} + enum_val = ColorsEnum.RED + assert enum_val in d + assert d[enum_val] == "red" + + +def test_in_dict_enum_value_by_repr_different_value_same_prefix(db0_fixture): + enum_val = ColorsEnum.RED + d = {enum_val: "red"} + repr_green = _get_color_green_repr() + assert repr_green not in d + + +# ---- dict lookup between EnumValue and EnumValueRepr on different prefixes ---- + +def test_in_dict_enum_value_by_repr_different_prefix(db0_fixture): + repr_val = _get_color_repr() + d = {repr_val: "red"} + db0.open("other-prefix", "rw") + enum_val = ColorsEnum.RED + assert db0.get_prefix_of(enum_val).name == "other-prefix" + assert enum_val in d + assert d[enum_val] == "red" + + +def test_in_dict_enum_repr_by_value_different_prefix(db0_fixture): + enum_val = ColorsEnum.RED + d = {enum_val: "red"} + db0.open("other-prefix", "rw") + repr_val = _get_color_repr() + assert repr_val in d + assert d[repr_val] == "red" + + +def test_in_dict_enum_value_by_repr_different_value_different_prefix(db0_fixture): + enum_val = ColorsEnum.RED + d = {enum_val: "red"} + db0.open("other-prefix", "rw") + repr_green = _get_color_green_repr() + assert repr_green not in d + + +# ---- list/in lookup with EnumValue across different prefixes ---- + +def test_in_list_enum_value_across_prefixes(db0_fixture): + val_1 = ColorsEnum.RED + lst = [val_1] + db0.open("other-prefix", "rw") + val_2 = ColorsEnum.RED + assert db0.get_prefix_of(val_1) != db0.get_prefix_of(val_2) + assert val_2 in lst + + +def test_in_list_enum_value_different_value_across_prefixes(db0_fixture): + val_1 = ColorsEnum.RED + lst = [val_1] + db0.open("other-prefix", "rw") + val_2 = ColorsEnum.GREEN + assert val_2 not in lst + + +# ---- list/in lookup with EnumValueRepr across different prefixes ---- + +def test_in_list_enum_value_repr_across_prefixes(db0_fixture): + repr_1 = _get_color_repr() + lst = [repr_1] + db0.open("other-prefix", "rw") + repr_2 = _get_color_repr() + assert repr_2 in lst + + +def test_in_list_enum_value_repr_different_value(db0_fixture): + repr_red = _get_color_repr() + lst = [repr_red] + repr_green = _get_color_green_repr() + assert repr_green not in lst + + +# ---- list/in lookup between EnumValue and EnumValueRepr on same prefix ---- + +def test_in_list_enum_value_by_repr_same_prefix(db0_fixture): + enum_val = ColorsEnum.RED + lst = [enum_val] + repr_val = _get_color_repr() + assert repr_val in lst + + +def test_in_list_enum_repr_by_value_same_prefix(db0_fixture): + repr_val = _get_color_repr() + lst = [repr_val] + enum_val = ColorsEnum.RED + assert enum_val in lst + + +def test_in_list_enum_value_by_repr_different_value_same_prefix(db0_fixture): + enum_val = ColorsEnum.RED + lst = [enum_val] + repr_green = _get_color_green_repr() + assert repr_green not in lst + + +# ---- list/in lookup between EnumValue and EnumValueRepr on different prefixes ---- + +def test_in_list_enum_value_by_repr_different_prefix(db0_fixture): + repr_val = _get_color_repr() + lst = [repr_val] + db0.open("other-prefix", "rw") + enum_val = ColorsEnum.RED + assert db0.get_prefix_of(enum_val).name == "other-prefix" + assert enum_val in lst + + +def test_in_list_enum_repr_by_value_different_prefix(db0_fixture): + enum_val = ColorsEnum.RED + lst = [enum_val] + db0.open("other-prefix", "rw") + repr_val = _get_color_repr() + assert repr_val in lst + + +def test_in_list_enum_value_by_repr_different_value_different_prefix(db0_fixture): + enum_val = ColorsEnum.RED + lst = [enum_val] + db0.open("other-prefix", "rw") + repr_green = _get_color_green_repr() + assert repr_green not in lst diff --git a/src/dbzero/object_model/enum/EnumValue.cpp b/src/dbzero/object_model/enum/EnumValue.cpp index 581a5184..59918ed2 100644 --- a/src/dbzero/object_model/enum/EnumValue.cpp +++ b/src/dbzero/object_model/enum/EnumValue.cpp @@ -125,7 +125,7 @@ namespace db0::object_model } std::int64_t EnumValueRepr::getPermHash() const { - return std::hash{}(m_str_repr); + return murmurhash64A(m_str_repr.c_str(), m_str_repr.size()); } bool EnumValue::operator==(const EnumValue &other) const