list_indexes support for multiple inheritance
This commit is contained in:
		| @@ -571,37 +571,53 @@ class Document(BaseDocument): | |||||||
|         if cls._meta.get('abstract'): |         if cls._meta.get('abstract'): | ||||||
|             return [] |             return [] | ||||||
|  |  | ||||||
|         indexes = [] |         # get all the base classes, subclasses and sieblings | ||||||
|         index_cls = cls._meta.get('index_cls', True) |         classes = [] | ||||||
|  |         def get_classes(cls): | ||||||
|  |  | ||||||
|  |             if (cls not in classes and | ||||||
|  |                isinstance(cls, TopLevelDocumentMetaclass)): | ||||||
|  |                 classes.append(cls) | ||||||
|  |  | ||||||
|  |             for base_cls in cls.__bases__: | ||||||
|  |                 if (isinstance(base_cls, TopLevelDocumentMetaclass) and | ||||||
|  |                    base_cls != Document and | ||||||
|  |                    not base_cls._meta.get('abstract') and | ||||||
|  |                    base_cls._get_collection().full_name == cls._get_collection().full_name and | ||||||
|  |                    base_cls not in classes): | ||||||
|  |                     classes.append(base_cls) | ||||||
|  |                     get_classes(base_cls) | ||||||
|  |             for subclass in cls.__subclasses__(): | ||||||
|  |                 if (isinstance(base_cls, TopLevelDocumentMetaclass) and | ||||||
|  |                    subclass._get_collection().full_name == cls._get_collection().full_name and | ||||||
|  |                    subclass not in classes): | ||||||
|  |                     classes.append(subclass) | ||||||
|  |                     get_classes(subclass) | ||||||
|  |  | ||||||
|  |         get_classes(cls) | ||||||
|  |  | ||||||
|  |         # get the indexes spec for all of the gathered classes | ||||||
|  |         def get_indexes_spec(cls): | ||||||
|  |             indexes = [] | ||||||
|  |  | ||||||
|         # Ensure document-defined indexes are created |  | ||||||
|             if cls._meta['index_specs']: |             if cls._meta['index_specs']: | ||||||
|                 index_spec = cls._meta['index_specs'] |                 index_spec = cls._meta['index_specs'] | ||||||
|                 for spec in index_spec: |                 for spec in index_spec: | ||||||
|                     spec = spec.copy() |                     spec = spec.copy() | ||||||
|                     fields = spec.pop('fields') |                     fields = spec.pop('fields') | ||||||
|                     indexes.append(fields) |                     indexes.append(fields) | ||||||
|  |             return indexes | ||||||
|  |  | ||||||
|         # add all of the indexes from the base classes |         indexes = [] | ||||||
|         if go_up: |         for cls in classes: | ||||||
|             for base_cls in cls.__bases__: |             for index in get_indexes_spec(cls): | ||||||
|                 if isinstance(base_cls, TopLevelDocumentMetaclass): |  | ||||||
|                     for index in base_cls.list_indexes(go_up=True, go_down=False): |  | ||||||
|                         if index not in indexes: |  | ||||||
|                             indexes.append(index) |  | ||||||
|  |  | ||||||
|         # add all of the indexes from subclasses |  | ||||||
|         if go_down: |  | ||||||
|             for subclass in cls.__subclasses__(): |  | ||||||
|                 for index in subclass.list_indexes(go_up=False, go_down=True): |  | ||||||
|                 if index not in indexes: |                 if index not in indexes: | ||||||
|                     indexes.append(index) |                     indexes.append(index) | ||||||
|  |  | ||||||
|         # finish up by appending { '_id': 1 } and { '_cls': 1 }, if needed |         # finish up by appending { '_id': 1 } and { '_cls': 1 }, if needed | ||||||
|         if go_up and go_down: |  | ||||||
|         if [(u'_id', 1)] not in indexes: |         if [(u'_id', 1)] not in indexes: | ||||||
|             indexes.append([(u'_id', 1)]) |             indexes.append([(u'_id', 1)]) | ||||||
|             if (index_cls and |         if (cls._meta.get('index_cls', True) and | ||||||
|            cls._meta.get('allow_inheritance', ALLOW_INHERITANCE) is True): |            cls._meta.get('allow_inheritance', ALLOW_INHERITANCE) is True): | ||||||
|              indexes.append([(u'_cls', 1)]) |              indexes.append([(u'_cls', 1)]) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -152,6 +152,43 @@ class ClassMethodsTest(unittest.TestCase): | |||||||
|         BlogPostWithTags._get_collection().drop_index('_cls_1_author_1_tags_1') |         BlogPostWithTags._get_collection().drop_index('_cls_1_author_1_tags_1') | ||||||
|         self.assertEqual(BlogPost.compare_indexes(), { 'missing': [[('_cls', 1), ('author', 1), ('tags', 1)]], 'extra': [] }) |         self.assertEqual(BlogPost.compare_indexes(), { 'missing': [[('_cls', 1), ('author', 1), ('tags', 1)]], 'extra': [] }) | ||||||
|  |  | ||||||
|  |     def test_compare_indexes_multiple_subclasses(self): | ||||||
|  |         """ Ensure that compare_indexes behaves correctly if called from a | ||||||
|  |         class, which base class has multiple subclasses | ||||||
|  |         """ | ||||||
|  |  | ||||||
|  |         class BlogPost(Document): | ||||||
|  |             author = StringField() | ||||||
|  |             title = StringField() | ||||||
|  |             description = StringField() | ||||||
|  |  | ||||||
|  |             meta = { | ||||||
|  |                 'allow_inheritance': True | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         class BlogPostWithTags(BlogPost): | ||||||
|  |             tags = StringField() | ||||||
|  |             tag_list = ListField(StringField()) | ||||||
|  |  | ||||||
|  |             meta = { | ||||||
|  |                 'indexes': [('author', 'tags')] | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         class BlogPostWithCustomField(BlogPost): | ||||||
|  |             custom = DictField() | ||||||
|  |  | ||||||
|  |             meta = { | ||||||
|  |                 'indexes': [('author', 'custom')] | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         BlogPost.ensure_indexes() | ||||||
|  |         BlogPostWithTags.ensure_indexes() | ||||||
|  |         BlogPostWithCustomField.ensure_indexes() | ||||||
|  |  | ||||||
|  |         self.assertEqual(BlogPost.compare_indexes(), { 'missing': [], 'extra': [] }) | ||||||
|  |         self.assertEqual(BlogPostWithTags.compare_indexes(), { 'missing': [], 'extra': [] }) | ||||||
|  |         self.assertEqual(BlogPostWithCustomField.compare_indexes(), { 'missing': [], 'extra': [] }) | ||||||
|  |  | ||||||
|     def test_list_indexes_inheritance(self): |     def test_list_indexes_inheritance(self): | ||||||
|         """ ensure that all of the indexes are listed regardless of the super- |         """ ensure that all of the indexes are listed regardless of the super- | ||||||
|         or sub-class that we call it from |         or sub-class that we call it from | ||||||
| @@ -190,7 +227,6 @@ class ClassMethodsTest(unittest.TestCase): | |||||||
|                          BlogPostWithTags.list_indexes()) |                          BlogPostWithTags.list_indexes()) | ||||||
|         self.assertEqual(BlogPost.list_indexes(), |         self.assertEqual(BlogPost.list_indexes(), | ||||||
|                          BlogPostWithTagsAndExtraText.list_indexes()) |                          BlogPostWithTagsAndExtraText.list_indexes()) | ||||||
|         print BlogPost.list_indexes() |  | ||||||
|         self.assertEqual(BlogPost.list_indexes(), |         self.assertEqual(BlogPost.list_indexes(), | ||||||
|                          [[('_cls', 1), ('author', 1), ('tags', 1)], |                          [[('_cls', 1), ('author', 1), ('tags', 1)], | ||||||
|                          [('_cls', 1), ('author', 1), ('tags', 1), ('extra_text', 1)], |                          [('_cls', 1), ('author', 1), ('tags', 1), ('extra_text', 1)], | ||||||
|   | |||||||
| @@ -189,6 +189,41 @@ class InheritanceTest(unittest.TestCase): | |||||||
|         self.assertEqual(Employee._get_collection_name(), |         self.assertEqual(Employee._get_collection_name(), | ||||||
|                          Person._get_collection_name()) |                          Person._get_collection_name()) | ||||||
|  |  | ||||||
|  |     def test_indexes_and_multiple_inheritance(self): | ||||||
|  |         """ Ensure that all of the indexes are created for a document with | ||||||
|  |         multiple inheritance. | ||||||
|  |         """ | ||||||
|  |  | ||||||
|  |         class A(Document): | ||||||
|  |             a = StringField() | ||||||
|  |  | ||||||
|  |             meta = { | ||||||
|  |                 'allow_inheritance': True, | ||||||
|  |                 'indexes': ['a'] | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         class B(Document): | ||||||
|  |             b = StringField() | ||||||
|  |  | ||||||
|  |             meta = { | ||||||
|  |                 'allow_inheritance': True, | ||||||
|  |                 'indexes': ['b'] | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |         class C(A, B): | ||||||
|  |             pass | ||||||
|  |  | ||||||
|  |         A.drop_collection() | ||||||
|  |         B.drop_collection() | ||||||
|  |         C.drop_collection() | ||||||
|  |  | ||||||
|  |         C.ensure_indexes() | ||||||
|  |  | ||||||
|  |         self.assertEqual( | ||||||
|  |             [idx['key'] for idx in C._get_collection().index_information().values()], | ||||||
|  |             [[(u'_cls', 1), (u'b', 1)], [(u'_id', 1)], [(u'_cls', 1), (u'a', 1)]] | ||||||
|  |         ) | ||||||
|  |  | ||||||
|     def test_polymorphic_queries(self): |     def test_polymorphic_queries(self): | ||||||
|         """Ensure that the correct subclasses are returned from a query |         """Ensure that the correct subclasses are returned from a query | ||||||
|         """ |         """ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user