Skip to content

Commit ed47ab6

Browse files
author
Xin Dong
committed
Fix bugs found so far in MongoModel. Cleaned up some places.
1 parent 8656868 commit ed47ab6

File tree

1 file changed

+41
-30
lines changed

1 file changed

+41
-30
lines changed

test/correctness/mongo_model.py

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939

4040
def elem_match_pred(value, query, options):
41-
if type(value) is list:
41+
if isinstance(value, list):
4242
if False not in [k.startswith("$") for k in query["$elemMatch"]]:
4343
for i in value:
4444
okay = True
@@ -76,6 +76,7 @@ def elem_match_pred(value, query, options):
7676
return False
7777

7878

79+
# Assumes the `document` passed in is a type of, or subtype of `OrderedDict`
7980
def expand(field, document, check_last_array, expand_array, add_last_array, check_none_at_all, check_none_next, debug):
8081
ret = []
8182

@@ -150,9 +151,9 @@ def evaluate(field, query, document, options, debug=False):
150151
if type(query) != dict:
151152

152153
def pred(value, query, options):
153-
if type(value) == OrderedDict:
154+
if isinstance(value, OrderedDict):
154155
value = dict(value)
155-
if type(query) == OrderedDict:
156+
if isinstance(value, OrderedDict):
156157
query = dict(query)
157158
return value == query
158159
elif '$ne' in query:
@@ -355,13 +356,13 @@ def include_in_projection(projection, k, v, node):
355356
return node.sub(k).included or (not is_simple(v) and node.sub(k).fields)
356357

357358

358-
def project(document, projection_fields):
359+
def project(documents, projection_fields):
359360
projection = Projection(projection_fields)
360361
projected_results = []
361-
for values in document:
362+
for document in documents:
362363
results = {}
363-
# print "Projecting %r with %r" % (values, projection_fields)
364-
for k, v in values.items():
364+
# print "Projecting %r with %r" % (document, projection_fields)
365+
for k, v in document.items():
365366
# print "Checking %r => %r with %s" % (k, v, projection.root)
366367
if k == '_id':
367368
if projection.include_id:
@@ -431,14 +432,13 @@ def getTypeCode(value):
431432
return "20"
432433
elif isinstance(value, (long, float, int)):
433434
return "30"
435+
elif isinstance(value, binary.Binary):
436+
# this needs to come before basestring because `bson.binary.Binary` is also a subtype of `basestring`
437+
return "70"
434438
elif isinstance(value, basestring):
435439
return "40"
436440
elif isinstance(value, OrderedDict):
437441
return "51"
438-
elif isinstance(value, (list, tuple)):
439-
return "60"
440-
elif isinstance(value, binary.Binary):
441-
return "70"
442442
elif isinstance(value, ObjectId):
443443
return "80"
444444
elif isinstance(value, datetime.datetime):
@@ -455,6 +455,7 @@ def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
455455
items = super(SortedDict, self).items()
456456
# group them together first
457457
tmp = OrderedDict()
458+
tmp["20"] = []
458459
tmp["30"] = []
459460
tmp["40"] = []
460461
tmp["51"] = []
@@ -469,6 +470,8 @@ def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
469470
for typeCode, kvs in tmp.items():
470471
if typeCode == "51":
471472
sortedItems.extend(sorted(kvs, key=lambda kv: bson.BSON.encode(SortedDict.fromOrderedDict(kv[0]))))
473+
elif typeCode == "70":
474+
sortedItems.extend(sorted(kvs, key=lambda kv: str(len(kv[0][:-1])) + str(kv[0].subtype) + kv[0][:-1]))
472475
else:
473476
sortedItems.extend(sorted(kvs))
474477
# print str(sortedItems)
@@ -525,13 +528,13 @@ def _insert(self, doc):
525528
def insert(self, input):
526529
oldData = deepcopy(self.data)
527530
try:
528-
if type(input) is OrderedDict:
531+
if isinstance(input, OrderedDict):
529532
self._insert(input)
530-
elif type(input) is list:
533+
elif isinstance(input, list):
531534
all_ids = set()
532535
for i in input:
533536
if '_id' in i:
534-
if not self.options.object_field_order_matters and type(i['_id']) is HashableOrderedDict:
537+
if not self.options.object_field_order_matters and isinstance(i['_id'], HashableOrderedDict):
535538
i['_id'] = HashableOrderedDict(sorted(i['_id'].items(), key=lambda (key, value): key))
536539
if i['_id'] in all_ids:
537540
# print i['_id']
@@ -831,8 +834,18 @@ def process_update_operator_pull_all(self, key, update_expression):
831834
raise MongoModelException("Cannot apply $pullAll to a non-array field.", code=10142)
832835

