diff --git a/src/braindrop/app/data/raindrops.py b/src/braindrop/app/data/raindrops.py index 6f6454d..7180efc 100644 --- a/src/braindrop/app/data/raindrops.py +++ b/src/braindrop/app/data/raindrops.py @@ -8,7 +8,7 @@ # Python imports. from dataclasses import dataclass from functools import total_ordering -from typing import Callable, Counter, Iterable, Iterator +from typing import Callable, Counter, Iterable, Iterator, TypeAlias ############################################################################## # Typing extension imports. @@ -84,14 +84,21 @@ def __eq__(self, value: object, /) -> bool: raise NotImplementedError +############################################################################## +Filters: TypeAlias = tuple["Filter", ...] +"""The type of a collection of filters.""" + + ############################################################################## class Filter: """Base class for the raindrop filters.""" - def __rand__(self, raindrop: Raindrop) -> bool: - del raindrop + def __rand__(self, _: Raindrop) -> bool: return False + def __radd__(self, filters: Filters) -> Filters: + return (*filters, self) + def __eq__(self, value: object) -> bool: if isinstance(value, Filter): return False @@ -175,7 +182,7 @@ def __init__( self, title: str = "", raindrops: Iterable[Raindrop] | None = None, - filters: tuple[Filter, ...] | None = None, + filters: Filters | None = None, source: Raindrops | None = None, root_collection: Collection | None = None, ) -> None: @@ -336,7 +343,7 @@ def __and__(self, new_filter: Filter) -> Raindrops: return Raindrops( self.title, (raindrop for raindrop in self if raindrop & new_filter), - (*self._filters, new_filter), + self._filters + new_filter, self._source, self._root_collection, ) diff --git a/tests/unit/test_raindrops.py b/tests/unit/test_raindrops.py index d9960a7..b75c719 100644 --- a/tests/unit/test_raindrops.py +++ b/tests/unit/test_raindrops.py @@ -3,6 +3,7 @@ ############################################################################## # Local imports. from braindrop.app.data import Raindrops, TagCount +from braindrop.app.data.raindrops import Filters from braindrop.raindrop import Raindrop, Tag @@ -61,19 +62,23 @@ def test_filter_with_tags() -> None: ############################################################################## def test_filter_with_text() -> None: - """Applying a test filter should have the expected result.""" + """Applying a text filter should have the expected result.""" needle = "needle" find_these = [ Raindrop(title=needle), Raindrop(excerpt=needle), Raindrop(note=needle), Raindrop(tags=[Tag(needle)]), + Raindrop(link=needle), + Raindrop(domain=needle), ] not_these = [ Raindrop(title="title"), Raindrop(excerpt="excerpt"), Raindrop(note="note"), Raindrop(tags=[Tag("tag")]), + Raindrop(link="link"), + Raindrop(domain="domain"), ] haystack = find_these + not_these raindrops = Raindrops(raindrops=haystack) @@ -81,6 +86,19 @@ def test_filter_with_text() -> None: assert list(raindrops.containing(needle)) == find_these +############################################################################## +def test_filter_with_type() -> None: + """Applying a type filter should have the expected result.""" + raindrop_a = Raindrop(type="article") + raindrop_b = Raindrop(type="link") + raindrops = Raindrops(raindrops=[raindrop_a, raindrop_b]) + assert len(raindrops) == 2 + assert len(raindrops.of_type("article")) == 1 + assert next(iter(raindrops.of_type("article"))) == raindrop_a + assert len(raindrops.of_type("link")) == 1 + assert next(iter(raindrops.of_type("link"))) == raindrop_b + + ############################################################################## def test_unfiltering() -> None: """We should be able to unfilter a Raidrops.""" @@ -115,4 +133,20 @@ def test_raindrop_in_raindrops() -> None: assert raindrop not in is_not_in +############################################################################## +def test_filters() -> None: + """We should be able to create a collection of filters.""" + text_filter = Raindrops.Containing("test") + type_filter = Raindrops.IsOfType("link") + tag_filter = Raindrops.Tagged("tag") + filters: Filters = () + filters += text_filter + assert len(filters) == 1 + filters += type_filter + assert len(filters) == 2 + filters += tag_filter + assert len(filters) == 3 + assert filters == (text_filter, type_filter, tag_filter) + + ### test_raindrops.py ends here