Merge branch 'master' into master

This commit is contained in:
erdenezul
2018-05-21 16:22:07 +08:00
committed by GitHub
34 changed files with 1480 additions and 211 deletions

View File

@@ -5,6 +5,7 @@ from mongoengine import *
from mongoengine.queryset import NULLIFY, PULL
from mongoengine.connection import get_db
from tests.utils import needs_mongodb_v26
__all__ = ("ClassMethodsTest", )
@@ -187,6 +188,26 @@ class ClassMethodsTest(unittest.TestCase):
self.assertEqual(BlogPostWithTags.compare_indexes(), { 'missing': [], 'extra': [] })
self.assertEqual(BlogPostWithCustomField.compare_indexes(), { 'missing': [], 'extra': [] })
@needs_mongodb_v26
def test_compare_indexes_for_text_indexes(self):
""" Ensure that compare_indexes behaves correctly for text indexes """
class Doc(Document):
a = StringField()
b = StringField()
meta = {'indexes': [
{'fields': ['$a', "$b"],
'default_language': 'english',
'weights': {'a': 10, 'b': 2}
}
]}
Doc.drop_collection()
Doc.ensure_indexes()
actual = Doc.compare_indexes()
expected = {'missing': [], 'extra': []}
self.assertEqual(actual, expected)
def test_list_indexes_inheritance(self):
""" ensure that all of the indexes are listed regardless of the super-
or sub-class that we call it from

View File

@@ -22,6 +22,8 @@ from mongoengine.queryset import NULLIFY, Q
from mongoengine.context_managers import switch_db, query_counter
from mongoengine import signals
from tests.utils import needs_mongodb_v26
TEST_IMAGE_PATH = os.path.join(os.path.dirname(__file__),
'../fields/mongoengine.png')
@@ -474,6 +476,24 @@ class InstanceTest(unittest.TestCase):
doc.save()
doc.reload()
def test_reload_with_changed_fields(self):
"""Ensures reloading will not affect changed fields"""
class User(Document):
name = StringField()
number = IntField()
User.drop_collection()
user = User(name="Bob", number=1).save()
user.name = "John"
user.number = 2
self.assertEqual(user._get_changed_fields(), ['name', 'number'])
user.reload('number')
self.assertEqual(user._get_changed_fields(), ['name'])
user.save()
user.reload()
self.assertEqual(user.name, "John")
def test_reload_referencing(self):
"""Ensures reloading updates weakrefs correctly."""
class Embedded(EmbeddedDocument):
@@ -519,7 +539,7 @@ class InstanceTest(unittest.TestCase):
doc.save()
doc.dict_field['extra'] = 1
doc = doc.reload(10, 'list_field')
self.assertEqual(doc._get_changed_fields(), [])
self.assertEqual(doc._get_changed_fields(), ['dict_field.extra'])
self.assertEqual(len(doc.list_field), 5)
self.assertEqual(len(doc.dict_field), 3)
self.assertEqual(len(doc.embedded_field.list_field), 4)
@@ -826,6 +846,22 @@ class InstanceTest(unittest.TestCase):
self.assertDbEqual([dict(other_doc.to_mongo()), dict(doc.to_mongo())])
@needs_mongodb_v26
def test_modify_with_positional_push(self):
class BlogPost(Document):
tags = ListField(StringField())
post = BlogPost.objects.create(tags=['python'])
self.assertEqual(post.tags, ['python'])
post.modify(push__tags__0=['code', 'mongo'])
self.assertEqual(post.tags, ['code', 'mongo', 'python'])
# Assert same order of the list items is maintained in the db
self.assertEqual(
BlogPost._get_collection().find_one({'_id': post.pk})['tags'],
['code', 'mongo', 'python']
)
def test_save(self):
"""Ensure that a document may be saved in the database."""
@@ -1323,6 +1359,23 @@ class InstanceTest(unittest.TestCase):
site = Site.objects.first()
self.assertEqual(site.page.log_message, "Error: Dummy message")
def test_update_list_field(self):
"""Test update on `ListField` with $pull + $in.
"""
class Doc(Document):
foo = ListField(StringField())
Doc.drop_collection()
doc = Doc(foo=['a', 'b', 'c'])
doc.save()
# Update
doc = Doc.objects.first()
doc.update(pull__foo__in=['a', 'c'])
doc = Doc.objects.first()
self.assertEqual(doc.foo, ['b'])
def test_embedded_update_db_field(self):
"""Test update on `EmbeddedDocumentField` fields when db_field
is other than default.
@@ -1866,6 +1919,25 @@ class InstanceTest(unittest.TestCase):
author.delete()
self.assertEqual(BlogPost.objects.count(), 0)
def test_reverse_delete_rule_pull(self):
"""Ensure that a referenced document is also deleted with
pull.
"""
class Record(Document):
name = StringField()
children = ListField(ReferenceField('self', reverse_delete_rule=PULL))
Record.drop_collection()
parent_record = Record(name='parent').save()
child_record = Record(name='child').save()
parent_record.children.append(child_record)
parent_record.save()
child_record.delete()
self.assertEqual(Record.objects(name='parent').get().children, [])
def test_reverse_delete_rule_with_custom_id_field(self):
"""Ensure that a referenced document with custom primary key
is also deleted upon deletion.
@@ -3149,6 +3221,33 @@ class InstanceTest(unittest.TestCase):
person.update(set__height=2.0)
@needs_mongodb_v26
def test_push_with_position(self):
"""Ensure that push with position works properly for an instance."""
class BlogPost(Document):
slug = StringField()
tags = ListField(StringField())
blog = BlogPost()
blog.slug = "ABC"
blog.tags = ["python"]
blog.save()
blog.update(push__tags__0=["mongodb", "code"])
blog.reload()
self.assertEqual(blog.tags, ['mongodb', 'code', 'python'])
def test_push_nested_list(self):
"""Ensure that push update works in nested list"""
class BlogPost(Document):
slug = StringField()
tags = ListField()
blog = BlogPost(slug="test").save()
blog.update(push__tags=["value1", 123])
blog.reload()
self.assertEqual(blog.tags, [["value1", 123]])
if __name__ == '__main__':
unittest.main()

View File

@@ -26,7 +26,7 @@ except ImportError:
from mongoengine import *
from mongoengine.connection import get_db
from mongoengine.base import (BaseDict, BaseField, EmbeddedDocumentList,
_document_registry)
_document_registry, LazyReference)
from tests.utils import MongoDBTestCase
@@ -937,7 +937,9 @@ class FieldTest(MongoDBTestCase):
comments = ListField(EmbeddedDocumentField(Comment))
tags = ListField(StringField())
authors = ListField(ReferenceField(User))
authors_as_lazy = ListField(LazyReferenceField(User))
generic = ListField(GenericReferenceField())
generic_as_lazy = ListField(GenericLazyReferenceField())
access_list = ListField(choices=AccessLevelChoices, display_sep=', ')
User.drop_collection()
@@ -987,6 +989,15 @@ class FieldTest(MongoDBTestCase):
post.authors = [user]
post.validate()
post.authors_as_lazy = [Comment()]
self.assertRaises(ValidationError, post.validate)
post.authors_as_lazy = [User()]
self.assertRaises(ValidationError, post.validate)
post.authors_as_lazy = [user]
post.validate()
post.generic = [1, 2]
self.assertRaises(ValidationError, post.validate)
@@ -999,6 +1010,18 @@ class FieldTest(MongoDBTestCase):
post.generic = [user]
post.validate()
post.generic_as_lazy = [1, 2]
self.assertRaises(ValidationError, post.validate)
post.generic_as_lazy = [User(), Comment()]
self.assertRaises(ValidationError, post.validate)
post.generic_as_lazy = [Comment()]
self.assertRaises(ValidationError, post.validate)
post.generic_as_lazy = [user]
post.validate()
def test_sorted_list_sorting(self):
"""Ensure that a sorted list field properly sorts values.
"""
@@ -4374,6 +4397,51 @@ class CachedReferenceFieldTest(MongoDBTestCase):
self.assertEqual(SocialData.objects(person__group=g2).count(), 1)
self.assertEqual(SocialData.objects(person__group=g2).first(), s2)
def test_cached_reference_field_push_with_fields(self):
class Product(Document):
name = StringField()
Product.drop_collection()
class Basket(Document):
products = ListField(CachedReferenceField(Product, fields=['name']))
Basket.drop_collection()
product1 = Product(name='abc').save()
product2 = Product(name='def').save()
basket = Basket(products=[product1]).save()
self.assertEqual(
Basket.objects._collection.find_one(),
{
'_id': basket.pk,
'products': [
{
'_id': product1.pk,
'name': product1.name
}
]
}
)
# push to list
basket.update(push__products=product2)
basket.reload()
self.assertEqual(
Basket.objects._collection.find_one(),
{
'_id': basket.pk,
'products': [
{
'_id': product1.pk,
'name': product1.name
},
{
'_id': product2.pk,
'name': product2.name
}
]
}
)
def test_cached_reference_field_update_all(self):
class Person(Document):
TYPES = (
@@ -4616,5 +4684,522 @@ class CachedReferenceFieldTest(MongoDBTestCase):
self.assertTrue(isinstance(ocorrence.animal, Animal))
class LazyReferenceFieldTest(MongoDBTestCase):
def test_lazy_reference_config(self):
# Make sure ReferenceField only accepts a document class or a string
# with a document class name.
self.assertRaises(ValidationError, LazyReferenceField, EmbeddedDocument)
def test_lazy_reference_simple(self):
class Animal(Document):
name = StringField()
tag = StringField()
class Ocurrence(Document):
person = StringField()
animal = LazyReferenceField(Animal)
Animal.drop_collection()
Ocurrence.drop_collection()
animal = Animal(name="Leopard", tag="heavy").save()
Ocurrence(person="test", animal=animal).save()
p = Ocurrence.objects.get()
self.assertIsInstance(p.animal, LazyReference)
fetched_animal = p.animal.fetch()
self.assertEqual(fetched_animal, animal)
# `fetch` keep cache on referenced document by default...
animal.tag = "not so heavy"
animal.save()
double_fetch = p.animal.fetch()
self.assertIs(fetched_animal, double_fetch)
self.assertEqual(double_fetch.tag, "heavy")
# ...unless specified otherwise
fetch_force = p.animal.fetch(force=True)
self.assertIsNot(fetch_force, fetched_animal)
self.assertEqual(fetch_force.tag, "not so heavy")
def test_lazy_reference_fetch_invalid_ref(self):
class Animal(Document):
name = StringField()
tag = StringField()
class Ocurrence(Document):
person = StringField()
animal = LazyReferenceField(Animal)
Animal.drop_collection()
Ocurrence.drop_collection()
animal = Animal(name="Leopard", tag="heavy").save()
Ocurrence(person="test", animal=animal).save()
animal.delete()
p = Ocurrence.objects.get()
self.assertIsInstance(p.animal, LazyReference)
with self.assertRaises(DoesNotExist):
p.animal.fetch()
def test_lazy_reference_set(self):
class Animal(Document):
meta = {'allow_inheritance': True}
name = StringField()
tag = StringField()
class Ocurrence(Document):
person = StringField()
animal = LazyReferenceField(Animal)
Animal.drop_collection()
Ocurrence.drop_collection()
class SubAnimal(Animal):
nick = StringField()
animal = Animal(name="Leopard", tag="heavy").save()
sub_animal = SubAnimal(nick='doggo', name='dog').save()
for ref in (
animal,
animal.pk,
DBRef(animal._get_collection_name(), animal.pk),
LazyReference(Animal, animal.pk),
sub_animal,
sub_animal.pk,
DBRef(sub_animal._get_collection_name(), sub_animal.pk),
LazyReference(SubAnimal, sub_animal.pk),
):
p = Ocurrence(person="test", animal=ref).save()
p.reload()
self.assertIsInstance(p.animal, LazyReference)
p.animal.fetch()
def test_lazy_reference_bad_set(self):
class Animal(Document):
name = StringField()
tag = StringField()
class Ocurrence(Document):
person = StringField()
animal = LazyReferenceField(Animal)
Animal.drop_collection()
Ocurrence.drop_collection()
class BadDoc(Document):
pass
animal = Animal(name="Leopard", tag="heavy").save()
baddoc = BadDoc().save()
for bad in (
42,
'foo',
baddoc,
DBRef(baddoc._get_collection_name(), animal.pk),
LazyReference(BadDoc, animal.pk)
):
with self.assertRaises(ValidationError):
p = Ocurrence(person="test", animal=bad).save()
def test_lazy_reference_query_conversion(self):
"""Ensure that LazyReferenceFields can be queried using objects and values
of the type of the primary key of the referenced object.
"""
class Member(Document):
user_num = IntField(primary_key=True)
class BlogPost(Document):
title = StringField()
author = LazyReferenceField(Member, dbref=False)
Member.drop_collection()
BlogPost.drop_collection()
m1 = Member(user_num=1)
m1.save()
m2 = Member(user_num=2)
m2.save()
post1 = BlogPost(title='post 1', author=m1)
post1.save()
post2 = BlogPost(title='post 2', author=m2)
post2.save()
post = BlogPost.objects(author=m1).first()
self.assertEqual(post.id, post1.id)
post = BlogPost.objects(author=m2).first()
self.assertEqual(post.id, post2.id)
# Same thing by passing a LazyReference instance
post = BlogPost.objects(author=LazyReference(Member, m2.pk)).first()
self.assertEqual(post.id, post2.id)
def test_lazy_reference_query_conversion_dbref(self):
"""Ensure that LazyReferenceFields can be queried using objects and values
of the type of the primary key of the referenced object.
"""
class Member(Document):
user_num = IntField(primary_key=True)
class BlogPost(Document):
title = StringField()
author = LazyReferenceField(Member, dbref=True)
Member.drop_collection()
BlogPost.drop_collection()
m1 = Member(user_num=1)
m1.save()
m2 = Member(user_num=2)
m2.save()
post1 = BlogPost(title='post 1', author=m1)
post1.save()
post2 = BlogPost(title='post 2', author=m2)
post2.save()
post = BlogPost.objects(author=m1).first()
self.assertEqual(post.id, post1.id)
post = BlogPost.objects(author=m2).first()
self.assertEqual(post.id, post2.id)
# Same thing by passing a LazyReference instance
post = BlogPost.objects(author=LazyReference(Member, m2.pk)).first()
self.assertEqual(post.id, post2.id)
def test_lazy_reference_passthrough(self):
class Animal(Document):
name = StringField()
tag = StringField()
class Ocurrence(Document):
animal = LazyReferenceField(Animal, passthrough=False)
animal_passthrough = LazyReferenceField(Animal, passthrough=True)
Animal.drop_collection()
Ocurrence.drop_collection()
animal = Animal(name="Leopard", tag="heavy").save()
Ocurrence(animal=animal, animal_passthrough=animal).save()
p = Ocurrence.objects.get()
self.assertIsInstance(p.animal, LazyReference)
with self.assertRaises(KeyError):
p.animal['name']
with self.assertRaises(AttributeError):
p.animal.name
self.assertEqual(p.animal.pk, animal.pk)
self.assertEqual(p.animal_passthrough.name, "Leopard")
self.assertEqual(p.animal_passthrough['name'], "Leopard")
# Should not be able to access referenced document's methods
with self.assertRaises(AttributeError):
p.animal.save
with self.assertRaises(KeyError):
p.animal['save']
def test_lazy_reference_not_set(self):
class Animal(Document):
name = StringField()
tag = StringField()
class Ocurrence(Document):
person = StringField()
animal = LazyReferenceField(Animal)
Animal.drop_collection()
Ocurrence.drop_collection()
Ocurrence(person='foo').save()
p = Ocurrence.objects.get()
self.assertIs(p.animal, None)
def test_lazy_reference_equality(self):
class Animal(Document):
name = StringField()
tag = StringField()
Animal.drop_collection()
animal = Animal(name="Leopard", tag="heavy").save()
animalref = LazyReference(Animal, animal.pk)
self.assertEqual(animal, animalref)
self.assertEqual(animalref, animal)
other_animalref = LazyReference(Animal, ObjectId("54495ad94c934721ede76f90"))
self.assertNotEqual(animal, other_animalref)
self.assertNotEqual(other_animalref, animal)
def test_lazy_reference_embedded(self):
class Animal(Document):
name = StringField()
tag = StringField()
class EmbeddedOcurrence(EmbeddedDocument):
in_list = ListField(LazyReferenceField(Animal))
direct = LazyReferenceField(Animal)
class Ocurrence(Document):
in_list = ListField(LazyReferenceField(Animal))
in_embedded = EmbeddedDocumentField(EmbeddedOcurrence)
direct = LazyReferenceField(Animal)
Animal.drop_collection()
Ocurrence.drop_collection()
animal1 = Animal('doggo').save()
animal2 = Animal('cheeta').save()
def check_fields_type(occ):
self.assertIsInstance(occ.direct, LazyReference)
for elem in occ.in_list:
self.assertIsInstance(elem, LazyReference)
self.assertIsInstance(occ.in_embedded.direct, LazyReference)
for elem in occ.in_embedded.in_list:
self.assertIsInstance(elem, LazyReference)
occ = Ocurrence(
in_list=[animal1, animal2],
in_embedded={'in_list': [animal1, animal2], 'direct': animal1},
direct=animal1
).save()
check_fields_type(occ)
occ.reload()
check_fields_type(occ)
occ.direct = animal1.id
occ.in_list = [animal1.id, animal2.id]
occ.in_embedded.direct = animal1.id
occ.in_embedded.in_list = [animal1.id, animal2.id]
check_fields_type(occ)
class GenericLazyReferenceFieldTest(MongoDBTestCase):
def test_generic_lazy_reference_simple(self):
class Animal(Document):
name = StringField()
tag = StringField()
class Ocurrence(Document):
person = StringField()
animal = GenericLazyReferenceField()
Animal.drop_collection()
Ocurrence.drop_collection()
animal = Animal(name="Leopard", tag="heavy").save()
Ocurrence(person="test", animal=animal).save()
p = Ocurrence.objects.get()
self.assertIsInstance(p.animal, LazyReference)
fetched_animal = p.animal.fetch()
self.assertEqual(fetched_animal, animal)
# `fetch` keep cache on referenced document by default...
animal.tag = "not so heavy"
animal.save()
double_fetch = p.animal.fetch()
self.assertIs(fetched_animal, double_fetch)
self.assertEqual(double_fetch.tag, "heavy")
# ...unless specified otherwise
fetch_force = p.animal.fetch(force=True)
self.assertIsNot(fetch_force, fetched_animal)
self.assertEqual(fetch_force.tag, "not so heavy")
def test_generic_lazy_reference_choices(self):
class Animal(Document):
name = StringField()
class Vegetal(Document):
name = StringField()
class Mineral(Document):
name = StringField()
class Ocurrence(Document):
living_thing = GenericLazyReferenceField(choices=[Animal, Vegetal])
thing = GenericLazyReferenceField()
Animal.drop_collection()
Vegetal.drop_collection()
Mineral.drop_collection()
Ocurrence.drop_collection()
animal = Animal(name="Leopard").save()
vegetal = Vegetal(name="Oak").save()
mineral = Mineral(name="Granite").save()
occ_animal = Ocurrence(living_thing=animal, thing=animal).save()
occ_vegetal = Ocurrence(living_thing=vegetal, thing=vegetal).save()
with self.assertRaises(ValidationError):
Ocurrence(living_thing=mineral).save()
occ = Ocurrence.objects.get(living_thing=animal)
self.assertEqual(occ, occ_animal)
self.assertIsInstance(occ.thing, LazyReference)
self.assertIsInstance(occ.living_thing, LazyReference)
occ.thing = vegetal
occ.living_thing = vegetal
occ.save()
occ.thing = mineral
occ.living_thing = mineral
with self.assertRaises(ValidationError):
occ.save()
def test_generic_lazy_reference_set(self):
class Animal(Document):
meta = {'allow_inheritance': True}
name = StringField()
tag = StringField()
class Ocurrence(Document):
person = StringField()
animal = GenericLazyReferenceField()
Animal.drop_collection()
Ocurrence.drop_collection()
class SubAnimal(Animal):
nick = StringField()
animal = Animal(name="Leopard", tag="heavy").save()
sub_animal = SubAnimal(nick='doggo', name='dog').save()
for ref in (
animal,
LazyReference(Animal, animal.pk),
{'_cls': 'Animal', '_ref': DBRef(animal._get_collection_name(), animal.pk)},
sub_animal,
LazyReference(SubAnimal, sub_animal.pk),
{'_cls': 'SubAnimal', '_ref': DBRef(sub_animal._get_collection_name(), sub_animal.pk)},
):
p = Ocurrence(person="test", animal=ref).save()
p.reload()
self.assertIsInstance(p.animal, (LazyReference, Document))
p.animal.fetch()
def test_generic_lazy_reference_bad_set(self):
class Animal(Document):
name = StringField()
tag = StringField()
class Ocurrence(Document):
person = StringField()
animal = GenericLazyReferenceField(choices=['Animal'])
Animal.drop_collection()
Ocurrence.drop_collection()
class BadDoc(Document):
pass
animal = Animal(name="Leopard", tag="heavy").save()
baddoc = BadDoc().save()
for bad in (
42,
'foo',
baddoc,
LazyReference(BadDoc, animal.pk)
):
with self.assertRaises(ValidationError):
p = Ocurrence(person="test", animal=bad).save()
def test_generic_lazy_reference_query_conversion(self):
class Member(Document):
user_num = IntField(primary_key=True)
class BlogPost(Document):
title = StringField()
author = GenericLazyReferenceField()
Member.drop_collection()
BlogPost.drop_collection()
m1 = Member(user_num=1)
m1.save()
m2 = Member(user_num=2)
m2.save()
post1 = BlogPost(title='post 1', author=m1)
post1.save()
post2 = BlogPost(title='post 2', author=m2)
post2.save()
post = BlogPost.objects(author=m1).first()
self.assertEqual(post.id, post1.id)
post = BlogPost.objects(author=m2).first()
self.assertEqual(post.id, post2.id)
# Same thing by passing a LazyReference instance
post = BlogPost.objects(author=LazyReference(Member, m2.pk)).first()
self.assertEqual(post.id, post2.id)
def test_generic_lazy_reference_not_set(self):
class Animal(Document):
name = StringField()
tag = StringField()
class Ocurrence(Document):
person = StringField()
animal = GenericLazyReferenceField()
Animal.drop_collection()
Ocurrence.drop_collection()
Ocurrence(person='foo').save()
p = Ocurrence.objects.get()
self.assertIs(p.animal, None)
def test_generic_lazy_reference_embedded(self):
class Animal(Document):
name = StringField()
tag = StringField()
class EmbeddedOcurrence(EmbeddedDocument):
in_list = ListField(GenericLazyReferenceField())
direct = GenericLazyReferenceField()
class Ocurrence(Document):
in_list = ListField(GenericLazyReferenceField())
in_embedded = EmbeddedDocumentField(EmbeddedOcurrence)
direct = GenericLazyReferenceField()
Animal.drop_collection()
Ocurrence.drop_collection()
animal1 = Animal('doggo').save()
animal2 = Animal('cheeta').save()
def check_fields_type(occ):
self.assertIsInstance(occ.direct, LazyReference)
for elem in occ.in_list:
self.assertIsInstance(elem, LazyReference)
self.assertIsInstance(occ.in_embedded.direct, LazyReference)
for elem in occ.in_embedded.in_list:
self.assertIsInstance(elem, LazyReference)
occ = Ocurrence(
in_list=[animal1, animal2],
in_embedded={'in_list': [animal1, animal2], 'direct': animal1},
direct=animal1
).save()
check_fields_type(occ)
occ.reload()
check_fields_type(occ)
animal1_ref = {'_cls': 'Animal', '_ref': DBRef(animal1._get_collection_name(), animal1.pk)}
animal2_ref = {'_cls': 'Animal', '_ref': DBRef(animal2._get_collection_name(), animal2.pk)}
occ.direct = animal1_ref
occ.in_list = [animal1_ref, animal2_ref]
occ.in_embedded.direct = animal1_ref
occ.in_embedded.in_list = [animal1_ref, animal2_ref]
check_fields_type(occ)
if __name__ == '__main__':
unittest.main()

View File

@@ -510,6 +510,24 @@ class GeoQueriesTest(MongoDBTestCase):
roads = Road.objects.filter(poly__geo_intersects={"$geometry": polygon}).count()
self.assertEqual(1, roads)
def test_aspymongo_with_only(self):
"""Ensure as_pymongo works with only"""
class Place(Document):
location = PointField()
Place.drop_collection()
p = Place(location=[24.946861267089844, 60.16311983618494])
p.save()
qs = Place.objects().only('location')
self.assertDictEqual(
qs.as_pymongo()[0]['location'],
{u'type': u'Point',
u'coordinates': [
24.946861267089844,
60.16311983618494]
}
)
def test_2dsphere_point_sets_correctly(self):
class Location(Document):
loc = PointField()

View File

@@ -1,6 +1,8 @@
import unittest
from mongoengine import connect, Document, IntField
from mongoengine import connect, Document, IntField, StringField, ListField
from tests.utils import needs_mongodb_v26
__all__ = ("FindAndModifyTest",)
@@ -94,6 +96,37 @@ class FindAndModifyTest(unittest.TestCase):
self.assertEqual(old_doc.to_mongo(), {"_id": 1})
self.assertDbEqual([{"_id": 0, "value": 0}, {"_id": 1, "value": -1}])
@needs_mongodb_v26
def test_modify_with_push(self):
class BlogPost(Document):
tags = ListField(StringField())
BlogPost.drop_collection()
blog = BlogPost.objects.create()
# Push a new tag via modify with new=False (default).
BlogPost(id=blog.id).modify(push__tags='code')
self.assertEqual(blog.tags, [])
blog.reload()
self.assertEqual(blog.tags, ['code'])
# Push a new tag via modify with new=True.
blog = BlogPost.objects(id=blog.id).modify(push__tags='java', new=True)
self.assertEqual(blog.tags, ['code', 'java'])
# Push a new tag with a positional argument.
blog = BlogPost.objects(id=blog.id).modify(
push__tags__0='python',
new=True)
self.assertEqual(blog.tags, ['python', 'code', 'java'])
# Push multiple new tags with a positional argument.
blog = BlogPost.objects(id=blog.id).modify(
push__tags__1=['go', 'rust'],
new=True)
self.assertEqual(blog.tags, ['python', 'go', 'rust', 'code', 'java'])
if __name__ == '__main__':
unittest.main()

View File

@@ -9,6 +9,7 @@ from nose.plugins.skip import SkipTest
import pymongo
from pymongo.errors import ConfigurationError
from pymongo.read_preferences import ReadPreference
from pymongo.results import UpdateResult
import six
from mongoengine import *
@@ -589,6 +590,20 @@ class QuerySetTest(unittest.TestCase):
Scores.objects(id=scores.id).update(max__high_score=500)
self.assertEqual(Scores.objects.get(id=scores.id).high_score, 1000)
@needs_mongodb_v26
def test_update_multiple(self):
class Product(Document):
item = StringField()
price = FloatField()
product = Product.objects.create(item='ABC', price=10.99)
product = Product.objects.create(item='ABC', price=10.99)
Product.objects(id=product.id).update(mul__price=1.25)
self.assertEqual(Product.objects.get(id=product.id).price, 13.7375)
unknown_product = Product.objects.create(item='Unknown')
Product.objects(id=unknown_product.id).update(mul__price=100)
self.assertEqual(Product.objects.get(id=unknown_product.id).price, 0)
def test_updates_can_have_match_operators(self):
class Comment(EmbeddedDocument):
@@ -656,14 +671,14 @@ class QuerySetTest(unittest.TestCase):
result = self.Person(name="Bob", age=25).update(
upsert=True, full_result=True)
self.assertTrue(isinstance(result, dict))
self.assertTrue("upserted" in result)
self.assertFalse(result["updatedExisting"])
self.assertTrue(isinstance(result, UpdateResult))
self.assertTrue("upserted" in result.raw_result)
self.assertFalse(result.raw_result["updatedExisting"])
bob = self.Person.objects.first()
result = bob.update(set__age=30, full_result=True)
self.assertTrue(isinstance(result, dict))
self.assertTrue(result["updatedExisting"])
self.assertTrue(isinstance(result, UpdateResult))
self.assertTrue(result.raw_result["updatedExisting"])
self.Person(name="Bob", age=20).save()
result = self.Person.objects(name="Bob").update(
@@ -830,11 +845,8 @@ class QuerySetTest(unittest.TestCase):
blogs.append(Blog(title="post %s" % i, posts=[post1, post2]))
Blog.objects.insert(blogs, load_bulk=False)
if mongodb_version < (2, 6):
self.assertEqual(q, 1)
else:
# profiling logs each doc now in the bulk op
self.assertEqual(q, 99)
# profiling logs each doc now in the bulk op
self.assertEqual(q, 99)
Blog.drop_collection()
Blog.ensure_indexes()
@@ -843,11 +855,7 @@ class QuerySetTest(unittest.TestCase):
self.assertEqual(q, 0)
Blog.objects.insert(blogs)
if mongodb_version < (2, 6):
self.assertEqual(q, 2) # 1 for insert, and 1 for in bulk fetch
else:
# 99 for insert, and 1 for in bulk fetch
self.assertEqual(q, 100)
self.assertEqual(q, 100) # 99 for insert 1 for fetch
Blog.drop_collection()
@@ -912,10 +920,6 @@ class QuerySetTest(unittest.TestCase):
self.assertEqual(Blog.objects.count(), 2)
Blog.objects.insert([blog2, blog3],
write_concern={"w": 0, 'continue_on_error': True})
self.assertEqual(Blog.objects.count(), 3)
def test_get_changed_fields_query_count(self):
"""Make sure we don't perform unnecessary db operations when
none of document's fields were updated.
@@ -1903,6 +1907,47 @@ class QuerySetTest(unittest.TestCase):
BlogPost.drop_collection()
@needs_mongodb_v26
def test_update_push_with_position(self):
"""Ensure that the 'push' update with position works properly.
"""
class BlogPost(Document):
slug = StringField()
tags = ListField(StringField())
BlogPost.drop_collection()
post = BlogPost.objects.create(slug="test")
BlogPost.objects.filter(id=post.id).update(push__tags="code")
BlogPost.objects.filter(id=post.id).update(push__tags__0=["mongodb", "python"])
post.reload()
self.assertEqual(post.tags, ['mongodb', 'python', 'code'])
BlogPost.objects.filter(id=post.id).update(set__tags__2="java")
post.reload()
self.assertEqual(post.tags, ['mongodb', 'python', 'java'])
#test push with singular value
BlogPost.objects.filter(id=post.id).update(push__tags__0='scala')
post.reload()
self.assertEqual(post.tags, ['scala', 'mongodb', 'python', 'java'])
def test_update_push_list_of_list(self):
"""Ensure that the 'push' update operation works in the list of list
"""
class BlogPost(Document):
slug = StringField()
tags = ListField()
BlogPost.drop_collection()
post = BlogPost(slug="test").save()
BlogPost.objects.filter(slug="test").update(push__tags=["value1", 123])
post.reload()
self.assertEqual(post.tags, [["value1", 123]])
def test_update_push_and_pull_add_to_set(self):
"""Ensure that the 'pull' update operation works correctly.
"""
@@ -2045,6 +2090,23 @@ class QuerySetTest(unittest.TestCase):
Site.objects(id=s.id).update_one(
pull_all__collaborators__helpful__user=['Ross'])
def test_pull_in_genericembedded_field(self):
class Foo(EmbeddedDocument):
name = StringField()
class Bar(Document):
foos = ListField(GenericEmbeddedDocumentField(
choices=[Foo, ]))
Bar.drop_collection()
foo = Foo(name="bar")
bar = Bar(foos=[foo]).save()
Bar.objects(id=bar.id).update(pull__foos=foo)
bar.reload()
self.assertEqual(len(bar.foos), 0)
def test_update_one_pop_generic_reference(self):
class BlogTag(Document):
@@ -2138,6 +2200,24 @@ class QuerySetTest(unittest.TestCase):
self.assertEqual(message.authors[1].name, "Ross")
self.assertEqual(message.authors[2].name, "Adam")
def test_set_generic_embedded_documents(self):
class Bar(EmbeddedDocument):
name = StringField()
class User(Document):
username = StringField()
bar = GenericEmbeddedDocumentField(choices=[Bar,])
User.drop_collection()
User(username='abc').save()
User.objects(username='abc').update(
set__bar=Bar(name='test'), upsert=True)
user = User.objects(username='abc').first()
self.assertEqual(user.bar.name, "test")
def test_reload_embedded_docs_instance(self):
class SubDoc(EmbeddedDocument):
@@ -2307,14 +2387,19 @@ class QuerySetTest(unittest.TestCase):
age = IntField()
with db_ops_tracker() as q:
adult = (User.objects.filter(age__gte=18)
adult1 = (User.objects.filter(age__gte=18)
.comment('looking for an adult')
.first())
adult2 = (User.objects.comment('looking for an adult')
.filter(age__gte=18)
.first())
ops = q.get_ops()
self.assertEqual(len(ops), 1)
op = ops[0]
self.assertEqual(op['query']['$query'], {'age': {'$gte': 18}})
self.assertEqual(op['query']['$comment'], 'looking for an adult')
self.assertEqual(len(ops), 2)
for op in ops:
self.assertEqual(op['query']['$query'], {'age': {'$gte': 18}})
self.assertEqual(op['query']['$comment'], 'looking for an adult')
def test_map_reduce(self):
"""Ensure map/reduce is both mapping and reducing.
@@ -4764,6 +4849,30 @@ class QuerySetTest(unittest.TestCase):
for obj in C.objects.no_sub_classes():
self.assertEqual(obj.__class__, C)
def test_query_generic_embedded_document(self):
"""Ensure that querying sub field on generic_embedded_field works
"""
class A(EmbeddedDocument):
a_name = StringField()
class B(EmbeddedDocument):
b_name = StringField()
class Doc(Document):
document = GenericEmbeddedDocumentField(choices=(A, B))
Doc.drop_collection()
Doc(document=A(a_name='A doc')).save()
Doc(document=B(b_name='B doc')).save()
# Using raw in filter working fine
self.assertEqual(Doc.objects(
__raw__={'document.a_name': 'A doc'}).count(), 1)
self.assertEqual(Doc.objects(
__raw__={'document.b_name': 'B doc'}).count(), 1)
self.assertEqual(Doc.objects(document__a_name='A doc').count(), 1)
self.assertEqual(Doc.objects(document__b_name='B doc').count(), 1)
def test_query_reference_to_custom_pk_doc(self):
class A(Document):

View File

@@ -1,5 +1,7 @@
import unittest
from bson.son import SON
from mongoengine import *
from mongoengine.queryset import Q, transform
@@ -28,12 +30,16 @@ class TransformTest(unittest.TestCase):
{'name': {'$exists': True}})
def test_transform_update(self):
class LisDoc(Document):
foo = ListField(StringField())
class DicDoc(Document):
dictField = DictField()
class Doc(Document):
pass
LisDoc.drop_collection()
DicDoc.drop_collection()
Doc.drop_collection()
@@ -50,6 +56,20 @@ class TransformTest(unittest.TestCase):
update = transform.update(DicDoc, pull__dictField__test=doc)
self.assertTrue(isinstance(update["$pull"]["dictField"]["test"], dict))
update = transform.update(LisDoc, pull__foo__in=['a'])
self.assertEqual(update, {'$pull': {'foo': {'$in': ['a']}}})
def test_transform_update_push(self):
"""Ensure the differences in behvaior between 'push' and 'push_all'"""
class BlogPost(Document):
tags = ListField(StringField())
update = transform.update(BlogPost, push__tags=['mongo', 'db'])
self.assertEqual(update, {'$push': {'tags': ['mongo', 'db']}})
update = transform.update(BlogPost, push_all__tags=['mongo', 'db'])
self.assertEqual(update, {'$push': {'tags': {'$each': ['mongo', 'db']}}})
def test_query_field_name(self):
"""Ensure that the correct field name is used when querying.
@@ -240,7 +260,31 @@ class TransformTest(unittest.TestCase):
events = Event.objects(location__within=box)
with self.assertRaises(InvalidQueryError):
events.count()
def test_update_pull_for_list_fields(self):
"""
Test added to check pull operation in update for
EmbeddedDocumentListField which is inside a EmbeddedDocumentField
"""
class Word(EmbeddedDocument):
word = StringField()
index = IntField()
class SubDoc(EmbeddedDocument):
heading = ListField(StringField())
text = EmbeddedDocumentListField(Word)
class MainDoc(Document):
title = StringField()
content = EmbeddedDocumentField(SubDoc)
word = Word(word='abc', index=1)
update = transform.update(MainDoc, pull__content__text=word)
self.assertEqual(update, {'$pull': {'content.text': SON([('word', u'abc'), ('index', 1)])}})
update = transform.update(MainDoc, pull__content__heading='xyz')
self.assertEqual(update, {'$pull': {'content.heading': 'xyz'}})
if __name__ == '__main__':
unittest.main()

View File

@@ -1,6 +1,6 @@
import unittest
from mongoengine.base.datastructures import StrictDict, SemiStrictDict
from mongoengine.base.datastructures import StrictDict
class TestStrictDict(unittest.TestCase):
@@ -76,44 +76,5 @@ class TestStrictDict(unittest.TestCase):
assert dict(**d) == {'a': 1, 'b': 2}
class TestSemiSrictDict(TestStrictDict):
def strict_dict_class(self, *args, **kwargs):
return SemiStrictDict.create(*args, **kwargs)
def test_init_fails_on_nonexisting_attrs(self):
# disable irrelevant test
pass
def test_setattr_raises_on_nonexisting_attr(self):
# disable irrelevant test
pass
def test_setattr_getattr_nonexisting_attr_succeeds(self):
d = self.dtype()
d.x = 1
self.assertEqual(d.x, 1)
def test_init_succeeds_with_nonexisting_attrs(self):
d = self.dtype(a=1, b=1, c=1, x=2)
self.assertEqual((d.a, d.b, d.c, d.x), (1, 1, 1, 2))
def test_iter_with_nonexisting_attrs(self):
d = self.dtype(a=1, b=1, c=1, x=2)
self.assertEqual(list(d), ['a', 'b', 'c', 'x'])
def test_iteritems_with_nonexisting_attrs(self):
d = self.dtype(a=1, b=1, c=1, x=2)
self.assertEqual(list(d.iteritems()), [('a', 1), ('b', 1), ('c', 1), ('x', 2)])
def tets_cmp_with_strict_dicts(self):
d = self.dtype(a=1, b=1, c=1)
dd = StrictDict.create(("a", "b", "c"))(a=1, b=1, c=1)
self.assertEqual(d, dd)
def test_cmp_with_strict_dict_with_nonexisting_attrs(self):
d = self.dtype(a=1, b=1, c=1, x=2)
dd = StrictDict.create(("a", "b", "c", "x"))(a=1, b=1, c=1, x=2)
self.assertEqual(d, dd)
if __name__ == '__main__':
unittest.main()