Skip to content

Commit

Permalink
Merge pull request #201 from stephenrauch/Fix-belong-with-empty-set-f…
Browse files Browse the repository at this point in the history
…or-MongoDB-and-GAE

Fix belongs() with empty set for MongoDB and GAE
  • Loading branch information
mdipierro committed May 27, 2015
2 parents 4d36919 + a887058 commit d8e24bc
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 5 deletions.
9 changes: 8 additions & 1 deletion pydal/adapters/google_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,11 @@ def BELONGS(self,first,second=None):
raise SyntaxError("Not supported")
if not isinstance(second, list):
second = list(second)
if len(second) == 0:
# return a filter which will return a null set
f = self.EQ(first,0)
f.filter_all = True
return f
return self.gaef(first,'in',second)

def CONTAINS(self,first,second,case_sensitive=False):
Expand All @@ -327,7 +332,7 @@ def NOT(self, first):
elif op == self.EQ:
r = self.gaef(f, '!=', s)
elif op == self.NE:
r = self.gaef(f, '==', s)
r = self.gaef(f, '=', s)
elif op == self.LT:
r = self.gaef(f, '>=', s)
elif op == self.LE:
Expand Down Expand Up @@ -409,6 +414,8 @@ def select_raw(self,query,fields=None,attributes=None,count_only=False):

if filters == None:
items = tableobj.query(default_options=qo)
elif hasattr(filters,'filter_all') and filters.filter_all:
items = []
elif (hasattr(filters,'_FilterNode__name') and
filters._FilterNode__name=='__key__' and
filters._FilterNode__opsymbol=='='):
Expand Down
17 changes: 13 additions & 4 deletions pydal/adapters/mongo.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,14 +448,22 @@ def NOT(self, first):
op = self.expand(first)
op_k = list(op)[0]
op_body = op[op_k]
r = None
if type(op_body) is list:
# apply De Morgan law for and/or
# not(A and B) -> not(A) or not(B)
# not(A or B) -> not(A) and not(B)
not_op = '$and' if op_k == '$or' else '$or'
r = {not_op: [self.NOT(first.first), self.NOT(first.second)]}
else:
r = {op_k: {'$not': op_body}}
try:
sub_ops = list(op_body.keys())
if len(sub_ops) == 1 and sub_ops[0] == '$ne':
r = {op_k: op_body['$ne']}
except:
r = {op_k: {'$ne': op_body}}
if r == None:
r = {op_k: {'$not': op_body}}
return r

def AND(self,first,second):
Expand All @@ -468,9 +476,10 @@ def OR(self,first,second):

def BELONGS(self, first, second):
if isinstance(second, str):
return {self.expand(first) : {"$in" : [ second[:-1]]} }
elif second==[] or second==() or second==set():
return {1:0}
# this is broken, the only way second is a string is if it has
# been converted to SQL. This no worky. This might be made to
# work if _select did not return SQL.
raise RuntimeError("nested queries not supported")
items = [self.expand(item, first.type) for item in second]
return {self.expand(first) : {"$in" : items} }

Expand Down
3 changes: 3 additions & 0 deletions tests/nosql.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,8 @@ def testRun(self):
self.assertEqual(db((db.tt.aa > '1') & (db.tt.aa < '3')).count(), 1)
self.assertEqual(db((db.tt.aa > '1') | (db.tt.aa < '3')).count(), 3)
# Test not operator
self.assertEqual(db(~(db.tt.aa != '1')).count(), 1)
self.assertEqual(db(~(db.tt.aa == '1')).count(), 2)
self.assertEqual(db((db.tt.aa > '1') & ~(db.tt.aa > '2')).count(), 1)
self.assertEqual(db(~(db.tt.aa > '1') & (db.tt.aa > '2')).count(), 0)
self.assertEqual(db(~((db.tt.aa < '1') | (db.tt.aa > '2'))).count(), 2)
Expand Down Expand Up @@ -422,6 +424,7 @@ def testRun(self):
self.assertEqual(db(db.tt.aa.belongs(['1', '3'])).count(), 2)
self.assertEqual(db(db.tt.aa.belongs(['1', '3'])).count(), 2)
self.assertEqual(db(db.tt.id.belongs([self.i_id])).count(), 1)
self.assertEqual(db(db.tt.id.belongs([])).count(), 0)

@unittest.skipIf(IS_GAE or IS_MONGODB, "Datastore/Mongodb belongs() does not accept nested queries")
def testNested(self):
Expand Down

0 comments on commit d8e24bc

Please sign in to comment.