summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 43cf5a2)
raw | patch | inline | side by side (parent: 43cf5a2)
author | kedder <kedder@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Sat, 8 Mar 2003 20:41:45 +0000 (20:41 +0000) | ||
committer | kedder <kedder@57a73879-2fb5-44c3-a270-3262357dd7e2> | |
Sat, 8 Mar 2003 20:41:45 +0000 (20:41 +0000) |
git-svn-id: http://svn.roundup-tracker.org/svnroot/roundup/trunk@1576 57a73879-2fb5-44c3-a270-3262357dd7e2
diff --git a/CHANGES.txt b/CHANGES.txt
index 6dd8699c0fa68ea3774aa9cb0a86459e765b6ee7..a5d04c9f0af291d5dcada3dca09162559e6c29ab 100644 (file)
--- a/CHANGES.txt
+++ b/CHANGES.txt
- added Node.get() method
- nicer page titles (sf feature 65197)
- relaxed CVS importing (sf feature 693277)
+- added support for searching on ranges of dates (see doc/user_guide.txt in
+ chapter "Searching Page" for details)
Fixed:
diff --git a/doc/user_guide.txt b/doc/user_guide.txt
index 567be4323943392fa00831f0433963df3cd42674..49ca3a3fa9d639575157a999c4bc17d4358edc6f 100644 (file)
--- a/doc/user_guide.txt
+++ b/doc/user_guide.txt
User Guide
==========
-:Version: $Revision: 1.13 $
+:Version: $Revision: 1.14 $
.. contents::
XXX: some information about how searching works
+Some fields in the search page (e.g. "Activity" or "Creation date") accept
+ranges of dates. You can specify range of dates in one of two formats:
+
+ 1. Native english syntax:
+ [[From] <value>][ To <value>]
+ Keywords "From" and "To" are case insensitive. Keyword "From" is optional.
+
+ 2. "Geek" syntax:
+ [<value>][; <value>]
+
+Either first or second <value> can be omitted in both syntaxes.
+
+For example:
+
+if you enter string "from 9:00" to "Creation date" field, roundup
+will find all issues, that were created today since 9 AM.
+
+Searching of "-2m; -1m" on activity field gives you issues, which were
+active between period of time since 2 months up-till month ago.
+
+Other possible examples (consider local time is Sat Mar 8 22:07:48 EET 2003):
+
+ >>> Range("from 2-12 to 4-2")
+ <Range from 2003-02-12.00:00:00 to 2003-04-02.00:00:00>
+
+ >>> Range("18:00 TO +2m")
+ <Range from 2003-03-08.18:00:00 to 2003-05-08.20:07:48>
+
+ >>> Range("12:00")
+ <Range from 2003-03-08.12:00:00 to None>
+
+ >>> Range("tO +3d")
+ <Range from None to 2003-03-11.20:07:48>
+
+ >>> Range("2002-11-10; 2002-12-12")
+ <Range from 2002-11-10.00:00:00 to 2002-12-12.00:00:00>
+
+ >>> Range("; 20:00 +1d")
+ <Range from None to 2003-03-09.20:00:00>
+
Under the covers
----------------
index 3297e2f52f885187003b8b7463e5cc3ce16c7f90..417e3d25a3a8abda04a0e2924930793671a072bd 100644 (file)
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-#$Id: back_anydbm.py,v 1.109 2003-03-06 07:33:29 richard Exp $
+#$Id: back_anydbm.py,v 1.110 2003-03-08 20:41:45 kedder Exp $
'''
This module defines a backend that saves the hyperdatabase in a database
chosen by anydbm. It is guaranteed to always be available in python
from roundup.backends import locking
from roundup.hyperdb import String, Password, Date, Interval, Link, \
Multilink, DatabaseError, Boolean, Number, Node
+from roundup.date import Range
#
# Now the database
LINK = 0
MULTILINK = 1
STRING = 2
+ DATE = 3
OTHER = 6
+
+ timezone = self.db.getUserTimezone()
for k, v in filterspec.items():
propclass = props[k]
if isinstance(propclass, Link):
v = v.replace('?', '.')
v = v.replace('*', '.*?')
l.append((STRING, k, re.compile(v, re.I)))
+ elif isinstance(propclass, Date):
+ try:
+ date_rng = Range(v, date.Date, offset=timezone)
+ l.append((DATE, k, date_rng))
+ except ValueError:
+ # If range creation fails - ignore that search parameter
+ pass
elif isinstance(propclass, Boolean):
if type(v) is type(''):
bv = v.lower() in ('yes', 'true', 'on', '1')
else:
bv = v
l.append((OTHER, k, bv))
- elif isinstance(propclass, Date):
- l.append((OTHER, k, date.Date(v)))
+ # kedder: dates are filtered by ranges
+ #elif isinstance(propclass, Date):
+ # l.append((OTHER, k, date.Date(v)))
elif isinstance(propclass, Interval):
l.append((OTHER, k, date.Interval(v)))
elif isinstance(propclass, Number):
# RE search
if node[k] is None or not v.search(node[k]):
break
+ elif t == DATE:
+ if node[k] is None: break
+ if v.to_value:
+ if not (v.from_value < node[k] and v.to_value > node[k]):
+ break
+ else:
+ if not (v.from_value < node[k]):
+ break
elif t == OTHER:
# straight value comparison for the other types
if node[k] != v:
index 6d0fc1e7acb21090a0828ef9d4541cc4ad958b69..ce6455c02838bed48e505207fcffa315fc49817c 100644 (file)
-# $Id: rdbms_common.py,v 1.40 2003-03-06 07:33:29 richard Exp $
+# $Id: rdbms_common.py,v 1.41 2003-03-08 20:41:45 kedder Exp $
''' Relational database (SQL) backend common code.
Basics:
from blobfiles import FileStorage
from roundup.indexer import Indexer
from sessions import Sessions, OneTimeKeys
+from roundup.date import Range
# number of rows to keep in memory
ROW_CACHE_SIZE = 100
cn = self.classname
+ timezone = self.db.getUserTimezone()
+
# figure the WHERE clause from the filterspec
props = self.getprops()
frum = ['_'+cn]
where.append('_%s in (%s)'%(k, s))
args = args + [date.Date(x).serialise() for x in v]
else:
- where.append('_%s=%s'%(k, a))
- args.append(date.Date(v).serialise())
+ try:
+ # Try to filter on range of dates
+ date_rng = Range(v, date.Date, offset=timezone)
+ if (date_rng.from_value):
+ where.append('_%s > %s'%(k, a))
+ args.append(date_rng.from_value.serialise())
+ if (date_rng.to_value):
+ where.append('_%s < %s'%(k, a))
+ args.append(date_rng.to_value.serialise())
+ except ValueError:
+ # If range creation fails - ignore that search parameter
+ pass
elif isinstance(propclass, Interval):
if isinstance(v, type([])):
s = ','.join([a for x in v])
diff --git a/roundup/date.py b/roundup/date.py
index 9c479175f7a3c74cdc89f42ac916a2a5dadebd95..3e6559ff0bad626efeee0264823ee649d33b00ef 100644 (file)
--- a/roundup/date.py
+++ b/roundup/date.py
# BASIS, AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE,
# SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#
-# $Id: date.py,v 1.45 2003-03-06 06:12:30 richard Exp $
+# $Id: date.py,v 1.46 2003-03-08 20:41:45 kedder Exp $
__doc__ = """
Date, time and time interval handling.
return (sign, y, m, d, H, M, S)
+class Range:
+ """
+ Represents range between two values
+ Ranges can be created using one of theese two alternative syntaxes:
+
+ 1. Native english syntax:
+ [[From] <value>][ To <value>]
+ Keywords "From" and "To" are case insensitive. Keyword "From" is optional.
+
+ 2. "Geek" syntax:
+ [<value>][; <value>]
+
+ Either first or second <value> can be omitted in both syntaxes.
+
+ Examples (consider local time is Sat Mar 8 22:07:48 EET 2003):
+ >>> Range("from 2-12 to 4-2")
+ <Range from 2003-02-12.00:00:00 to 2003-04-02.00:00:00>
+
+ >>> Range("18:00 TO +2m")
+ <Range from 2003-03-08.18:00:00 to 2003-05-08.20:07:48>
+
+ >>> Range("12:00")
+ <Range from 2003-03-08.12:00:00 to None>
+
+ >>> Range("tO +3d")
+ <Range from None to 2003-03-11.20:07:48>
+
+ >>> Range("2002-11-10; 2002-12-12")
+ <Range from 2002-11-10.00:00:00 to 2002-12-12.00:00:00>
+
+ >>> Range("; 20:00 +1d")
+ <Range from None to 2003-03-09.20:00:00>
+
+ """
+ def __init__(self, spec, type, **params):
+ """Initializes Range of type <type> from given <spec> string.
+
+ Sets two properties - from_value and to_value. None assigned to any of
+ this properties means "infinitum" (-infinitum to from_value and
+ +infinitum to to_value)
+ """
+ self.range_type = type
+ re_range = r'(?:^|(?:from)?(.+?))(?:to(.+?)$|$)'
+ re_geek_range = r'(?:^|(.+?))(?:;(.+?)$|$)'
+ # Check which syntax to use
+ if spec.find(';') == -1:
+ # Native english
+ mch_range = re.search(re_range, spec.strip(), re.IGNORECASE)
+ else:
+ # Geek
+ mch_range = re.search(re_geek_range, spec.strip())
+ if mch_range:
+ self.from_value, self.to_value = mch_range.groups()
+ if self.from_value:
+ self.from_value = type(self.from_value.strip(), **params)
+ if self.to_value:
+ self.to_value = type(self.to_value.strip(), **params)
+ else:
+ raise ValueError, "Invalid range"
+
+ def __str__(self):
+ return "from %s to %s" % (self.from_value, self.to_value)
+
+ def __repr__(self):
+ return "<Range %s>" % self.__str__()
+
+def test_range():
+ rspecs = ("from 2-12 to 4-2", "18:00 TO +2m", "12:00", "tO +3d",
+ "2002-11-10; 2002-12-12", "; 20:00 +1d")
+ for rspec in rspecs:
+ print '>>> Range("%s")' % rspec
+ print `Range(rspec, Date)`
+ print
def test():
intervals = (" 3w 1 d 2:00", " + 2d", "3w")
print `Date(date) + Interval(interval)`
if __name__ == '__main__':
- test()
+ test_range()
# vim: set filetype=python ts=4 sw=4 et si