# -*- coding: utf-8 -*-
import sys
sys.path[0:0] = [""]
import unittest
from bson import SON
from mongoengine import *
from mongoengine.connection import get_db
__all__ = ("DeltaTest",)
class DeltaTest(unittest.TestCase):
    def setUp(self):
        connect(db='mongoenginetest')
        self.db = get_db()
        class Person(Document):
            name = StringField()
            age = IntField()
            non_field = True
            meta = {"allow_inheritance": True}
        self.Person = Person
    def tearDown(self):
        for collection in self.db.collection_names():
            if 'system.' in collection:
                continue
            self.db.drop_collection(collection)
    def test_delta(self):
        self.delta(Document)
        self.delta(DynamicDocument)
    def delta(self, DocClass):
        class Doc(DocClass):
            string_field = StringField()
            int_field = IntField()
            dict_field = DictField()
            list_field = ListField()
        Doc.drop_collection()
        doc = Doc()
        doc.save()
        doc = Doc.objects.first()
        self.assertEqual(doc._get_changed_fields(), [])
        self.assertEqual(doc._delta(), ({}, {}))
        doc.string_field = 'hello'
        self.assertEqual(doc._get_changed_fields(), ['string_field'])
        self.assertEqual(doc._delta(), ({'string_field': 'hello'}, {}))
        doc._changed_fields = []
        doc.int_field = 1
        self.assertEqual(doc._get_changed_fields(), ['int_field'])
        self.assertEqual(doc._delta(), ({'int_field': 1}, {}))
        doc._changed_fields = []
        dict_value = {'hello': 'world', 'ping': 'pong'}
        doc.dict_field = dict_value
        self.assertEqual(doc._get_changed_fields(), ['dict_field'])
        self.assertEqual(doc._delta(), ({'dict_field': dict_value}, {}))
        doc._changed_fields = []
        list_value = ['1', 2, {'hello': 'world'}]
        doc.list_field = list_value
        self.assertEqual(doc._get_changed_fields(), ['list_field'])
        self.assertEqual(doc._delta(), ({'list_field': list_value}, {}))
        # Test unsetting
        doc._changed_fields = []
        doc.dict_field = {}
        self.assertEqual(doc._get_changed_fields(), ['dict_field'])
        self.assertEqual(doc._delta(), ({}, {'dict_field': 1}))
        doc._changed_fields = []
        doc.list_field = []
        self.assertEqual(doc._get_changed_fields(), ['list_field'])
        self.assertEqual(doc._delta(), ({}, {'list_field': 1}))
    def test_delta_recursive(self):
        self.delta_recursive(Document, EmbeddedDocument)
        self.delta_recursive(DynamicDocument, EmbeddedDocument)
        self.delta_recursive(Document, DynamicEmbeddedDocument)
        self.delta_recursive(DynamicDocument, DynamicEmbeddedDocument)
    def delta_recursive(self, DocClass, EmbeddedClass):
        class Embedded(EmbeddedClass):
            string_field = StringField()
            int_field = IntField()
            dict_field = DictField()
            list_field = ListField()
        class Doc(DocClass):
            string_field = StringField()
            int_field = IntField()
            dict_field = DictField()
            list_field = ListField()
            embedded_field = EmbeddedDocumentField(Embedded)
        Doc.drop_collection()
        doc = Doc()
        doc.save()
        doc = Doc.objects.first()
        self.assertEqual(doc._get_changed_fields(), [])
        self.assertEqual(doc._delta(), ({}, {}))
        embedded_1 = Embedded()
        embedded_1.string_field = 'hello'
        embedded_1.int_field = 1
        embedded_1.dict_field = {'hello': 'world'}
        embedded_1.list_field = ['1', 2, {'hello': 'world'}]
        doc.embedded_field = embedded_1
        self.assertEqual(doc._get_changed_fields(), ['embedded_field'])
        embedded_delta = {
            'string_field': 'hello',
            'int_field': 1,
            'dict_field': {'hello': 'world'},
            'list_field': ['1', 2, {'hello': 'world'}]
        }
        self.assertEqual(doc.embedded_field._delta(), (embedded_delta, {}))
        self.assertEqual(doc._delta(),
                         ({'embedded_field': embedded_delta}, {}))
        doc.save()
        doc = doc.reload(10)
        doc.embedded_field.dict_field = {}
        self.assertEqual(doc._get_changed_fields(),
                         ['embedded_field.dict_field'])
        self.assertEqual(doc.embedded_field._delta(), ({}, {'dict_field': 1}))
        self.assertEqual(doc._delta(), ({}, {'embedded_field.dict_field': 1}))
        doc.save()
        doc = doc.reload(10)
        self.assertEqual(doc.embedded_field.dict_field, {})
        doc.embedded_field.list_field = []
        self.assertEqual(doc._get_changed_fields(),
                         ['embedded_field.list_field'])
        self.assertEqual(doc.embedded_field._delta(), ({}, {'list_field': 1}))
        self.assertEqual(doc._delta(), ({}, {'embedded_field.list_field': 1}))
        doc.save()
        doc = doc.reload(10)
        self.assertEqual(doc.embedded_field.list_field, [])
        embedded_2 = Embedded()
        embedded_2.string_field = 'hello'
        embedded_2.int_field = 1
        embedded_2.dict_field = {'hello': 'world'}
        embedded_2.list_field = ['1', 2, {'hello': 'world'}]
        doc.embedded_field.list_field = ['1', 2, embedded_2]
        self.assertEqual(doc._get_changed_fields(),
                         ['embedded_field.list_field'])
        self.assertEqual(doc.embedded_field._delta(), ({
            'list_field': ['1', 2, {
                '_cls': 'Embedded',
                'string_field': 'hello',
                'dict_field': {'hello': 'world'},
                'int_field': 1,
                'list_field': ['1', 2, {'hello': 'world'}],
            }]
        }, {}))
        self.assertEqual(doc._delta(), ({
            'embedded_field.list_field': ['1', 2, {
                '_cls': 'Embedded',
                'string_field': 'hello',
                'dict_field': {'hello': 'world'},
                'int_field': 1,
                'list_field': ['1', 2, {'hello': 'world'}],
            }]
        }, {}))
        doc.save()
        doc = doc.reload(10)
        self.assertEqual(doc.embedded_field.list_field[0], '1')
        self.assertEqual(doc.embedded_field.list_field[1], 2)
        for k in doc.embedded_field.list_field[2]._fields:
            self.assertEqual(doc.embedded_field.list_field[2][k],
                             embedded_2[k])
        doc.embedded_field.list_field[2].string_field = 'world'
        self.assertEqual(doc._get_changed_fields(),
                         ['embedded_field.list_field.2.string_field'])
        self.assertEqual(doc.embedded_field._delta(),
                         ({'list_field.2.string_field': 'world'}, {}))
        self.assertEqual(doc._delta(),
                         ({'embedded_field.list_field.2.string_field': 'world'}, {}))
        doc.save()
        doc = doc.reload(10)
        self.assertEqual(doc.embedded_field.list_field[2].string_field,
                         'world')
        # Test multiple assignments
        doc.embedded_field.list_field[2].string_field = 'hello world'
        doc.embedded_field.list_field[2] = doc.embedded_field.list_field[2]
        self.assertEqual(doc._get_changed_fields(),
                         ['embedded_field.list_field'])
        self.assertEqual(doc.embedded_field._delta(), ({
            'list_field': ['1', 2, {
            '_cls': 'Embedded',
            'string_field': 'hello world',
            'int_field': 1,
            'list_field': ['1', 2, {'hello': 'world'}],
            'dict_field': {'hello': 'world'}}]}, {}))
        self.assertEqual(doc._delta(), ({
            'embedded_field.list_field': ['1', 2, {
                '_cls': 'Embedded',
                'string_field': 'hello world',
                'int_field': 1,
                'list_field': ['1', 2, {'hello': 'world'}],
                'dict_field': {'hello': 'world'}}
            ]}, {}))
        doc.save()
        doc = doc.reload(10)
        self.assertEqual(doc.embedded_field.list_field[2].string_field,
                         'hello world')
        # Test list native methods
        doc.embedded_field.list_field[2].list_field.pop(0)
        self.assertEqual(doc._delta(),
                         ({'embedded_field.list_field.2.list_field':
                          [2, {'hello': 'world'}]}, {}))
        doc.save()
        doc = doc.reload(10)
        doc.embedded_field.list_field[2].list_field.append(1)
        self.assertEqual(doc._delta(),
                         ({'embedded_field.list_field.2.list_field':
                          [2, {'hello': 'world'}, 1]}, {}))
        doc.save()
        doc = doc.reload(10)
        self.assertEqual(doc.embedded_field.list_field[2].list_field,
                         [2, {'hello': 'world'}, 1])
        doc.embedded_field.list_field[2].list_field.sort(key=str)
        doc.save()
        doc = doc.reload(10)
        self.assertEqual(doc.embedded_field.list_field[2].list_field,
                         [1, 2, {'hello': 'world'}])
        del(doc.embedded_field.list_field[2].list_field[2]['hello'])
        self.assertEqual(doc._delta(),
                         ({'embedded_field.list_field.2.list_field': [1, 2, {}]}, {}))
        doc.save()
        doc = doc.reload(10)
        del(doc.embedded_field.list_field[2].list_field)
        self.assertEqual(doc._delta(),
                         ({}, {'embedded_field.list_field.2.list_field': 1}))
        doc.save()
        doc = doc.reload(10)
        doc.dict_field['Embedded'] = embedded_1
        doc.save()
        doc = doc.reload(10)
        doc.dict_field['Embedded'].string_field = 'Hello World'
        self.assertEqual(doc._get_changed_fields(),
                         ['dict_field.Embedded.string_field'])
        self.assertEqual(doc._delta(),
                         ({'dict_field.Embedded.string_field': 'Hello World'}, {}))
    def test_circular_reference_deltas(self):
        self.circular_reference_deltas(Document, Document)
        self.circular_reference_deltas(Document, DynamicDocument)
        self.circular_reference_deltas(DynamicDocument, Document)
        self.circular_reference_deltas(DynamicDocument, DynamicDocument)
    def circular_reference_deltas(self, DocClass1, DocClass2):
        class Person(DocClass1):
            name = StringField()
            owns = ListField(ReferenceField('Organization'))
        class Organization(DocClass2):
            name = StringField()
            owner = ReferenceField('Person')
        Person.drop_collection()
        Organization.drop_collection()
        person = Person(name="owner").save()
        organization = Organization(name="company").save()
        person.owns.append(organization)
        organization.owner = person
        person.save()
        organization.save()
        p = Person.objects[0].select_related()
        o = Organization.objects.first()
        self.assertEqual(p.owns[0], o)
        self.assertEqual(o.owner, p)
    def test_circular_reference_deltas_2(self):
        self.circular_reference_deltas_2(Document, Document)
        self.circular_reference_deltas_2(Document, DynamicDocument)
        self.circular_reference_deltas_2(DynamicDocument, Document)
        self.circular_reference_deltas_2(DynamicDocument, DynamicDocument)
    def circular_reference_deltas_2(self, DocClass1, DocClass2, dbref=True):
        class Person(DocClass1):
            name = StringField()
            owns = ListField(ReferenceField('Organization', dbref=dbref))
            employer = ReferenceField('Organization', dbref=dbref)
        class Organization(DocClass2):
            name = StringField()
            owner = ReferenceField('Person', dbref=dbref)
            employees = ListField(ReferenceField('Person', dbref=dbref))
        Person.drop_collection()
        Organization.drop_collection()
        person = Person(name="owner").save()
        employee = Person(name="employee").save()
        organization = Organization(name="company").save()
        person.owns.append(organization)
        organization.owner = person
        organization.employees.append(employee)
        employee.employer = organization
        person.save()
        organization.save()
        employee.save()


Answer:         p = Person.objects.get(name="owner")