833836
def evaluate(self, query, document):
834-
field = query.keys()[0]
835-
return evaluate(field, query[field], document, self.options, True)
837+
if len(query) == 0:
838+
return True # match empty query, since coll.find({}) returns all docs
839+
acc = True
840+
for field in query.keys():
841+
if field == '_id':
842+
tmp = OrderedDict()
843+
for k,v in sorted(query[field].items(), key= lambda i: i[0]):
844+
tmp[k] = v
845+
acc = acc and evaluate(field, tmp, document, self.options, True)
846+
else:
847+
acc = acc and evaluate(field, query[field], document, self.options, True)
848+
return acc
836849

837850
def process_update_operator_pull(self, key, update_expression):
838851
# print "Update Operator: $pull ", update
@@ -848,10 +861,10 @@ def process_update_operator_pull(self, key, update_expression):
848861
if self.evaluate(v, item):
849862
# print "item match0!, remove: ", item
850863
self.data[key][k].remove(item)
851-
elif isinstance(v, list):
852-
if item in v:
853-
# print "item match1!, remove: ", item
854-
self.data[key][k].remove(item)
864+
elif isinstance(v, list):
865+
if item in v:
866+
# print "item match1!, remove: ", item
867+
self.data[key][k].remove(item)
855868
else:
856869
self.data[key][k] = [x for x in self.data[key][k] if x != v]
857870
else:
@@ -956,9 +969,6 @@ def process_update_operator(self, key, update, new_doc=False):
956969
self.mapUpdateOperator[k](key, update[k])
957970
else:
958971
self.replace(key, update)
959-
for index in self.indexes:
960-
if not index.inError:
961-
index.validate_and_build_entry(self.data.values())
962972
except MongoModelException as e:
963973
self.data[key] = old_data
964974
raise e
@@ -1136,6 +1146,7 @@ def update(self, query, update, upsert, multi):
11361146
if not index.inError:
11371147
index.validate_and_build_entry(self.data.values())
11381148
except MongoModelException as e:
1149+
# print "*********************** Reseting update due to {}".format(e)
11391150
self.data = old_data
11401151
raise e
11411152

@@ -1225,11 +1236,11 @@ def validate_self(self):
12251236
raise MongoModelException("No index name specified", code=29967)
12261237

12271238
def build(self, documents):
1228-
self.validate_and_build_entry(documents)
1239+
self.validate_and_build_entry(documents, first_build=True)
12291240

12301241
# Validate the entry(ies) that will be built on this particular document for the following invariants:
12311242
# - If it's compund index, the cartesian product of all index values cannot exceed 1000
1232-
def validate_and_build_entry(self, documents):
1243+
def validate_and_build_entry(self, documents, first_build=False):
12331244
for document in documents:
12341245
nValues = 1
12351246
for key in self.keys:
@@ -1244,20 +1255,20 @@ def validate_and_build_entry(self, documents):
12441255
debug=False)
12451256
nValues * len(values)
12461257
if nValues > 1000 and not self.isSimple:
1247-
self.inError = True
1258+
self.inError = first_build
12481259
raise MongoModelException("Multi-multikey index size exceeds maximum value.", code=0)
12491260

12501261
class MongoUniqueIndex(MongoIndex):
12511262
def __init__(self, indexKeys, kwargs):
12521263
super(MongoUniqueIndex, self).__init__(indexKeys, kwargs)
12531264

12541265
def build(self, documents):
1255-
super(MongoUniqueIndex, self).validate_and_build_entry(documents)
1256-
self.validate_and_build_entry(documents)
1266+
super(MongoUniqueIndex, self).validate_and_build_entry(documents, first_build=True)
1267+
self.validate_and_build_entry(documents, first_build=True)
12571268

12581269
# Validate the entry(ies) that will be built on this particular document for the following invariants:
12591270
# - No duplicates
1260-
def validate_and_build_entry(self, documents):
1271+
def validate_and_build_entry(self, documents, first_build=False):
12611272
seen = set()
12621273
for document in documents:
12631274
entry = ""
@@ -1279,7 +1290,7 @@ def validate_and_build_entry(self, documents):
12791290
# import pprint
12801291
# print "Violation doc"
12811292
# pprint.pprint(dict(document))
1282-
self.inError = True
1293+
self.inError = first_build
12831294
raise MongoModelException("Duplicated value not allowed by unique index", code=11000)
12841295
else:
12851296
# print "Inserting {} for key {}".format(entry, key)

0 commit comments

Comments
 (0)