mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-07 06:15:36 +00:00
Add filters support for lookups of single select fields
This commit is contained in:
parent
5558139eb8
commit
be27e89fb0
19 changed files with 1358 additions and 95 deletions
backend
changelog/entries/unreleased/feature
web-frontend
locales
modules
core
database
test/unit/database
|
@ -5,9 +5,7 @@ from baserow.contrib.database.fields.dependencies.circular_reference_checker imp
|
|||
)
|
||||
from baserow.contrib.database.fields.field_types import FormulaFieldType
|
||||
from baserow.contrib.database.fields.models import FormulaField
|
||||
from baserow.contrib.database.formula.types.formula_types import (
|
||||
BaserowFormulaSingleSelectType,
|
||||
)
|
||||
from baserow.contrib.database.fields.registries import field_type_registry
|
||||
|
||||
|
||||
class TypeFormulaRequestSerializer(serializers.ModelSerializer):
|
||||
|
@ -27,10 +25,14 @@ class BaserowFormulaSelectOptionsSerializer(serializers.ListField):
|
|||
from baserow.contrib.database.fields.models import SelectOption
|
||||
|
||||
field = data.instance
|
||||
if field.formula_type != BaserowFormulaSingleSelectType.type:
|
||||
return []
|
||||
field_type = field_type_registry.get_by_model(field)
|
||||
|
||||
select_options = SelectOption.objects.filter(
|
||||
field_id__in=get_all_field_dependencies(field)
|
||||
)
|
||||
return [self.child.to_representation(item) for item in select_options]
|
||||
# Select options are needed for view filters in the frontend,
|
||||
# but let's avoid the potentially slow query if not required.
|
||||
if field_type.can_represent_select_options(field):
|
||||
select_options = SelectOption.objects.filter(
|
||||
field_id__in=get_all_field_dependencies(field)
|
||||
)
|
||||
return [self.child.to_representation(item) for item in select_options]
|
||||
else:
|
||||
return []
|
||||
|
|
|
@ -443,7 +443,9 @@ class DatabaseConfig(AppConfig):
|
|||
view_filter_type_registry.register(UserIsNotViewFilterType())
|
||||
|
||||
from .views.array_view_filters import (
|
||||
HasAnySelectOptionEqualViewFilterType,
|
||||
HasEmptyValueViewFilterType,
|
||||
HasNoneSelectOptionEqualViewFilterType,
|
||||
HasNotEmptyValueViewFilterType,
|
||||
HasNotValueContainsViewFilterType,
|
||||
HasNotValueContainsWordViewFilterType,
|
||||
|
@ -463,6 +465,8 @@ class DatabaseConfig(AppConfig):
|
|||
view_filter_type_registry.register(HasValueLengthIsLowerThanViewFilterType())
|
||||
view_filter_type_registry.register(HasEmptyValueViewFilterType())
|
||||
view_filter_type_registry.register(HasNotEmptyValueViewFilterType())
|
||||
view_filter_type_registry.register(HasAnySelectOptionEqualViewFilterType())
|
||||
view_filter_type_registry.register(HasNoneSelectOptionEqualViewFilterType())
|
||||
|
||||
from .views.view_aggregations import (
|
||||
AverageViewAggregationType,
|
||||
|
|
|
@ -4890,6 +4890,9 @@ class FormulaFieldType(FormulaArrayFilterSupport, ReadOnlyFieldType):
|
|||
def can_represent_files(self, field):
|
||||
return self.to_baserow_formula_type(field.specific).can_represent_files
|
||||
|
||||
def can_represent_select_options(self, field):
|
||||
return self.to_baserow_formula_type(field.specific).can_represent_select_options
|
||||
|
||||
def get_permission_error_when_user_changes_field_to_depend_on_forbidden_field(
|
||||
self, user: AbstractUser, changed_field: Field, forbidden_field: Field
|
||||
) -> Exception:
|
||||
|
@ -5268,14 +5271,24 @@ class LookupFieldType(FormulaFieldType):
|
|||
"target_field_id",
|
||||
"target_field_name",
|
||||
]
|
||||
serializer_field_names = BASEROW_FORMULA_TYPE_ALLOWED_FIELDS + [
|
||||
request_serializer_field_names = (
|
||||
BASEROW_FORMULA_TYPE_REQUEST_SERIALIZER_FIELD_NAMES
|
||||
+ [
|
||||
"through_field_id",
|
||||
"through_field_name",
|
||||
"target_field_id",
|
||||
"target_field_name",
|
||||
"formula_type",
|
||||
]
|
||||
)
|
||||
serializer_field_names = BASEROW_FORMULA_TYPE_SERIALIZER_FIELD_NAMES + [
|
||||
"through_field_id",
|
||||
"through_field_name",
|
||||
"target_field_id",
|
||||
"target_field_name",
|
||||
"formula_type",
|
||||
]
|
||||
serializer_field_overrides = {
|
||||
request_serializer_field_overrides = {
|
||||
"through_field_name": serializers.CharField(
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
|
@ -5311,14 +5324,6 @@ class LookupFieldType(FormulaFieldType):
|
|||
"error": serializers.CharField(required=False, read_only=True),
|
||||
}
|
||||
|
||||
@property
|
||||
def request_serializer_field_names(self):
|
||||
return self.serializer_field_names
|
||||
|
||||
@property
|
||||
def request_serializer_field_overrides(self):
|
||||
return self.serializer_field_overrides
|
||||
|
||||
def before_create(
|
||||
self, table, primary, allowed_field_values, order, user, field_kwargs
|
||||
):
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
from functools import reduce
|
||||
from typing import TYPE_CHECKING, List
|
||||
|
||||
from django.contrib.postgres.fields import JSONField
|
||||
from django.db import models
|
||||
from django.db.models import BooleanField, F, Q, Value
|
||||
|
||||
from baserow.contrib.database.fields.field_filters import (
|
||||
AnnotatedQ,
|
||||
OptionallyAnnotatedQ,
|
||||
)
|
||||
from baserow.contrib.database.formula.expression_generator.django_expressions import (
|
||||
JSONArrayContainsSelectOptionValueExpr,
|
||||
JSONArrayContainsSelectOptionValueSimilarToExpr,
|
||||
JSONArrayEqualSelectOptionIdExpr,
|
||||
)
|
||||
|
||||
from .base import (
|
||||
HasValueContainsFilterSupport,
|
||||
HasValueContainsWordFilterSupport,
|
||||
HasValueEmptyFilterSupport,
|
||||
HasValueFilterSupport,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from baserow.contrib.database.fields.models import Field
|
||||
|
||||
|
||||
class SingleSelectFormulaTypeFilterSupport(
|
||||
HasValueEmptyFilterSupport,
|
||||
HasValueFilterSupport,
|
||||
HasValueContainsFilterSupport,
|
||||
HasValueContainsWordFilterSupport,
|
||||
):
|
||||
def get_in_array_empty_query(self, field_name, model_field, field: "Field"):
|
||||
return Q(**{f"{field_name}__contains": Value([{"value": None}], JSONField())})
|
||||
|
||||
def get_in_array_is_query(
|
||||
self,
|
||||
field_name: str,
|
||||
value: str | List[str],
|
||||
model_field: models.Field,
|
||||
field: "Field",
|
||||
) -> OptionallyAnnotatedQ:
|
||||
if not value:
|
||||
return Q()
|
||||
elif isinstance(value, str):
|
||||
try:
|
||||
# If the value is a single value it must be a valid ID.
|
||||
int(value)
|
||||
except ValueError:
|
||||
return Q()
|
||||
value = [value]
|
||||
|
||||
annotations, q = {}, []
|
||||
for v in value:
|
||||
hashed_value = hash(v)
|
||||
annotation_key = f"{field_name}_has_value_{hashed_value}"
|
||||
annotation_query = JSONArrayEqualSelectOptionIdExpr(
|
||||
F(field_name), Value(f"{v}"), output_field=BooleanField()
|
||||
)
|
||||
annotations[annotation_key] = annotation_query
|
||||
q.append(Q(**{annotation_key: True}))
|
||||
|
||||
return AnnotatedQ(
|
||||
annotation=annotations,
|
||||
q=reduce(lambda a, b: a | b, q),
|
||||
)
|
||||
|
||||
def get_in_array_contains_query(
|
||||
self, field_name: str, value: str, model_field: models.Field, field: "Field"
|
||||
) -> OptionallyAnnotatedQ:
|
||||
annotation_query = JSONArrayContainsSelectOptionValueExpr(
|
||||
F(field_name), Value(f"%{value}%"), output_field=BooleanField()
|
||||
)
|
||||
hashed_value = hash(value)
|
||||
return AnnotatedQ(
|
||||
annotation={
|
||||
f"{field_name}_has_value_contains_{hashed_value}": annotation_query
|
||||
},
|
||||
q={f"{field_name}_has_value_contains_{hashed_value}": True},
|
||||
)
|
||||
|
||||
def get_in_array_contains_word_query(
|
||||
self, field_name: str, value: str, model_field: models.Field, field: "Field"
|
||||
) -> OptionallyAnnotatedQ:
|
||||
annotation_query = JSONArrayContainsSelectOptionValueSimilarToExpr(
|
||||
F(field_name), Value(f"{value}"), output_field=BooleanField()
|
||||
)
|
||||
hashed_value = hash(value)
|
||||
return AnnotatedQ(
|
||||
annotation={
|
||||
f"{field_name}_has_value_contains_word_{hashed_value}": annotation_query
|
||||
},
|
||||
q={f"{field_name}_has_value_contains_word_{hashed_value}": True},
|
||||
)
|
|
@ -1725,6 +1725,11 @@ class FieldType(
|
|||
|
||||
return False
|
||||
|
||||
def can_represent_select_options(self, field):
|
||||
"""Indicates whether the field can be used to represent select options."""
|
||||
|
||||
return False
|
||||
|
||||
def get_permission_error_when_user_changes_field_to_depend_on_forbidden_field(
|
||||
self, user: AbstractUser, changed_field: Field, forbidden_field: Field
|
||||
) -> Exception:
|
||||
|
|
|
@ -209,3 +209,45 @@ class JSONArrayContainsValueLengthLowerThanExpr(BaserowFilterExpression):
|
|||
""" # nosec B608 %(value)s
|
||||
)
|
||||
# fmt: on
|
||||
|
||||
|
||||
class JSONArrayEqualSelectOptionIdExpr(BaserowFilterExpression):
|
||||
# fmt: off
|
||||
template = (
|
||||
f"""
|
||||
EXISTS(
|
||||
SELECT filtered_field -> 'value' ->> 'id'
|
||||
FROM JSONB_ARRAY_ELEMENTS(%(field_name)s) as filtered_field
|
||||
WHERE (filtered_field -> 'value' ->> 'id') LIKE (%(value)s)
|
||||
)
|
||||
""" # nosec B608
|
||||
)
|
||||
# fmt: on
|
||||
|
||||
|
||||
class JSONArrayContainsSelectOptionValueExpr(BaserowFilterExpression):
|
||||
# fmt: off
|
||||
template = (
|
||||
f"""
|
||||
EXISTS(
|
||||
SELECT filtered_field -> 'value' ->> 'value'
|
||||
FROM JSONB_ARRAY_ELEMENTS(%(field_name)s) as filtered_field
|
||||
WHERE UPPER(filtered_field -> 'value' ->> 'value') LIKE UPPER(%(value)s)
|
||||
)
|
||||
""" # nosec B608
|
||||
)
|
||||
# fmt: on
|
||||
|
||||
|
||||
class JSONArrayContainsSelectOptionValueSimilarToExpr(BaserowFilterExpression):
|
||||
# fmt: off
|
||||
template = (
|
||||
r"""
|
||||
EXISTS(
|
||||
SELECT filtered_field -> 'value' ->> 'value'
|
||||
FROM JSONB_ARRAY_ELEMENTS(%(field_name)s) as filtered_field
|
||||
WHERE filtered_field -> 'value' ->> 'value' ~* ('\y' || %(value)s || '\y')
|
||||
)
|
||||
""" # nosec B608 %(value)s
|
||||
)
|
||||
# fmt: on
|
||||
|
|
|
@ -258,6 +258,10 @@ class BaserowFormulaType(abc.ABC):
|
|||
def can_represent_files(self) -> bool:
|
||||
return False
|
||||
|
||||
@property
|
||||
def can_represent_select_options(self) -> bool:
|
||||
return False
|
||||
|
||||
@property
|
||||
def item_is_in_nested_value_object_when_in_array(self) -> bool:
|
||||
return True
|
||||
|
|
|
@ -29,6 +29,9 @@ from baserow.contrib.database.fields.filter_support.base import (
|
|||
from baserow.contrib.database.fields.filter_support.exceptions import (
|
||||
FilterNotSupportedException,
|
||||
)
|
||||
from baserow.contrib.database.fields.filter_support.single_select import (
|
||||
SingleSelectFormulaTypeFilterSupport,
|
||||
)
|
||||
from baserow.contrib.database.fields.mixins import get_date_time_format
|
||||
from baserow.contrib.database.fields.utils.duration import (
|
||||
D_H_M_S,
|
||||
|
@ -1295,8 +1298,32 @@ class BaserowFormulaArrayType(
|
|||
def can_represent_files(self, field):
|
||||
return self.sub_type.can_represent_files(field)
|
||||
|
||||
def can_represent_select_options(self, field) -> bool:
|
||||
return self.sub_type.can_represent_select_options(field)
|
||||
|
||||
class BaserowFormulaSingleSelectType(BaserowJSONBObjectBaseType):
|
||||
@classmethod
|
||||
def get_serializer_field_overrides(cls):
|
||||
from baserow.contrib.database.api.fields.serializers import (
|
||||
SelectOptionSerializer,
|
||||
)
|
||||
from baserow.contrib.database.api.formula.serializers import (
|
||||
BaserowFormulaSelectOptionsSerializer,
|
||||
)
|
||||
|
||||
return {
|
||||
"select_options": BaserowFormulaSelectOptionsSerializer(
|
||||
child=SelectOptionSerializer(),
|
||||
required=False,
|
||||
allow_null=True,
|
||||
read_only=True,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class BaserowFormulaSingleSelectType(
|
||||
SingleSelectFormulaTypeFilterSupport,
|
||||
BaserowJSONBObjectBaseType,
|
||||
):
|
||||
type = "single_select"
|
||||
baserow_field_type = "single_select"
|
||||
can_order_by = True
|
||||
|
@ -1310,6 +1337,10 @@ class BaserowFormulaSingleSelectType(BaserowJSONBObjectBaseType):
|
|||
BaserowFormulaTextType,
|
||||
]
|
||||
|
||||
@property
|
||||
def can_represent_select_options(self) -> bool:
|
||||
return True
|
||||
|
||||
@property
|
||||
def limit_comparable_types(self) -> List[Type["BaserowFormulaValidType"]]:
|
||||
return []
|
||||
|
|
|
@ -14,6 +14,7 @@ from baserow.contrib.database.fields.registries import field_type_registry
|
|||
from baserow.contrib.database.formula import BaserowFormulaTextType
|
||||
from baserow.contrib.database.formula.types.formula_types import (
|
||||
BaserowFormulaCharType,
|
||||
BaserowFormulaSingleSelectType,
|
||||
BaserowFormulaURLType,
|
||||
)
|
||||
|
||||
|
@ -33,13 +34,13 @@ class HasEmptyValueViewFilterType(ViewFilterType):
|
|||
FormulaFieldType.array_of(BaserowFormulaTextType.type),
|
||||
FormulaFieldType.array_of(BaserowFormulaCharType.type),
|
||||
FormulaFieldType.array_of(BaserowFormulaURLType.type),
|
||||
FormulaFieldType.array_of(BaserowFormulaSingleSelectType.type),
|
||||
),
|
||||
]
|
||||
|
||||
def get_filter(self, field_name, value, model_field, field) -> OptionallyAnnotatedQ:
|
||||
field_type = field_type_registry.get_by_model(field)
|
||||
try:
|
||||
field_type = field_type_registry.get_by_model(field)
|
||||
|
||||
if not isinstance(field_type, HasValueEmptyFilterSupport):
|
||||
raise FilterNotSupportedException()
|
||||
|
||||
|
@ -66,13 +67,13 @@ class HasValueEqualViewFilterType(ViewFilterType):
|
|||
FormulaFieldType.array_of(BaserowFormulaTextType.type),
|
||||
FormulaFieldType.array_of(BaserowFormulaCharType.type),
|
||||
FormulaFieldType.array_of(BaserowFormulaURLType.type),
|
||||
FormulaFieldType.array_of(BaserowFormulaSingleSelectType.type),
|
||||
),
|
||||
]
|
||||
|
||||
def get_filter(self, field_name, value, model_field, field) -> OptionallyAnnotatedQ:
|
||||
field_type = field_type_registry.get_by_model(field)
|
||||
try:
|
||||
field_type = field_type_registry.get_by_model(field)
|
||||
|
||||
if not isinstance(field_type, HasValueFilterSupport):
|
||||
raise FilterNotSupportedException()
|
||||
|
||||
|
@ -101,13 +102,13 @@ class HasValueContainsViewFilterType(ViewFilterType):
|
|||
FormulaFieldType.array_of(BaserowFormulaTextType.type),
|
||||
FormulaFieldType.array_of(BaserowFormulaCharType.type),
|
||||
FormulaFieldType.array_of(BaserowFormulaURLType.type),
|
||||
FormulaFieldType.array_of(BaserowFormulaSingleSelectType.type),
|
||||
),
|
||||
]
|
||||
|
||||
def get_filter(self, field_name, value, model_field, field) -> OptionallyAnnotatedQ:
|
||||
field_type = field_type_registry.get_by_model(field)
|
||||
try:
|
||||
field_type = field_type_registry.get_by_model(field)
|
||||
|
||||
if not isinstance(field_type, HasValueContainsFilterSupport):
|
||||
raise FilterNotSupportedException()
|
||||
|
||||
|
@ -136,13 +137,13 @@ class HasValueContainsWordViewFilterType(ViewFilterType):
|
|||
FormulaFieldType.array_of(BaserowFormulaTextType.type),
|
||||
FormulaFieldType.array_of(BaserowFormulaCharType.type),
|
||||
FormulaFieldType.array_of(BaserowFormulaURLType.type),
|
||||
FormulaFieldType.array_of(BaserowFormulaSingleSelectType.type),
|
||||
),
|
||||
]
|
||||
|
||||
def get_filter(self, field_name, value, model_field, field) -> OptionallyAnnotatedQ:
|
||||
field_type = field_type_registry.get_by_model(field)
|
||||
try:
|
||||
field_type = field_type_registry.get_by_model(field)
|
||||
|
||||
if not isinstance(field_type, HasValueContainsWordFilterSupport):
|
||||
raise FilterNotSupportedException()
|
||||
|
||||
|
@ -175,9 +176,8 @@ class HasValueLengthIsLowerThanViewFilterType(ViewFilterType):
|
|||
]
|
||||
|
||||
def get_filter(self, field_name, value, model_field, field) -> OptionallyAnnotatedQ:
|
||||
field_type = field_type_registry.get_by_model(field)
|
||||
try:
|
||||
field_type = field_type_registry.get_by_model(field)
|
||||
|
||||
if not isinstance(field_type, HasValueLengthIsLowerThanFilterSupport):
|
||||
raise FilterNotSupportedException()
|
||||
|
||||
|
@ -186,3 +186,31 @@ class HasValueLengthIsLowerThanViewFilterType(ViewFilterType):
|
|||
)
|
||||
except Exception:
|
||||
return self.default_filter_on_exception()
|
||||
|
||||
|
||||
class HasAnySelectOptionEqualViewFilterType(HasValueEqualViewFilterType):
|
||||
"""
|
||||
This filter can be used to verify if any of the select options in an array
|
||||
are equal to the option IDs provided.
|
||||
"""
|
||||
|
||||
type = "has_any_select_option_equal"
|
||||
compatible_field_types = [
|
||||
FormulaFieldType.compatible_with_formula_types(
|
||||
FormulaFieldType.array_of(BaserowFormulaSingleSelectType.type),
|
||||
),
|
||||
]
|
||||
|
||||
def get_filter(self, field_name, value, model_field, field) -> OptionallyAnnotatedQ:
|
||||
return super().get_filter(field_name, value.split(","), model_field, field)
|
||||
|
||||
|
||||
class HasNoneSelectOptionEqualViewFilterType(
|
||||
NotViewFilterTypeMixin, HasAnySelectOptionEqualViewFilterType
|
||||
):
|
||||
"""
|
||||
This filter can be used to verify if none of the select options in an array are
|
||||
equal to the option IDs provided
|
||||
"""
|
||||
|
||||
type = "has_none_select_option_equal"
|
||||
|
|
|
@ -49,6 +49,12 @@ def uuid_field_factory(data_fixture, table, user):
|
|||
return data_fixture.create_uuid_field(name="target", user=user, table=table)
|
||||
|
||||
|
||||
def single_select_field_factory(data_fixture, table, user):
|
||||
return data_fixture.create_single_select_field(
|
||||
name="target", user=user, table=table
|
||||
)
|
||||
|
||||
|
||||
def setup(data_fixture, target_field_factory):
|
||||
user = data_fixture.create_user()
|
||||
database = data_fixture.create_database_application(user=user)
|
||||
|
@ -85,28 +91,47 @@ def setup(data_fixture, target_field_factory):
|
|||
)
|
||||
|
||||
|
||||
def text_field_value_factory(data_fixture, target_field, value=None):
|
||||
return value or ""
|
||||
|
||||
|
||||
def single_select_field_value_factory(data_fixture, target_field, value=None):
|
||||
return (
|
||||
data_fixture.create_select_option(field=target_field, value=value)
|
||||
if value
|
||||
else None
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"target_field_factory",
|
||||
"target_field_factory,target_field_value_factory",
|
||||
[
|
||||
text_field_factory,
|
||||
long_text_field_factory,
|
||||
email_field_factory,
|
||||
phone_number_field_factory,
|
||||
url_field_factory,
|
||||
(text_field_factory, text_field_value_factory),
|
||||
(long_text_field_factory, text_field_value_factory),
|
||||
(email_field_factory, text_field_value_factory),
|
||||
(phone_number_field_factory, text_field_value_factory),
|
||||
(url_field_factory, text_field_value_factory),
|
||||
(single_select_field_factory, single_select_field_value_factory),
|
||||
],
|
||||
)
|
||||
@pytest.mark.django_db
|
||||
def test_has_empty_value_filter_text_field_types(data_fixture, target_field_factory):
|
||||
def test_has_empty_value_filter_text_field_types(
|
||||
data_fixture, target_field_factory, target_field_value_factory
|
||||
):
|
||||
test_setup = setup(data_fixture, target_field_factory)
|
||||
|
||||
row_A_value = target_field_value_factory(data_fixture, test_setup.target_field, "A")
|
||||
row_B_value = target_field_value_factory(data_fixture, test_setup.target_field, "B")
|
||||
row_empty_value = target_field_value_factory(data_fixture, test_setup.target_field)
|
||||
|
||||
other_row_A = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": "A"}
|
||||
**{f"field_{test_setup.target_field.id}": row_A_value}
|
||||
)
|
||||
other_row_B = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": "B"}
|
||||
**{f"field_{test_setup.target_field.id}": row_B_value}
|
||||
)
|
||||
other_row_empty = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": ""}
|
||||
**{f"field_{test_setup.target_field.id}": row_empty_value}
|
||||
)
|
||||
row_1 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
|
@ -189,29 +214,34 @@ def test_has_empty_value_filter_uuid_field_types(data_fixture):
|
|||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"target_field_factory",
|
||||
"target_field_factory,target_field_value_factory",
|
||||
[
|
||||
text_field_factory,
|
||||
long_text_field_factory,
|
||||
email_field_factory,
|
||||
phone_number_field_factory,
|
||||
url_field_factory,
|
||||
(text_field_factory, text_field_value_factory),
|
||||
(long_text_field_factory, text_field_value_factory),
|
||||
(email_field_factory, text_field_value_factory),
|
||||
(phone_number_field_factory, text_field_value_factory),
|
||||
(url_field_factory, text_field_value_factory),
|
||||
(single_select_field_factory, single_select_field_value_factory),
|
||||
],
|
||||
)
|
||||
@pytest.mark.django_db
|
||||
def test_has_not_empty_value_filter_text_field_types(
|
||||
data_fixture, target_field_factory
|
||||
data_fixture, target_field_factory, target_field_value_factory
|
||||
):
|
||||
test_setup = setup(data_fixture, target_field_factory)
|
||||
|
||||
row_A_value = target_field_value_factory(data_fixture, test_setup.target_field, "A")
|
||||
row_B_value = target_field_value_factory(data_fixture, test_setup.target_field, "B")
|
||||
row_empty_value = target_field_value_factory(data_fixture, test_setup.target_field)
|
||||
|
||||
other_row_A = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": "A"}
|
||||
**{f"field_{test_setup.target_field.id}": row_A_value}
|
||||
)
|
||||
other_row_B = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": "B"}
|
||||
**{f"field_{test_setup.target_field.id}": row_B_value}
|
||||
)
|
||||
other_row_empty = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": ""}
|
||||
**{f"field_{test_setup.target_field.id}": row_empty_value}
|
||||
)
|
||||
row_1 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
|
@ -1560,3 +1590,540 @@ def test_has_value_length_is_lower_than_uuid_field_types(data_fixture):
|
|||
).all()
|
||||
]
|
||||
assert len(ids) == 4
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_has_value_equal_filter_single_select_field(data_fixture):
|
||||
test_setup = setup(data_fixture, single_select_field_factory)
|
||||
|
||||
opt_a = data_fixture.create_select_option(field=test_setup.target_field, value="a")
|
||||
opt_b = data_fixture.create_select_option(field=test_setup.target_field, value="b")
|
||||
opt_c = data_fixture.create_select_option(field=test_setup.target_field, value="c")
|
||||
|
||||
other_row_a = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_a}
|
||||
)
|
||||
other_row_b = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_b}
|
||||
)
|
||||
other_row_c = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_c}
|
||||
)
|
||||
|
||||
row_1 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_a.id, other_row_b.id]
|
||||
},
|
||||
)
|
||||
row_2 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={f"field_{test_setup.link_row_field.id}": [other_row_a.id]},
|
||||
)
|
||||
row_3 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_b.id, other_row_c.id]
|
||||
},
|
||||
)
|
||||
|
||||
view_filter = data_fixture.create_view_filter(
|
||||
view=test_setup.grid_view,
|
||||
field=test_setup.lookup_field,
|
||||
type="has_value_equal",
|
||||
value=str(opt_a.id),
|
||||
)
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 2
|
||||
assert row_1.id in ids
|
||||
assert row_2.id in ids
|
||||
|
||||
view_filter.value = str(opt_b.id)
|
||||
view_filter.save()
|
||||
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 2
|
||||
assert row_1.id in ids
|
||||
assert row_3.id in ids
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_has_not_value_equal_filter_single_select_field(data_fixture):
|
||||
test_setup = setup(data_fixture, single_select_field_factory)
|
||||
|
||||
opt_a = data_fixture.create_select_option(field=test_setup.target_field, value="a")
|
||||
opt_b = data_fixture.create_select_option(field=test_setup.target_field, value="b")
|
||||
opt_c = data_fixture.create_select_option(field=test_setup.target_field, value="c")
|
||||
|
||||
other_row_a = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_a}
|
||||
)
|
||||
other_row_b = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_b}
|
||||
)
|
||||
other_row_c = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_c}
|
||||
)
|
||||
|
||||
row_1 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_a.id, other_row_b.id]
|
||||
},
|
||||
)
|
||||
row_2 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={f"field_{test_setup.link_row_field.id}": [other_row_a.id]},
|
||||
)
|
||||
row_3 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_b.id, other_row_c.id]
|
||||
},
|
||||
)
|
||||
|
||||
view_filter = data_fixture.create_view_filter(
|
||||
view=test_setup.grid_view,
|
||||
field=test_setup.lookup_field,
|
||||
type="has_not_value_equal",
|
||||
value=str(opt_c.id),
|
||||
)
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 2
|
||||
assert row_1.id in ids
|
||||
assert row_2.id in ids
|
||||
|
||||
view_filter.value = str(opt_b.id)
|
||||
view_filter.save()
|
||||
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 1
|
||||
assert row_2.id in ids
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_has_value_contains_filter_single_select_field(data_fixture):
|
||||
test_setup = setup(data_fixture, single_select_field_factory)
|
||||
|
||||
opt_a = data_fixture.create_select_option(field=test_setup.target_field, value="a")
|
||||
opt_b = data_fixture.create_select_option(field=test_setup.target_field, value="ba")
|
||||
opt_c = data_fixture.create_select_option(field=test_setup.target_field, value="c")
|
||||
|
||||
other_row_a = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_a}
|
||||
)
|
||||
other_row_b = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_b}
|
||||
)
|
||||
other_row_c = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_c}
|
||||
)
|
||||
|
||||
row_1 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_a.id, other_row_b.id]
|
||||
},
|
||||
)
|
||||
row_2 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={f"field_{test_setup.link_row_field.id}": [other_row_a.id]},
|
||||
)
|
||||
row_3 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_b.id, other_row_c.id]
|
||||
},
|
||||
)
|
||||
|
||||
view_filter = data_fixture.create_view_filter(
|
||||
view=test_setup.grid_view,
|
||||
field=test_setup.lookup_field,
|
||||
type="has_value_contains",
|
||||
value="a",
|
||||
)
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 3
|
||||
assert row_1.id in ids
|
||||
assert row_2.id in ids
|
||||
assert row_3.id in ids
|
||||
|
||||
view_filter.value = "c"
|
||||
view_filter.save()
|
||||
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 1
|
||||
assert row_3.id in ids
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_has_not_value_contains_filter_single_select_field(data_fixture):
|
||||
test_setup = setup(data_fixture, single_select_field_factory)
|
||||
|
||||
opt_a = data_fixture.create_select_option(field=test_setup.target_field, value="a")
|
||||
opt_b = data_fixture.create_select_option(field=test_setup.target_field, value="ba")
|
||||
opt_c = data_fixture.create_select_option(field=test_setup.target_field, value="c")
|
||||
|
||||
other_row_a = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_a}
|
||||
)
|
||||
other_row_b = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_b}
|
||||
)
|
||||
other_row_c = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_c}
|
||||
)
|
||||
|
||||
row_1 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_a.id, other_row_b.id]
|
||||
},
|
||||
)
|
||||
row_2 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={f"field_{test_setup.link_row_field.id}": [other_row_a.id]},
|
||||
)
|
||||
row_3 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_b.id, other_row_c.id]
|
||||
},
|
||||
)
|
||||
|
||||
view_filter = data_fixture.create_view_filter(
|
||||
view=test_setup.grid_view,
|
||||
field=test_setup.lookup_field,
|
||||
type="has_not_value_contains",
|
||||
value="a",
|
||||
)
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 0
|
||||
|
||||
view_filter.value = "c"
|
||||
view_filter.save()
|
||||
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 2
|
||||
assert row_1.id in ids
|
||||
assert row_2.id in ids
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_has_value_contains_word_filter_single_select_field(data_fixture):
|
||||
test_setup = setup(data_fixture, single_select_field_factory)
|
||||
|
||||
opt_a = data_fixture.create_select_option(field=test_setup.target_field, value="a")
|
||||
opt_b = data_fixture.create_select_option(field=test_setup.target_field, value="b")
|
||||
opt_c = data_fixture.create_select_option(field=test_setup.target_field, value="ca")
|
||||
|
||||
other_row_a = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_a}
|
||||
)
|
||||
other_row_b = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_b}
|
||||
)
|
||||
other_row_c = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_c}
|
||||
)
|
||||
|
||||
row_1 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_a.id, other_row_b.id]
|
||||
},
|
||||
)
|
||||
row_2 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={f"field_{test_setup.link_row_field.id}": [other_row_a.id]},
|
||||
)
|
||||
row_3 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_b.id, other_row_c.id]
|
||||
},
|
||||
)
|
||||
|
||||
view_filter = data_fixture.create_view_filter(
|
||||
view=test_setup.grid_view,
|
||||
field=test_setup.lookup_field,
|
||||
type="has_value_contains_word",
|
||||
value="a",
|
||||
)
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 2
|
||||
assert row_1.id in ids
|
||||
assert row_2.id in ids
|
||||
|
||||
view_filter.value = "ca"
|
||||
view_filter.save()
|
||||
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 1
|
||||
assert row_3.id in ids
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_has_not_value_contains_word_filter_single_select_field(data_fixture):
|
||||
test_setup = setup(data_fixture, single_select_field_factory)
|
||||
|
||||
opt_a = data_fixture.create_select_option(field=test_setup.target_field, value="a")
|
||||
opt_b = data_fixture.create_select_option(field=test_setup.target_field, value="b")
|
||||
opt_c = data_fixture.create_select_option(field=test_setup.target_field, value="ca")
|
||||
|
||||
other_row_a = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_a}
|
||||
)
|
||||
other_row_b = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_b}
|
||||
)
|
||||
other_row_c = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_c}
|
||||
)
|
||||
|
||||
row_1 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_a.id, other_row_b.id]
|
||||
},
|
||||
)
|
||||
row_2 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={f"field_{test_setup.link_row_field.id}": [other_row_a.id]},
|
||||
)
|
||||
row_3 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_b.id, other_row_c.id]
|
||||
},
|
||||
)
|
||||
|
||||
view_filter = data_fixture.create_view_filter(
|
||||
view=test_setup.grid_view,
|
||||
field=test_setup.lookup_field,
|
||||
type="has_not_value_contains_word",
|
||||
value="a",
|
||||
)
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 1
|
||||
assert row_3.id in ids
|
||||
|
||||
view_filter.value = "ca"
|
||||
view_filter.save()
|
||||
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 2
|
||||
assert row_1.id in ids
|
||||
assert row_2.id in ids
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_has_any_select_option_equal_filter_single_select_field(data_fixture):
|
||||
test_setup = setup(data_fixture, single_select_field_factory)
|
||||
|
||||
opt_a = data_fixture.create_select_option(field=test_setup.target_field, value="a")
|
||||
opt_b = data_fixture.create_select_option(field=test_setup.target_field, value="b")
|
||||
opt_c = data_fixture.create_select_option(field=test_setup.target_field, value="c")
|
||||
|
||||
other_row_a = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_a}
|
||||
)
|
||||
other_row_b = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_b}
|
||||
)
|
||||
other_row_c = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_c}
|
||||
)
|
||||
|
||||
row_1 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_a.id, other_row_b.id]
|
||||
},
|
||||
)
|
||||
row_2 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={f"field_{test_setup.link_row_field.id}": [other_row_a.id]},
|
||||
)
|
||||
row_3 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_b.id, other_row_c.id]
|
||||
},
|
||||
)
|
||||
|
||||
view_filter = data_fixture.create_view_filter(
|
||||
view=test_setup.grid_view,
|
||||
field=test_setup.lookup_field,
|
||||
type="has_any_select_option_equal",
|
||||
value=f"{opt_a.id},{opt_c.id}",
|
||||
)
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 3
|
||||
assert row_1.id in ids
|
||||
assert row_2.id in ids
|
||||
assert row_3.id in ids
|
||||
|
||||
view_filter.value = f"{opt_b.id},{opt_c.id}"
|
||||
view_filter.save()
|
||||
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 2
|
||||
assert row_1.id in ids
|
||||
assert row_3.id in ids
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_has_none_select_option_equal_filter_single_select_field(data_fixture):
|
||||
test_setup = setup(data_fixture, single_select_field_factory)
|
||||
|
||||
opt_a = data_fixture.create_select_option(field=test_setup.target_field, value="a")
|
||||
opt_b = data_fixture.create_select_option(field=test_setup.target_field, value="b")
|
||||
opt_c = data_fixture.create_select_option(field=test_setup.target_field, value="ca")
|
||||
|
||||
other_row_a = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_a}
|
||||
)
|
||||
other_row_b = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_b}
|
||||
)
|
||||
other_row_c = test_setup.other_table_model.objects.create(
|
||||
**{f"field_{test_setup.target_field.id}": opt_c}
|
||||
)
|
||||
|
||||
row_1 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_a.id, other_row_b.id]
|
||||
},
|
||||
)
|
||||
row_2 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={f"field_{test_setup.link_row_field.id}": [other_row_a.id]},
|
||||
)
|
||||
row_3 = test_setup.row_handler.create_row(
|
||||
user=test_setup.user,
|
||||
table=test_setup.table,
|
||||
values={
|
||||
f"field_{test_setup.link_row_field.id}": [other_row_b.id, other_row_c.id]
|
||||
},
|
||||
)
|
||||
|
||||
view_filter = data_fixture.create_view_filter(
|
||||
view=test_setup.grid_view,
|
||||
field=test_setup.lookup_field,
|
||||
type="has_none_select_option_equal",
|
||||
value=f"{opt_a.id},{opt_c.id}",
|
||||
)
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 0
|
||||
|
||||
view_filter.value = f"{opt_b.id},{opt_c.id}"
|
||||
view_filter.save()
|
||||
|
||||
ids = [
|
||||
r.id
|
||||
for r in test_setup.view_handler.apply_filters(
|
||||
test_setup.grid_view, test_setup.model.objects.all()
|
||||
).all()
|
||||
]
|
||||
assert len(ids) == 1
|
||||
assert row_2.id in ids
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "feature",
|
||||
"message": "Add filters support for lookups of single select fields.",
|
||||
"issue_number": 3182,
|
||||
"bullet_points": [],
|
||||
"created_at": "2024-11-06"
|
||||
}
|
|
@ -198,6 +198,8 @@
|
|||
"hasValueContainsWord": "has value contains word",
|
||||
"hasNotValueContainsWord": "doesn't have value contains word",
|
||||
"hasValueLengthIsLowerThan": "has value length is lower than",
|
||||
"hasAnySelectOptionEqual": "has any select option equal",
|
||||
"hasNoneSelectOptionEqual": "doesn't have select option equal",
|
||||
"contains": "contains",
|
||||
"containsNot": "doesn't contain",
|
||||
"containsWord": "contains word",
|
||||
|
|
|
@ -36,14 +36,16 @@
|
|||
export function mix(...chain) {
|
||||
const [baseClass, ...mixins] = chain.reverse()
|
||||
|
||||
class Mixed extends baseClass {}
|
||||
|
||||
for (const mixin of mixins) {
|
||||
for (const [key, value] of Object.entries(mixin)) {
|
||||
/* eslint no-prototype-builtins: "off" */
|
||||
if (!baseClass.prototype.hasOwnProperty(key)) {
|
||||
baseClass.prototype[key] = value
|
||||
if (!Mixed.prototype.hasOwnProperty(key)) {
|
||||
Mixed.prototype[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return baseClass
|
||||
return Mixed
|
||||
}
|
||||
|
|
|
@ -71,3 +71,105 @@ export const hasValueLengthIsLowerThanFilterMixin = {
|
|||
return genericHasValueLengthLowerThanFilter
|
||||
},
|
||||
}
|
||||
|
||||
export const formulaArrayFilterMixin = {
|
||||
getSubType(field) {
|
||||
return this.app.$registry.get('formula_type', field.array_formula_type)
|
||||
},
|
||||
|
||||
getHasEmptyValueFilterFunction(field) {
|
||||
const subType = this.getSubType(field)
|
||||
return subType.getHasEmptyValueFilterFunction(field)
|
||||
},
|
||||
|
||||
getHasValueLengthIsLowerThanFilterFunction(field) {
|
||||
const subType = this.getSubType(field)
|
||||
return subType.getHasValueLengthIsLowerThanFilterFunction(field)
|
||||
},
|
||||
|
||||
getHasValueContainsFilterFunction(field) {
|
||||
const subType = this.getSubType(field)
|
||||
return subType.getHasValueContainsFilterFunction(field)
|
||||
},
|
||||
|
||||
getHasValueContainsWordFilterFunction(field) {
|
||||
const subType = this.getSubType(field)
|
||||
return subType.getHasValueContainsWordFilterFunction(field)
|
||||
},
|
||||
|
||||
hasValueContainsWordFilter(cellValue, filterValue, field) {
|
||||
const subType = this.getSubType(field)
|
||||
return subType.hasValueContainsWordFilter(cellValue, filterValue, field)
|
||||
},
|
||||
|
||||
hasNotValueContainsWordFilter(cellValue, filterValue, field) {
|
||||
const subType = this.getSubType(field)
|
||||
return subType.hasNotValueContainsWordFilter(cellValue, filterValue, field)
|
||||
},
|
||||
|
||||
getHasValueEqualFilterFunction(field) {
|
||||
const subType = this.getSubType(field)
|
||||
return subType.getHasValueEqualFilterFunction(field)
|
||||
},
|
||||
|
||||
hasValueEqualFilter(cellValue, filterValue, field) {
|
||||
const subType = this.getSubType(field)
|
||||
return subType.hasValueEqualFilter(cellValue, filterValue, field)
|
||||
},
|
||||
|
||||
hasNotValueEqualFilter(cellValue, filterValue, field) {
|
||||
const subType = this.getSubType(field)
|
||||
return subType.hasNotValueEqualFilter(cellValue, filterValue, field)
|
||||
},
|
||||
}
|
||||
|
||||
export const hasSelectOptionIdEqualMixin = Object.assign(
|
||||
{},
|
||||
hasValueEqualFilterMixin,
|
||||
{
|
||||
getHasValueEqualFilterFunction(field) {
|
||||
const mapOptionIdsToValues = (cellVal) =>
|
||||
cellVal.map((v) => ({
|
||||
id: v.id,
|
||||
value: String(v.value?.id || ''),
|
||||
}))
|
||||
const hasValueEqualFilter = (cellVal, fltValue) =>
|
||||
genericHasValueEqualFilter(mapOptionIdsToValues(cellVal), fltValue)
|
||||
|
||||
return (cellValue, filterValue) => {
|
||||
const filterValues = filterValue.trim().split(',')
|
||||
return filterValues.reduce((acc, fltValue) => {
|
||||
return acc || hasValueEqualFilter(cellValue, String(fltValue))
|
||||
}, false)
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export const hasSelectOptionValueContainsFilterMixin = Object.assign(
|
||||
{},
|
||||
hasValueContainsFilterMixin,
|
||||
{
|
||||
getHasValueContainsFilterFunction(field) {
|
||||
return (cellValue, filterValue) =>
|
||||
genericHasValueContainsFilter(
|
||||
cellValue.map((v) => ({ id: v.id, value: v.value?.value || '' })),
|
||||
filterValue
|
||||
)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
export const hasSelectOptionValueContainsWordFilterMixin = Object.assign(
|
||||
{},
|
||||
hasValueContainsWordFilterMixin,
|
||||
{
|
||||
getHasValueContainsWordFilterFunction(field) {
|
||||
return (cellValue, filterValue) =>
|
||||
genericHasValueContainsWordFilter(
|
||||
cellValue.map((v) => ({ id: v.id, value: v.value?.value || '' })),
|
||||
filterValue
|
||||
)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
|
|
@ -2,6 +2,8 @@ import ViewFilterTypeText from '@baserow/modules/database/components/view/ViewFi
|
|||
import ViewFilterTypeNumber from '@baserow/modules/database/components/view/ViewFilterTypeNumber'
|
||||
import { FormulaFieldType } from '@baserow/modules/database/fieldTypes'
|
||||
import { ViewFilterType } from '@baserow/modules/database/viewFilters'
|
||||
import ViewFilterTypeSelectOptions from '@baserow/modules/database/components/view/ViewFilterTypeSelectOptions'
|
||||
import ViewFilterTypeMultipleSelectOptions from '@baserow/modules/database/components/view/ViewFilterTypeMultipleSelectOptions'
|
||||
|
||||
export class HasEmptyValueViewFilterType extends ViewFilterType {
|
||||
static getType() {
|
||||
|
@ -18,6 +20,7 @@ export class HasEmptyValueViewFilterType extends ViewFilterType {
|
|||
FormulaFieldType.compatibleWithFormulaTypes('array(text)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(char)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(url)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(single_select)'),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -41,6 +44,7 @@ export class HasNotEmptyValueViewFilterType extends ViewFilterType {
|
|||
FormulaFieldType.compatibleWithFormulaTypes('array(text)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(char)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(url)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(single_select)'),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -60,7 +64,10 @@ export class HasValueEqualViewFilterType extends ViewFilterType {
|
|||
}
|
||||
|
||||
getInputComponent(field) {
|
||||
return ViewFilterTypeText
|
||||
const mapping = {
|
||||
single_select: ViewFilterTypeSelectOptions,
|
||||
}
|
||||
return mapping[field.array_formula_type] || ViewFilterTypeText
|
||||
}
|
||||
|
||||
getCompatibleFieldTypes() {
|
||||
|
@ -68,6 +75,7 @@ export class HasValueEqualViewFilterType extends ViewFilterType {
|
|||
FormulaFieldType.compatibleWithFormulaTypes('array(text)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(char)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(url)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(single_select)'),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -87,7 +95,10 @@ export class HasNotValueEqualViewFilterType extends ViewFilterType {
|
|||
}
|
||||
|
||||
getInputComponent(field) {
|
||||
return ViewFilterTypeText
|
||||
const mapping = {
|
||||
single_select: ViewFilterTypeSelectOptions,
|
||||
}
|
||||
return mapping[field.array_formula_type] || ViewFilterTypeText
|
||||
}
|
||||
|
||||
getCompatibleFieldTypes() {
|
||||
|
@ -95,6 +106,7 @@ export class HasNotValueEqualViewFilterType extends ViewFilterType {
|
|||
FormulaFieldType.compatibleWithFormulaTypes('array(text)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(char)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(url)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(single_select)'),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -122,6 +134,7 @@ export class HasValueContainsViewFilterType extends ViewFilterType {
|
|||
FormulaFieldType.compatibleWithFormulaTypes('array(text)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(char)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(url)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(single_select)'),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -149,6 +162,7 @@ export class HasNotValueContainsViewFilterType extends ViewFilterType {
|
|||
FormulaFieldType.compatibleWithFormulaTypes('array(text)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(char)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(url)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(single_select)'),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -176,6 +190,7 @@ export class HasValueContainsWordViewFilterType extends ViewFilterType {
|
|||
FormulaFieldType.compatibleWithFormulaTypes('array(text)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(char)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(url)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(single_select)'),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -203,6 +218,7 @@ export class HasNotValueContainsWordViewFilterType extends ViewFilterType {
|
|||
FormulaFieldType.compatibleWithFormulaTypes('array(text)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(char)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(url)'),
|
||||
FormulaFieldType.compatibleWithFormulaTypes('array(single_select)'),
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -244,3 +260,49 @@ export class HasValueLengthIsLowerThanViewFilterType extends ViewFilterType {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class HasAnySelectOptionEqualViewFilterType extends ViewFilterType {
|
||||
static getType() {
|
||||
return 'has_any_select_option_equal'
|
||||
}
|
||||
|
||||
getName() {
|
||||
const { i18n } = this.app
|
||||
return i18n.t('viewFilter.hasAnySelectOptionEqual')
|
||||
}
|
||||
|
||||
getInputComponent(field) {
|
||||
return ViewFilterTypeMultipleSelectOptions
|
||||
}
|
||||
|
||||
getCompatibleFieldTypes() {
|
||||
return [FormulaFieldType.compatibleWithFormulaTypes('array(single_select)')]
|
||||
}
|
||||
|
||||
matches(cellValue, filterValue, field, fieldType) {
|
||||
return fieldType.hasValueEqualFilter(cellValue, filterValue, field)
|
||||
}
|
||||
}
|
||||
|
||||
export class HasNoneSelectOptionEqualViewFilterType extends ViewFilterType {
|
||||
static getType() {
|
||||
return 'has_none_select_option_equal'
|
||||
}
|
||||
|
||||
getName() {
|
||||
const { i18n } = this.app
|
||||
return i18n.t('viewFilter.hasNoneSelectOptionEqual')
|
||||
}
|
||||
|
||||
getInputComponent(field) {
|
||||
return ViewFilterTypeMultipleSelectOptions
|
||||
}
|
||||
|
||||
getCompatibleFieldTypes() {
|
||||
return [FormulaFieldType.compatibleWithFormulaTypes('array(single_select)')]
|
||||
}
|
||||
|
||||
matches(cellValue, filterValue, field, fieldType) {
|
||||
return fieldType.hasNotValueEqualFilter(cellValue, filterValue, field)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,6 +53,10 @@ import {
|
|||
hasValueContainsFilterMixin,
|
||||
hasValueContainsWordFilterMixin,
|
||||
hasValueLengthIsLowerThanFilterMixin,
|
||||
hasSelectOptionIdEqualMixin,
|
||||
hasSelectOptionValueContainsFilterMixin,
|
||||
hasSelectOptionValueContainsWordFilterMixin,
|
||||
formulaArrayFilterMixin,
|
||||
} from '@baserow/modules/database/arrayFilterMixins'
|
||||
import _ from 'lodash'
|
||||
|
||||
|
@ -517,11 +521,7 @@ export class BaserowFormulaInvalidType extends BaserowFormulaTypeDefinition {
|
|||
}
|
||||
|
||||
export class BaserowFormulaArrayType extends mix(
|
||||
hasEmptyValueFilterMixin,
|
||||
hasValueEqualFilterMixin,
|
||||
hasValueContainsFilterMixin,
|
||||
hasValueContainsWordFilterMixin,
|
||||
hasValueLengthIsLowerThanFilterMixin,
|
||||
formulaArrayFilterMixin,
|
||||
BaserowFormulaTypeDefinition
|
||||
) {
|
||||
static getType() {
|
||||
|
@ -705,38 +705,6 @@ export class BaserowFormulaArrayType extends mix(
|
|||
)
|
||||
return subType.getHasEmptyValueFilterFunction(field)
|
||||
}
|
||||
|
||||
getHasValueEqualFilterFunction(field) {
|
||||
const subType = this.app.$registry.get(
|
||||
'formula_type',
|
||||
field.array_formula_type
|
||||
)
|
||||
return subType.getHasValueEqualFilterFunction(field)
|
||||
}
|
||||
|
||||
getHasValueContainsFilterFunction(field) {
|
||||
const subType = this.app.$registry.get(
|
||||
'formula_type',
|
||||
field.array_formula_type
|
||||
)
|
||||
return subType.getHasValueContainsFilterFunction(field)
|
||||
}
|
||||
|
||||
getHasValueContainsWordFilterFunction(field) {
|
||||
const subType = this.app.$registry.get(
|
||||
'formula_type',
|
||||
field.array_formula_type
|
||||
)
|
||||
return subType.getHasValueContainsWordFilterFunction(field)
|
||||
}
|
||||
|
||||
getHasValueLengthIsLowerThanFilterFunction(field) {
|
||||
const subType = this.app.$registry.get(
|
||||
'formula_type',
|
||||
field.array_formula_type
|
||||
)
|
||||
return subType.getHasValueLengthIsLowerThanFilterFunction(field)
|
||||
}
|
||||
}
|
||||
|
||||
export class BaserowFormulaFileType extends BaserowFormulaTypeDefinition {
|
||||
|
@ -842,7 +810,13 @@ export class BaserowFormulaFileType extends BaserowFormulaTypeDefinition {
|
|||
}
|
||||
}
|
||||
|
||||
export class BaserowFormulaSingleSelectType extends BaserowFormulaTypeDefinition {
|
||||
export class BaserowFormulaSingleSelectType extends mix(
|
||||
hasEmptyValueFilterMixin,
|
||||
hasSelectOptionIdEqualMixin,
|
||||
hasSelectOptionValueContainsFilterMixin,
|
||||
hasSelectOptionValueContainsWordFilterMixin,
|
||||
BaserowFormulaTypeDefinition
|
||||
) {
|
||||
static getType() {
|
||||
return 'single_select'
|
||||
}
|
||||
|
@ -984,7 +958,14 @@ export class BaserowFormulaLinkType extends BaserowFormulaTypeDefinition {
|
|||
}
|
||||
}
|
||||
|
||||
export class BaserowFormulaURLType extends BaserowFormulaTypeDefinition {
|
||||
export class BaserowFormulaURLType extends mix(
|
||||
hasEmptyValueFilterMixin,
|
||||
hasValueEqualFilterMixin,
|
||||
hasValueContainsFilterMixin,
|
||||
hasValueContainsWordFilterMixin,
|
||||
hasValueLengthIsLowerThanFilterMixin,
|
||||
BaserowFormulaTypeDefinition
|
||||
) {
|
||||
static getType() {
|
||||
return 'url'
|
||||
}
|
||||
|
|
|
@ -105,6 +105,8 @@ import {
|
|||
HasValueContainsWordViewFilterType,
|
||||
HasNotValueContainsWordViewFilterType,
|
||||
HasValueLengthIsLowerThanViewFilterType,
|
||||
HasAnySelectOptionEqualViewFilterType,
|
||||
HasNoneSelectOptionEqualViewFilterType,
|
||||
} from '@baserow/modules/database/arrayViewFilters'
|
||||
import {
|
||||
CSVImporterType,
|
||||
|
@ -487,6 +489,14 @@ export default (context) => {
|
|||
'viewFilter',
|
||||
new HasValueLengthIsLowerThanViewFilterType(context)
|
||||
)
|
||||
app.$registry.register(
|
||||
'viewFilter',
|
||||
new HasAnySelectOptionEqualViewFilterType(context)
|
||||
)
|
||||
app.$registry.register(
|
||||
'viewFilter',
|
||||
new HasNoneSelectOptionEqualViewFilterType(context)
|
||||
)
|
||||
app.$registry.register('viewFilter', new ContainsViewFilterType(context))
|
||||
app.$registry.register('viewFilter', new ContainsNotViewFilterType(context))
|
||||
app.$registry.register('viewFilter', new ContainsWordViewFilterType(context))
|
||||
|
|
|
@ -59,7 +59,7 @@ export function genericHasEmptyValueFilter(cellValue, filterValue) {
|
|||
for (let i = 0; i < cellValue.length; i++) {
|
||||
const value = cellValue[i].value
|
||||
|
||||
if (value === '') {
|
||||
if (value === '' || value === null) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -435,4 +435,317 @@ describe('Text-based array view filters', () => {
|
|||
)
|
||||
}
|
||||
)
|
||||
|
||||
const hasSelectOptionsEqualCases = [
|
||||
{
|
||||
cellValue: [],
|
||||
filterValue: '1',
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
cellValue: [
|
||||
{ value: { id: 2, value: 'B' } },
|
||||
{ value: { id: 1, value: 'A' } },
|
||||
],
|
||||
filterValue: '1',
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
cellValue: [{ value: { id: 1, value: 'A' } }],
|
||||
filterValue: '2',
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
cellValue: [{ value: { id: 3, value: 'Aa' } }],
|
||||
filterValue: '1',
|
||||
expected: false,
|
||||
},
|
||||
]
|
||||
|
||||
const hasSelectOptionEqualSupportedFields = [
|
||||
{
|
||||
TestFieldType: FormulaFieldType,
|
||||
formula_type: 'array',
|
||||
array_formula_type: 'single_select',
|
||||
},
|
||||
]
|
||||
|
||||
describe.each(hasSelectOptionEqualSupportedFields)(
|
||||
'HasValueEqualViewFilterType %j',
|
||||
(field) => {
|
||||
test.each(hasSelectOptionsEqualCases)(
|
||||
'filter matches values %j',
|
||||
(testValues) => {
|
||||
const fieldType = new field.TestFieldType({
|
||||
app: testApp._app,
|
||||
})
|
||||
const result = new HasValueEqualViewFilterType({
|
||||
app: testApp._app,
|
||||
}).matches(
|
||||
testValues.cellValue,
|
||||
testValues.filterValue,
|
||||
field,
|
||||
fieldType
|
||||
)
|
||||
expect(result).toBe(testValues.expected)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
describe.each(hasSelectOptionEqualSupportedFields)(
|
||||
'HasNotValueEqualViewFilterType %j',
|
||||
(field) => {
|
||||
test.each(hasSelectOptionsEqualCases)(
|
||||
'filter not matches values %j',
|
||||
(testValues) => {
|
||||
const fieldType = new field.TestFieldType({
|
||||
app: testApp._app,
|
||||
})
|
||||
const result = new HasNotValueEqualViewFilterType({
|
||||
app: testApp._app,
|
||||
}).matches(
|
||||
testValues.cellValue,
|
||||
testValues.filterValue,
|
||||
field,
|
||||
fieldType
|
||||
)
|
||||
expect(result).toBe(!testValues.expected)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
const hasSelectOptionContainsCases = [
|
||||
{
|
||||
cellValue: [],
|
||||
filterValue: 'A',
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
cellValue: [
|
||||
{ value: { id: 2, value: 'B' } },
|
||||
{ value: { id: 1, value: 'A' } },
|
||||
],
|
||||
filterValue: 'A',
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
cellValue: [{ value: { id: 1, value: 'A' } }],
|
||||
filterValue: 'B',
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
cellValue: [{ value: { id: 3, value: 'Aa' } }],
|
||||
filterValue: 'a',
|
||||
expected: true,
|
||||
},
|
||||
]
|
||||
|
||||
const hasSelectOptionContainsSupportedFields = [
|
||||
{
|
||||
TestFieldType: FormulaFieldType,
|
||||
formula_type: 'array',
|
||||
array_formula_type: 'single_select',
|
||||
},
|
||||
]
|
||||
|
||||
describe.each(hasSelectOptionContainsSupportedFields)(
|
||||
'HasValueContainsViewFilterType %j',
|
||||
(field) => {
|
||||
test.each(hasSelectOptionContainsCases)(
|
||||
'filter matches values %j',
|
||||
(testValues) => {
|
||||
const fieldType = new field.TestFieldType({
|
||||
app: testApp._app,
|
||||
})
|
||||
const result = new HasValueContainsViewFilterType({
|
||||
app: testApp._app,
|
||||
}).matches(
|
||||
testValues.cellValue,
|
||||
testValues.filterValue,
|
||||
field,
|
||||
fieldType
|
||||
)
|
||||
expect(result).toBe(testValues.expected)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
describe.each(hasSelectOptionContainsSupportedFields)(
|
||||
'HasNotValueContainsViewFilterType %j',
|
||||
(field) => {
|
||||
test.each(hasSelectOptionContainsCases)(
|
||||
'filter not matches values %j',
|
||||
(testValues) => {
|
||||
const fieldType = new field.TestFieldType({
|
||||
app: testApp._app,
|
||||
})
|
||||
const result = new HasNotValueContainsViewFilterType({
|
||||
app: testApp._app,
|
||||
}).matches(
|
||||
testValues.cellValue,
|
||||
testValues.filterValue,
|
||||
field,
|
||||
fieldType
|
||||
)
|
||||
expect(result).toBe(!testValues.expected)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
const hasSelectOptionContainsWordCases = [
|
||||
{
|
||||
cellValue: [],
|
||||
filterValue: 'A',
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
cellValue: [
|
||||
{ value: { id: 2, value: 'B' } },
|
||||
{ value: { id: 1, value: 'Aa' } },
|
||||
],
|
||||
filterValue: 'Aa',
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
cellValue: [{ value: { id: 1, value: 'A' } }],
|
||||
filterValue: 'B',
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
cellValue: [{ value: { id: 3, value: 'Aa' } }],
|
||||
filterValue: 'a',
|
||||
expected: false,
|
||||
},
|
||||
]
|
||||
|
||||
const hasSelectOptionsContainsWordSupportedFields = [
|
||||
{
|
||||
TestFieldType: FormulaFieldType,
|
||||
formula_type: 'array',
|
||||
array_formula_type: 'single_select',
|
||||
},
|
||||
]
|
||||
|
||||
describe.each(hasSelectOptionsContainsWordSupportedFields)(
|
||||
'HasValueContainsWordViewFilterType %j',
|
||||
(field) => {
|
||||
test.each(hasSelectOptionContainsWordCases)(
|
||||
'filter matches values %j',
|
||||
(testValues) => {
|
||||
const fieldType = new field.TestFieldType({
|
||||
app: testApp._app,
|
||||
})
|
||||
const result = new HasValueContainsWordViewFilterType({
|
||||
app: testApp._app,
|
||||
}).matches(
|
||||
testValues.cellValue,
|
||||
testValues.filterValue,
|
||||
field,
|
||||
fieldType
|
||||
)
|
||||
expect(result).toBe(testValues.expected)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
describe.each(hasSelectOptionsContainsWordSupportedFields)(
|
||||
'HasNotValueContainsWordViewFilterType %j',
|
||||
(field) => {
|
||||
test.each(hasSelectOptionContainsWordCases)(
|
||||
'filter not matches values %j',
|
||||
(testValues) => {
|
||||
const fieldType = new field.TestFieldType({
|
||||
app: testApp._app,
|
||||
})
|
||||
const result = new HasNotValueContainsWordViewFilterType({
|
||||
app: testApp._app,
|
||||
}).matches(
|
||||
testValues.cellValue,
|
||||
testValues.filterValue,
|
||||
field,
|
||||
fieldType
|
||||
)
|
||||
expect(result).toBe(!testValues.expected)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
const hasEmptySelectOptionsCases = [
|
||||
{
|
||||
cellValue: [],
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
cellValue: [{ value: { id: 1, value: 'a' } }, { value: null }],
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
cellValue: [{ value: null }],
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
cellValue: [{ value: { id: 2, value: 'b' } }],
|
||||
expected: false,
|
||||
},
|
||||
]
|
||||
|
||||
const hasEmptySelectOptionSupportedFields = [
|
||||
{
|
||||
TestFieldType: FormulaFieldType,
|
||||
formula_type: 'array',
|
||||
array_formula_type: 'single_select',
|
||||
},
|
||||
]
|
||||
|
||||
describe.each(hasEmptySelectOptionSupportedFields)(
|
||||
'HasEmptyValueViewFilterType %j',
|
||||
(field) => {
|
||||
test.each(hasEmptySelectOptionsCases)(
|
||||
'filter not matches values %j',
|
||||
(testValues) => {
|
||||
const fieldType = new field.TestFieldType({
|
||||
app: testApp._app,
|
||||
})
|
||||
const result = new HasEmptyValueViewFilterType({
|
||||
app: testApp._app,
|
||||
}).matches(
|
||||
testValues.cellValue,
|
||||
testValues.filterValue,
|
||||
field,
|
||||
fieldType
|
||||
)
|
||||
expect(result).toBe(testValues.expected)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
describe.each(hasEmptySelectOptionSupportedFields)(
|
||||
'HasNotEmptyValueViewFilterType %j',
|
||||
(field) => {
|
||||
test.each(hasEmptySelectOptionsCases)(
|
||||
'filter not matches values %j',
|
||||
(testValues) => {
|
||||
const fieldType = new field.TestFieldType({
|
||||
app: testApp._app,
|
||||
})
|
||||
const result = new HasNotEmptyValueViewFilterType({
|
||||
app: testApp._app,
|
||||
}).matches(
|
||||
testValues.cellValue,
|
||||
testValues.filterValue,
|
||||
field,
|
||||
fieldType
|
||||
)
|
||||
expect(result).toBe(!testValues.expected)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
Loading…
Add table
Reference in a new issue