-
Notifications
You must be signed in to change notification settings - Fork 1.2k
added a feature to save object data in order #1497
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6810953
84a8f1e
e32a977
5957dc7
6aaf9ba
f2fe58c
9cd3dcd
ffbb2c9
d8b238d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,8 +5,10 @@ | |
| import math | ||
| import itertools | ||
| import re | ||
| import pymongo | ||
|
|
||
| from nose.plugins.skip import SkipTest | ||
| from collections import OrderedDict | ||
| import six | ||
|
|
||
| try: | ||
|
|
@@ -25,9 +27,12 @@ | |
| from mongoengine import * | ||
| from mongoengine.connection import get_db | ||
| from mongoengine.base import (BaseDict, BaseField, EmbeddedDocumentList, | ||
| _document_registry) | ||
| _document_registry, TopLevelDocumentMetaclass) | ||
|
|
||
| from tests.utils import MongoDBTestCase | ||
| from tests.utils import MongoDBTestCase, MONGO_TEST_DB | ||
| from mongoengine.python_support import IS_PYMONGO_3 | ||
| if IS_PYMONGO_3: | ||
| from bson import CodecOptions | ||
|
|
||
| __all__ = ("FieldTest", "EmbeddedDocumentListFieldTestCase") | ||
|
|
||
|
|
@@ -4499,6 +4504,67 @@ class CustomData(Document): | |
| self.assertTrue(hasattr(CustomData.c_field, 'custom_data')) | ||
| self.assertEqual(custom_data['a'], CustomData.c_field.custom_data['a']) | ||
|
|
||
| def test_dynamicfield_with_container_class(self): | ||
| """ | ||
| Tests that object can be stored in order by DynamicField class | ||
| with container_class parameter. | ||
| """ | ||
| raw_data = [('d', 1), ('c', 2), ('b', 3), ('a', 4)] | ||
|
|
||
| class Doc(Document): | ||
| ordered_data = DynamicField(container_class=OrderedDict) | ||
| unordered_data = DynamicField() | ||
|
|
||
| Doc.drop_collection() | ||
|
|
||
| doc = Doc(ordered_data=OrderedDict(raw_data), unordered_data=dict(raw_data)).save() | ||
|
|
||
| # checks that the data is in order | ||
| self.assertEqual(type(doc.ordered_data), OrderedDict) | ||
| self.assertEqual(type(doc.unordered_data), dict) | ||
| self.assertEqual(','.join(doc.ordered_data.keys()), 'd,c,b,a') | ||
|
|
||
| # checks that the data is stored to the database in order | ||
| pymongo_db = pymongo.MongoClient()[MONGO_TEST_DB] | ||
| if IS_PYMONGO_3: | ||
| codec_option = CodecOptions(document_class=OrderedDict) | ||
| db_doc = pymongo_db.doc.with_options(codec_options=codec_option).find_one() | ||
| else: | ||
| db_doc = pymongo_db.doc.find_one(as_class=OrderedDict) | ||
|
|
||
| self.assertEqual(','.join(doc.ordered_data.keys()), 'd,c,b,a') | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is an invalid test - it should verify the |
||
|
|
||
| def test_dynamicfield_with_wrong_container_class(self): | ||
| with self.assertRaises(ValidationError): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, |
||
| class DocWithInvalidField: | ||
| data = DynamicField(container_class=list) | ||
|
|
||
| def test_dynamicfield_with_wrong_container_class_and_reload_docuemnt(self): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function name is incorrect - the container class is not wrong in this test. |
||
| # This is because 'codec_options' is supported on pymongo3 or later | ||
| if IS_PYMONGO_3: | ||
| class OrderedDocument(Document): | ||
| my_metaclass = TopLevelDocumentMetaclass | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You shouldn't have to override the metaclass here. I expect you did this because you ran into issues when subclassing the |
||
| __metaclass__ = TopLevelDocumentMetaclass | ||
|
|
||
| @classmethod | ||
| def _get_collection(cls): | ||
| collection = super(OrderedDocument, cls)._get_collection() | ||
| opts = CodecOptions(document_class=OrderedDict) | ||
|
|
||
| return collection.with_options(codec_options=opts) | ||
|
|
||
| raw_data = [('d', 1), ('c', 2), ('b', 3), ('a', 4)] | ||
|
|
||
| class Doc(OrderedDocument): | ||
| data = DynamicField(container_class=OrderedDict) | ||
|
|
||
| Doc.drop_collection() | ||
|
|
||
| doc = Doc(data=OrderedDict(raw_data)).save() | ||
| doc.reload() | ||
|
|
||
| self.assertEqual(type(doc.data), OrderedDict) | ||
| self.assertEqual(','.join(doc.data.keys()), 'd,c,b,a') | ||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,10 +2,15 @@ | |
| import unittest | ||
|
|
||
| from bson import DBRef, ObjectId | ||
| from collections import OrderedDict | ||
|
|
||
| from mongoengine import * | ||
| from mongoengine.connection import get_db | ||
| from mongoengine.context_managers import query_counter | ||
| from mongoengine.python_support import IS_PYMONGO_3 | ||
| from mongoengine.base import TopLevelDocumentMetaclass | ||
| if IS_PYMONGO_3: | ||
| from bson import CodecOptions | ||
|
|
||
|
|
||
| class FieldTest(unittest.TestCase): | ||
|
|
@@ -1287,5 +1292,70 @@ class Playlist(Document): | |
|
|
||
| self.assertEqual(q, 2) | ||
|
|
||
| def test_dynamic_field_dereference(self): | ||
| class Merchandise(Document): | ||
| name = StringField() | ||
| price = IntField() | ||
|
|
||
| class Store(Document): | ||
| merchandises = DynamicField() | ||
|
|
||
| Merchandise.drop_collection() | ||
| Store.drop_collection() | ||
|
|
||
| merchandises = { | ||
| '#1': Merchandise(name='foo', price=100).save(), | ||
| '#2': Merchandise(name='bar', price=120).save(), | ||
| '#3': Merchandise(name='baz', price=110).save(), | ||
| } | ||
| Store(merchandises=merchandises).save() | ||
|
|
||
| store = Store.objects().first() | ||
| for obj in store.merchandises.values(): | ||
| self.assertFalse(isinstance(obj, Merchandise)) | ||
|
|
||
| store.select_related() | ||
| for obj in store.merchandises.values(): | ||
| self.assertTrue(isinstance(obj, Merchandise)) | ||
|
|
||
| def test_dynamic_field_dereference_with_ordering_guarantee_on_pymongo3(self): | ||
| # This is because 'codec_options' is supported on pymongo3 or later | ||
| if IS_PYMONGO_3: | ||
| class OrderedDocument(Document): | ||
| my_metaclass = TopLevelDocumentMetaclass | ||
| __metaclass__ = TopLevelDocumentMetaclass | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto - should be an abstract class instead. |
||
|
|
||
| @classmethod | ||
| def _get_collection(cls): | ||
| collection = super(OrderedDocument, cls)._get_collection() | ||
| opts = CodecOptions(document_class=OrderedDict) | ||
|
|
||
| return collection.with_options(codec_options=opts) | ||
|
|
||
| class Merchandise(Document): | ||
| name = StringField() | ||
| price = IntField() | ||
|
|
||
| class Store(OrderedDocument): | ||
| merchandises = DynamicField(container_class=OrderedDict) | ||
|
|
||
| Merchandise.drop_collection() | ||
| Store.drop_collection() | ||
|
|
||
| merchandises = OrderedDict() | ||
| merchandises['#1'] = Merchandise(name='foo', price=100).save() | ||
| merchandises['#2'] = Merchandise(name='bar', price=120).save() | ||
| merchandises['#3'] = Merchandise(name='baz', price=110).save() | ||
|
|
||
| Store(merchandises=merchandises).save() | ||
|
|
||
| store = Store.objects().first() | ||
|
|
||
| store.select_related() | ||
|
|
||
| # confirms that the load data order is same with the one at storing | ||
| self.assertTrue(type(store.merchandises), OrderedDict) | ||
| self.assertEqual(','.join(store.merchandises.keys()), '#1,#2,#3') | ||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shouldn't throw a
ValidationError, which is reserved to invalid data, not an invalid field definition.