2 # -*- coding: utf-8 -*-
5 # Define a condition to join for example to Table instances.
6 # If this condition involves several fields, you may define a
7 # single Predicate using tuple of fields.
9 # Copyright (C) UPMC Paris Universitas
11 # Jordan Augé <jordan.auge@lip6.fr>
12 # Marc-Olivier Buob <marc-olivier.buob@lip6.fr>
14 from types import StringTypes
15 from manifold.util.type import returns, accepts
17 from operator import (
18 and_, or_, inv, add, mul, sub, mod, truediv, lt, le, ne, gt, ge, eq, neg
21 # Define the inclusion operators
22 class contains(type): pass
23 class included(type): pass
25 # New modifier: { contains
37 'CONTAINS' : contains,
54 def __init__(self, *args, **kwargs):
56 Build a Predicate instance.
59 - 3 args (left, operator, right)
60 left: The left operand (it may be a String instance or a tuple)
61 operator: See Predicate.operators, this is the binary operator
62 involved in this Predicate.
63 right: The right value (it may be a String instance
64 or a literal (String, numerical value, tuple...))
65 - 1 argument (list or tuple), containing three arguments
66 (variable, operator, value)
70 elif len(args) == 1 and isinstance(args[0], (tuple,list)) and len(args[0]) == 3:
71 key, op, value = args[0]
72 elif len(args) == 1 and isinstance(args[0], Predicate):
73 key, op, value = args[0].get_tuple()
75 raise Exception, "Bad initializer for Predicate (args = %r)" % args
77 assert not isinstance(value, (frozenset, dict, set)), "Invalid value type (type = %r)" % type(value)
78 if isinstance(value, list):
82 if isinstance(op, StringTypes):
84 if op in self.operators.keys():
85 self.op = self.operators[op]
86 elif op in self.operators_short.keys():
87 self.op = self.operators_short[op]
91 if isinstance(value, list):
92 self.value = tuple(value)
100 The '%s' representation of this Predicate.
102 key, op, value = self.get_str_tuple()
103 if isinstance(value, (tuple, list, set, frozenset)):
104 value = [repr(v) for v in value]
105 value = "[%s]" % ", ".join(value)
106 return "%s %s %r" % (key, op, value)
108 @returns(StringTypes)
112 The '%r' representation of this Predicate.
114 return "Predicate<%s %s %r>" % self.get_str_tuple()
119 The hash of this Predicate (this allows to define set of
120 Predicate instances).
122 return hash(self.get_tuple())
125 def __eq__(self, predicate):
128 True iif self == predicate.
132 return self.get_tuple() == predicate.get_tuple()
137 The left operand of this Predicate. It may be a String
138 or a tuple of Strings.
142 def set_key(self, key):
144 Set the left operand of this Predicate.
146 key: The new left operand.
156 def set_value(self, value):
160 return (self.key, self.op, self.value)
162 def get_str_op(self):
163 op_str = [s for s, op in self.operators.iteritems() if op == self.op]
166 def get_str_tuple(self):
167 return (self.key, self.get_str_op(), self.value,)
170 return list(self.get_str_tuple())
172 def match(self, dic, ignore_missing=False):
173 if isinstance(self.key, tuple):
174 print "PREDICATE MATCH", self.key
176 print "-----------------------------"
179 if self.key not in dic:
180 return ignore_missing
183 if isinstance(self.value, list):
184 return (dic[self.key] in self.value) # array ?
186 return (dic[self.key] == self.value)
188 if isinstance(self.value, list):
189 return (dic[self.key] not in self.value) # array ?
191 return (dic[self.key] != self.value) # array ?
193 if isinstance(self.value, StringTypes):
195 return dic[self.key].startswith('%s.' % self.value)
197 return (dic[self.key] < self.value)
199 if isinstance(self.value, StringTypes):
200 return dic[self.key] == self.value or dic[self.key].startswith('%s.' % self.value)
202 return (dic[self.key] <= self.value)
204 if isinstance(self.value, StringTypes):
206 return self.value.startswith('%s.' % dic[self.key])
208 return (dic[self.key] > self.value)
210 if isinstance(self.value, StringTypes):
212 return dic[self.key] == self.value or self.value.startswith('%s.' % dic[self.key])
214 return (dic[self.key] >= self.value)
215 elif self.op == and_:
216 return (dic[self.key] & self.value) # array ?
218 return (dic[self.key] | self.value) # array ?
219 elif self.op == contains:
220 method, subfield = self.key.split('.', 1)
221 return not not [ x for x in dic[method] if x[subfield] == self.value]
222 elif self.op == included:
223 return dic[self.key] in self.value
225 raise Exception, "Unexpected table format: %r" % dic
227 def filter(self, dic):
229 Filter dic according to the current predicate.
234 method, subfield = self.key.split('.', 1)
235 if not method in dic:
238 if isinstance(dic[method], dict):
239 # We have a 1..1 relationship: apply the same filter to the dict
240 subpred = Predicate(subfield, self.op, self.value)
241 match = subpred.match(dic[method])
242 return dic if match else None
244 elif isinstance(dic[method], (list, tuple)):
247 if self.op == contains:
248 return dic if self.match(dic) else None
250 subpred = Predicate(subfield, self.op, self.value)
251 dic[method] = subpred.filter(dic[method])
254 raise Exception, "Unexpected table format: %r", dic
258 # Individual field operations: this could be simplified, since we are now using operators_short !!
260 print "current predicate", self
261 print "matching", dic
263 return dic if self.match(dic) else None
265 def get_field_names(self):
266 if isinstance(self.key, (list, tuple, set, frozenset)):
269 return set([self.key])
271 def get_value_names(self):
272 if isinstance(self.value, (list, tuple, set, frozenset)):
273 return set(self.value)
275 return set([self.value])
277 def has_empty_value(self):
278 if isinstance(self.value, (list, tuple, set, frozenset)):
279 return not any(self.value)
281 return not self.value