1
0
Fork 0
mirror of https://gitlab.com/bramw/baserow.git synced 2025-03-31 19:35:02 +00:00

Resolve "Higher than and lower than frontend filters are not working with formulas"

This commit is contained in:
Davide Silvestri 2024-01-24 09:46:42 +00:00
parent 59192c94f3
commit 709e895494
9 changed files with 174 additions and 55 deletions

View file

@ -0,0 +1,7 @@
{
"type": "bug",
"message": "Fix higher_than and lower_than frontend view filters for formula fields.",
"issue_number": 2289,
"bullet_points": [],
"created_at": "2024-01-17"
}

View file

@ -144,8 +144,6 @@ export default {
this.$registry
)
console.log(newRowValues)
this.$store.dispatch('rowModal/updated', {
tableId: this.tableId,
values: newRowValues,

View file

@ -36,7 +36,11 @@ export default {
methods: {
formattedDuration(value) {
const metadata = this.entry.fields_metadata[this.fieldIdentifier]
return DurationFieldType.formatValue(metadata, value)
const durationFieldType = this.$registry.get(
'field',
DurationFieldType.getType()
)
return durationFieldType.formatValue(metadata, value)
},
},
}

View file

@ -7,14 +7,14 @@
</template>
<script>
import { DurationFieldType } from '@baserow/modules/database/fieldTypes'
import { formatDurationValue } from '@baserow/modules/database/utils/duration'
export default {
name: 'FunctionalGridViewFieldDuration',
functional: true,
methods: {
formatValue(field, value) {
return DurationFieldType.formatValue(field, value)
return formatDurationValue(value, field.duration_format)
},
},
}

View file

@ -741,7 +741,7 @@ export class FieldType extends Registerable {
* moment object, or a duration field can accept a string like '1:30' to
* convert it to a number of seconds.
*/
static parseInputValue(field, value) {
parseInputValue(field, value) {
return value
}
}
@ -1351,7 +1351,7 @@ export class NumberFieldType extends FieldType {
return true
}
static parseInputValue(field, value) {
parseInputValue(field, value) {
return parseFloat(value)
}
}
@ -1683,8 +1683,8 @@ class BaseDateFieldType extends FieldType {
* correct format for the field. If it can't be parsed null is returned.
*/
prepareValueForPaste(field, clipboardData, richClipboardData) {
const dateValue = DateFieldType.parseInputValue(field, clipboardData || '')
return DateFieldType.formatDate(field, dateValue)
const dateValue = this.parseInputValue(field, clipboardData || '')
return this.formatValue(field, dateValue)
}
/**
@ -1724,7 +1724,7 @@ class BaseDateFieldType extends FieldType {
return formats
}
static parseInputValue(field, dateString) {
parseInputValue(field, dateString) {
const formats = DateFieldType.getDateFormatsOptionsForValue(
field,
dateString
@ -1751,8 +1751,8 @@ class BaseDateFieldType extends FieldType {
return date
}
static formatDate(field, date) {
const momentDate = moment.utc(date)
formatValue(field, value) {
const momentDate = moment.utc(value)
if (momentDate.isValid()) {
return field.date_include_time
? momentDate.format()
@ -1838,9 +1838,9 @@ export class DateFieldType extends BaseDateFieldType {
}
parseQueryParameter(field, value) {
return DateFieldType.formatDate(
return this.formatValue(
field.field,
DateFieldType.parseInputValue(field.field, value)
this.parseInputValue(field.field, value)
)
}
}
@ -2280,11 +2280,11 @@ export class DurationFieldType extends FieldType {
}
parseQueryParameter(field, value, options) {
return DurationFieldType.parseInputValue(field, value)
return this.parseInputValue(field.field, value)
}
toSearchableString(field, value, delimiter = ', ') {
return DurationFieldType.formatValue(field, value)
return this.formatValue(field, value)
}
getSort(name, order) {
@ -2350,22 +2350,22 @@ export class DurationFieldType extends FieldType {
return RowHistoryFieldDuration
}
static formatValue(field, value) {
formatValue(field, value) {
return formatDurationValue(value, field.duration_format)
}
static parseInputValue(field, value) {
parseInputValue(field, value) {
const format = field.duration_format
const preparedValue = parseDurationValue(value, format)
return roundDurationValueToFormat(preparedValue, format)
}
toHumanReadableString(field, value, delimiter = ', ') {
return DurationFieldType.formatValue(field, value)
return this.formatValue(field, value)
}
prepareValueForCopy(field, value) {
return DurationFieldType.formatValue(field, value)
return this.formatValue(field, value)
}
prepareRichValueForCopy(field, value) {
@ -2376,7 +2376,7 @@ export class DurationFieldType extends FieldType {
if (richClipboardData && isNumeric(richClipboardData)) {
return richClipboardData
}
return DurationFieldType.parseInputValue(field, clipboardData)
return this.parseInputValue(field, clipboardData)
}
getCanGroupByInView(field) {
@ -3543,6 +3543,14 @@ export class FormulaFieldType extends FieldType {
const subType = this.app.$registry.get('formula_type', field.formula_type)
return subType.canGroupByInView(field)
}
parseInputValue(field, value) {
const underlyingFieldType = this.app.$registry.get(
'field',
this._mapFormulaTypeToFieldType(field.formula_type)
)
return underlyingFieldType.parseInputValue(field, value)
}
}
export class CountFieldType extends FormulaFieldType {

View file

@ -12,6 +12,11 @@ export default {
formattedValue: '',
}
},
computed: {
fieldType() {
return this.$registry.get('field', DurationFieldType.getType())
},
},
watch: {
value(value) {
this.updateFormattedValue(this.field, value)
@ -31,7 +36,7 @@ export default {
return this.errorMsg
},
formatValue(field, value) {
return DurationFieldType.formatValue(field, value)
return this.fieldType.formatValue(field, value)
},
updateFormattedValue(field, value) {
this.formattedValue = this.formatValue(field, value)
@ -41,7 +46,7 @@ export default {
if (this.errorMsg !== null) {
return
}
const newCopy = DurationFieldType.parseInputValue(field, value)
const newCopy = this.fieldType.parseInputValue(field, value)
if (newCopy !== this.copy) {
this.copy = newCopy
return newCopy

View file

@ -1341,13 +1341,9 @@ export class HigherThanViewFilterType extends ViewFilterType {
return true
}
rowValue = fieldType.constructor.parseInputValue(field, rowValue)
filterValue = fieldType.constructor.parseInputValue(field, filterValue)
return (
Number.isFinite(rowValue) &&
Number.isFinite(filterValue) &&
rowValue > filterValue
)
const rowVal = fieldType.parseInputValue(field, rowValue)
const fltVal = fieldType.parseInputValue(field, filterValue)
return Number.isFinite(rowVal) && Number.isFinite(fltVal) && rowVal > fltVal
}
}
@ -1388,13 +1384,9 @@ export class LowerThanViewFilterType extends ViewFilterType {
return true
}
rowValue = fieldType.constructor.parseInputValue(field, rowValue)
filterValue = fieldType.constructor.parseInputValue(field, filterValue)
return (
Number.isFinite(rowValue) &&
Number.isFinite(filterValue) &&
rowValue < filterValue
)
const rowVal = fieldType.parseInputValue(field, rowValue)
const fltVal = fieldType.parseInputValue(field, filterValue)
return Number.isFinite(rowVal) && Number.isFinite(fltVal) && rowVal < fltVal
}
}

View file

@ -603,17 +603,20 @@ const queryParametersForParsing = [
},
{
fieldType: new DurationFieldType(),
input: { value: '1:01', field: { duration_format: 'h:mm' } },
input: { value: '1:01', field: { field: { duration_format: 'h:mm' } } },
output: 3660,
},
{
fieldType: new DurationFieldType(),
input: { value: '1:01:01', field: { duration_format: 'h:mm:ss' } },
input: {
value: '1:01:01',
field: { field: { duration_format: 'h:mm:ss' } },
},
output: 3661,
},
{
fieldType: new DurationFieldType(),
input: { value: 61, field: { duration_format: 'h:mm' } },
input: { value: 61, field: { field: { duration_format: 'h:mm' } } },
output: 60, // the value is rounded according to the duration format
},
]

View file

@ -31,7 +31,11 @@ import {
HigherThanViewFilterType,
LowerThanViewFilterType,
} from '@baserow/modules/database/viewFilters'
import { DurationFieldType } from '@baserow/modules/database/fieldTypes'
import {
DurationFieldType,
NumberFieldType,
FormulaFieldType,
} from '@baserow/modules/database/fieldTypes'
const dateBeforeCases = [
{
@ -1126,6 +1130,42 @@ const durationLowerThanCases = [
},
]
const numberValueIsHigherThanCases = [
{
rowValue: 2,
filterValue: 0,
expected: true,
},
{
rowValue: null,
filterValue: 0,
expected: false,
},
{
rowValue: 0,
filterValue: '0',
expected: false,
},
]
const numberValueIsLowerThanCases = [
{
rowValue: 1,
filterValue: '2',
expected: true,
},
{
rowValue: null,
filterValue: 0,
expected: false,
},
{
rowValue: 0,
filterValue: '0',
expected: false,
},
]
describe('All Tests', () => {
let testApp = null
@ -1405,10 +1445,28 @@ describe('All Tests', () => {
).toBe(true)
})
test.each(durationHigherThanCases)('HigherThanFilterType', (values) => {
const fieldType = new DurationFieldType()
test.each(durationHigherThanCases)(
'DurationHigherThanFilterType',
(values) => {
const fieldType = new DurationFieldType({
app: testApp,
})
const { field } = values.context
const result = new HigherThanViewFilterType({ app: testApp }).matches(
values.rowValue,
values.filterValue,
field,
fieldType
)
expect(result).toBe(values.expected)
}
)
test.each(durationLowerThanCases)('DurationLowerThanFilterType', (values) => {
const app = testApp.getApp()
const fieldType = new DurationFieldType({ app })
const { field } = values.context
const result = new HigherThanViewFilterType({ app: testApp }).matches(
const result = new LowerThanViewFilterType({ app }).matches(
values.rowValue,
values.filterValue,
field,
@ -1417,15 +1475,59 @@ describe('All Tests', () => {
expect(result).toBe(values.expected)
})
test.each(durationLowerThanCases)('LowerThanFilterType', (values) => {
const fieldType = new DurationFieldType()
const { field } = values.context
const result = new LowerThanViewFilterType({ app: testApp }).matches(
values.rowValue,
values.filterValue,
field,
fieldType
)
expect(result).toBe(values.expected)
})
test.each(numberValueIsHigherThanCases)(
'NumberHigherThanFilterType',
(values) => {
const app = testApp.getApp()
const result = new HigherThanViewFilterType({ app }).matches(
values.rowValue,
values.filterValue,
{ type: 'number' },
new NumberFieldType({ app })
)
expect(result).toBe(values.expected)
}
)
test.each(numberValueIsHigherThanCases)(
'FormulaNumberHigherThanFilterType',
(values) => {
const app = testApp.getApp()
const result = new HigherThanViewFilterType({ app }).matches(
values.rowValue,
values.filterValue,
{ type: 'formula', formula_type: 'number' },
new FormulaFieldType({ app })
)
expect(result).toBe(values.expected)
}
)
test.each(numberValueIsLowerThanCases)(
'NumberLowerThanFilterType',
(values) => {
const app = testApp.getApp()
const result = new LowerThanViewFilterType({ app }).matches(
values.rowValue,
values.filterValue,
{ type: 'number' },
new NumberFieldType({ app })
)
expect(result).toBe(values.expected)
}
)
test.each(numberValueIsLowerThanCases)(
'FormulaNumberLowerThanFilterType',
(values) => {
const app = testApp.getApp()
const result = new LowerThanViewFilterType({ app }).matches(
values.rowValue,
values.filterValue,
{ type: 'formula', formula_type: 'number' },
new FormulaFieldType({ app })
)
expect(result).toBe(values.expected)
}
)
})