Esempio n. 1
0
 def test_source_option(self):
     """
     should use the source option as the target association name if provided
     """
     association = HasManyThrough(target_klass=self.Site, id='dumb_comments',
                                  through='articles', source='comments')
     self.assertEqual(association.source_association().id, 'comments')
Esempio n. 2
0
    def setUp(self):
        self.klass = fixtures.association_models.Test
        self.id = 'has_many_through'
        self.association = HasManyThrough(target_klass=self.klass, id=self.id)
        self.adapter = TestAdapter

        # assign fixtures.association_models.ModelClass to self.ModelClass
        for m in self.MODELS:
            setattr(self, m, getattr(fixtures.association_models, m))
Esempio n. 3
0
 def test_source_association_exists_on_proxy(self):
     """
     should raise when the source association is not defined on the proxy
     association's class
     """
     association = HasManyThrough(target_klass=self.Site, id=self.id,
             through='articles')
     self.assertRaises(errors.AssociationNotFound,
                       association.source_association)
Esempio n. 4
0
 def test_association_name(self):
     """should use the source association that matches the association id"""
     association = HasManyThrough(target_klass=self.Site, id='comments',
             through='articles')
     self.assertEqual(association.source_association().id, 'comments')
Esempio n. 5
0
 def test_through_exists(self):
     """should raise when through is not an existing association"""
     association = HasManyThrough(target_klass=self.Site, id=self.id,
             through='a_tunnel')
     self.assertRaises(errors.AssociationNotFound,
                       association.proxy_association)
Esempio n. 6
0
 def test_not_polymorphic(self):
     """should not allow polymorphic associations"""
     association = HasManyThrough(target_klass=self.Site, id='comments',
             through='articles', as_='whatever')
     self.assertEqual(association.polymorphic(), False)
