Skip to content

Commit acf690d

Browse files
author
Andrey Lebedev
committed
searching on ranges of intervals is implemented
1 parent 4c4bf7a commit acf690d

File tree

7 files changed

+88
-22
lines changed

7 files changed

+88
-22
lines changed

CHANGES.txt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,17 @@ Feature:
4747
- added Node.get() method
4848
- nicer page titles (sf feature 65197)
4949
- relaxed CVS importing (sf feature 693277)
50-
- added support for searching on ranges of dates (see doc/user_guide.txt in
51-
chapter "Searching Page" for details) (closes sf feature 700178)
50+
- added support for searching on ranges of dates and intervals (see
51+
doc/user_guide.txt in chapter "Searching Page" for details) (closes sf
52+
feature 700178)
5253
- role names made case insensitive
5354
- added ability to restore retired nodes
5455
- more lenient date input and addition Interval input support (sf bug 677764)
5556
- roundup mailgw now handles apop
5657
- implemented ability to search for multilink properties with no value
5758
- Class.find() may now find unset Links (sf bug 700620)
5859
- more flexibility in classhelp link labelling (sf feature 608204)
59-
- added command-line functionality for roundup-adming (sf feature 687664)
60+
- added command-line functionality for roundup-admin (sf feature 687664)
6061
- added nicer popup windows for topic, nosy, etc (has add/remove buttons)
6162
thanks Gus Gollings
6263
- HTML templating files now have a .html extension

doc/upgrading.txt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ name:confirm -> :confirm:name
7070
timezone if he/she has provided timezone information. To make it possible
7171
some modification to tracker's schema and HTML templates are required.
7272
First you should add string property 'timezone' to user class in dbinit.py
73-
like this:
73+
like this::
7474

