Skip to content

Commit 9de1f92

Browse files
author
Richard Jones
committed
more compliance testing, this time for find()
1 parent fd1abb3 commit 9de1f92

File tree

3 files changed

+81
-123
lines changed

3 files changed

+81
-123
lines changed

roundup/backends/back_mysql.py

Lines changed: 0 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -411,92 +411,6 @@ def filter(self, search_matches, filterspec, sort=(None,None),
411411
# return the IDs (the first column)
412412
return [row[0] for row in l]
413413

414-
# mysql doesn't implement INTERSECT
415-
def find(self, **propspec):
416-
'''Get the ids of nodes in this class which link to the given nodes.
417-
418-
'propspec' consists of keyword args propname=nodeid or
419-
propname={nodeid:1, }
420-
'propname' must be the name of a property in this class, or a
421-
KeyError is raised. That property must be a Link or
422-
Multilink property, or a TypeError is raised.
423-
424-
Any node in this class whose 'propname' property links to any of the
425-
nodeids will be returned. Used by the full text indexing, which knows
426-
that "foo" occurs in msg1, msg3 and file7, so we have hits on these
427-
issues:
428-
429-
db.issue.find(messages={'1':1,'3':1}, files={'7':1})
430-
'''
431-
if __debug__:
432-
print >>hyperdb.DEBUG, 'find', (self, propspec)
433-
434-
# shortcut
435-
if not propspec:
436-
return []
437-
438-
# validate the args
439-
props = self.getprops()
440-
propspec = propspec.items()
441-
for propname, nodeids in propspec:
442-
# check the prop is OK
443-
prop = props[propname]
444-
if not isinstance(prop, Link) and not isinstance(prop, Multilink):
445-
raise TypeError, "'%s' not a Link/Multilink property"%propname
446-
447-
# first, links
448-
a = self.db.arg
449-
where = ['__retired__ <> %s'%a]
450-
allvalues = (1,)
451-
for prop, values in propspec:
452-
if not isinstance(props[prop], hyperdb.Link):
453-
continue
454-
if type(values) is type({}) and len(values) == 1:
455-
values = values.keys()[0]
456-
if type(values) is type(''):
457-
allvalues += (values,)
458-
where.append('_%s = %s'%(prop, a))
459-
elif values is None:
460-
where.append('_%s is NULL'%prop)
461-
else:
462-
allvalues += tuple(values.keys())
463-
where.append('_%s in (%s)'%(prop, ','.join([a]*len(values))))
464-
tables = []
465-
if where:
466-
tables.append('select id as nodeid from _%s where %s'%(
467-
self.classname, ' and '.join(where)))
468-
469-
# now multilinks
470-
for prop, values in propspec:
471-
if not isinstance(props[prop], hyperdb.Multilink):
472-
continue
473-
if type(values) is type(''):
474-
allvalues += (values,)
475-
s = a
476-
else:
477-
allvalues += tuple(values.keys())
478-
s = ','.join([a]*len(values))
479-
tables.append('select nodeid from %s_%s where linkid in (%s)'%(
480-
self.classname, prop, s))
481-
482-
raise NotImplemented, "XXX this code's farked"
483-
d = {}
484-
self.db.sql(sql, allvalues)
485-
for result in self.db.sql_fetchall():
486-
d[result[0]] = 1
487-
488-
for query in tables[1:]:
489-
self.db.sql(sql, allvalues)
490-
for result in self.db.sql_fetchall():
491-
if not d.has_key(result[0]):
492-
continue
493-
494-
if __debug__:
495-
print >>hyperdb.DEBUG, 'find ... ', l
496-
l = d.keys()
497-
l.sort()
498-
return l
499-
500414
class Class(MysqlClass, rdbms_common.Class):
501415
pass
502416
class IssueClass(MysqlClass, rdbms_common.IssueClass):

roundup/backends/rdbms_common.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $Id: rdbms_common.py,v 1.73 2004-01-20 03:58:38 richard Exp $
1+
# $Id: rdbms_common.py,v 1.74 2004-01-20 05:55:51 richard Exp $
22
''' Relational database (SQL) backend common code.
33
44
Basics:
@@ -1789,8 +1789,9 @@ def find(self, **propspec):
17891789

17901790
# first, links
17911791
a = self.db.arg
1792-
where = ['__retired__ <> %s'%a]
17931792
allvalues = (1,)
1793+
o = []
1794+
where = []
17941795
for prop, values in propspec:
17951796
if not isinstance(props[prop], hyperdb.Link):
17961797
continue
@@ -1804,25 +1805,34 @@ def find(self, **propspec):
18041805
else:
18051806
allvalues += tuple(values.keys())
18061807
where.append('_%s in (%s)'%(prop, ','.join([a]*len(values))))
1807-
tables = []
1808+
tables = ['_%s'%self.classname]
18081809
if where:
1809-
tables.append('select id as nodeid from _%s where %s'%(
1810-
self.classname, ' and '.join(where)))
1810+
o.append('(' + ' and '.join(where) + ')')
18111811

18121812
# now multilinks
18131813
for prop, values in propspec:
18141814
if not isinstance(props[prop], hyperdb.Multilink):
18151815
continue
1816+
if not values:
1817+
continue
18161818
if type(values) is type(''):
18171819
allvalues += (values,)
18181820
s = a
18191821
else:
18201822
allvalues += tuple(values.keys())
18211823
s = ','.join([a]*len(values))
1822-
tables.append('select nodeid from %s_%s where linkid in (%s)'%(
1823-
self.classname, prop, s))
1824+
tn = '%s_%s'%(self.classname, prop)
1825+
tables.append(tn)
1826+
o.append('(id=%s.nodeid and %s.linkid in (%s))'%(tn, tn, s))
18241827

1825-
sql = '\nintersect\n'.join(tables)
1828+
if not o:
1829+
return []
1830+
elif len(o) > 1:
1831+
o = '(' + ' or '.join(['(%s)'%i for i in o]) + ')'
1832+
else:
1833+
o = o[0]
1834+
t = ', '.join(tables)
1835+
sql = 'select distinct(id) from %s where __retired__ <> %s and %s'%(t, a, o)
18261836
self.db.sql(sql, allvalues)
18271837
l = [x[0] for x in self.db.sql_fetchall()]
18281838
if __debug__:

test/db_test_base.py

Lines changed: 63 additions & 29 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: db_test_base.py,v 1.13 2004-01-20 03:58:38 richard Exp $
18+
# $Id: db_test_base.py,v 1.14 2004-01-20 05:55:51 richard Exp $
1919

2020
import unittest, os, shutil, errno, imp, sys, time, pprint
2121

@@ -621,54 +621,88 @@ def testForcedReindexing(self):
621621
#
622622
# searching tests follow
623623
#
624-
def testFind(self):
624+
def testFindIncorrectProperty(self):
625625
self.assertRaises(TypeError, self.db.issue.find, title='fubar')
626626

627-
self.db.user.create(username='test')
628-
ids = []
629-
ids.append(self.db.issue.create(status="1", nosy=['1']))
630-
oddid = self.db.issue.create(status="2", nosy=['2'], assignedto='2')
631-
ids.append(self.db.issue.create(status="1", nosy=['1','2']))
632-
self.db.issue.create(status="3", nosy=['1'], assignedto='1')
633-
ids.sort()
634-
635-
# should match first and third
627+
def _find_test_setup(self):
628+
self.db.file.create(content='')
629+
self.db.file.create(content='')
630+
self.db.user.create(username='')
631+
one = self.db.issue.create(status="1", nosy=['1'])
632+
two = self.db.issue.create(status="2", nosy=['2'], files=['1'],
633+
assignedto='2')
634+
three = self.db.issue.create(status="1", nosy=['1','2'])
635+
four = self.db.issue.create(status="3", assignedto='1',
636+
files=['1','2'])
637+
return one, two, three, four
638+
639+
def testFindLink(self):
640+
one, two, three, four = self._find_test_setup()
636641
got = self.db.issue.find(status='1')
637642
got.sort()
638-
self.assertEqual(got, ids)
643+
self.assertEqual(got, [one, three])
639644
got = self.db.issue.find(status={'1':1})
640645
got.sort()
641-
self.assertEqual(got, ids)
646+
self.assertEqual(got, [one, three])
642647

643-
# none
648+
def testFindLinkFail(self):
649+
self._find_test_setup()
644650
self.assertEqual(self.db.issue.find(status='4'), [])
645651
self.assertEqual(self.db.issue.find(status={'4':1}), [])
646652

647-
# should match first and third
653+
def testFindLinkUnset(self):
654+
one, two, three, four = self._find_test_setup()
648655
got = self.db.issue.find(assignedto=None)
649656
got.sort()
650-
self.assertEqual(got, ids)
657+
self.assertEqual(got, [one, three])
651658
got = self.db.issue.find(assignedto={None:1})
652659
got.sort()
653-
self.assertEqual(got, ids)
660+
self.assertEqual(got, [one, three])
661+
662+
def testFindMultilink(self):
663+
one, two, three, four = self._find_test_setup()
664+
got = self.db.issue.find(nosy='2')
665+
got.sort()
666+
self.assertEqual(got, [two, three])
667+
got = self.db.issue.find(nosy={'2':1})
668+
got.sort()
669+
self.assertEqual(got, [two, three])
670+
got = self.db.issue.find(nosy={'2':1}, files={})
671+
got.sort()
672+
self.assertEqual(got, [two, three])
654673

655-
# should match first three
674+
def testFindMultiMultilink(self):
675+
one, two, three, four = self._find_test_setup()
676+
got = self.db.issue.find(nosy='2', files='1')
677+
got.sort()
678+
self.assertEqual(got, [two, three, four])
679+
got = self.db.issue.find(nosy={'2':1}, files={'1':1})
680+
got.sort()
681+
self.assertEqual(got, [two, three, four])
682+
683+
def testFindMultilinkFail(self):
684+
self._find_test_setup()
685+
self.assertEqual(self.db.issue.find(nosy='3'), [])
686+
self.assertEqual(self.db.issue.find(nosy={'3':1}), [])
687+
688+
def testFindMultilinkUnset(self):
689+
self._find_test_setup()
690+
self.assertEqual(self.db.issue.find(nosy={}), [])
691+
692+
def testFindLinkAndMultilink(self):
693+
one, two, three, four = self._find_test_setup()
656694
got = self.db.issue.find(status='1', nosy='2')
657695
got.sort()
658-
ids.append(oddid)
659-
ids.sort()
660-
self.assertEqual(got, ids)
696+
self.assertEqual(got, [one, two, three])
661697
got = self.db.issue.find(status={'1':1}, nosy={'2':1})
662698
got.sort()
663-
self.assertEqual(got, ids)
664-
665-
# none
666-
self.assertEqual(self.db.issue.find(status='4', nosy='3'), [])
667-
self.assertEqual(self.db.issue.find(status={'4':1}, nosy={'3':1}), [])
699+
self.assertEqual(got, [one, two, three])
668700

669-
# test retiring a node
670-
self.db.issue.retire(ids[0])
671-
self.assertEqual(len(self.db.issue.find(status='1', nosy='2')), 2)
701+
def testFindRetired(self):
702+
one, two, three, four = self._find_test_setup()
703+
self.assertEqual(len(self.db.issue.find(status='1')), 2)
704+
self.db.issue.retire(one)
705+
self.assertEqual(len(self.db.issue.find(status='1')), 1)
672706

673707
def testStringFind(self):
674708
self.assertRaises(TypeError, self.db.issue.stringFind, status='1')

0 commit comments

Comments
 (0)