Esempio n. 7
0
class HasManyThroughTestCase(BaseAssociationTestCase):

    MODELS = ['Site', 'Comment', 'Article', 'Person']

    def setUp(self):
        self.klass = fixtures.association_models.Test
        self.id = 'has_many_through'
        self.association = HasManyThrough(target_klass=self.klass, id=self.id)
        self.adapter = TestAdapter

        # assign fixtures.association_models.ModelClass to self.ModelClass
        for m in self.MODELS:
            setattr(self, m, getattr(fixtures.association_models, m))

    def tearDown(self):
        """reset read adapter instances for each model"""
        for m in self.MODELS:
            model = getattr(self, m)
            model.reader.clear()
            model._primary_key = 'id'

    def test_type(self):
        """should set association type to has_many_through"""
        self.assertEqual(self.association.type(), 'has_many_through')

    def test_collection(self):
        """should set collection to true"""
        self.assertEqual(self.association.collection(), True)

    def test_not_polymorphic(self):
        """should not allow polymorphic associations"""
        association = HasManyThrough(target_klass=self.Site, id='comments',
                through='articles', as_='whatever')
        self.assertEqual(association.polymorphic(), False)

    def test_through_exists(self):
        """should raise when through is not an existing association"""
        association = HasManyThrough(target_klass=self.Site, id=self.id,
                through='a_tunnel')
        self.assertRaises(errors.AssociationNotFound,
                          association.proxy_association)

    def test_source_association_exists_on_proxy(self):
        """
        should raise when the source association is not defined on the proxy
        association's class
        """
        association = HasManyThrough(target_klass=self.Site, id=self.id,
                through='articles')
        self.assertRaises(errors.AssociationNotFound,
                          association.source_association)

    def test_association_name(self):
        """should use the source association that matches the association id"""
        association = HasManyThrough(target_klass=self.Site, id='comments',
                through='articles')
        self.assertEqual(association.source_association().id, 'comments')

    def test_source_option(self):
        """
        should use the source option as the target association name if provided
        """
        association = HasManyThrough(target_klass=self.Site, id='dumb_comments',
                                     through='articles', source='comments')
        self.assertEqual(association.source_association().id, 'comments')

    def test_relation_mapped_to_source(self):
        """should return a relation mapped to the source association's class"""
        self.adapter.data = {'id': 1}
        site = self.Site.first()
        comments = site.article_comments

        self.assertEqual(type(comments), pyperry.Relation)
        self.assertEqual(comments.klass, self.Comment)

    def test_executes_2_queries(self):
        """should execute two queries when calling the association method"""
        self.adapter.data = {'id': 1}
        site = self.Site.first()

        self.adapter.calls = []
        comments = site.article_comments.all()
        self.assertEqual(len(self.adapter.calls), 2)

    def test_when_source_is_has(self):
        """
        should use the primary key values from the proxy association and the
        foreign key attribute from the source association when the source
        association is a has association
        """
        self.adapter.data = {'id': 1}
        site = self.Site.first()
        self.adapter.calls = []

        self.adapter.data = [{'id': 1}, {'id': 2}, {'id': 3}]
        relation = site.article_comments
        where_values = relation.query()['where']
        self.assertEqual(len(self.adapter.calls), 1)

        where_values.sort()
        self.assertEqual(self.Comment, relation.klass)
        self.assertEqual(where_values[0], {'parent_id': [1,2,3]})
        self.assertEqual(where_values[1], {'parent_type': 'Article'})

    def test_custom_proxy_pk_when_source_is_has(self):
        """
        should use the source association's primary_key attribute to
        collect the proxy_ids when the source association is a has
        """
        self.adapter.data = {'id': 1}
        person = self.Person.first()
        self.adapter.calls = []

        self.Site.set_primary_key('name')

        self.adapter.data = [{'id': 1, 'name': 'a'}, {'id': 2, 'name': 'b'},
                {'id': 3, 'name': 'c'}]
        relation = person.maintained_articles
        where_values = relation.query()['where']
        self.assertEqual(len(self.adapter.calls), 1)

        self.assertEqual(self.Article, relation.klass)
        # For this test we are assuming that Article.site_id references
        # Site.name instead of assuming Article.site_id references Site.id
        self.assertEqual(where_values, [{'site_id': ['a','b','c']}])


    def test_when_source_is_belongs_to(self):
        """
        should use the foreign key values from the proxy association and the
        primary key attribute from the source association when the source
        association is a belongs_to association
        """
        self.adapter.data = {'id': 1}
        article = self.Article.first()

        self.adapter.calls = []
        self.adapter.data = [{'id': 1, 'person_id': 11},
                {'id': 2, 'person_id': 12}, {'id': 3, 'person_id': 13}]

        relation = article.comment_authors
        where_values = relation.query()['where']

        self.assertEqual(len(self.adapter.calls), 1)
        self.assertEqual(relation.klass, self.Person)
        self.assertEqual([{'id': [11, 12, 13]}], where_values)

    def test_when_source_is_polymorphic_belongs_to(self):
        """
        should use the source_type attribute to determine the source's class
        when the source association is a polymorphic belongs_to asssociation
        """
        self.adapter.data = {'id': 1}
        person = self.Person.first()

        self.adapter.calls = []
        self.adapter.data = [
            {'id': 1, 'parent_id': 11, 'parent_type': 'FooBar'},
            {'id': 2, 'parent_id': 12, 'parent_type': 'FooBar'},
            {'id': 3, 'parent_id': 13, 'parent_type': 'FooBar'}
        ] # parent_type should be ignored by has many through

        relation = person.commented_articles
        where_values = relation.query()['where']

        self.assertEqual(len(self.adapter.calls), 1)
        self.assertEqual(relation.klass, self.Article)
        self.assertEqual([{'id': [11, 12, 13]}], where_values)

    def test_fresh(self):
        """
        should apply the fresh scope to both the proxy association and the
        source association
        """
        raise SkipTest
        # TODO: currently it is not possible to share the fresh scope between
        # the proxy and source associations

        self.adapter.data = {'id': 1}
        self.Article.add_middleware('read', LocalCache)
        self.Comment.add_middleware('read', LocalCache)
        self.Article._adapters = {}
        self.Comment._adapters = {}

        site = self.Site.first()
        self.adapter.calls = []

        relation = site.article_comments()
        relation.all()
        self.assertEqual(len(self.adapter.calls), 2)

        relation.all()
        self.assertEqual(len(self.adapter.calls), 2) # should hit cache

        relation = relation.fresh().all()
        self.assertEqual(len(self.adapter.calls), 4) # should skip cache