7575
user = Class(db, "user",
7676
username=String(), password=Password(),
@@ -98,6 +98,25 @@ name:confirm -> :confirm:name
9898
However you are not forced to make these modifications. By default roundup
9999
will assume timezone=0 and will work as previous versions did.
100100

101+
102+
0.6.0 Notes for metakit backend users
103+
-------------------------------------
104+
105+
- Roundup 0.6.0 introduced searching on ranges of dates and intervals. To
106+
support it, some modifications to interval storing routine were made. So if
107+
your tracker uses metakit backend and your db schema contains intervals
108+
property, searches on that property will not be accurate for db items that
109+
was stored before roundup' upgrade. However all new records should be
110+
searchable on intervals.
111+
112+
It is possible to convert your database to new format: you can export and
113+
import back all your data (consult "Migrating backends" in "Maintenance"
114+
documentation). After this operation all your interval properties should
115+
become searchable.
116+
117+
Users of backends others than metakit should not worry about this issue.
118+
119+
101120
Migrating from 0.4.x to 0.5.0
102121
=============================
103122

doc/user_guide.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
User Guide
33
==========
44

5-
:Version: $Revision: 1.19 $
5+
:Version: $Revision: 1.20 $
66

77
.. contents::
88

@@ -141,6 +141,8 @@ Interval properties
141141

142142
XXX explain...
143143

144+
When searching on interval properties use the same syntax as for dates.
145+
144146

145147
Web Interface
146148
=============

roundup/backends/back_anydbm.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
#$Id: back_anydbm.py,v 1.118 2003-03-26 11:19:28 richard Exp $
18+
#$Id: back_anydbm.py,v 1.119 2003-04-20 11:58:45 kedder Exp $
1919
'''
2020
This module defines a backend that saves the hyperdatabase in a database
2121
chosen by anydbm. It is guaranteed to always be available in python
@@ -1639,6 +1639,7 @@ def filter(self, search_matches, filterspec, sort=(None,None),
16391639
MULTILINK = 1
16401640
STRING = 2
16411641
DATE = 3
1642+
INTERVAL = 4
16421643
OTHER = 6
16431644

16441645
timezone = self.db.getUserTimezone()
@@ -1695,18 +1696,21 @@ def filter(self, search_matches, filterspec, sort=(None,None),
16951696
l.append((DATE, k, date_rng))
16961697
except ValueError:
16971698
# If range creation fails - ignore that search parameter
1698-
pass
1699+
pass
1700+
elif isinstance(propclass, Interval):
1701+
try:
1702+
intv_rng = Range(v, date.Interval)
1703+
l.append((INTERVAL, k, intv_rng))
1704+
except ValueError:
1705+
# If range creation fails - ignore that search parameter
1706+
pass
1707+
16991708
elif isinstance(propclass, Boolean):
17001709
if type(v) is type(''):
17011710
bv = v.lower() in ('yes', 'true', 'on', '1')
17021711
else:
17031712
bv = v
17041713
l.append((OTHER, k, bv))
1705-
# kedder: dates are filtered by ranges
1706-
#elif isinstance(propclass, Date):
1707-
# l.append((OTHER, k, date.Date(v)))
1708-
elif isinstance(propclass, Interval):
1709-
l.append((OTHER, k, date.Interval(v)))
17101714
elif isinstance(propclass, Number):
17111715
l.append((OTHER, k, int(v)))
17121716
else:
@@ -1760,7 +1764,7 @@ def filter(self, search_matches, filterspec, sort=(None,None),
17601764
# RE search
17611765
if node[k] is None or not v.search(node[k]):
17621766
break
1763-
elif t == DATE:
1767+
elif t == DATE or t == INTERVAL:
17641768
if node[k] is None: break
17651769
if v.to_value:
17661770
if not (v.from_value < node[k] and v.to_value > node[k]):

roundup/backends/back_metakit.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: back_metakit.py,v 1.45 2003-03-26 10:44:00 richard Exp $
1+
# $Id: back_metakit.py,v 1.46 2003-04-20 11:58:45 kedder Exp $
22
'''
33
Metakit backend for Roundup, originally by Gordon McMillan.
44
@@ -603,10 +603,11 @@ def set(self, nodeid, **propvalues):
603603
if value is None:
604604
setattr(row, key, '')
605605
else:
606-
setattr(row, key, str(value))
606+
# kedder: we should store interval values serialized
607+
setattr(row, key, value.serialise())
607608
changes[key] = str(oldvalue)
608609
propvalues[key] = str(value)
609-
610+
610611
elif isinstance(prop, hyperdb.Number):
611612
if value is None:
612613
value = 0
@@ -963,6 +964,10 @@ def filter(self, search_matches, filterspec, sort=(None,None),
963964
if date_rng.from_value:
964965
t = date_rng.from_value.get_tuple()
965966
where[propname] = int(calendar.timegm(t))
967+
else:
968+
# use minimum possible value to exclude items without
969+
# 'prop' property
970+
where[propname] = 0
966971
if date_rng.to_value:
967972
t = date_rng.to_value.get_tuple()
968973
wherehigh[propname] = int(calendar.timegm(t))
@@ -972,7 +977,24 @@ def filter(self, search_matches, filterspec, sort=(None,None),
972977
# If range creation fails - ignore that search parameter
973978
pass
974979
elif isinstance(prop, hyperdb.Interval):
975-
where[propname] = str(date.Interval(value))
980+
try:
981+
# Try to filter on range of intervals
982+
date_rng = Range(value, date.Interval)
983+
if date_rng.from_value:
984+
#t = date_rng.from_value.get_tuple()
985+
where[propname] = date_rng.from_value.serialise()
986+
else:
987+
# use minimum possible value to exclude items without
988+
# 'prop' property
989+
where[propname] = '-99999999999999'
990+
if date_rng.to_value:
991+
#t = date_rng.to_value.get_tuple()
992+
wherehigh[propname] = date_rng.to_value.serialise()
993+
else:
994+
wherehigh[propname] = None
995+
except ValueError:
996+
# If range creation fails - ignore that search parameter
997+
pass
976998
elif isinstance(prop, hyperdb.Number):
977999
where[propname] = int(value)
9781000
else:
@@ -1187,7 +1209,7 @@ def import_list(self, propnames, proplist):
11871209
if isinstance(prop, hyperdb.Date):
11881210
value = int(calendar.timegm(value))
11891211
elif isinstance(prop, hyperdb.Interval):
1190-
value = str(date.Interval(value))
1212+
value = date.Interval(value).serialise()
11911213
elif isinstance(prop, hyperdb.Number):
11921214
value = int(value)
11931215
elif isinstance(prop, hyperdb.Boolean):

roundup/backends/rdbms_common.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: rdbms_common.py,v 1.53 2003-04-08 06:41:48 richard Exp $
1+
# $Id: rdbms_common.py,v 1.54 2003-04-20 11:58:45 kedder Exp $
22
''' Relational database (SQL) backend common code.
33
44
Basics:
@@ -1866,8 +1866,20 @@ def filter(self, search_matches, filterspec, sort=(None,None),
18661866
where.append('_%s in (%s)'%(k, s))
18671867
args = args + [date.Interval(x).serialise() for x in v]
18681868
else:
1869-
where.append('_%s=%s'%(k, a))
1870-
args.append(date.Interval(v).serialise())
1869+
try:
1870+
# Try to filter on range of intervals
1871+
date_rng = Range(v, date.Interval)
1872+
if (date_rng.from_value):
1873+
where.append('_%s > %s'%(k, a))
1874+
args.append(date_rng.from_value.serialise())
1875+
if (date_rng.to_value):
1876+
where.append('_%s < %s'%(k, a))
1877+
args.append(date_rng.to_value.serialise())
1878+
except ValueError:
1879+
# If range creation fails - ignore that search parameter
1880+
pass
1881+
#where.append('_%s=%s'%(k, a))
1882+
#args.append(date.Interval(v).serialise())
18711883
else:
18721884
if isinstance(v, type([])):
18731885
s = ','.join([a for x in v])

test/test_db.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
1616
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1717
#
18-
# $Id: test_db.py,v 1.84 2003-03-26 11:19:28 richard Exp $
18+
# $Id: test_db.py,v 1.85 2003-04-20 11:58:45 kedder Exp $
1919

2020
import unittest, os, shutil, time
2121

@@ -691,13 +691,19 @@ def testFilteringMany(self):
691691

692692
def testFilteringRange(self):
693693
ae, filt = self.filteringSetup()
694+
# Date ranges
694695
ae(filt(None, {'deadline': 'from 2003-02-10 to 2003-02-23'}), ['2'])
695696
ae(filt(None, {'deadline': '2003-02-10; 2003-02-23'}), ['2'])
696697
ae(filt(None, {'deadline': '; 2003-02-16'}), ['1'])
697698
# Lets assume people won't invent a time machine, otherwise this test
698699
# may fail :)
699700
ae(filt(None, {'deadline': 'from 2003-02-16'}), ['2', '3'])
700701
ae(filt(None, {'deadline': '2003-02-16'}), ['2', '3'])
702+
# Interval ranges
703+
ae(filt(None, {'foo': 'from 0:50 to 2:00'}), ['1'])
704+
ae(filt(None, {'foo': 'from 0:50 to 1d 2:00'}), ['1', '2'])
705+
ae(filt(None, {'foo': 'from 5:50'}), ['2'])
706+
ae(filt(None, {'foo': 'to 0:50'}), [])
701707

702708
def testFilteringIntervalSort(self):
703709
ae, filt = self.filteringSetup()

0 commit comments

Comments
 (0)