Пример #1
0
def test_persistence_of_json_with_array_data(test_domain):
    test_domain.register(Event)

    event = Event(
        name="UserCreated",
        payload=[
            {
                "email": "*****@*****.**",
                "password": "******"
            },
            {
                "email": "*****@*****.**",
                "password": "******"
            },
        ],
    )
    current_domain.get_dao(Event).save(event)

    refreshed_event = current_domain.get_dao(Event).get(event.id)
    assert refreshed_event is not None
    assert refreshed_event.payload == [
        {
            "email": "*****@*****.**",
            "password": "******"
        },
        {
            "email": "*****@*****.**",
            "password": "******"
        },
    ]
    def get_by_tag_name(self, tag_name):
        tag_dao = current_domain.get_dao(Tag)

        try:
            return tag_dao.find_by(name=tag_name.lower())
        except ObjectNotFoundError:
            return None
 def get_by_token(cls, token: str) -> User:
     # FIXME Should return None if token has expired
     user_dao = current_domain.get_dao(User)
     try:
         user = user_dao.find_by(token=token)
         return user
     except ObjectNotFoundError:
         return None
    def get_by_author(self, author: str, limit: int, offset: int):
        user_repo = current_domain.repository_for(User)
        article_dao = current_domain.get_dao(Article)
        user = user_repo.get_by_username(author)
        if user is not None:
            return (article_dao.query.filter(author_id=user.id).limit(
                limit).offset(offset).order_by('-updated_at').all())

        return None
Пример #5
0
def test_array_overlap_query(test_domain):
    test_domain.register(ArrayUser)

    dao = current_domain.get_dao(ArrayUser)
    dao.create(email="*****@*****.**",
               roles=["JUDGE", "ADMIN"],
               integers=[9, 10])
    dao.create(email="*****@*****.**",
               roles=["ADMIN"],
               integers=[11])

    assert len(
        dao.query.filter(roles__overlap=["JUDGE", "ADMIN"]).all().items) == 2
Пример #6
0
def test_array_any_query(test_domain):
    test_domain.register(ArrayUser)

    dao = current_domain.get_dao(ArrayUser)

    dao.create(email="*****@*****.**",
               roles=["JUDGE", "ADMIN"],
               integers=[9, 10])
    dao.create(email="*****@*****.**",
               roles=["ADMIN"],
               integers=[11])

    assert dao.find_by(roles__any="JUDGE").email == "*****@*****.**"
Пример #7
0
    def get(self, identifier):
        """This is a utility method to fetch data from the persistence store by its key identifier. All child objects,
        including enclosed entities, are returned as part of this call.

        Returns the fetched aggregate.

        All other data filtering capabilities can be implemented by using the underlying DAO's
        :meth:`BaseDAO.filter` method.

        Filter methods are typically implemented as domain-contextual queries, like `find_adults()`,
        `find_residents_of_area(zipcode)`, etc. It is also possible to make use of more complicated,
        domain-friendly design patterns like the `Specification` pattern.
        """
        dao = current_domain.get_dao(self.meta_.aggregate_cls)
        return dao.get(identifier)
Пример #8
0
    def _fetch_objects(self, key, value):
        """ Fetch linked entities.

        This method returns a well-formed query, containing the foreign-key constraint.
        The query will NOT be fired at this stage, and records will only be fetched
        when the consumer accesses the `HasMany` field values.

        The number of underlying entities fetched at one time is limited by the
        config attribute `AGGREGATE_CHILDREN_LIMIT`. By default, the value is `100`.
        Be aware that increasing this limit will mean more entity objects will be
        loaded into memory along with the aggregate.
        """
        children_dao = current_domain.get_dao(self.to_cls)
        return children_dao.query.filter(**{
            key: value
        }).limit(current_domain.config["AGGREGATE_CHILDREN_LIMIT"])
Пример #9
0
    def remove(self, aggregate):
        """This method helps remove aggregates from the persistence store.

        Returns the removed aggregate.

        Protean mimics the behavior of a `set` collection in such methods. The repository promotes the
        illusion that we are dealing with collection like objects, so that the domain layer remains clean
        and oblivious to underlying persistence mechanisms. All changes are synced to the persistence store
        automatically by the Repository as and when appropriate.

        If there is a :ref:`Unit of Work <unit-of-work>` in progress, then the changes are performed on the
        UoW's active session. They are committed whenever the entire UoW is committed. If there is no
        transaction in progress, changes are committed immediately to the persistence store. This mechanism
        is part of the DAO's design, and is automatically used wherever one tries to persist data.
        """
        dao = current_domain.get_dao(self.meta_.aggregate_cls)
        dao.delete(aggregate)

        return aggregate
