@@ -5,21 +5,27 @@ def __init__(self, query, connection, using):
5
5
self .connection = connection
6
6
self .using = using
7
7
8
- def get_filters (self , where ):
8
+ def get_filters (self , where , correct = False ):
9
9
assert where .connector == "AND"
10
- assert not where .negated
11
10
filters = {}
12
11
for child in where .children :
13
12
if isinstance (child , self .query .where_class ):
14
- # TODO: probably needs to check for dupe keys
15
- filters .update (self .get_filters (child ))
13
+ child_filters = self .get_filters (child )
14
+ for k , v in child_filters .iteritems ():
15
+ if k in filters :
16
+ v = {"$and" : [filters [k ], v ]}
17
+ if where .negated :
18
+ v = {"$not" : v }
19
+ filters [k ] = v
16
20
else :
17
- field , val = self .make_atom (* child )
21
+ field , val = self .make_atom (* child , ** { "negated" : where . negated } )
18
22
filters [field ] = val
23
+ if correct :
24
+ self .correct_filters (filters )
19
25
return filters
20
26
21
- def make_atom (self , lhs , lookup_type , value_annotation , params_or_value ):
22
- assert lookup_type == "exact"
27
+ def make_atom (self , lhs , lookup_type , value_annotation , params_or_value , negated ):
28
+ assert lookup_type in [ "exact" , "isnull" ], lookup_type
23
29
if hasattr (lhs , "process" ):
24
30
lhs , params = lhs .process (lookup_type , params_or_value , self .connection )
25
31
else :
@@ -30,7 +36,33 @@ def make_atom(self, lhs, lookup_type, value_annotation, params_or_value):
30
36
assert table == self .query .model ._meta .db_table
31
37
if column == self .query .model ._meta .pk .column :
32
38
column = "_id"
33
- return column , params [0 ]
39
+
40
+ if lookup_type == "exact" :
41
+ val = params [0 ]
42
+ if negated :
43
+ val = {"$ne" : val }
44
+ return column , val
45
+ elif lookup_type == "isnull" :
46
+ val = None
47
+ if value_annotation == negated :
48
+ val = {"$not" : val }
49
+ return column , val
50
+
51
+ def correct_filters (self , filters ):
52
+ for k , v in filters .items ():
53
+ if isinstance (v , dict ) and v .keys () == ["$not" ]:
54
+ if isinstance (v ["$not" ], dict ) and v ["$not" ].keys () == ["$and" ]:
55
+ del filters [k ]
56
+ or_vals = [self .negate (k , v ) for v in v ["$not" ]["$and" ]]
57
+ assert "$or" not in filters
58
+ filters ["$or" ] = or_vals
59
+
60
+ def negate (self , k , v ):
61
+ if isinstance (v , dict ):
62
+ if v .keys () == ["$not" ]:
63
+ return {k : v ["$not" ]}
64
+ return {k : {"$not" : v }}
65
+ return {k : {"$ne" : v }}
34
66
35
67
def build_query (self , aggregates = False ):
36
68
assert len ([a for a in self .query .alias_map if self .query .alias_refcount [a ]]) <= 1
@@ -42,7 +74,7 @@ def build_query(self, aggregates=False):
42
74
assert self .query .high_mark is None
43
75
assert not self .query .order_by
44
76
45
- filters = self .get_filters (self .query .where )
77
+ filters = self .get_filters (self .query .where , correct = True )
46
78
return self .connection .db [self .query .model ._meta .db_table ].find (filters )
47
79
48
80
def results_iter (self ):
0 commit comments