Skip to content

Commit 3f2d351

Browse files
committed
Make rev multilink for Link work
Fix searching of retired items. Fix implementation for anydbm.
1 parent 2116ba4 commit 3f2d351

File tree

3 files changed

+140
-13
lines changed

3 files changed

+140
-13
lines changed

roundup/backends/rdbms_common.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2419,11 +2419,20 @@ def _filter_multilink_expression_fallback(self, proptree, expr):
24192419
# would be nice but this tricky: Think about the cases
24202420
# where the multilink table does not have join values
24212421
# needed in evaluation.
2422-
2423-
stmnt = "SELECT c.id, m.%s FROM _%s c " \
2424-
"LEFT OUTER JOIN %s m " \
2425-
"ON c.id = m.%s ORDER BY c.id" % (
2426-
lid, classname, multilink_table, nid)
2422+
w = j = ''
2423+
s = 'm.%s' % lid
2424+
if proptree.need_retired:
2425+
w = ' and m.__retired__=0'
2426+
elif proptree.need_child_retired:
2427+
tn2 = '_' + proptree.classname
2428+
j = ' LEFT OUTER JOIN %s ON %s.id = m.%s' % (tn2, tn2, lid)
2429+
w = ' and %s.__retired__=0'%(tn2)
2430+
s = '%s.id' % tn2
2431+
2432+
stmnt = "SELECT c.id, %s FROM _%s as c " \
2433+
"LEFT OUTER JOIN %s as m " \
2434+
"ON c.id = m.%s%s%s ORDER BY c.id" % (
2435+
s, classname, multilink_table, nid, j, w)
24272436
self.db.sql(stmnt)
24282437

24292438
# collect all multilink items for a class item
@@ -2467,9 +2476,18 @@ def _filter_multilink_expression(self, proptree, v):
24672476
return self._filter_multilink_expression_fallback(
24682477
proptree, expr)
24692478

2479+
w = j = ''
2480+
if proptree.need_retired:
2481+
w = ' and %s.__retired__=0'%(multilink_table)
2482+
elif proptree.need_child_retired:
2483+
tn1 = multilink_table
2484+
tn2 = '_' + proptree.classname
2485+
j = ', %s' % tn2
2486+
w = ' and %s.%s=%s.id and %s.__retired__=0'%(tn1, lid, tn2, tn2)
2487+
24702488
atom = \
2471-
"%s IN(SELECT %s FROM %s WHERE %s=a.id)" % (
2472-
self.db.arg, lid, multilink_table, nid)
2489+
"%s IN(SELECT %s FROM %s%s WHERE %s=a.id%s)" % (
2490+
self.db.arg, lid, multilink_table, j, nid, w)
24732491
atom_nil = self._subselect(proptree, 'a')
24742492

24752493
lambda_atom = lambda n: atom if n.x >= 0 else atom_nil

roundup/hyperdb.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -617,18 +617,18 @@ def search(self, search_matches=None, sort=True, retired=False):
617617
# expression on them
618618
expr = Expression(nval)
619619
by_id = {}
620-
for id in cl.getnodeids(retired=False):
620+
for id in self.cls.getnodeids(retired=False):
621621
by_id[id] = set()
622622
items = set()
623-
for id in self.cls.getnodeids(retired=False):
623+
for id in cl.getnodeids(retired=False):
624624
node = cl.getnode(id)
625625
if node[pn]:
626626
v = node[pn]
627627
if not isinstance(v, type([])):
628628
v = [v]
629629
for x in v:
630630
if x not in by_id:
631-
by_id[x] = set()
631+
continue
632632
by_id[x].add(id)
633633
for k in by_id:
634634
if expr.evaluate(by_id[k]):

test/db_test_base.py

Lines changed: 112 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,6 +1898,70 @@ def ls(x):
18981898
self.assertEqual(ls(self.db.user.get('7', 'issues')), [])
18991899
self.assertEqual(ls(self.db.user.get('10', 'issues')), ['7', '8'])
19001900