Пример #10
0
    def add(self, aggregate):  # noqa: C901
        """This method helps persist or update aggregates into the persistence store.

        Returns the persisted aggregate.

        Protean adopts a collection-oriented design pattern to handle persistence. What this means is that
        the Repository interface does not hint in any way that there is an underlying persistence mechanism,
        avoiding any notion of saving or persisting data in the design layer. The task of syncing the data
        back into the persistence store is handled automatically.

        To be specific, a Repository mimics a `set` collection. Whatever the implementation, the repository
        will not allow instances of the same object to be added twice. Also, when retrieving objects from
        a Repository and modifying them, you don’t need to “re-save” them to the Repository.

        If there is a :ref:`Unit of Work <unit-of-work>` in progress, then the changes are performed on the
        UoW's active session. They are committed whenever the entire UoW is committed. If there is no
        transaction in progress, changes are committed immediately to the persistence store. This mechanism
        is part of the DAO's design, and is automatically used wherever one tries to persist data.
        """

        # Ensure that aggregate is clean and good to save
        # FIXME Let `clean()` raise validation errors
        errors = aggregate.clean() or {}
        # Raise any errors found during load
        if errors:
            logger.error(errors)
            raise ValidationError(errors)

        # If there are HasMany fields in the aggregate, sync child objects added/removed,
        #   but not yet persisted to the database.
        #
        # The details of in-transit child objects are maintained as part of the `has_many_field` itself
        #   in a variable called `_temp_cache`
        for field_name, field in aggregate.meta_.declared_fields.items():
            if isinstance(field, HasMany):
                has_many_field = getattr(aggregate, field_name)

                for item in has_many_field._temp_cache["removed"]:
                    dao = current_domain.get_dao(field.to_cls)
                    dao.delete(item)
                has_many_field._temp_cache["removed"] = list(
                )  # Empty contents of `removed` cache

                for item in has_many_field._temp_cache["added"]:
                    dao = current_domain.get_dao(field.to_cls)
                    item.state_.mark_new()
                    dao.save(item)
                has_many_field._temp_cache["added"] = list(
                )  # Empty contents of `added` cache

            if isinstance(field, HasOne):
                if field.has_changed:
                    dao = current_domain.get_dao(field.to_cls)
                    if field.change == "ADDED":
                        dao.save(field.value)
                    elif field.change == "UPDATED":
                        if field.change_old_value is not None:
                            # The object was replaced, so delete the old record
                            dao.delete(field.change_old_value)
                        else:
                            # The same object was updated, so mark it as new to be able to save
                            # FIXME This should have been automatic with `is_changed` flag in `state_`
                            field.value.state_.mark_new()

                        dao.save(field.value)
                    else:
                        dao.delete(field.change_old_value)

                    # Reset temporary fields after processing
                    field.change = None
                    field.change_old_value = None

        # Persist only if the aggregate object is new, or it has changed since last persistence
        if (not aggregate.state_.is_persisted) or (
                aggregate.state_.is_persisted and aggregate.state_.is_changed):
            dao = current_domain.get_dao(self.meta_.aggregate_cls)
            dao.save(aggregate)

        return aggregate
 def get_by_slug(self, slug: str) -> Article:
     article_dao = current_domain.get_dao(Article)
     try:
         return article_dao.find_by(slug=slug)
     except ObjectNotFoundError:
         return None
 def get_by_tag(self, tag: str, limit: int, offset: int):
     article_dao = current_domain.get_dao(Article)
     return (article_dao.query.filter(tag_list__contains=tag).limit(
         limit).offset(offset).order_by('-updated_at').all())
 def list_articles(self, limit: int, offset: int):
     article_dao = current_domain.get_dao(Article)
     return article_dao.query.limit(limit).offset(offset).order_by(
         '-updated_at').all()
 def get_all(self):
     tag_dao = current_domain.get_dao(Tag)
     return tag_dao.query.limit(1000).all()
 def get_by_username(cls, username: str) -> User:
     user_dao = current_domain.get_dao(User)
     try:
         return user_dao.find_by(username=username)
     except ObjectNotFoundError:
         return None
 def get_by_email(cls, email: str) -> User:
     user_dao = current_domain.get_dao(User)
     try:
         return user_dao.find_by(email=email)
     except ObjectNotFoundError:
         return None
Пример #17
0
 def _fetch_objects(self, key, value):
     """Fetch Multiple linked objects"""
     return current_domain.get_dao(self.to_cls).find_by(**{key: value})
Пример #18
0
 def get_most_recent_event_by_type(cls, kind: str) -> EventLog:
     event_dao = current_domain.get_dao(EventLog)
     return (event_dao.query.filter(
         kind=kind.__name__).order_by("-timestamp").all().first)
Пример #19
0
 def _fetch_objects(self, key, value):
     """Fetch single linked object"""
     try:
         return current_domain.get_dao(self.to_cls).find_by(**{key: value})
     except exceptions.ObjectNotFoundError:
         return None
Пример #20
0
 def get_all_events_of_type(cls, kind: str) -> EventLog:
     event_dao = current_domain.get_dao(EventLog)
     return (event_dao.query.filter(
         kind=kind.__name__).order_by("-timestamp").all().items)
Пример #21
0
 def find_adults(self, minimum_age: int = 21) -> List[Person]:
     return current_domain.get_dao(Person).filter(age__gte=minimum_age)