Skip to content

Commit

Permalink
feat: add does-not-contain action to the filter
Browse files Browse the repository at this point in the history
  • Loading branch information
alex-karpov authored and daxartio committed Apr 29, 2024
1 parent e9457d6 commit 2a517e2
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 10 deletions.
3 changes: 3 additions & 0 deletions languages/ru_RU/LC_MESSAGES/sportorg.po
Original file line number Diff line number Diff line change
Expand Up @@ -1551,6 +1551,9 @@ msgstr "кр."
msgid "contain"
msgstr "содержит"

msgid "doesn't contain"
msgstr "не содержит"

msgid "equal to"
msgstr "равно"

Expand Down
11 changes: 8 additions & 3 deletions sportorg/gui/dialogs/filter_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,14 @@ def __init__(self, table=None):
self.label.setText(headers[i])
self.label.setObjectName('filter_label_' + str(i))
self.label.setMaximumWidth(120)
self.combo_action = AdvComboBox(
self, {translate('contain'), translate('equal to')}, max_width=90
)
actions = [
translate('equal to'),
translate('contain'),
translate("doesn't contain"),
]
default_action = actions[0]
self.combo_action = AdvComboBox(self, actions, max_width=90)
self.combo_action.setCurrentText(default_action)
self.combo_action.setObjectName('filter_action_' + str(i))
self.combo_value = AdvComboBox(self)
self.combo_value.setMinimumWidth(150)
Expand Down
34 changes: 27 additions & 7 deletions sportorg/gui/tabs/memory_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,18 +108,15 @@ def apply_filter(self):
current_array.extend(self.filter_backup)
self.filter_backup.clear()
for column in self.filter.keys():
check_regexp = re.escape(self.filter.get(column)[0])
action = self.filter.get(column)[1]
filter_action = self.filter.get(column)[1]
filter_value = self.filter.get(column)[0]

check = re.compile('.*' + check_regexp + '.*')

if action == translate('equal to'):
check = re.compile(check_regexp + '$')
check = self.compile_regex(filter_action, filter_value)

i = 0
while i < len(current_array):
value = self.get_item(current_array[i], column)
if not check.match(str(value)):
if not self.match_value(check, str(value)):
self.filter_backup.append(current_array.pop(i))
i -= 1
i += 1
Expand All @@ -129,6 +126,29 @@ def apply_filter(self):
self.set_source_array(current_array)
self.init_cache()

@staticmethod
def compile_regex(action: str, raw_value: str) -> re.Pattern:
"""Compiles a regular expression pattern based on filter action filter value.
Args:
action (str): The action to perform (contain, equal to, doesn't contain).
raw_value (str): The filter value to match against.
Returns:
Pattern[str]: The compiled regular expression pattern.
"""
value = re.escape(raw_value)
regex_string = {
translate('contain'): f'.*{value}.*',
translate('equal to'): f'{value}$',
translate("doesn't contain"): f'^((?!{value}).)*$',
}.get(action, '.*')
return re.compile(regex_string)

@staticmethod
def match_value(check: re.Pattern, value: str) -> bool:
return bool(check.match(value))

def apply_search(self):
if not self.search:
return
Expand Down
93 changes: 93 additions & 0 deletions tests/test_memory_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import pytest

from sportorg.gui.tabs.memory_model import AbstractSportOrgMemoryModel
from sportorg.language import translate


@pytest.mark.parametrize(
'pattern, value, expected',
[
('', '', True),
('', 'Ivan', False),
('Ivan', '', False),
('Ivan', 'Ivan', True),
('Ivan', 'Aleksey', False),
('ivan', 'Ivan', False),
('Ivan', 'Ivanov', False),
('Ivan', 'Ivanov Ivan', False),
('Ivan', 'Ivanov Ivan Ivanovich', False),
('Иван', 'Иван', True),
('1993', '1993', True),
('1993', '4651993', False),
],
)
def test_filter_equal_to_action(pattern, value, expected):
model = AbstractSportOrgMemoryModel
check = model.compile_regex(translate('equal to'), pattern)
result = model.match_value(check, str(value))
assert result == expected


@pytest.mark.parametrize(
'pattern, value, expected',
[
('', '', True),
('', 'Ivan', True),
('Ivan', '', False),
('Ivan', 'Ivan', True),
('Ivan', 'Aleksey', False),
('ivan', 'Ivan', False),
('Ivan', 'Ivanov', True),
('Ivan', 'Sidorov Ivan', True),
('Ivan', 'Sidorov Ivan Petrovich', True),
('Иван', 'Иван', True),
('1993', '1993', True),
('1993', '4651993', True),
],
)
def test_filter_contain_to_action(pattern, value, expected):
model = AbstractSportOrgMemoryModel
check = model.compile_regex(translate('contain'), pattern)
result = model.match_value(check, str(value))
assert result == expected


@pytest.mark.parametrize(
'pattern, value, expected',
[
('', '', True),
('', 'Ivan', False),
('Ivan', '', True),
('Ivan', 'Ivan', False),
('Ivan', 'Aleksey', True),
('ivan', 'Ivan', True),
('Ivan', 'Ivanov', False),
('Ivan', 'Sidorov Ivan', False),
('Ivan', 'Sidorov Ivan Petrovich', False),
('Иван', 'Иван', False),
('1993', '1993', False),
('1993', '4651993', False),
],
)
def test_filter_doesnt_contain_to_action(pattern, value, expected):
model = AbstractSportOrgMemoryModel
check = model.compile_regex(translate("doesn't contain"), pattern)
result = model.match_value(check, str(value))
assert result == expected


@pytest.mark.parametrize(
'pattern, value, expected',
[
('', '', True),
('', 'Ivan', True),
('Ivan', '', True),
('Ivan', 'Ivan', True),
('Ivan', 'Aleksey', True),
],
)
def test_filter_wrong_action(pattern, value, expected):
model = AbstractSportOrgMemoryModel
check = model.compile_regex(translate('wrong action'), pattern)
result = model.match_value(check, value)
assert result == expected

0 comments on commit 2a517e2

Please sign in to comment.