Oh Mann... ich bekomm' einfach die Kurve nicht...!
Ich hab' mein Modul dahingehend erweitert, dass Treffer samt (left, right) zurückgegeben werden, damit ich diese dann in der Ausgabe hervorheben kann. Zudem werden Ergebnisse von Abfragen, die mit `And` verkettet sind, erst dann zurückgegeben, wenn auch beide Seiten der `And` Bedingungen erfüllt sind. Hier liegt aber der Knackpunkt: Wenn ich eine `And` Kette wiederum mit `And` verknüpfe, werden beide Seiten separat behandelt, also:
Code: Alles auswählen
In [17]: left = And(Contains(Constant('bla'), Key('test')), Contains(Constant('alb'), Key('test')))
In [18]: submit(left, {'test': 'alb bla'})
Out[18]: defaultdict(<type 'list'>, {'test': ['bla', 'alb'], 'obj': {'test': 'alb bla'}})
Soweit gut, beide Bedingungen treffen zu.
Code: Alles auswählen
In [19]: right = Contains(Constant('lab'), Key('test'))
In [20]: submit(right, {'test': 'alb bla'})
Out[20]: defaultdict(<type 'list'>, {})
Hier wird korrekterweise nichts zurückgegeben, da die Bedingung nicht zutrifft.
Code: Alles auswählen
In [21]: submit(And(left, right), {'test': 'alb bla'})
Out[21]: defaultdict(<type 'list'>, {'test': ['bla', 'alb'], 'obj': {'test': 'alb bla'}})
Hier wird der Treffer aus `left` ausgegeben, weil dieses `And` auch zutrifft. Ich möchte allerdings, dass auch `right` berücksichtigt wird und somit nichts zurückgegeben wird.
Hier der Code:
Code: Alles auswählen
class Key(object):
def __init__(self, name):
self.name = name
def submit(self, obj):
yield (None, None, (obj[self.name], self.name), None)
class Constant(object):
def __init__(self, value):
self.value = value
def submit(self, obj=None):
yield (None, None, self.value, None)
class Contains(object):
def __init__(self, left, right):
self.left, self.right = left, right
def submit(self, obj):
left_value = yield (None, None, None, self.left.submit(obj))
right_value = yield (None, None, None, self.right.submit(obj))
result = left_value in right_value[0]
if result:
yield (None, (right_value[1], left_value), result, None)
else:
yield (None, None, result, None)
class And(object):
def __init__(self, left, right):
self.left, self.right = left, right
def submit(self, obj):
left_value = yield (True, None, None, self.left.submit(obj))
right_value = yield (True, None, None, self.right.submit(obj))
result = left_value and right_value
yield (False, result, result, None)
def submit(expression, obj):
stack = [expression.submit(obj)]
result = collections.defaultdict(list)
reserved_matches = collections.defaultdict(list)
value = None
reserve = None
while stack:
try:
reserve_, match, value, expression = stack[-1].send(value)
reserve = reserve_ if reserve_ is not None else reserve
if match is not None:
if reserve is None:
result[match[0]].append(match[1])
elif reserve:
reserved_matches[match[0]].append(match[1])
elif not reserve:
if match:
for key in reserved_matches:
result[key].extend(reserved_matches[key])
reserved_matches = collections.defaultdict(list)
reserve = None
except StopIteration:
stack.pop()
if expression is not None:
stack.append(expression)
if result:
result['obj'] = obj
return result
Das Ergebnis aus `left` müsste also noch so lange in `reserved_matches` bleiben, bis klar ist, dass keine weitere `And` Bedingung mehr zutreffen muss... Allerdings weiß `left` ja nicht, dass es ein left innerhalb einer `And` Verkettung ist.... Könnte mich jemand bitte aus meinem Sumpf ziehen??
mutetella