Esempio n. 8
0
 def test_source_option(self):
     """
     should use the source option as the target association name if provided
     """
     association = HasManyThrough(self.Site, "dumb_comments", through="articles", source="comments")
     self.assertEqual(association.source_association().id, "comments")
Esempio n. 9
0
 def test_association_name(self):
     """should use the source association that matches the association id"""
     association = HasManyThrough(self.Site, "comments", through="articles")
     self.assertEqual(association.source_association().id, "comments")
Esempio n. 10
0
 def test_not_polymorphic(self):
     """should not allow polymorphic associations"""
     association = HasManyThrough(self.Site, "comments", through="articles", as_="whatever")
     self.assertEqual(association.polymorphic(), False)
Esempio n. 11
0
class HasManyThroughTestCase(BaseAssociationTestCase):

    MODELS = ["Site", "Comment", "Article", "Person"]

    def setUp(self):
        self.klass = fixtures.association_models.Test
        self.id = "has_many_through"
        self.association = HasManyThrough(self.klass, self.id)
        self.adapter = TestAdapter

        # assign fixtures.association_models.ModelClass to self.ModelClass
        for m in self.MODELS:
            setattr(self, m, getattr(fixtures.association_models, m))

    def tearDown(self):
        """reset read adapter instances for each model"""
        for m in self.MODELS:
            model = getattr(self, m)
            model._adapters = {}
            if "_middlewares" in model.adapter_config["read"]:
                del model.adapter_config["read"]["_middlewares"]
            model.set_primary_key("id")

    def test_type(self):
        """should set association type to has_many_through"""
        self.assertEqual(self.association.type(), "has_many_through")

    def test_collection(self):
        """should set collection to true"""
        self.assertEqual(self.association.collection(), True)

    def test_not_polymorphic(self):
        """should not allow polymorphic associations"""
        association = HasManyThrough(self.Site, "comments", through="articles", as_="whatever")
        self.assertEqual(association.polymorphic(), False)

    def test_through_exists(self):
        """should raise when through is not an existing association"""
        association = HasManyThrough(self.Site, self.id, through="a_tunnel")
        self.assertRaises(errors.AssociationNotFound, association.proxy_association)

    def test_source_association_exists_on_proxy(self):
        """
        should raise when the source association is not defined on the proxy
        association's class
        """
        association = HasManyThrough(self.Site, self.id, through="articles")
        self.assertRaises(errors.AssociationNotFound, association.source_association)

    def test_association_name(self):
        """should use the source association that matches the association id"""
        association = HasManyThrough(self.Site, "comments", through="articles")
        self.assertEqual(association.source_association().id, "comments")

    def test_source_option(self):
        """
        should use the source option as the target association name if provided
        """
        association = HasManyThrough(self.Site, "dumb_comments", through="articles", source="comments")
        self.assertEqual(association.source_association().id, "comments")

    def test_relation_mapped_to_source(self):
        """should return a relation mapped to the source association's class"""
        self.adapter.data = {"id": 1}
        site = self.Site.first()
        comments = site.article_comments()

        self.assertEqual(type(comments), pyperry.Relation)
        self.assertEqual(comments.klass, self.Comment)

    def test_executes_2_queries(self):
        """should execute two queries when calling the association method"""
        self.adapter.data = {"id": 1}
        site = self.Site.first()

        self.adapter.calls = []
        comments = site.article_comments().all()
        self.assertEqual(len(self.adapter.calls), 2)

    def test_when_source_is_has(self):
        """
        should use the primary key values from the proxy association and the
        foreign key attribute from the source association when the source
        association is a has association
        """
        self.adapter.data = {"id": 1}
        site = self.Site.first()
        self.adapter.calls = []

        self.adapter.data = [{"id": 1}, {"id": 2}, {"id": 3}]
        relation = site.article_comments()
        where_values = relation.query()["where"]
        self.assertEqual(len(self.adapter.calls), 1)

        where_values.sort()
        self.assertEqual(self.Comment, relation.klass)
        self.assertEqual(where_values[0], {"parent_id": [1, 2, 3]})
        self.assertEqual(where_values[1], {"parent_type": "Article"})

    def test_custom_proxy_pk_when_source_is_has(self):
        """
        should use the source association's primary_key attribute to
        collect the proxy_ids when the source association is a has
        """
        self.adapter.data = {"id": 1}
        person = self.Person.first()
        self.adapter.calls = []

        self.Site.set_primary_key("name")

        self.adapter.data = [{"id": 1, "name": "a"}, {"id": 2, "name": "b"}, {"id": 3, "name": "c"}]
        relation = person.maintained_articles()
        where_values = relation.query()["where"]
        self.assertEqual(len(self.adapter.calls), 1)

        self.assertEqual(self.Article, relation.klass)
        # For this test we are assuming that Article.site_id references
        # Site.name instead of assuming Article.site_id references Site.id
        self.assertEqual(where_values, [{"site_id": ["a", "b", "c"]}])

    def test_when_source_is_belongs_to(self):
        """
        should use the foreign key values from the proxy association and the
        primary key attribute from the source association when the source
        association is a belongs_to association
        """
        self.adapter.data = {"id": 1}
        article = self.Article.first()

        self.adapter.calls = []
        self.adapter.data = [{"id": 1, "person_id": 11}, {"id": 2, "person_id": 12}, {"id": 3, "person_id": 13}]

        relation = article.comment_authors()
        where_values = relation.query()["where"]

        self.assertEqual(len(self.adapter.calls), 1)
        self.assertEqual(relation.klass, self.Person)
        self.assertEqual([{"id": [11, 12, 13]}], where_values)

    def test_when_source_is_polymorphic_belongs_to(self):
        """
        should use the source_type attribute to determine the source's class
        when the source association is a polymorphic belongs_to asssociation
        """
        self.adapter.data = {"id": 1}
        person = self.Person.first()

        self.adapter.calls = []
        self.adapter.data = [
            {"id": 1, "parent_id": 11, "parent_type": "FooBar"},
            {"id": 2, "parent_id": 12, "parent_type": "FooBar"},
            {"id": 3, "parent_id": 13, "parent_type": "FooBar"},
        ]  # parent_type should be ignored by has many through

        relation = person.commented_articles()
        where_values = relation.query()["where"]

        self.assertEqual(len(self.adapter.calls), 1)
        self.assertEqual(relation.klass, self.Article)
        self.assertEqual([{"id": [11, 12, 13]}], where_values)

    def test_fresh(self):
        """
        should apply the fresh scope to both the proxy association and the
        source association
        """
        raise SkipTest
        # TODO: currently it is not possible to share the fresh scope between
        # the proxy and source associations

        self.adapter.data = {"id": 1}
        self.Article.add_middleware("read", LocalCache)
        self.Comment.add_middleware("read", LocalCache)
        self.Article._adapters = {}
        self.Comment._adapters = {}

        site = self.Site.first()
        self.adapter.calls = []

        relation = site.article_comments()
        relation.all()
        self.assertEqual(len(self.adapter.calls), 2)

        relation.all()
        self.assertEqual(len(self.adapter.calls), 2)  # should hit cache

        relation = relation.fresh().all()
        self.assertEqual(len(self.adapter.calls), 4)  # should skip cache