Add "between" verb for numeric grid filters

This commit is contained in:
Lance Edgar 2022-11-15 16:29:15 -06:00
parent 3e8924e7cc
commit deed2111fb
3 changed files with 134 additions and 3 deletions

View file

@ -76,8 +76,7 @@ class NumericValueRenderer(FilterValueRenderer):
"""
Input renderer for numeric values.
"""
# TODO
# data_type = 'number'
data_type = 'number'
def render(self, value=None, **kwargs):
kwargs.setdefault('step', '0.001')
@ -137,6 +136,7 @@ class GridFilter(object):
'less_equal': "less than or equal to",
'is_empty': "is empty",
'is_not_empty': "is not empty",
'between': "between",
'is_null': "is null",
'is_not_null': "is not null",
'is_true': "is true",
@ -378,6 +378,47 @@ class AlchemyGridFilter(GridFilter):
return query
return query.filter(self.column <= self.encode_value(value))
def filter_between(self, query, value):
"""
Filter data with a "between" query. Really this uses ">=" and
"<=" (inclusive) logic instead of SQL "between" keyword.
"""
if value is None or value == '':
return query
if '|' not in value:
return query
values = value.split('|')
if len(values) != 2:
return query
start_value, end_value = values
# we'll only filter if we have start and/or end value
if not start_value and not end_value:
return query
return self.filter_for_range(query, start_value, end_value)
def filter_for_range(self, query, start_value, end_value):
"""
This method should actually apply filter(s) to the query,
according to the given value range. Subclasses may override
this logic.
"""
if start_value:
if self.value_invalid(start_value):
return query
query = query.filter(self.column >= start_value)
if end_value:
if self.value_invalid(end_value):
return query
query = query.filter(self.column <= end_value)
return query
class AlchemyStringFilter(AlchemyGridFilter):
"""
@ -532,7 +573,8 @@ class AlchemyNumericFilter(AlchemyGridFilter):
# expose greater-than / less-than verbs in addition to core
default_verbs = ['equal', 'not_equal', 'greater_than', 'greater_equal',
'less_than', 'less_equal', 'is_null', 'is_not_null', 'is_any']
'less_than', 'less_equal', 'between',
'is_null', 'is_not_null', 'is_any']
# TODO: what follows "works" in that it prevents an error...but from the
# user's perspective it still fails silently...need to improve on front-end
@ -541,6 +583,13 @@ class AlchemyNumericFilter(AlchemyGridFilter):
# term for integer field...
def value_invalid(self, value):
# first just make sure it's somewhat numeric
try:
float(value)
except ValueError:
return True
return bool(value and len(six.text_type(value)) > 8)
def filter_equal(self, query, value):
@ -726,6 +775,7 @@ class AlchemyDateFilter(AlchemyGridFilter):
return query
return query.filter(self.column <= self.encode_value(date))
# TODO: this should be merged into parent class
def filter_between(self, query, value):
"""
Filter data with a "between" query. Really this uses ">=" and "<="
@ -753,6 +803,7 @@ class AlchemyDateFilter(AlchemyGridFilter):
return self.filter_date_range(query, start_date, end_date)
# TODO: this should be merged into parent class
def filter_date_range(self, query, start_date, end_date):
"""
This method should actually apply filter(s) to the query, according to

View file

@ -1,4 +1,53 @@
const GridFilterNumericValue = {
template: '#grid-filter-numeric-value-template',
props: {
value: String,
wantsRange: Boolean,
},
data() {
return {
startValue: null,
endValue: null,
}
},
mounted() {
if (this.wantsRange) {
if (this.value.includes('|')) {
let values = this.value.split('|')
if (values.length == 2) {
this.startValue = values[0]
this.endValue = values[1]
} else {
this.startValue = this.value
}
} else {
this.startValue = this.value
}
} else {
this.startValue = this.value
}
},
methods: {
focus() {
this.$refs.startValue.focus()
},
startValueChanged(value) {
if (this.wantsRange) {
value += '|' + this.endValue
}
this.$emit('input', value)
},
endValueChanged(value) {
value = this.startValue + '|' + value
this.$emit('input', value)
},
},
}
Vue.component('grid-filter-numeric-value', GridFilterNumericValue)
const GridFilterDateValue = {
template: '#grid-filter-date-value-template',
props: {

View file

@ -1,5 +1,29 @@
## -*- coding: utf-8; -*-
<script type="text/x-template" id="grid-filter-numeric-value-template">
<div class="level">
<div class="level-left">
<div class="level-item">
<b-input v-model="startValue"
ref="startValue"
@input="startValueChanged">
</b-input>
</div>
<div v-show="wantsRange"
class="level-item">
and
</div>
<div v-show="wantsRange"
class="level-item">
<b-input v-model="endValue"
ref="endValue"
@input="endValueChanged">
</b-input>
</div>
</div>
</div>
</script>
<script type="text/x-template" id="grid-filter-date-value-template">
<div class="level">
<div class="level-left">
@ -75,6 +99,13 @@
</option>
</b-select>
<grid-filter-numeric-value v-if="filter.data_type == 'number'"
v-model="filter.value"
v-show="valuedVerb()"
:wants-range="filter.verb == 'between'"
ref="valueInput">
</grid-filter-numeric-value>
<b-input v-if="filter.data_type == 'string' && !multiValuedVerb()"
v-model="filter.value"
v-show="valuedVerb()"