mirror of
https://gitlab.com/bramw/baserow.git
synced 2025-04-07 22:35:36 +00:00
Resolve "Introduce “greater than or equal” (>=) and “less than or equal” (<=) filter types"
This commit is contained in:
parent
1bccbb31e2
commit
5664304685
9 changed files with 612 additions and 79 deletions
backend
src/baserow/contrib/database
tests/baserow/contrib/database/view
changelog/entries/unreleased/feature
web-frontend
locales
modules/database
test/unit/database
|
@ -294,6 +294,7 @@ class DatabaseConfig(AppConfig):
|
|||
FilenameContainsViewFilterType,
|
||||
FilesLowerThanViewFilterType,
|
||||
HasFileTypeViewFilterType,
|
||||
HigherThanOrEqualViewFilterType,
|
||||
HigherThanViewFilterType,
|
||||
IsEvenAndWholeViewFilterType,
|
||||
LengthIsLowerThanViewFilterType,
|
||||
|
@ -301,6 +302,7 @@ class DatabaseConfig(AppConfig):
|
|||
LinkRowHasNotViewFilterType,
|
||||
LinkRowHasViewFilterType,
|
||||
LinkRowNotContainsViewFilterType,
|
||||
LowerThanOrEqualViewFilterType,
|
||||
LowerThanViewFilterType,
|
||||
MultipleCollaboratorsHasNotViewFilterType,
|
||||
MultipleCollaboratorsHasViewFilterType,
|
||||
|
@ -327,7 +329,9 @@ class DatabaseConfig(AppConfig):
|
|||
view_filter_type_registry.register(DoesntContainWordViewFilterType())
|
||||
view_filter_type_registry.register(LengthIsLowerThanViewFilterType())
|
||||
view_filter_type_registry.register(HigherThanViewFilterType())
|
||||
view_filter_type_registry.register(HigherThanOrEqualViewFilterType())
|
||||
view_filter_type_registry.register(LowerThanViewFilterType())
|
||||
view_filter_type_registry.register(LowerThanOrEqualViewFilterType())
|
||||
view_filter_type_registry.register(IsEvenAndWholeViewFilterType())
|
||||
view_filter_type_registry.register(DateEqualViewFilterType())
|
||||
view_filter_type_registry.register(DateBeforeViewFilterType())
|
||||
|
|
|
@ -311,43 +311,6 @@ class LengthIsLowerThanViewFilterType(ViewFilterType):
|
|||
return self.default_filter_on_exception()
|
||||
|
||||
|
||||
class HigherThanViewFilterType(ViewFilterType):
|
||||
"""
|
||||
The higher than filter checks if the field value is higher than the filter value.
|
||||
It only works if a numeric number is provided. It is at compatible with
|
||||
models.IntegerField and models.DecimalField.
|
||||
"""
|
||||
|
||||
type = "higher_than"
|
||||
compatible_field_types = [
|
||||
NumberFieldType.type,
|
||||
RatingFieldType.type,
|
||||
AutonumberFieldType.type,
|
||||
DurationFieldType.type,
|
||||
FormulaFieldType.compatible_with_formula_types(
|
||||
BaserowFormulaNumberType.type,
|
||||
),
|
||||
]
|
||||
|
||||
def get_filter(self, field_name, value, model_field, field):
|
||||
value = value.strip()
|
||||
|
||||
# If an empty value has been provided we do not want to filter at all.
|
||||
if value == "":
|
||||
return Q()
|
||||
|
||||
if isinstance(model_field, IntegerField) and value.find(".") != -1:
|
||||
decimal = Decimal(value)
|
||||
value = floor(decimal)
|
||||
|
||||
# Check if the model_field accepts the value.
|
||||
try:
|
||||
value = model_field.get_prep_value(value)
|
||||
return Q(**{f"{field_name}__gt": value})
|
||||
except Exception:
|
||||
return self.default_filter_on_exception()
|
||||
|
||||
|
||||
class IsEvenAndWholeViewFilterType(ViewFilterType):
|
||||
"""
|
||||
The is even and whole filter checks if the field value is an even number
|
||||
|
@ -372,14 +335,14 @@ class IsEvenAndWholeViewFilterType(ViewFilterType):
|
|||
)
|
||||
|
||||
|
||||
class LowerThanViewFilterType(ViewFilterType):
|
||||
class NumericComparisonViewFilterType(ViewFilterType):
|
||||
"""
|
||||
The lower than filter checks if the field value is lower than the filter value.
|
||||
It only works if a numeric number is provided. It is at compatible with
|
||||
models.IntegerField and models.DecimalField.
|
||||
Base filter type for basic numeric comparisons. It defines common logic for
|
||||
'lower than', 'lower than or equal', 'higher than' and 'higher than or equal'
|
||||
view filter types.
|
||||
"""
|
||||
|
||||
type = "lower_than"
|
||||
operator = None
|
||||
compatible_field_types = [
|
||||
NumberFieldType.type,
|
||||
RatingFieldType.type,
|
||||
|
@ -390,6 +353,9 @@ class LowerThanViewFilterType(ViewFilterType):
|
|||
),
|
||||
]
|
||||
|
||||
def should_round_value_to_compare(self, value, model_field):
|
||||
return isinstance(model_field, IntegerField) and value.find(".") != -1
|
||||
|
||||
def get_filter(self, field_name, value, model_field, field):
|
||||
value = value.strip()
|
||||
|
||||
|
@ -397,18 +363,64 @@ class LowerThanViewFilterType(ViewFilterType):
|
|||
if value == "":
|
||||
return Q()
|
||||
|
||||
if isinstance(model_field, IntegerField) and value.find(".") != -1:
|
||||
decimal = Decimal(value)
|
||||
value = ceil(decimal)
|
||||
if self.should_round_value_to_compare(value, model_field):
|
||||
decimal_value = Decimal(value)
|
||||
value = self.rounding_func(decimal_value)
|
||||
|
||||
# Check if the model_field accepts the value.
|
||||
try:
|
||||
value = model_field.get_prep_value(value)
|
||||
return Q(**{f"{field_name}__lt": value})
|
||||
return Q(**{f"{field_name}__{self.operator}": value})
|
||||
except Exception:
|
||||
return self.default_filter_on_exception()
|
||||
|
||||
|
||||
class LowerThanViewFilterType(NumericComparisonViewFilterType):
|
||||
"""
|
||||
The lower than filter checks if the field value is lower than the filter value.
|
||||
It only works if a numeric number is provided.
|
||||
"""
|
||||
|
||||
type = "lower_than"
|
||||
operator = "lt"
|
||||
rounding_func = floor
|
||||
|
||||
|
||||
class LowerThanOrEqualViewFilterType(NumericComparisonViewFilterType):
|
||||
"""
|
||||
The lower than or equal filter checks if the field value is lower or if it
|
||||
equals to the filter value.
|
||||
It only works if a numeric number is provided.
|
||||
"""
|
||||
|
||||
type = "lower_than_or_equal"
|
||||
operator = "lte"
|
||||
rounding_func = floor
|
||||
|
||||
|
||||
class HigherThanViewFilterType(NumericComparisonViewFilterType):
|
||||
"""
|
||||
The higher than filter checks if the field value is higher than the filter value.
|
||||
It only works if a numeric number is provided.
|
||||
"""
|
||||
|
||||
type = "higher_than"
|
||||
operator = "gt"
|
||||
rounding_func = ceil
|
||||
|
||||
|
||||
class HigherThanOrEqualViewFilterType(NumericComparisonViewFilterType):
|
||||
"""
|
||||
The higher than or equal filter checks if the field value is higher than or
|
||||
if it equals to the filter value.
|
||||
It only works if a numeric number is provided.
|
||||
"""
|
||||
|
||||
type = "higher_than_or_equal"
|
||||
operator = "gte"
|
||||
rounding_func = ceil
|
||||
|
||||
|
||||
class TimezoneAwareDateViewFilterType(ViewFilterType):
|
||||
compatible_field_types = [
|
||||
DateFieldType.type,
|
||||
|
|
|
@ -1494,6 +1494,115 @@ def test_higher_than_filter_type(data_fixture):
|
|||
assert len(ids) == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_higher_than_or_equal_filter_type(data_fixture):
|
||||
user = data_fixture.create_user()
|
||||
table = data_fixture.create_database_table(user=user)
|
||||
grid_view = data_fixture.create_grid_view(table=table)
|
||||
integer_field = data_fixture.create_number_field(table=table, number_negative=True)
|
||||
decimal_field = data_fixture.create_number_field(
|
||||
table=table,
|
||||
number_decimal_places=2,
|
||||
number_negative=True,
|
||||
)
|
||||
|
||||
handler = ViewHandler()
|
||||
model = table.get_model()
|
||||
|
||||
row = model.objects.create(
|
||||
**{
|
||||
f"field_{integer_field.id}": 10,
|
||||
f"field_{decimal_field.id}": 20.20,
|
||||
}
|
||||
)
|
||||
model.objects.create(
|
||||
**{
|
||||
f"field_{integer_field.id}": None,
|
||||
f"field_{decimal_field.id}": None,
|
||||
}
|
||||
)
|
||||
row_3 = model.objects.create(
|
||||
**{
|
||||
f"field_{integer_field.id}": 99,
|
||||
f"field_{decimal_field.id}": 99.99,
|
||||
}
|
||||
)
|
||||
row_4 = model.objects.create(
|
||||
**{
|
||||
f"field_{integer_field.id}": -10,
|
||||
f"field_{decimal_field.id}": -30.33,
|
||||
}
|
||||
)
|
||||
|
||||
view_filter = data_fixture.create_view_filter(
|
||||
view=grid_view, field=integer_field, type="higher_than_or_equal", value="1"
|
||||
)
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert (
|
||||
len(ids) == 2
|
||||
) # Only rows with values 10 and 99 are equal to or greater than 1
|
||||
assert row.id in ids
|
||||
assert row_3.id in ids
|
||||
|
||||
view_filter.value = "10"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 2 # Rows with 10 and 99 are equal to or greater than 10
|
||||
assert row.id in ids
|
||||
assert row_3.id in ids
|
||||
|
||||
view_filter.value = "99"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 1 # Only row_3 matches because it's equal to or greater than 99
|
||||
assert row_3.id in ids
|
||||
|
||||
view_filter.value = "100"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 0 # No rows match
|
||||
|
||||
view_filter.value = "not_number"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 0
|
||||
|
||||
view_filter.value = "0"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 2 # Rows with 10 and 99 are equal to or greater than 0
|
||||
|
||||
view_filter.value = "-10"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert (
|
||||
len(ids) == 3
|
||||
) # Includes row, row_3, and row_4 because it's equal to or greater than -10
|
||||
|
||||
view_filter.field = decimal_field
|
||||
view_filter.value = "20.20"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert (
|
||||
len(ids) == 2
|
||||
) # Matches row and row_3 with values equal to or greater than 20.20
|
||||
|
||||
view_filter.value = "99.99"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 1 # Only row_3 matches
|
||||
|
||||
view_filter.value = "100"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 0
|
||||
|
||||
view_filter.value = "not_number"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_lower_than_filter_type(data_fixture):
|
||||
user = data_fixture.create_user()
|
||||
|
@ -1646,6 +1755,75 @@ def test_lower_than_filter_type(data_fixture):
|
|||
assert len(ids) == 0
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_lower_than_or_equal_filter_type(data_fixture):
|
||||
user = data_fixture.create_user()
|
||||
table = data_fixture.create_database_table(user=user)
|
||||
grid_view = data_fixture.create_grid_view(table=table)
|
||||
integer_field = data_fixture.create_number_field(table=table, number_negative=True)
|
||||
decimal_field = data_fixture.create_number_field(
|
||||
table=table,
|
||||
number_decimal_places=2,
|
||||
number_negative=True,
|
||||
)
|
||||
|
||||
handler = ViewHandler()
|
||||
model = table.get_model()
|
||||
|
||||
row = model.objects.create(
|
||||
**{
|
||||
f"field_{integer_field.id}": 10,
|
||||
f"field_{decimal_field.id}": 20.20,
|
||||
}
|
||||
)
|
||||
model.objects.create(
|
||||
**{
|
||||
f"field_{integer_field.id}": None,
|
||||
f"field_{decimal_field.id}": None,
|
||||
}
|
||||
)
|
||||
row_3 = model.objects.create(
|
||||
**{
|
||||
f"field_{integer_field.id}": 99,
|
||||
f"field_{decimal_field.id}": 99.99,
|
||||
}
|
||||
)
|
||||
row_4 = model.objects.create(
|
||||
**{
|
||||
f"field_{integer_field.id}": -10,
|
||||
f"field_{decimal_field.id}": -30.33,
|
||||
}
|
||||
)
|
||||
|
||||
view_filter = data_fixture.create_view_filter(
|
||||
view=grid_view, field=integer_field, type="lower_than_or_equal", value="1"
|
||||
)
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 1
|
||||
assert row_4.id in ids
|
||||
|
||||
view_filter.value = "100"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 3 # Includes row, row_3, row_4;
|
||||
|
||||
view_filter.value = "-10"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 1 # Only row_4 matches
|
||||
|
||||
view_filter.value = "9"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 1 # Only row_4 matches
|
||||
|
||||
view_filter.field = decimal_field
|
||||
view_filter.value = "20.20"
|
||||
view_filter.save()
|
||||
ids = [r.id for r in handler.apply_filters(grid_view, model.objects.all()).all()]
|
||||
assert len(ids) == 2 # Includes row and row_4;
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_is_even_and_whole_number_filter_type(data_fixture):
|
||||
"""
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"type": "feature",
|
||||
"message": "Introduce 'greater than or equal to' and 'lower than or equal to' filter types for number fields",
|
||||
"issue_number": 1988,
|
||||
"bullet_points": [],
|
||||
"created_at": "2024-03-29"
|
||||
}
|
|
@ -179,6 +179,7 @@
|
|||
"has": "has",
|
||||
"hasNot": "doesn't have",
|
||||
"higherThan": "higher than",
|
||||
"higherThanOrEqual": "higher than or equal",
|
||||
"is": "is",
|
||||
"isNot": "is not",
|
||||
"isEmpty": "is empty",
|
||||
|
@ -204,6 +205,7 @@
|
|||
"isWithinWeeks": "is within weeks",
|
||||
"isWithinMonths": "is within months",
|
||||
"lowerThan": "lower than",
|
||||
"lowerThanOrEqual": "lower than or equal",
|
||||
"isEvenAndWhole": "is even and whole",
|
||||
"lengthIsLowerThan": "length is lower than",
|
||||
"hasFileType": "has file type",
|
||||
|
|
|
@ -45,7 +45,9 @@ import {
|
|||
ContainsNotViewFilterType,
|
||||
LengthIsLowerThanViewFilterType,
|
||||
HigherThanViewFilterType,
|
||||
HigherThanOrEqualViewFilterType,
|
||||
LowerThanViewFilterType,
|
||||
LowerThanOrEqualViewFilterType,
|
||||
IsEvenAndWholeViewFilterType,
|
||||
SingleSelectEqualViewFilterType,
|
||||
SingleSelectNotEqualViewFilterType,
|
||||
|
@ -398,7 +400,15 @@ export default (context) => {
|
|||
new LengthIsLowerThanViewFilterType(context)
|
||||
)
|
||||
app.$registry.register('viewFilter', new HigherThanViewFilterType(context))
|
||||
app.$registry.register(
|
||||
'viewFilter',
|
||||
new HigherThanOrEqualViewFilterType(context)
|
||||
)
|
||||
app.$registry.register('viewFilter', new LowerThanViewFilterType(context))
|
||||
app.$registry.register(
|
||||
'viewFilter',
|
||||
new LowerThanOrEqualViewFilterType(context)
|
||||
)
|
||||
app.$registry.register(
|
||||
'viewFilter',
|
||||
new IsEvenAndWholeViewFilterType(context)
|
||||
|
|
|
@ -1326,16 +1326,10 @@ export class DateEqualsDayOfMonthViewFilterType extends LocalizedDateViewFilterT
|
|||
}
|
||||
}
|
||||
|
||||
export class HigherThanViewFilterType extends ViewFilterType {
|
||||
static getType() {
|
||||
return 'higher_than'
|
||||
}
|
||||
|
||||
getName() {
|
||||
const { i18n } = this.app
|
||||
return i18n.t('viewFilter.higherThan')
|
||||
}
|
||||
|
||||
// Base filter type for basic numeric comparisons. It defines common logic for
|
||||
// 'lower than', 'lower than or equal', 'higher than' and 'higher than or equal'
|
||||
// view filter types.
|
||||
export class NumericComparisonViewFilterType extends ViewFilterType {
|
||||
getExample() {
|
||||
return '100'
|
||||
}
|
||||
|
@ -1358,6 +1352,22 @@ export class HigherThanViewFilterType extends ViewFilterType {
|
|||
]
|
||||
}
|
||||
|
||||
// This method should be implemented by subclasses to define their comparison logic.
|
||||
matches(rowValue, filterValue, field, fieldType) {
|
||||
throw new Error('matches method must be implemented by subclasses')
|
||||
}
|
||||
}
|
||||
|
||||
export class HigherThanViewFilterType extends NumericComparisonViewFilterType {
|
||||
static getType() {
|
||||
return 'higher_than'
|
||||
}
|
||||
|
||||
getName() {
|
||||
const { i18n } = this.app
|
||||
return i18n.t('viewFilter.higherThan')
|
||||
}
|
||||
|
||||
matches(rowValue, filterValue, field, fieldType) {
|
||||
if (filterValue === '') {
|
||||
return true
|
||||
|
@ -1369,7 +1379,30 @@ export class HigherThanViewFilterType extends ViewFilterType {
|
|||
}
|
||||
}
|
||||
|
||||
export class LowerThanViewFilterType extends ViewFilterType {
|
||||
export class HigherThanOrEqualViewFilterType extends NumericComparisonViewFilterType {
|
||||
static getType() {
|
||||
return 'higher_than_or_equal'
|
||||
}
|
||||
|
||||
getName() {
|
||||
const { i18n } = this.app
|
||||
return i18n.t('viewFilter.higherThanOrEqual')
|
||||
}
|
||||
|
||||
matches(rowValue, filterValue, field, fieldType) {
|
||||
if (filterValue === '') {
|
||||
return true
|
||||
}
|
||||
|
||||
const rowVal = fieldType.parseInputValue(field, rowValue)
|
||||
const fltVal = fieldType.parseInputValue(field, filterValue)
|
||||
return (
|
||||
Number.isFinite(rowVal) && Number.isFinite(fltVal) && rowVal >= fltVal
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class LowerThanViewFilterType extends NumericComparisonViewFilterType {
|
||||
static getType() {
|
||||
return 'lower_than'
|
||||
}
|
||||
|
@ -1379,28 +1412,6 @@ export class LowerThanViewFilterType extends ViewFilterType {
|
|||
return i18n.t('viewFilter.lowerThan')
|
||||
}
|
||||
|
||||
getExample() {
|
||||
return '100'
|
||||
}
|
||||
|
||||
getInputComponent(field) {
|
||||
const inputComponent = {
|
||||
[RatingFieldType.getType()]: ViewFilterTypeRating,
|
||||
[DurationFieldType.getType()]: ViewFilterTypeDuration,
|
||||
}
|
||||
return inputComponent[field?.type] || ViewFilterTypeNumber
|
||||
}
|
||||
|
||||
getCompatibleFieldTypes() {
|
||||
return [
|
||||
'number',
|
||||
'rating',
|
||||
'autonumber',
|
||||
'duration',
|
||||
FormulaFieldType.compatibleWithFormulaTypes('number'),
|
||||
]
|
||||
}
|
||||
|
||||
matches(rowValue, filterValue, field, fieldType) {
|
||||
if (filterValue === '') {
|
||||
return true
|
||||
|
@ -1412,6 +1423,29 @@ export class LowerThanViewFilterType extends ViewFilterType {
|
|||
}
|
||||
}
|
||||
|
||||
export class LowerThanOrEqualViewFilterType extends NumericComparisonViewFilterType {
|
||||
static getType() {
|
||||
return 'lower_than_or_equal'
|
||||
}
|
||||
|
||||
getName() {
|
||||
const { i18n } = this.app
|
||||
return i18n.t('viewFilter.lowerThanOrEqual')
|
||||
}
|
||||
|
||||
matches(rowValue, filterValue, field, fieldType) {
|
||||
if (filterValue === '') {
|
||||
return true
|
||||
}
|
||||
|
||||
const rowVal = fieldType.parseInputValue(field, rowValue)
|
||||
const fltVal = fieldType.parseInputValue(field, filterValue)
|
||||
return (
|
||||
Number.isFinite(rowVal) && Number.isFinite(fltVal) && rowVal <= fltVal
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export class IsEvenAndWholeViewFilterType extends ViewFilterType {
|
||||
static getType() {
|
||||
return 'is_even_and_whole'
|
||||
|
|
|
@ -998,6 +998,36 @@ exports[`ViewFilterForm component Full view filter component 1`] = `
|
|||
|
||||
<!---->
|
||||
|
||||
<span
|
||||
class="select__item-name-text"
|
||||
title="viewFilter.higherThanOrEqual"
|
||||
>
|
||||
viewFilter.higherThanOrEqual
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!---->
|
||||
</a>
|
||||
|
||||
<i
|
||||
class="select__item-active-icon iconoir-check"
|
||||
/>
|
||||
</li>
|
||||
<li
|
||||
class="select__item select__item--no-options"
|
||||
>
|
||||
<a
|
||||
class="select__item-link"
|
||||
>
|
||||
<div
|
||||
class="select__item-name"
|
||||
>
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<span
|
||||
class="select__item-name-text"
|
||||
title="viewFilter.lowerThan"
|
||||
|
@ -1009,6 +1039,36 @@ exports[`ViewFilterForm component Full view filter component 1`] = `
|
|||
<!---->
|
||||
</a>
|
||||
|
||||
<i
|
||||
class="select__item-active-icon iconoir-check"
|
||||
/>
|
||||
</li>
|
||||
<li
|
||||
class="select__item select__item--no-options"
|
||||
>
|
||||
<a
|
||||
class="select__item-link"
|
||||
>
|
||||
<div
|
||||
class="select__item-name"
|
||||
>
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<span
|
||||
class="select__item-name-text"
|
||||
title="viewFilter.lowerThanOrEqual"
|
||||
>
|
||||
viewFilter.lowerThanOrEqual
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!---->
|
||||
</a>
|
||||
|
||||
<i
|
||||
class="select__item-active-icon iconoir-check"
|
||||
/>
|
||||
|
@ -1438,6 +1498,36 @@ exports[`ViewFilterForm component Test rating filter 1`] = `
|
|||
|
||||
<!---->
|
||||
|
||||
<span
|
||||
class="select__item-name-text"
|
||||
title="viewFilter.higherThanOrEqual"
|
||||
>
|
||||
viewFilter.higherThanOrEqual
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!---->
|
||||
</a>
|
||||
|
||||
<i
|
||||
class="select__item-active-icon iconoir-check"
|
||||
/>
|
||||
</li>
|
||||
<li
|
||||
class="select__item select__item--no-options"
|
||||
>
|
||||
<a
|
||||
class="select__item-link"
|
||||
>
|
||||
<div
|
||||
class="select__item-name"
|
||||
>
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<span
|
||||
class="select__item-name-text"
|
||||
title="viewFilter.lowerThan"
|
||||
|
@ -1449,6 +1539,36 @@ exports[`ViewFilterForm component Test rating filter 1`] = `
|
|||
<!---->
|
||||
</a>
|
||||
|
||||
<i
|
||||
class="select__item-active-icon iconoir-check"
|
||||
/>
|
||||
</li>
|
||||
<li
|
||||
class="select__item select__item--no-options"
|
||||
>
|
||||
<a
|
||||
class="select__item-link"
|
||||
>
|
||||
<div
|
||||
class="select__item-name"
|
||||
>
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<span
|
||||
class="select__item-name-text"
|
||||
title="viewFilter.lowerThanOrEqual"
|
||||
>
|
||||
viewFilter.lowerThanOrEqual
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!---->
|
||||
</a>
|
||||
|
||||
<i
|
||||
class="select__item-active-icon iconoir-check"
|
||||
/>
|
||||
|
@ -1878,6 +1998,36 @@ exports[`ViewFilterForm component Test rating filter 2`] = `
|
|||
|
||||
<!---->
|
||||
|
||||
<span
|
||||
class="select__item-name-text"
|
||||
title="viewFilter.higherThanOrEqual"
|
||||
>
|
||||
viewFilter.higherThanOrEqual
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!---->
|
||||
</a>
|
||||
|
||||
<i
|
||||
class="select__item-active-icon iconoir-check"
|
||||
/>
|
||||
</li>
|
||||
<li
|
||||
class="select__item select__item--no-options"
|
||||
>
|
||||
<a
|
||||
class="select__item-link"
|
||||
>
|
||||
<div
|
||||
class="select__item-name"
|
||||
>
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<span
|
||||
class="select__item-name-text"
|
||||
title="viewFilter.lowerThan"
|
||||
|
@ -1889,6 +2039,36 @@ exports[`ViewFilterForm component Test rating filter 2`] = `
|
|||
<!---->
|
||||
</a>
|
||||
|
||||
<i
|
||||
class="select__item-active-icon iconoir-check"
|
||||
/>
|
||||
</li>
|
||||
<li
|
||||
class="select__item select__item--no-options"
|
||||
>
|
||||
<a
|
||||
class="select__item-link"
|
||||
>
|
||||
<div
|
||||
class="select__item-name"
|
||||
>
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<!---->
|
||||
|
||||
<span
|
||||
class="select__item-name-text"
|
||||
title="viewFilter.lowerThanOrEqual"
|
||||
>
|
||||
viewFilter.lowerThanOrEqual
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!---->
|
||||
</a>
|
||||
|
||||
<i
|
||||
class="select__item-active-icon iconoir-check"
|
||||
/>
|
||||
|
|
|
@ -29,7 +29,9 @@ import {
|
|||
DateEqualsCurrentYearViewFilterType,
|
||||
IsEvenAndWholeViewFilterType,
|
||||
HigherThanViewFilterType,
|
||||
HigherThanOrEqualViewFilterType,
|
||||
LowerThanViewFilterType,
|
||||
LowerThanOrEqualViewFilterType,
|
||||
SingleSelectIsAnyOfViewFilterType,
|
||||
SingleSelectIsNoneOfViewFilterType,
|
||||
} from '@baserow/modules/database/viewFilters'
|
||||
|
@ -1225,6 +1227,44 @@ const numberValueIsHigherThanCases = [
|
|||
},
|
||||
]
|
||||
|
||||
const numberValueIsHigherThanOrEqualCases = [
|
||||
{
|
||||
rowValue: 2,
|
||||
filterValue: 3,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
rowValue: 2,
|
||||
filterValue: 0,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
rowValue: null,
|
||||
filterValue: 0,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
rowValue: 1,
|
||||
filterValue: '-1',
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
rowValue: 0,
|
||||
filterValue: '0',
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
rowValue: -1,
|
||||
filterValue: '-1',
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
rowValue: -1,
|
||||
filterValue: '0',
|
||||
expected: false,
|
||||
},
|
||||
]
|
||||
|
||||
const numberValueIsLowerThanCases = [
|
||||
{
|
||||
rowValue: 1,
|
||||
|
@ -1243,6 +1283,44 @@ const numberValueIsLowerThanCases = [
|
|||
},
|
||||
]
|
||||
|
||||
const numberValueIsLowerThanOrEqualCases = [
|
||||
{
|
||||
rowValue: 2,
|
||||
filterValue: 3,
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
rowValue: 2,
|
||||
filterValue: 0,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
rowValue: null,
|
||||
filterValue: 0,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
rowValue: 1,
|
||||
filterValue: '-1',
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
rowValue: 0,
|
||||
filterValue: '0',
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
rowValue: -1,
|
||||
filterValue: '-1',
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
rowValue: -1,
|
||||
filterValue: '0',
|
||||
expected: true,
|
||||
},
|
||||
]
|
||||
|
||||
describe('All Tests', () => {
|
||||
let testApp = null
|
||||
|
||||
|
@ -1566,6 +1644,20 @@ describe('All Tests', () => {
|
|||
}
|
||||
)
|
||||
|
||||
test.each(numberValueIsHigherThanOrEqualCases)(
|
||||
'NumberHigherThanOrEqualFilterType',
|
||||
(values) => {
|
||||
const app = testApp.getApp()
|
||||
const result = new HigherThanOrEqualViewFilterType({ app }).matches(
|
||||
values.rowValue,
|
||||
values.filterValue,
|
||||
{ type: 'number' },
|
||||
new NumberFieldType({ app })
|
||||
)
|
||||
expect(result).toBe(values.expected)
|
||||
}
|
||||
)
|
||||
|
||||
test.each(numberValueIsHigherThanCases)(
|
||||
'FormulaNumberHigherThanFilterType',
|
||||
(values) => {
|
||||
|
@ -1594,6 +1686,20 @@ describe('All Tests', () => {
|
|||
}
|
||||
)
|
||||
|
||||
test.each(numberValueIsLowerThanOrEqualCases)(
|
||||
'NumberLowerThanOrEqualFilterType',
|
||||
(values) => {
|
||||
const app = testApp.getApp()
|
||||
const result = new LowerThanOrEqualViewFilterType({ app }).matches(
|
||||
values.rowValue,
|
||||
values.filterValue,
|
||||
{ type: 'number' },
|
||||
new NumberFieldType({ app })
|
||||
)
|
||||
expect(result).toBe(values.expected)
|
||||
}
|
||||
)
|
||||
|
||||
test.each(numberValueIsLowerThanCases)(
|
||||
'FormulaNumberLowerThanFilterType',
|
||||
(values) => {
|
||||
|
|
Loading…
Add table
Reference in a new issue