1901+
def testFilteringRevLinkExpression(self):
1902+
ae, iiter = self.filteringSetupTransitiveSearch('user')
1903+
# We have
1904+
# issue assignedto
1905+
# 1: 6
1906+
# 2: 6
1907+
# 3: 7
1908+
# 4: 8
1909+
# 5: 9
1910+
# 6: 10
1911+
# 7: 10
1912+
# 8: 10
1913+
for filt in iiter():
1914+
# Explicit 'or'
1915+
ae(filt(None, {'issues': ['3', '4', '-4']}), ['7', '8'])
1916+
# Implicit or with '-1'
1917+
ae(filt(None, {'issues': ['3', '4', '-1']}),
1918+
['1', '2', '3', '4', '5', '7', '8'])
1919+
# Explicit or with '-1': 3 or 4 or empty
1920+
ae(filt(None, {'issues': ['3', '4', '-4', '-1', '-4']}),
1921+
['1', '2', '3', '4', '5', '7', '8'])
1922+
# '3' and empty
1923+
ae(filt(None, {'issues': ['3', '-1', '-3']}), [])
1924+
# '6' and '7' and '8'
1925+
ae(filt(None, {'issues': ['6', '7', '-3', '8', '-3']}), ['10'])
1926+
# '6' and '7' or '1' and '2'
1927+
ae(filt(None, {'issues': ['6', '7', '-3', '1', '2', '-3', '-4']}),
1928+
['6', '10'])
1929+
# '1' or '4'
1930+
ae(filt(None, {'issues': ['1', '4', '-4']}), ['6', '8'])
1931+
1932+
# Now retire some linked-to issues and retry
1933+
self.db.issue.retire('6')
1934+
self.db.issue.retire('2')
1935+
self.db.issue.retire('3')
1936+
self.db.commit()
1937+
# We have now
1938+
# issue assignedto
1939+
# 1: 6
1940+
# 4: 8
1941+
# 5: 9
1942+
# 7: 10
1943+
# 8: 10
1944+
for filt in iiter():
1945+
# Explicit 'or'
1946+
ae(filt(None, {'issues': ['3', '4', '-4']}), ['8'])
1947+
# Implicit or with '-1'
1948+
ae(filt(None, {'issues': ['3', '4', '-1']}),
1949+
['1', '2', '3', '4', '5', '7', '8'])
1950+
# Explicit or with '-1': 3 or 4 or empty
1951+
ae(filt(None, {'issues': ['3', '4', '-4', '-1', '-4']}),
1952+
['1', '2', '3', '4', '5', '7', '8'])
1953+
# '3' and empty
1954+
ae(filt(None, {'issues': ['3', '-1', '-3']}), [])
1955+
# '6' and '7' and '8'
1956+
ae(filt(None, {'issues': ['6', '7', '-3', '8', '-3']}), [])
1957+
# '7' and '8'
1958+
ae(filt(None, {'issues': ['7', '8', '-3']}), ['10'])
1959+
# '6' and '7' or '1' and '2'
1960+
ae(filt(None, {'issues': ['6', '7', '-3', '1', '2', '-3', '-4']}),
1961+
[])
1962+
# '1' or '4'
1963+
ae(filt(None, {'issues': ['1', '4', '-4']}), ['6', '8'])
1964+
19011965
def testFilteringLinkSortSearchMultilink(self):
19021966
ae, iiter = self.filteringSetup()
19031967
a = 'assignedto'
@@ -2054,10 +2118,12 @@ def testFilteringRevMultilinkExpression(self):
20542118
# 7: 5
20552119
# 8:
20562120
# Retire users '9' and '10' to reduce list
2057-
self.db.user.retire ('9')
2058-
self.db.user.retire ('10')
2059-
self.db.commit ()
2121+
self.db.user.retire('9')
2122+
self.db.user.retire('10')
2123+
self.db.commit()
20602124
for filt in iiter():
2125+
# not empty
2126+
ae(filt(None, {ni: ['-1', '-2']}), ['3', '4', '5'])
20612127
# '1' or '2'
20622128
ae(filt(None, {ni: ['1', '2', '-4']}), ['4', '5'])
20632129
# '6' or '7'
@@ -2081,6 +2147,49 @@ def testFilteringRevMultilinkExpression(self):
20812147
# ('4' and empty) or ('2' or empty)
20822148
ae(filt(None, {ni: ['4', '-1', '-3', '2', '-1', '-4', '-4']}),
20832149
['1', '2', '5', '6', '7', '8'])
2150+
# Retire issues 2, 6 and retry
2151+
self.db.issue.retire('2')
2152+
self.db.issue.retire('6')
2153+
self.db.commit()
2154+
# After this setup we have the following values for nosy:
2155+
# issue nosy
2156+
# 1: 4
2157+
# 3:
2158+
# 4:
2159+
# 5:
2160+
# 7: 5
2161+
# 8:
2162+
for filt in iiter():
2163+
# not empty
2164+
ae(filt(None, {ni: ['-1', '-2']}), ['4', '5'])
2165+
# '1' or '2' (implicit)
2166+
ae(filt(None, {ni: ['1', '2']}), ['4'])
2167+
# '1' or '2'
2168+
ae(filt(None, {ni: ['1', '2', '-4']}), ['4'])
2169+
# '6' or '7'
2170+
ae(filt(None, {ni: ['6', '7', '-4']}), ['5'])
2171+
# '6' and '7'
2172+
ae(filt(None, {ni: ['6', '7', '-3']}), [])
2173+
# '6' and not '1'
2174+
ae(filt(None, {ni: ['6', '1', '-2', '-3']}), [])
2175+
# not '1'
2176+
ae(filt(None, {ni: ['1', '-2']}),
2177+
['1', '2', '3', '5', '6', '7', '8'])
2178+
# '2' or empty (implicit or)
2179+
ae(filt(None, {ni: ['-1', '2']}), ['1', '2', '3', '6', '7', '8'])
2180+
# '2' or empty (explicit or)
2181+
ae(filt(None, {ni: ['-1', '2', '-4']}),
2182+
['1', '2', '3', '6', '7', '8'])
2183+
# empty or '2' (explicit or)
2184+
ae(filt(None, {ni: ['2', '-1', '-4']}),
2185+
['1', '2', '3', '6', '7', '8'])
2186+
# '2' and empty (should always return empty list)
2187+
ae(filt(None, {ni: ['-1', '2', '-3']}), [])
2188+
# empty and '2' (should always return empty list)
2189+
ae(filt(None, {ni: ['2', '-1', '-3']}), [])
2190+
# ('4' and empty) or ('2' or empty)
2191+
ae(filt(None, {ni: ['4', '-1', '-3', '2', '-1', '-4', '-4']}),
2192+
['1', '2', '3', '6', '7', '8'])
20842193

20852194
def testFilteringMany(self):
20862195
ae, iiter = self.filteringSetup()

0 commit comments

Comments
 (0)