Skip to content

Commit 29a856d

Browse files
committed
Better Date filtering
Allow filtering by multiple date ranges or empty date. Date ranges are separated by comma, an empty date is represented by '-'.
1 parent 21c0a97 commit 29a856d

File tree

5 files changed

+59
-12
lines changed

5 files changed

+59
-12
lines changed

CHANGES.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ Features:
6060
fine.
6161
- Added markdown rendering using either markdown or markdown2.
6262
(Christof Meerwald)
63+
- Allow filtering by multiple date ranges or empty date. Date ranges are
64+
separated by comma, an empty date is represented by '-'
6365

6466
Fixed:
6567

doc/overview.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,9 @@ Each type of property has its own appropriate filtering widget:
544544
- *string* properties appear as text fields supporting
545545
case-insensitive substring match
546546
- *date* properties appear as a text field which accepts a date
547-
range with start, end or both
547+
range with start, end or both. Multiple date ranges can be specified
548+
separated by a comma. An empty date can be searched for by specifying
549+
'-' instead of a date range
548550
- *link* properties appear as a group of selectable options
549551
(the filter selects the *union* of the sets of items
550552
associated with the active options)

roundup/backends/back_anydbm.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1764,8 +1764,14 @@ def _filter(self, search_matches, filterspec, proptree,
17641764
l.append((STRING, k, re.compile(x, re.I)))
17651765
elif isinstance(propclass, hyperdb.Date):
17661766
try:
1767-
date_rng = propclass.range_from_raw(v, self.db)
1768-
l.append((DATE, k, date_rng))
1767+
ranges = []
1768+
for d in v.split(','):
1769+
if d == '-':
1770+
ranges.append(None)
1771+
continue
1772+
date_rng = propclass.range_from_raw(d, self.db)
1773+
ranges.append(date_rng)
1774+
l.append((DATE, k, ranges))
17691775
except ValueError:
17701776
# If range creation fails - ignore that search parameter
17711777
pass
@@ -1862,7 +1868,22 @@ def _filter(self, search_matches, filterspec, proptree,
18621868
else:
18631869
# RE search
18641870
match = v.search(nv)
1865-
elif t == DATE or t == INTERVAL:
1871+
elif t == DATE:
1872+
for x in v:
1873+
if x is None or nv is None:
1874+
if nv is None and x is None:
1875+
match = 1
1876+
break
1877+
continue
1878+
elif x.to_value:
1879+
if x.from_value <= nv <= x.to_value:
1880+
match = 1
1881+
break
1882+
else:
1883+
if x.from_value <= nv:
1884+
match = 1
1885+
break
1886+
elif t == INTERVAL:
18661887
if nv is None:
18671888
match = v is None
18681889
else:

roundup/backends/rdbms_common.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2609,14 +2609,24 @@ def _filter_sql (self, search_matches, filterspec, srt=[], grp=[], retr=0,
26092609
args = args + [dc(date.Date(x)) for x in v]
26102610
else:
26112611
try:
2612-
# Try to filter on range of dates
2613-
date_rng = propclass.range_from_raw(v, self.db)
2614-
if date_rng.from_value:
2615-
where.append('_%s._%s >= %s'%(pln, k, a))
2616-
args.append(dc(date_rng.from_value))
2617-
if date_rng.to_value:
2618-
where.append('_%s._%s <= %s'%(pln, k, a))
2619-
args.append(dc(date_rng.to_value))
2612+
wh = []
2613+
ar = []
2614+
for d in v.split(','):
2615+
w1 = []
2616+
if d == '-':
2617+
wh.append('_%s._%s is NULL'%(pln, k))
2618+
continue
2619+
# Try to filter on range of dates
2620+
date_rng = propclass.range_from_raw(d, self.db)
2621+
if date_rng.from_value:
2622+
w1.append('_%s._%s >= %s'%(pln, k, a))
2623+
ar.append(dc(date_rng.from_value))
2624+
if date_rng.to_value:
2625+
w1.append('_%s._%s <= %s'%(pln, k, a))
2626+
ar.append(dc(date_rng.to_value))
2627+
wh.append (' and '.join (w1))
2628+
where.append ('(' + ' or '.join (wh) + ')')
2629+
args.extend (ar)
26202630
except ValueError:
26212631
# If range creation fails - ignore that search parameter
26222632
pass

test/db_test_base.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1883,6 +1883,18 @@ def testFilteringRangeMonths(self):
18831883
r = filt(None, dict(deadline='2001-%02d'%month))
18841884
assert len(r) == month, 'month %d != length %d'%(month, len(r))
18851885

1886+
def testFilteringDateRangeMulti(self):
1887+
ae, filter, filter_iter = self.filteringSetup()
1888+
self.db.issue.create(title='no deadline')
1889+
self.db.commit()
1890+
for filt in filter, filter_iter:
1891+
r = filt (None, dict(deadline='-'))
1892+
self.assertEqual(r, ['5'])
1893+
r = filt (None, dict(deadline=';2003-02-01,2004;'))
1894+
self.assertEqual(r, ['2', '4'])
1895+
r = filt (None, dict(deadline='-,;2003-02-01,2004;'))
1896+
self.assertEqual(r, ['2', '4', '5'])
1897+
18861898
def testFilteringRangeInterval(self):
18871899
ae, filter, filter_iter = self.filteringSetup()
18881900
for filt in filter, filter_iter:

0 commit comments

Comments
 (0)