# minos-python: The framework which helps you create reactive microservices in Python
-[](https://pypi.org/project/minos-microservice-aggregate/)
-[](https://pypi.org/project/minos-microservice-common/)
-[](https://pypi.org/project/minos-microservice-cqrs/)
-[](https://pypi.org/project/minos-microservice-networks/)
-[](https://pypi.org/project/minos-microservice-saga/)
+
+[](https://pypi.org/project/minos-microservice-common/)
[](https://minos-framework.github.io/minos-python)
[](https://github.com/minos-framework/minos-python/blob/main/LICENSE)
[](https://codecov.io/gh/minos-framework/minos-python)
[](https://stackoverflow.com/questions/tagged/minos)
[](https://gitter.im/minos-framework/community)
+[](https://github.com/minos-framework/minos-python)
## Summary
-Minos is a framework which helps you create [reactive](https://www.reactivemanifesto.org/) microservices in Python.
-Internally, it leverages Event Sourcing, CQRS and a message driven architecture to fulfil the commitments of an
-asynchronous environment.
+Minos is a framework which helps you create [reactive](https://www.reactivemanifesto.org/) microservices in Python. Internally, it leverages Event Sourcing, CQRS and a message driven architecture to fulfil the commitments of an asynchronous environment.
-## Documentation
+### Roadmap
+
+#### 0.6.x
+* [#78](https://github.com/minos-framework/minos-python/issues/78) Implement a circuit breaker for `minos-broker-kafka`.
+* [#87](https://github.com/minos-framework/minos-python/issues/87) Implement idempotency for `BrokerSubscriber` message processing.
+* [#100](https://github.com/minos-framework/minos-python/issues/100) Create the `minos-serializers-avro` plugin.
+* [#148](https://github.com/minos-framework/minos-python/issues/148) Create the `minos-rest-aiohttp`.
+* [#149](https://github.com/minos-framework/minos-python/issues/149) Add `minos-graphql-aiohttp` plugin.
+* [#150](https://github.com/minos-framework/minos-python/issues/150) Refactor configuration file and `MinosConfig` accessor.
+* [#151](https://github.com/minos-framework/minos-python/issues/151) Expose `OpenAPI` and `AsyncAPI` specifications.
+* [#152](https://github.com/minos-framework/minos-python/issues/152) Provide a testing suite to test the microservice.
+
+## Foundational Patterns
+
+The `minos` framework is built strongly inspired by the following set of patterns:
+
+* [Microservice architecture](https://microservices.io/patterns/microservices.html): Architect an application as a collection of loosely coupled services.
+* [Decompose by subdomain](https://microservices.io/patterns/decomposition/decompose-by-subdomain.html): Define services corresponding to Domain-Driven Design (DDD) subdomains
+* [Self-contained Service](https://microservices.io/patterns/decomposition/self-contained-service.html): Microservices can respond to a synchronous request without waiting for the response from any other service.
+* [Database per service](https://microservices.io/patterns/data/database-per-service.html): Keep each microservice's persistent data private to that service and accessible only via its API. A service's transactions only involve its database.
+* [Saga](https://microservices.io/patterns/data/saga.html): Transaction that spans multiple services.
+* [CQRS](https://microservices.io/patterns/data/cqrs.html): view database, which is a read-only replica that is designed to support queries that retrieves data from microservice. The application keeps the replica up to date by subscribing to Domain events published by the service that own the data.
+* [Domain event](https://microservices.io/patterns/data/domain-event.html): A service often needs to publish events when it updates its data. These events might be needed, for example, to update a CQRS view.
+* [Event Sourcing](https://microservices.io/patterns/data/event-sourcing.html): Event sourcing persists the state of a business entity such an Order or a Customer as a sequence of state-changing events. Whenever the state of a business entity changes, a new event is appended to the list of events. Since saving an event is a single operation, it is inherently atomic. The application reconstructs an entity's current state by replaying the events.
+* [Messaging](https://microservices.io/patterns/communication-style/messaging.html): Services communicating by exchanging messages over messaging channels. (Apache Kafka is used in this case)
+* [API gateway](https://microservices.io/patterns/apigateway.html): Single entry point for all clients. The API gateway proxy/route to the appropriate service.
+* [Service registry](https://microservices.io/patterns/service-registry.html): Database of services. A service registry might invoke a service instance's health check API to verify that it is able to handle requests
+* [Self Registration](https://microservices.io/patterns/self-registration.html): Each service instance register on startup and unregister on stop.
+* [Access token](https://microservices.io/patterns/security/access-token.html): The API Gateway authenticates the request and passes an access token (e.g. JSON Web Token) that securely identifies the requestor in each request to the services. A service can include the access token in requests it makes to other services.
+* [Health Check API](https://microservices.io/patterns/observability/health-check-api.html): A service has a health check API endpoint (e.g. HTTP `/health`) that returns the health of the service.
+
+## Installation
+
+The easiest way to manage a project is with the `minos` command-line interface, which provides commands to setup both the project skeleton (configures containerization, databases, brokers, etc.) and the microservice skeleton (the base microservice structure, environment configuration, etc.).
+
+You can install it with:
+
+```shell
+pip install minos-cli
+```
+
+Here is a summary containing the most useful commands:
+
+* `minos new project $NAME`: Create a new Project
+* `minos set $RESOURCE $BACKEND`: Configure an environment resource (broker, database, etc.).
+* `minos deploy project`: Deploy a project.
+* `minos new microservice $NAME`: Create a new microservice.
+* `minos deploy microservice` deploy a microservice.
+
+For more information, visit the [`minos-cli`](https://github.com/minos-framework/minos-cli) repository.
+
+## QuickStart
+
+This section includes a quickstart guide to create your first `minos` microservice, so that anyone can get the gist of the framework.
+
+### Set up the environment
+
+The required environment to run this quickstart is the following:
+
+* A `python>=3.9` interpreter with version equal or greater to .
+* A `kafka` instance available at `localhost:9092`
+* A `postgres` instance available at `localhost:5432` with the `foo_db` and `foobar_db` databases accessible with the `user:pass` credentials.
+* Two TCP sockets available to use at `localhost:4545` and `localhost:4546`.
+
+Note that these parameters can be customized on the configuration files.
+
+### Install the dependencies
+
+If you want to directly use `minos` without the command-line utility, the following command will install the needed packages:
+
+```shell
+pip install \
+ minos-microservice-aggregate \
+ minos-microservice-common \
+ minos-microservice-cqrs \
+ minos-microservice-networks \
+ minos-microservice-saga \
+ minos-broker-kafka
+```
+
+
+### Configure a Microservice
+
+To keep things simpler, this quickstart will create a microservice assuming all the source code is stored on a single `foo/main.py` file. In addition to the source file, a `foo/config.yml` will contain all the configuration stuff.
+
+The directory structure will become:
+
+```shell
+.
+└── foo
+ ├── config.yml
+ └── main.py
+```
+
+Create a `foo/config.yml` file and add the following lines:
+
+ Click to show the full file
+
+```yaml
+# foo/config.yml
+
+service:
+ name: foo
+ aggregate: main.Foo
+ injections:
+ lock_pool: minos.common.PostgreSqlLockPool
+ postgresql_pool: minos.common.PostgreSqlPool
+ broker_publisher: minos.plugins.kafka.PostgreSqlQueuedKafkaBrokerPublisher
+ broker_subscriber_builder: minos.plugins.kafka.PostgreSqlQueuedKafkaBrokerSubscriberBuilder
+ broker_pool: minos.networks.BrokerClientPool
+ transaction_repository: minos.aggregate.PostgreSqlTransactionRepository
+ event_repository: minos.aggregate.PostgreSqlEventRepository
+ snapshot_repository: minos.aggregate.PostgreSqlSnapshotRepository
+ saga_manager: minos.saga.SagaManager
+ discovery: minos.networks.DiscoveryConnector
+ services:
+ - minos.networks.BrokerHandlerService
+ - minos.networks.RestService
+ - minos.networks.PeriodicTaskSchedulerService
+middleware:
+ - minos.saga.transactional_command
+services:
+ - minos.aggregate.TransactionService
+ - minos.aggregate.SnapshotService
+ - minos.saga.SagaService
+ - main.FooCommandService
+ - main.FooQueryService
+rest:
+ host: 0.0.0.0
+ port: 4545
+broker:
+ host: localhost
+ port: 9092
+ queue:
+ database: foo_db
+ user: user
+ password: pass
+ host: localhost
+ port: 5432
+ records: 1000
+ retry: 2
+repository:
+ database: foo_db
+ user: user
+ password: pass
+ host: localhost
+ port: 5432
+snapshot:
+ database: foo_db
+ user: user
+ password: pass
+ host: localhost
+ port: 5432
+saga:
+ storage:
+ path: "./foo.lmdb"
+discovery:
+ client: minos.networks.InMemoryDiscoveryClient
+ host: localhost
+ port: 5567
+```
+
+
+
+Create a `foo/main.py` file and add the following content:
+
+```python
+# foo/main.py
+
+from pathlib import Path
+from minos.aggregate import Aggregate, RootEntity
+from minos.common import EntrypointLauncher
+from minos.cqrs import CommandService, QueryService
+
+
+class Foo(RootEntity):
+ """Foo RootEntity class."""
+
+
+class FooAggregate(Aggregate[Foo]):
+ """Foo Aggregate class."""
+
+
+class FooCommandService(CommandService):
+ """Foo Command Service class."""
+
+
+class FooQueryService(QueryService):
+ """Foo Query Service class."""
+
+
+if __name__ == '__main__':
+ launcher = EntrypointLauncher.from_config(Path(__file__).parent / "config.yml")
+ launcher.launch()
+```
+
+Execute the following command to start the microservice:
+
+```shell
+python foo/main.py
+```
+
+### Create an Aggregate
+
+The way to model data in `minos` is highly inspired by the [Event Sourcing](https://microservices.io/patterns/data/event-sourcing.html) ideas. For this reason, the classes to be used to model data are:
+
+* `minos.aggregate.Entity`: A model that has an identifier that gives it a unique identity, in the sense that some values from which it is composed could change, but its identity will continue being the same.
+* `minos.aggregate.ExternalEntity`: A model that belongs to another microservice (or aggregate boundary) but needs to be used for some reason inside this microservice (or aggregate boundary).
+* `minos.aggregate.RootEntity`: Is an `Entity` superset that provides global identity across the project compared to standard `Entity` models, that has only local identity (the `RootEntity` can be accessed from another microservices as `ExternalEntity` models, but standard `Entity` models can only be accessed within the microservice that define them). The `RootEntity` is also the one that interacts with the persistence layer (the `EventRepository` and `SnapshotRepository` instances).
+* `minos.aggregate.Ref`: A wrapper class that provides the functionality to store a reference of other `RootEntity` or `ExternalEntity` instances.
+* `minos.aggregate.EntitySet`: A container of `Entity` instances that takes advantage of the incremental behaviour of the `EventRepository`.
+* `minos.aggregate.ValueObject`: A model that is only identified by the values that compose it, so that if some of them changes, then the model becomes completely different (for that reason, these models are immutable).
+* `minos.aggregate.ValueObjectSet`: A container of `ValueObject` instances that takes advantage of the incremental behaviour of the `EventRepository.
+* `minos.aggregate.Aggregate`: A collection of `Entity` and/or `ValueObject` models that are related to each other through a `RootEntity`.
+* `minos.aggregate.Event`: A model that contains the difference between the a `RootEntity` instance and its previous version (if any).
+
+Here is an example of the creation the `Foo` aggregate. In this case, it has two attributes, a `bar` being a `str`, and a `foobar` being an optional reference to the external `FooBar` aggregate, which it is assumed that it has a `something` attribute.
+
+```python
+# foo/main.py
+
+from __future__ import annotations
+from typing import Optional
+from uuid import UUID
+from minos.aggregate import Aggregate, RootEntity, ExternalEntity, Ref
+
+
+class Foo(RootEntity):
+ """Foo RootEntity class."""
+
+ bar: str
+ foobar: Optional[Ref[FooBar]]
+
+
+class FooBar(ExternalEntity):
+ """FooBar ExternalEntity clas."""
+
+ something: str
+
+
+class FooAggregate(Aggregate[Foo]):
+ """Foo Aggregate class."""
+
+ @staticmethod
+ async def create_foo(bar: str) -> UUID:
+ """Create a new Foo instance
+
+ :param bar: The bar of the new instance.
+ :return: The identifier of the new instance.
+ """
+ foo = await Foo.create(bar)
+
+ return foo.uuid
+
+ @staticmethod
+ async def update_foobar(uuid: UUID, foobar: Optional[Ref[FooBar]]) -> None:
+ """Update the foobar attribute of the ``Foo`` instance.
+
+ :param uuid: The identifier of the ``Foo`` instance.
+ :param foobar: The foobar value to be set.
+ :return: This method does not return anything.
+ """
+ foo = await Foo.get(uuid)
+ foo.foobar = foobar
+ await foo.save()
+```
+
+
+ Click to show the full file
+
+```python
+# foo/main.py
+
+from __future__ import annotations
+
+from pathlib import Path
+from typing import Optional
+from uuid import UUID
+
+from minos.aggregate import Aggregate, RootEntity, ExternalEntity, Ref
+from minos.common import EntrypointLauncher
+from minos.cqrs import CommandService, QueryService
+
+
+class Foo(RootEntity):
+ """Foo RootEntity class."""
+
+ bar: str
+ foobar: Optional[Ref[FooBar]]
+
+
+class FooBar(ExternalEntity):
+ """FooBar ExternalEntity clas."""
+
+ something: str
+
+
+class FooAggregate(Aggregate[Foo]):
+ """Foo Aggregate class."""
+
+ @staticmethod
+ async def create_foo(bar: str) -> UUID:
+ """Create a new Foo instance
+
+ :param bar: The bar of the new instance.
+ :return: The identifier of the new instance.
+ """
+ foo = await Foo.create(bar)
+
+ return foo.uuid
+
+ @staticmethod
+ async def update_foobar(uuid: UUID, foobar: Optional[Ref[FooBar]]) -> None:
+ """Update the foobar attribute of the ``Foo`` instance.
+
+ :param uuid: The identifier of the ``Foo`` instance.
+ :param foobar: The foobar value to be set.
+ :return: This method does not return anything.
+ """
+ foo = await Foo.get(uuid)
+ foo.foobar = foobar
+ await foo.save()
+
+
+class FooCommandService(CommandService):
+ """Foo Command Service class."""
+
+
+class FooQueryService(QueryService):
+ """Foo Query Service class."""
+
+
+if __name__ == '__main__':
+ launcher = EntrypointLauncher.from_config(Path(__file__).parent / "config.yml")
+ launcher.launch()
+```
+
+
+
+### Expose a Command
+
+Here is an example of the definition of a command to create `Foo` instances. To do that, it is necessary to define a `CommandService` that contains the handling function. It will handle both the broker messages sent to the `"CreateFoo"` topic and the rest calls to the `"/foos"` path with the `"POST"` method. In this case, the handling function unpacks the `Request`'s content and then calls the `create` method from the `Aggregate`, which stores the `Foo` instance following an event-driven strategy (it also publishes the `"FooCreated"` event). Finally, a `Response` is returned to be handled by the external caller (another microservice or the API-gateway).
+
+```python
+# foo/main.py
+
+from minos.cqrs import CommandService
+from minos.networks import enroute, Request, Response
+
+
+class FooCommandService(CommandService):
+ """Foo Command Service class."""
+
+ @enroute.broker.command("CreateFoo")
+ @enroute.rest.command("/foos", "POST")
+ async def create_foo(self, request: Request) -> Response:
+ """Create a new Foo.
+
+ :param request: The ``Request`` that contains the ``bar`` attribute.
+ :return: A ``Response`` containing identifier of the already created instance.
+ """
+ content = await request.content()
+ bar = content["bar"]
+
+ uuid = await FooAggregate.create_foo(bar)
+
+ return Response({"uuid": uuid})
+```
+
+
+ Click to show the full file
+
+```python
+# foo/main.py
+
+from __future__ import annotations
+
+from pathlib import Path
+from typing import Optional
+from uuid import UUID
+
+from minos.aggregate import Aggregate, RootEntity, ExternalEntity, Ref
+from minos.common import EntrypointLauncher
+from minos.cqrs import CommandService, QueryService
+from minos.networks import Request, Response, enroute
+
+
+class Foo(RootEntity):
+ """Foo RootEntity class."""
+
+ bar: str
+ foobar: Optional[Ref[FooBar]]
+
+
+class FooBar(ExternalEntity):
+ """FooBar ExternalEntity clas."""
+
+ something: str
+
+
+class FooAggregate(Aggregate[Foo]):
+ """Foo Aggregate class."""
+
+ @staticmethod
+ async def create_foo(bar: str) -> UUID:
+ """Create a new Foo instance
+
+ :param bar: The bar of the new instance.
+ :return: The identifier of the new instance.
+ """
+ foo = await Foo.create(bar)
+
+ return foo.uuid
+
+ @staticmethod
+ async def update_foobar(uuid: UUID, foobar: Optional[Ref[FooBar]]) -> None:
+ """Update the foobar attribute of the ``Foo`` instance.
+
+ :param uuid: The identifier of the ``Foo`` instance.
+ :param foobar: The foobar value to be set.
+ :return: This method does not return anything.
+ """
+ foo = await Foo.get(uuid)
+ foo.foobar = foobar
+ await foo.save()
+
+
+class FooCommandService(CommandService):
+ """Foo Command Service class."""
+
+ @enroute.broker.command("CreateFoo")
+ @enroute.rest.command("/foos", "POST")
+ async def create_foo(self, request: Request) -> Response:
+ """Create a new Foo.
+
+ :param request: The ``Request`` that contains the ``bar`` attribute.
+ :return: A ``Response`` containing identifier of the already created instance.
+ """
+ content = await request.content()
+ bar = content["bar"]
+
+ uuid = await FooAggregate.create_foo(bar)
+
+ return Response({"uuid": uuid})
+
+
+class FooQueryService(QueryService):
+ """Foo Query Service class."""
+
+
+if __name__ == '__main__':
+ launcher = EntrypointLauncher.from_config(Path(__file__).parent / "config.yml")
+ launcher.launch()
+```
+
+
+
+Execute the following command to start the microservice:
+
+```shell
+python foo/main.py
+```
+
+To check that everything works fine, execute the following command:
+
+```shell
+curl --location --request POST 'http://localhost:4545/foos' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "bar": "test"
+}'
+```
+
+And the expected response will be similar to:
+
+```json
+{
+ "uuid": "YOUR_UUID"
+}
+```
+
+### Subscribe to an Event and Expose a Query
+
+Here is an example of the event and query handling. In this case, it must be defined on a `QueryService` class. In this case a `"FooCreated"` and `"FooUpdated.foobar"` events are handled (they will print the content on the microservice's logs). The event contents typically contains instances of `AggregateDiff` type, which is referred to the difference respect to the previously stored instance. The exposed query is connected to the calls that come from the `"/foos/example"` path and `"GET"` method and a naive string is returned.
+
+*Disclaimer*: A real `QueryService` implementation must populate a query-oriented database based on the events to which is subscribed to, and expose queries performed over that query-oriented database.
+
+```python
+# foo/main.py
+
+from minos.cqrs import QueryService
+from minos.networks import enroute, Request, Response
+
+
+class FooQueryService(QueryService):
+ """Foo Query Service class."""
+
+ @enroute.broker.event("FooCreated")
+ async def foo_created(self, request: Request) -> None:
+ """Handle the "FooCreated" event.
+
+ :param request: The ``Request`` that contains a ``Event``.
+ :return: This method does not return anything.
+ """
+ event = await request.content()
+ print(f"A Foo was created: {event}")
+
+ @enroute.broker.event("FooUpdated.foobar")
+ async def foo_foobar_updated(self, request: Request) -> None:
+ """Handle the "FooUpdated.foobar" event.
+
+ :param request: The ``Request`` that contains a ``Event``.
+ :return: This method does not return anything.
+ """
+ event = await request.content()
+ print(f"The 'foobar' field of a Foo was updated: {event}")
+
+ @enroute.rest.query("/foos/example", "GET")
+ async def example(self, request: Request) -> Response:
+ """Handle the example query.
+
+ :param request: The ``Request`` that contains the necessary information.
+ :return: A ``Response`` instance.
+ """
+ return Response("This is an example response!")
+```
+
+
+ Click to show the full file
+
+```python
+# foo/main.py
+
+from __future__ import annotations
-The official API Reference is publicly available at [GiHub Pages](https://minos-framework.github.io/minos-python).
+from pathlib import Path
+from typing import Optional
+from uuid import UUID
+
+from minos.aggregate import Aggregate, RootEntity, ExternalEntity, Ref
+from minos.common import EntrypointLauncher
+from minos.cqrs import CommandService, QueryService
+from minos.networks import Request, Response, enroute
+
+
+class Foo(RootEntity):
+ """Foo RootEntity class."""
+
+ bar: str
+ foobar: Optional[Ref[FooBar]]
+
+
+class FooBar(ExternalEntity):
+ """FooBar ExternalEntity clas."""
+
+ something: str
+
+
+class FooAggregate(Aggregate[Foo]):
+ """Foo Aggregate class."""
+
+ @staticmethod
+ async def create_foo(bar: str) -> UUID:
+ """Create a new Foo instance
+
+ :param bar: The bar of the new instance.
+ :return: The identifier of the new instance.
+ """
+ foo = await Foo.create(bar)
+
+ return foo.uuid
+
+ @staticmethod
+ async def update_foobar(uuid: UUID, foobar: Optional[Ref[FooBar]]) -> None:
+ """Update the foobar attribute of the ``Foo`` instance.
+
+ :param uuid: The identifier of the ``Foo`` instance.
+ :param foobar: The foobar value to be set.
+ :return: This method does not return anything.
+ """
+ foo = await Foo.get(uuid)
+ foo.foobar = foobar
+ await foo.save()
+
+
+class FooCommandService(CommandService):
+ """Foo Command Service class."""
+
+ @enroute.broker.command("CreateFoo")
+ @enroute.rest.command("/foos", "POST")
+ async def create_foo(self, request: Request) -> Response:
+ """Create a new Foo.
+
+ :param request: The ``Request`` that contains the ``bar`` attribute.
+ :return: A ``Response`` containing identifier of the already created instance.
+ """
+ content = await request.content()
+ bar = content["bar"]
+
+ uuid = await FooAggregate.create_foo(bar)
+
+ return Response({"uuid": uuid})
+
+
+class FooQueryService(QueryService):
+ """Foo Query Service class."""
+
+ @enroute.broker.event("FooCreated")
+ async def foo_created(self, request: Request) -> None:
+ """Handle the "FooCreated" event.
+
+ :param request: The ``Request`` that contains a ``Event``.
+ :return: This method does not return anything.
+ """
+ event = await request.content()
+ print(f"A Foo was created: {event}")
+
+ @enroute.broker.event("FooUpdated.foobar")
+ async def foo_foobar_updated(self, request: Request) -> None:
+ """Handle the "FooUpdated.foobar" event.
+
+ :param request: The ``Request`` that contains a ``Event``.
+ :return: This method does not return anything.
+ """
+ event = await request.content()
+ print(f"The 'foobar' field of a Foo was updated: {event}")
+
+ @enroute.rest.query("/foos/example", "GET")
+ async def example(self, request: Request) -> Response:
+ """Handle the example query.
+
+ :param request: The ``Request`` that contains the necessary information.
+ :return: A ``Response`` instance.
+ """
+ return Response("This is an example response!")
+
+
+if __name__ == '__main__':
+ launcher = EntrypointLauncher.from_config(Path(__file__).parent / "config.yml")
+ launcher.launch()
+```
+
+
+
+Execute the following command to start the microservice:
+
+```shell
+python foo/main.py
+```
+
+Now, if a new instance is created (with a rest call, like in the [previous section](#Expose a Command)), the `FooCreated` event will be handled and the microservice's console will print something like:
+
+```
+A Foo was created: Event(...)
+```
+
+Also, to check that everything is fine the example query can be executed with:
+
+```shell
+curl --location --request GET 'http://localhost:4545/foos/example'
+```
+
+And the expected result should be something like:
+
+```
+"This is an example response!"
+```
+
+### Interact with another Microservice
+
+Here is an example of the interaction between two microservices through a SAGA pattern. In this case, the interaction starts with a call to the `"/foos/add-foobar"` path and the `"POST"` method, which performs a `SagaManager` run over the `ADD_FOOBAR_SAGA` saga. This saga has two steps, one remote that executes the `"CreateFooBar"` command (possibly defined on the supposed `"foobar"` microservice), and a local step that is executed on this microservice. The `CreateFooBarDTO` defines the structure of the request to be sent when the `"CreateFooBar"` command is executed.
+
+```python
+# foo/main.py
+
+from minos.common import ModelType
+from minos.cqrs import CommandService
+from minos.networks import enroute, Request
+from minos.saga import Saga, SagaContext, SagaRequest, SagaResponse
+
+
+class FooCommandService(CommandService):
+ """Foo Command Service class."""
+
+ @enroute.rest.command("/foos/add-foobar", "POST")
+ async def update_foo(self, request: Request) -> None:
+ """Run a saga example.
+
+ :param request: The ``Request`` that contains the initial saga's context.
+ :return: This method does not return anything.
+ """
+ content = await request.content()
+
+ context = SagaContext(uuid=content["uuid"], something=content["something"])
+ await self.saga_manager.run(ADD_FOOBAR_SAGA, context)
+
+
+def _create_foobar(context: SagaContext) -> SagaRequest:
+ something = context["something"]
+ content = CreateFooBarDTO(56, something)
+ return SagaRequest("CreateFooBar", content)
+
+
+async def _success_foobar(context: SagaContext, response: SagaResponse) -> SagaContext:
+ context["foobar_uuid"] = await response.content()
+ return context
+
+
+async def _error_foobar(context: SagaContext, response: SagaResponse) -> SagaContext:
+ raise ValueError("The foobar could not be created!")
+
+
+async def _update_foo(context: SagaContext) -> None:
+ await FooAggregate.update_foobar(context["uuid"], context["foobar_uuid"])
+
+
+CreateFooBarDTO = ModelType.build("AnotherDTO", {"number": int, "text": str})
+
+ADD_FOOBAR_SAGA = (
+ Saga()
+ .remote_step()
+ .on_execute(_create_foobar)
+ .on_success(_success_foobar)
+ .on_error(_error_foobar)
+ .local_step()
+ .on_execute(_update_foo)
+ .commit()
+)
+```
+
+
+ Click to show the full file
+
+```python
+# foo/main.py
+
+from __future__ import annotations
+
+from pathlib import Path
+from typing import Optional
+from uuid import UUID
+
+from minos.aggregate import Aggregate, RootEntity, ExternalEntity, Ref
+from minos.common import ModelType, EntrypointLauncher
+from minos.cqrs import CommandService, QueryService
+from minos.networks import Request, Response, enroute
+from minos.saga import Saga, SagaContext, SagaRequest, SagaResponse
+
+
+class Foo(RootEntity):
+ """Foo RootEntity class."""
+
+ bar: str
+ foobar: Optional[Ref[FooBar]]
+
+
+class FooBar(ExternalEntity):
+ """FooBar ExternalEntity clas."""
+
+ something: str
+
+
+class FooAggregate(Aggregate[Foo]):
+ """Foo Aggregate class."""
+
+ @staticmethod
+ async def create_foo(bar: str) -> UUID:
+ """Create a new Foo instance
+
+ :param bar: The bar of the new instance.
+ :return: The identifier of the new instance.
+ """
+ foo = await Foo.create(bar)
+
+ return foo.uuid
+
+ @staticmethod
+ async def update_foobar(uuid: UUID, foobar: Optional[Ref[FooBar]]) -> None:
+ """Update the foobar attribute of the ``Foo`` instance.
+
+ :param uuid: The identifier of the ``Foo`` instance.
+ :param foobar: The foobar value to be set.
+ :return: This method does not return anything.
+ """
+ foo = await Foo.get(uuid)
+ foo.foobar = foobar
+ await foo.save()
+
+
+class FooCommandService(CommandService):
+ """Foo Command Service class."""
+
+ @enroute.broker.command("CreateFoo")
+ @enroute.rest.command("/foos", "POST")
+ async def create_foo(self, request: Request) -> Response:
+ """Create a new Foo.
+
+ :param request: The ``Request`` that contains the ``bar`` attribute.
+ :return: A ``Response`` containing identifier of the already created instance.
+ """
+ content = await request.content()
+ bar = content["bar"]
+
+ uuid = await FooAggregate.create_foo(bar)
+
+ return Response({"uuid": uuid})
+
+ @enroute.rest.command("/foos/add-foobar", "POST")
+ async def update_foo(self, request: Request) -> None:
+ """Run a saga example.
+
+ :param request: The ``Request`` that contains the initial saga's context.
+ :return: This method does not return anything.
+ """
+ content = await request.content()
+
+ context = SagaContext(uuid=content["uuid"], something=content["something"])
+ await self.saga_manager.run(ADD_FOOBAR_SAGA, context)
+
+
+def _create_foobar(context: SagaContext) -> SagaRequest:
+ something = context["something"]
+ content = CreateFooBarDTO(56, something)
+ return SagaRequest("CreateFooBar", content)
+
+
+async def _success_foobar(context: SagaContext, response: SagaResponse) -> SagaContext:
+ context["foobar_uuid"] = await response.content()
+ return context
+
+
+async def _error_foobar(context: SagaContext, response: SagaResponse) -> SagaContext:
+ raise ValueError("The foobar could not be created!")
+
+
+async def _update_foo(context: SagaContext) -> None:
+ await FooAggregate.update_foobar(context["uuid"], context["foobar_uuid"])
+
+
+CreateFooBarDTO = ModelType.build("AnotherDTO", {"number": int, "text": str})
+
+ADD_FOOBAR_SAGA = (
+ Saga()
+ .remote_step()
+ .on_execute(_create_foobar)
+ .on_success(_success_foobar)
+ .on_error(_error_foobar)
+ .local_step()
+ .on_execute(_update_foo)
+ .commit()
+)
+
+
+class FooQueryService(QueryService):
+ """Foo Query Service class."""
+
+ @enroute.broker.event("FooCreated")
+ async def foo_created(self, request: Request) -> None:
+ """Handle the "FooCreated" event.
+
+ :param request: The ``Request`` that contains a ``Event``.
+ :return: This method does not return anything.
+ """
+ event = await request.content()
+ print(f"A Foo was created: {event}")
+
+ @enroute.broker.event("FooUpdated.foobar")
+ async def foo_foobar_updated(self, request: Request) -> None:
+ """Handle the "FooUpdated.foobar" event.
+
+ :param request: The ``Request`` that contains a ``Event``.
+ :return: This method does not return anything.
+ """
+ event = await request.content()
+ print(f"The 'foobar' field of a Foo was updated: {event}")
+
+ @enroute.rest.query("/foos/example", "GET")
+ async def example(self, request: Request) -> Response:
+ """Handle the example query.
+
+ :param request: The ``Request`` that contains the necessary information.
+ :return: A ``Response`` instance.
+ """
+ return Response("This is an example response!")
+
+
+if __name__ == '__main__':
+ launcher = EntrypointLauncher.from_config(Path(__file__).parent / "config.yml")
+ launcher.launch()
+```
+
+
+
+Execute the following command to start the `foo` microservice:
+
+```shell
+python foo/main.py
+```
+
+**Disclaimer**: Note that in this case another microservice is needed to complete the saga.
+
+#### The `foobar` Microservice
+
+The `foobar` microservice will simply have a `CreateFooBar` command to create new instances of its `FooBar` root entity.
+
+The directory structure will become:
+
+```shell
+.
+├── foo
+│ ├── config.yml
+│ └── main.py
+└── foobar
+ ├── config.yml
+ └── main.py
+```
+
+Here is the `foobar/config.yml` config file:
+
+ Click to show the full file
+
+```yaml
+# foobar/config.yml
+
+service:
+ name: foobar
+ aggregate: main.FooBar
+ injections:
+ lock_pool: minos.common.PostgreSqlLockPool
+ postgresql_pool: minos.common.PostgreSqlPool
+ broker_publisher: minos.plugins.kafka.PostgreSqlQueuedKafkaBrokerPublisher
+ broker_subscriber_builder: minos.plugins.kafka.PostgreSqlQueuedKafkaBrokerSubscriberBuilder
+ broker_pool: minos.networks.BrokerClientPool
+ transaction_repository: minos.aggregate.PostgreSqlTransactionRepository
+ event_repository: minos.aggregate.PostgreSqlEventRepository
+ snapshot_repository: minos.aggregate.PostgreSqlSnapshotRepository
+ saga_manager: minos.saga.SagaManager
+ discovery: minos.networks.DiscoveryConnector
+ services:
+ - minos.networks.BrokerHandlerService
+ - minos.networks.RestService
+ - minos.networks.PeriodicTaskSchedulerService
+middleware:
+ - minos.saga.transactional_command
+services:
+ - minos.aggregate.TransactionService
+ - minos.aggregate.SnapshotService
+ - minos.saga.SagaService
+ - main.FooBarCommandService
+rest:
+ host: 0.0.0.0
+ port: 4546
+broker:
+ host: localhost
+ port: 9092
+ queue:
+ database: foobar_db
+ user: user
+ password: pass
+ host: localhost
+ port: 5432
+ records: 1000
+ retry: 2
+repository:
+ database: foobar_db
+ user: user
+ password: pass
+ host: localhost
+ port: 5432
+snapshot:
+ database: foobar_db
+ user: user
+ password: pass
+ host: localhost
+ port: 5432
+saga:
+ storage:
+ path: "./foobar.lmdb"
+discovery:
+ client: minos.networks.InMemoryDiscoveryClient
+ host: localhost
+ port: 5567
+```
+
+
+
+Here is the `foobar/main.py` source file:
+
+ Click to show the full file
+
+```python
+from __future__ import annotations
+
+from pathlib import Path
+from uuid import UUID
+
+from minos.aggregate import Aggregate, RootEntity
+from minos.common import EntrypointLauncher
+from minos.cqrs import CommandService
+from minos.networks import Request, Response, enroute
+
+
+class FooBar(RootEntity):
+ """FooBar Root Entity clas."""
+
+ something: str
+
+
+class FooBarAggregate(Aggregate[FooBar]):
+ """FooBar Aggregate class."""
+
+ @staticmethod
+ async def create_foobar(something: str) -> UUID:
+ """Create a new ``FooBar`` instance.
+
+ :param something: The something attribute.
+ :return: The identifier of the new instance.
+ """
+ foobar = await FooBar.create(something)
+ return foobar.uuid
+
+
+class FooBarCommandService(CommandService):
+ """Foo Command Service class."""
+
+ @enroute.broker.command("CreateFooBar")
+ async def create_foobar(self, request: Request) -> Response:
+ """Create a new FooBar.
+
+ :param request: The ``Request`` that contains the ``something`` attribute.
+ :return: A ``Response`` containing identifier of the already created instance.
+ """
+ content = await request.content()
+ something = content["text"]
+
+ uuid = await FooBarAggregate.create_foobar(something)
+
+ return Response(uuid)
+
+
+if __name__ == '__main__':
+ launcher = EntrypointLauncher.from_config(Path(__file__).parent / "config.yml")
+ launcher.launch()
+
+```
+
+
+
+Execute the following command to start the `foobar` microservice:
+
+```shell
+python foobar/main.py
+```
+
+To check that everything works fine, execute the following command:
+
+```shell
+curl --location --request POST 'http://localhost:4545/foos/add-foobar' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+ "uuid": "YOUR_UUID",
+ "something": "something"
+}'
+```
+
+This request will start a new Saga, that sends a command to the `foobar` microservice, retrieve the `FooBar` identifier and update the `Foo` instance. After that, the `FooQueryService` will handle the update event and print a message similar to this one on the console.
+
+```
+The 'foobar' field of a Foo was updated: Event(...)
+```
## Packages
@@ -34,24 +1096,32 @@ This project follows a modular structure based on python packages.
The core packages provide the base implementation of the framework.
* [minos-microservice-aggregate](https://minos-framework.github.io/minos-python/packages/core/minos-microservice-aggregate): The Aggregate pattern implementation.
-* [minos-microservice-common](https://minos-framework.github.io/minos-python/packages/core/minos-microservice-common): The common core.
+* [minos-microservice-common](https://minos-framework.github.io/minos-python/packages/core/minos-microservice-common): The common core package.
* [minos-microservice-cqrs](https://minos-framework.github.io/minos-python/packages/core/minos-microservice-cqrs): The CQRS pattern implementation.
-* [minos-microservice-networks](https://minos-framework.github.io/minos-python/packages/core/minos-microservice-networks): The networks core.
+* [minos-microservice-networks](https://minos-framework.github.io/minos-python/packages/core/minos-microservice-networks): The networks core package.
* [minos-microservice-saga](https://minos-framework.github.io/minos-python/packages/core/minos-microservice-saga): The SAGA pattern implementation.
### Plugins
-The plugin packages provide connectors to external technologies like brokers, discovery services, databases, serializers and so on.
+The plugin packages provide connectors to external technologies like brokers, discovery services, databases, serializers and so on.
+
+* [minos-broker-kafka](https://minos-framework.github.io/minos-python/packages/plugins/minos-broker-kafka): The `kafka` plugin package.
+* [minos-discovery-minos](https://minos-framework.github.io/minos-python/packages/plugins/minos-discovery-minos): The `minos-discovery` plugin package.
+
+## Documentation
+
+The official API Reference is publicly available at the [GitHub Pages](https://minos-framework.github.io/minos-python).
## Source Code
-The source code of this project is hosted at [GitHub](https://github.com/minos-framework/minos-python).
+The source code of this project is hosted at the [GitHub Repository](https://github.com/minos-framework/minos-python).
## Getting Help
For usage questions, the best place to go to is [StackOverflow](https://stackoverflow.com/questions/tagged/minos).
## Discussion and Development
+
Most development discussions take place over the [GitHub Issues](https://github.com/minos-framework/minos-python/issues). In addition, a [Gitter channel](https://gitter.im/minos-framework/community) is available for development-related questions.
## How to contribute
diff --git a/packages/core/minos-microservice-aggregate/.pre-commit-config.yaml b/packages/core/minos-microservice-aggregate/.pre-commit-config.yaml
deleted file mode 100644
index 2b944a41d..000000000
--- a/packages/core/minos-microservice-aggregate/.pre-commit-config.yaml
+++ /dev/null
@@ -1,39 +0,0 @@
-default_stages: [ push ]
-repos:
- - repo: local
- hooks:
- - id: install
- pass_filenames: false
- name: Install dependencies
- entry: make install
- language: system
-
- - id: reformat
- pass_filenames: false
- name: Reformat package
- entry: make reformat
- language: system
-
- - id: lint
- pass_filenames: false
- name: Lint package
- entry: make lint
- language: system
-
- - id: test
- pass_filenames: false
- name: Test package
- entry: make test
- language: system
-
- - id: docs
- pass_filenames: false
- name: Generate documentation
- entry: make docs
- language: system
-
- - id: build
- pass_filenames: false
- entry: make dist
- name: Generate build
- language: system
diff --git a/packages/core/minos-microservice-aggregate/HISTORY.md b/packages/core/minos-microservice-aggregate/HISTORY.md
index 305a48804..7c9707bce 100644
--- a/packages/core/minos-microservice-aggregate/HISTORY.md
+++ b/packages/core/minos-microservice-aggregate/HISTORY.md
@@ -50,3 +50,18 @@
* Be compatible with `minos-microservice-common~=0.4.0`.
* Be compatible with `minos-microservice-networks~=0.4.0`.
+
+## 0.4.1 (2022-01-31)
+
+* Update `README.md`.
+
+
+## 0.5.0 (2022-02-03)
+
+* Rename `Aggregate` as `RootEntity`.
+* Rename `AggregateRef` as `ExternalEntity`.
+* Rename `ModelRef` as `Ref`.
+* Rename `AggregateDiff` as `Event`.
+* Create the `Aggregate` base class, with the purpose to move the business logic from the `minos.cqrs.CommandService` to this brand-new class.
+* Refactor internal module hierarchy.
+* Minor changes.
\ No newline at end of file
diff --git a/packages/core/minos-microservice-aggregate/Makefile b/packages/core/minos-microservice-aggregate/Makefile
index 9b3b57da2..854bc90bc 100644
--- a/packages/core/minos-microservice-aggregate/Makefile
+++ b/packages/core/minos-microservice-aggregate/Makefile
@@ -32,3 +32,11 @@ install:
update:
poetry update
+
+check:
+ $(MAKE) install
+ $(MAKE) reformat
+ $(MAKE) lint
+ $(MAKE) test
+ $(MAKE) docs
+ $(MAKE) dist
diff --git a/packages/core/minos-microservice-aggregate/README.md b/packages/core/minos-microservice-aggregate/README.md
index 709e5499a..3e13dd2b3 100644
--- a/packages/core/minos-microservice-aggregate/README.md
+++ b/packages/core/minos-microservice-aggregate/README.md
@@ -1,7 +1,16 @@
-# Minos Microservice Aggregate
+
+
+
-[](https://codecov.io/gh/Clariteia/minos_microservice_aggregate)
-
+## minos-microservice-aggregate
+
+[](https://pypi.org/project/minos-microservice-aggregate/)
+[](https://minos-framework.github.io/minos-python)
+[](https://github.com/minos-framework/minos-python/blob/main/LICENSE)
+[](https://codecov.io/gh/minos-framework/minos-python)
+[](https://stackoverflow.com/questions/tagged/minos)
+
+## Summary
Minos is a framework which helps you create [reactive](https://www.reactivemanifesto.org/) microservices in Python.
Internally, it leverages Event Sourcing, CQRS and a message driven architecture to fulfil the commitments of an
@@ -9,76 +18,19 @@ asynchronous environment.
## Documentation
-The official documentation as well as the API you can find it under https://clariteia.github.io/minos_microservice_aggregate/.
-Please, submit any issue regarding documentation as well!
-
-## Set up a development environment
-
-Minos uses `poetry` as its default package manager. Please refer to the
-[Poetry installation guide](https://python-poetry.org/docs/#installation) for instructions on how to install it.
-
-Now you con install all the dependencies by running
-```bash
-make install
-```
-
-In order to make the pre-commits checks available to git, run
-```bash
-pre-commit install
-```
-
-Make yourself sure you are able to run the tests. Refer to the appropriate section in this guide.
-
-## Run the tests
-
-In order to run the tests, please make sure you have the [Docker Engine](https://docs.docker.com/engine/install/)
-and [Docker Compose](https://docs.docker.com/compose/install/) installed.
-
-Move into `tests/` directory
-
-```bash
-cd tests/
-```
-Run service dependencies:
-
-```bash
-docker-compose up -d
-```
-
-Install library dependencies:
-
-```bash
-make install
-```
-
-Run tests:
-
-```bash
-make test
-```
-
-## How to contribute
-
-Minos being an open-source project, we are looking forward to having your contributions. No matter whether it is a pull
-request with new features, or the creation of an issue related to a bug you have found.
-
-Please consider these guidelines before you submit any modification.
+The official API Reference is publicly available at the [GitHub Pages](https://minos-framework.github.io/minos-python).
-### Create an issue
+## Source Code
-1. If you happen to find a bug, please file a new issue filling the 'Bug report' template.
-2. Set the appropriate labels, so we can categorise it easily.
-3. Wait for any core developer's feedback on it.
+The source code of this project is hosted at the [GitHub Repository](https://github.com/minos-framework/minos-python).
-### Submit a Pull Request
+## Getting Help
-1. Create an issue following the previous steps.
-2. Fork the project.
-3. Push your changes to a local branch.
-4. Run the tests!
-5. Submit a pull request from your fork's branch.
+For usage questions, the best place to go to is [StackOverflow](https://stackoverflow.com/questions/tagged/minos).
-## Credits
+## Discussion and Development
+Most development discussions take place over the [GitHub Issues](https://github.com/minos-framework/minos-python/issues). In addition, a [Gitter channel](https://gitter.im/minos-framework/community) is available for development-related questions.
-This package was created with [Cookiecutter](https://github.com/audreyr/cookiecutter) and the [Minos Package](https://github.com/Clariteia/minos-pypackage) project template.
+## License
+This project is distributed under the [MIT](https://raw.githubusercontent.com/minos-framework/minos-python/main/LICENSE) license.
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/__init__.py b/packages/core/minos-microservice-aggregate/minos/aggregate/__init__.py
index 869432819..7353aa527 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/__init__.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/__init__.py
@@ -1,22 +1,47 @@
__author__ = "Minos Framework Devs"
__email__ = "hey@minos.run"
-__version__ = "0.4.0"
+__version__ = "0.5.0"
+from .actions import (
+ Action,
+)
+from .aggregate import (
+ Aggregate,
+)
+from .collections import (
+ IncrementalSet,
+ IncrementalSetDiff,
+ IncrementalSetDiffEntry,
+)
from .contextvars import (
IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR,
)
+from .entities import (
+ Entity,
+ EntitySet,
+ ExternalEntity,
+ Ref,
+ RefExtractor,
+ RefInjector,
+ RefResolver,
+ RootEntity,
+)
from .events import (
+ Event,
EventEntry,
EventRepository,
+ FieldDiff,
+ FieldDiffContainer,
+ IncrementalFieldDiff,
InMemoryEventRepository,
PostgreSqlEventRepository,
)
from .exceptions import (
AggregateException,
- AggregateNotFoundException,
- DeletedAggregateException,
+ AlreadyDeletedException,
EventRepositoryConflictException,
EventRepositoryException,
+ NotFoundException,
SnapshotRepositoryConflictException,
SnapshotRepositoryException,
TransactionNotFoundException,
@@ -24,26 +49,6 @@
TransactionRepositoryException,
ValueObjectException,
)
-from .models import (
- Action,
- Aggregate,
- AggregateDiff,
- AggregateRef,
- Entity,
- EntitySet,
- FieldDiff,
- FieldDiffContainer,
- IncrementalFieldDiff,
- IncrementalSet,
- IncrementalSetDiff,
- IncrementalSetDiffEntry,
- ModelRef,
- ModelRefExtractor,
- ModelRefInjector,
- ModelRefResolver,
- ValueObject,
- ValueObjectSet,
-)
from .queries import (
Condition,
Ordering,
@@ -68,3 +73,7 @@
TransactionService,
TransactionStatus,
)
+from .value_objects import (
+ ValueObject,
+ ValueObjectSet,
+)
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/actions.py b/packages/core/minos-microservice-aggregate/minos/aggregate/actions.py
similarity index 100%
rename from packages/core/minos-microservice-aggregate/minos/aggregate/models/actions.py
rename to packages/core/minos-microservice-aggregate/minos/aggregate/actions.py
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/aggregate.py b/packages/core/minos-microservice-aggregate/minos/aggregate/aggregate.py
new file mode 100644
index 000000000..3fbce9609
--- /dev/null
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/aggregate.py
@@ -0,0 +1,111 @@
+from __future__ import (
+ annotations,
+)
+
+from typing import (
+ Generic,
+ TypeVar,
+ get_args,
+)
+
+from dependency_injector.wiring import (
+ Provide,
+ inject,
+)
+
+from minos.common import (
+ MinosConfig,
+ MinosSetup,
+ NotProvidedException,
+)
+
+from .entities import (
+ RootEntity,
+)
+from .events import (
+ EventRepository,
+)
+from .snapshots import (
+ SnapshotRepository,
+)
+from .transactions import (
+ TransactionRepository,
+)
+
+RT = TypeVar("RT", bound=RootEntity)
+
+
+class Aggregate(Generic[RT], MinosSetup):
+ """Base Service class"""
+
+ transaction_repository: TransactionRepository
+ event_repository: EventRepository
+ snapshot_repository: SnapshotRepository
+
+ def __init__(
+ self,
+ transaction_repository: TransactionRepository,
+ event_repository: EventRepository,
+ snapshot_repository: SnapshotRepository,
+ *args,
+ **kwargs,
+ ):
+ super().__init__(*args, **kwargs)
+ self._check_root()
+
+ self.transaction_repository = transaction_repository
+ self.event_repository = event_repository
+ self.snapshot_repository = snapshot_repository
+
+ @classmethod
+ def _from_config(cls, config: MinosConfig, **kwargs) -> Aggregate:
+ kwargs["transaction_repository"] = cls._get_transaction_repository(**kwargs)
+ kwargs["event_repository"] = cls._get_event_repository(**kwargs)
+ kwargs["snapshot_repository"] = cls._get_snapshot_repository(**kwargs)
+ return cls(**kwargs)
+
+ # noinspection PyUnusedLocal
+ @staticmethod
+ @inject
+ def _get_transaction_repository(
+ transaction_repository: TransactionRepository = Provide["transaction_repository"], **kwargs
+ ) -> TransactionRepository:
+ if transaction_repository is None or isinstance(transaction_repository, Provide):
+ raise NotProvidedException(f"A {TransactionRepository!r} object must be provided.")
+ return transaction_repository
+
+ # noinspection PyUnusedLocal
+ @staticmethod
+ @inject
+ def _get_event_repository(
+ event_repository: EventRepository = Provide["event_repository"], **kwargs
+ ) -> EventRepository:
+ if event_repository is None or isinstance(event_repository, Provide):
+ raise NotProvidedException(f"A {EventRepository!r} object must be provided.")
+ return event_repository
+
+ # noinspection PyUnusedLocal
+ @staticmethod
+ @inject
+ def _get_snapshot_repository(
+ snapshot_repository: SnapshotRepository = Provide["snapshot_repository"], **kwargs
+ ) -> SnapshotRepository:
+ if snapshot_repository is None or isinstance(snapshot_repository, Provide):
+ raise NotProvidedException(f"A {SnapshotRepository!r} object must be provided.")
+ return snapshot_repository
+
+ def _check_root(self):
+ self.root # If root is not valid it will raise an exception.
+
+ @property
+ def root(self) -> type[RootEntity]:
+ """Get the root entity of the aggregate.
+
+ :return: A ``RootEntity`` type.
+ """
+ # noinspection PyUnresolvedReferences
+ bases = self.__orig_bases__
+ root = get_args(bases[0])[0]
+ if not isinstance(root, type) or not issubclass(root, RootEntity):
+ raise TypeError(f"{type(self)!r} must contain a {RootEntity!r} as generic value.")
+ return root
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/collections.py b/packages/core/minos-microservice-aggregate/minos/aggregate/collections.py
similarity index 100%
rename from packages/core/minos-microservice-aggregate/minos/aggregate/models/collections.py
rename to packages/core/minos-microservice-aggregate/minos/aggregate/collections.py
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/entities/__init__.py b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/__init__.py
new file mode 100644
index 000000000..7be22cdf7
--- /dev/null
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/__init__.py
@@ -0,0 +1,14 @@
+from .collections import (
+ EntitySet,
+)
+from .models import (
+ Entity,
+ ExternalEntity,
+ RootEntity,
+)
+from .refs import (
+ Ref,
+ RefExtractor,
+ RefInjector,
+ RefResolver,
+)
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/entities.py b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/collections.py
similarity index 93%
rename from packages/core/minos-microservice-aggregate/minos/aggregate/models/entities.py
rename to packages/core/minos-microservice-aggregate/minos/aggregate/entities/collections.py
index ed77886eb..f68273ced 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/models/entities.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/collections.py
@@ -16,9 +16,12 @@
)
from uuid import (
UUID,
- uuid4,
)
+from minos.aggregate.collections import (
+ IncrementalSet,
+ IncrementalSetDiff,
+)
from minos.common import (
DataDecoder,
DataEncoder,
@@ -28,23 +31,6 @@
SchemaEncoder,
)
-from .collections import (
- IncrementalSet,
- IncrementalSetDiff,
-)
-
-
-class Entity(DeclarativeModel):
- """Entity class ."""
-
- uuid: UUID
-
- def __init__(self, *args, uuid: Optional[UUID] = None, **kwargs):
- if uuid is None:
- uuid = uuid4()
- super().__init__(uuid, *args, **kwargs)
-
-
T = TypeVar("T", bound=Model)
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/aggregates.py b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/models.py
similarity index 74%
rename from packages/core/minos-microservice-aggregate/minos/aggregate/models/aggregates.py
rename to packages/core/minos-microservice-aggregate/minos/aggregate/entities/models.py
index 937644b85..0cd08fb34 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/models/aggregates.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/models.py
@@ -14,6 +14,7 @@
)
from uuid import (
UUID,
+ uuid4,
)
from dependency_injector.wiring import (
@@ -21,39 +22,54 @@
inject,
)
-from minos.common import (
- NULL_DATETIME,
- NULL_UUID,
- NotProvidedException,
-)
-
-from ..events import (
+from minos.aggregate.events import (
+ Event,
EventEntry,
EventRepository,
+ IncrementalFieldDiff,
)
-from ..exceptions import (
+from minos.aggregate.exceptions import (
EventRepositoryException,
)
-from ..queries import (
+from minos.aggregate.queries import (
_Condition,
_Ordering,
)
-from ..snapshots import (
+from minos.aggregate.snapshots import (
SnapshotRepository,
)
-from .diffs import (
- AggregateDiff,
- IncrementalFieldDiff,
-)
-from .entities import (
- Entity,
+from minos.common import (
+ NULL_DATETIME,
+ NULL_UUID,
+ DeclarativeModel,
+ NotProvidedException,
)
logger = logging.getLogger(__name__)
-class Aggregate(Entity):
- """Base aggregate class."""
+class Entity(DeclarativeModel):
+ """Entity class."""
+
+ uuid: UUID
+
+ def __init__(self, *args, uuid: Optional[UUID] = None, **kwargs):
+ if uuid is None:
+ uuid = uuid4()
+ super().__init__(uuid, *args, **kwargs)
+
+
+class ExternalEntity(Entity):
+ """External Entity class."""
+
+ version: int
+
+ def __init__(self, uuid: UUID, *args, **kwargs):
+ super().__init__(uuid=uuid, *args, **kwargs)
+
+
+class RootEntity(Entity):
+ """Base Root Entity class."""
version: int
created_at: datetime
@@ -90,8 +106,8 @@ async def get(
"""Get one instance from the database based on its identifier.
:param uuid: The identifier of the instance.
- :param _snapshot: Snapshot to be set to the aggregate.
- :return: A list of aggregate instances.
+ :param _snapshot: Snapshot to be set to the root entity.
+ :return: A ``RootEntity`` instance.
"""
if _snapshot is None or isinstance(_snapshot, Provide):
raise NotProvidedException("A snapshot instance is required.")
@@ -116,25 +132,24 @@ async def find(
is to retrieve them without any order pattern.
:param limit: Optional argument to return only a subset of instances. The default behaviour is to return all the
instances that meet the given condition.
- :param _snapshot: Snapshot to be set to the aggregate.
- :return: A list of aggregate instances.
- :return: An aggregate instance.
+ :param _snapshot: Snapshot to be set to the instances.
+ :return: An asynchronous iterator of ``RootEntity`` instances.
"""
if _snapshot is None or isinstance(_snapshot, Provide):
raise NotProvidedException("A snapshot instance is required.")
# noinspection PyTypeChecker
iterable = _snapshot.find(cls.classname, condition, ordering, limit, _snapshot=_snapshot, **kwargs)
# noinspection PyTypeChecker
- async for aggregate in iterable:
- yield aggregate
+ async for instance in iterable:
+ yield instance
@classmethod
async def create(cls: Type[T], *args, **kwargs) -> T:
- """Create a new ``Aggregate`` instance.
+ """Create a new ``RootEntity`` instance.
:param args: Additional positional arguments.
:param kwargs: Additional named arguments.
- :return: A new ``Aggregate`` instance.
+ :return: A new ``RootEntity`` instance.
"""
if "uuid" in kwargs:
raise EventRepositoryException(
@@ -155,8 +170,8 @@ async def create(cls: Type[T], *args, **kwargs) -> T:
instance: T = cls(*args, **kwargs)
- aggregate_diff = AggregateDiff.from_aggregate(instance)
- entry = await instance._repository.submit(aggregate_diff)
+ event = Event.from_root_entity(instance)
+ entry = await instance._repository.submit(event)
instance._update_from_repository_entry(entry)
@@ -164,10 +179,10 @@ async def create(cls: Type[T], *args, **kwargs) -> T:
# noinspection PyMethodParameters,PyShadowingBuiltins
async def update(self: T, **kwargs) -> T:
- """Update an existing ``Aggregate`` instance.
+ """Update an existing ``RootEntity`` instance.
:param kwargs: Additional named arguments.
- :return: An updated ``Aggregate`` instance.
+ :return: An updated ``RootEntity`` instance.
"""
if "version" in kwargs:
@@ -187,11 +202,11 @@ async def update(self: T, **kwargs) -> T:
setattr(self, key, value)
previous = await self.get(self.uuid, _repository=self._repository, _snapshot=self._snapshot)
- aggregate_diff = self.diff(previous)
- if not len(aggregate_diff.fields_diff):
+ event = self.diff(previous)
+ if not len(event.fields_diff):
return self
- entry = await self._repository.submit(aggregate_diff)
+ entry = await self._repository.submit(event)
self._update_from_repository_entry(entry)
@@ -233,46 +248,45 @@ async def refresh(self) -> None:
self._fields |= new.fields
async def delete(self) -> None:
- """Delete the given aggregate instance.
+ """Delete the given root entity instance.
:return: This method does not return anything.
"""
- aggregate_diff = AggregateDiff.from_deleted_aggregate(self)
- entry = await self._repository.submit(aggregate_diff)
+ event = Event.from_deleted_root_entity(self)
+ entry = await self._repository.submit(event)
self._update_from_repository_entry(entry)
def _update_from_repository_entry(self, entry: EventEntry) -> None:
- self.uuid = entry.aggregate_uuid
+ self.uuid = entry.uuid
self.version = entry.version
if entry.action.is_create:
self.created_at = entry.created_at
self.updated_at = entry.created_at
- def diff(self, another: Aggregate) -> AggregateDiff:
- """Compute the difference with another aggregate.
+ def diff(self, another: RootEntity) -> Event:
+ """Compute the difference with another instance.
- Both ``Aggregate`` instances (``self`` and ``another``) must share the same ``uuid`` value.
+ Both ``RootEntity`` instances (``self`` and ``another``) must share the same ``uuid`` value.
- :param another: Another ``Aggregate`` instance.
+ :param another: Another ``RootEntity`` instance.
:return: An ``FieldDiffContainer`` instance.
"""
- return AggregateDiff.from_difference(self, another)
+ return Event.from_difference(self, another)
- def apply_diff(self, aggregate_diff: AggregateDiff) -> None:
+ def apply_diff(self, event: Event) -> None:
"""Apply the differences over the instance.
- :param aggregate_diff: The ``FieldDiffContainer`` containing the values to be set.
+ :param event: The ``FieldDiffContainer`` containing the values to be set.
:return: This method does not return anything.
"""
- if self.uuid != aggregate_diff.uuid:
+ if self.uuid != event.uuid:
raise ValueError(
- f"To apply the difference, it must have same uuid. "
- f"Expected: {self.uuid!r} Obtained: {aggregate_diff.uuid!r}"
+ f"To apply the difference, it must have same uuid. " f"Expected: {self.uuid!r} Obtained: {event.uuid!r}"
)
- logger.debug(f"Applying {aggregate_diff!r} to {self!r}...")
- for diff in aggregate_diff.fields_diff.flatten_values():
+ logger.debug(f"Applying {event!r} to {self!r}...")
+ for diff in event.fields_diff.flatten_values():
if isinstance(diff, IncrementalFieldDiff):
container = getattr(self, diff.name)
if diff.action.is_delete:
@@ -281,27 +295,27 @@ def apply_diff(self, aggregate_diff: AggregateDiff) -> None:
container.add(diff.value)
else:
setattr(self, diff.name, diff.value)
- self.version = aggregate_diff.version
- self.updated_at = aggregate_diff.created_at
+ self.version = event.version
+ self.updated_at = event.created_at
@classmethod
- def from_diff(cls: Type[T], aggregate_diff: AggregateDiff, *args, **kwargs) -> T:
- """Build a new instance from an ``AggregateDiff``.
+ def from_diff(cls: Type[T], event: Event, *args, **kwargs) -> T:
+ """Build a new instance from an ``Event``.
- :param aggregate_diff: The difference that contains the data.
+ :param event: The difference that contains the data.
:param args: Additional positional arguments.
:param kwargs: Additional named arguments.
- :return: A new ``Aggregate`` instance.
+ :return: A new ``RootEntity`` instance.
"""
return cls(
*args,
- uuid=aggregate_diff.uuid,
- version=aggregate_diff.version,
- created_at=aggregate_diff.created_at,
- updated_at=aggregate_diff.created_at,
- **aggregate_diff.get_all(),
+ uuid=event.uuid,
+ version=event.version,
+ created_at=event.created_at,
+ updated_at=event.created_at,
+ **event.get_all(),
**kwargs,
)
-T = TypeVar("T", bound=Aggregate)
+T = TypeVar("T", bound=RootEntity)
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/__init__.py b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/__init__.py
similarity index 51%
rename from packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/__init__.py
rename to packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/__init__.py
index e50c49696..2d0d3bffa 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/__init__.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/__init__.py
@@ -1,13 +1,12 @@
from .extractors import (
- ModelRefExtractor,
+ RefExtractor,
)
from .injectors import (
- ModelRefInjector,
+ RefInjector,
)
from .models import (
- AggregateRef,
- ModelRef,
+ Ref,
)
from .resolvers import (
- ModelRefResolver,
+ RefResolver,
)
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/extractors.py b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/extractors.py
similarity index 92%
rename from packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/extractors.py
rename to packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/extractors.py
index 1a4c39f4f..298727725 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/extractors.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/extractors.py
@@ -22,11 +22,11 @@
)
from .models import (
- ModelRef,
+ Ref,
)
-class ModelRefExtractor:
+class RefExtractor:
"""Model Reference Extractor class."""
def __init__(self, value: Any, type_: Optional[type] = None, as_uuids: bool = True):
@@ -49,9 +49,9 @@ def build(self) -> dict[str, set[UUID]]:
return ans
- def _build(self, value: Any, type_: type, ans: dict[str, set[ModelRef]]) -> None:
+ def _build(self, value: Any, type_: type, ans: dict[str, set[Ref]]) -> None:
if get_origin(type_) is Union:
- type_ = next((t for t in get_args(type_) if get_origin(t) is ModelRef), type_)
+ type_ = next((t for t in get_args(type_) if get_origin(t) is Ref), type_)
if isinstance(value, (tuple, list, set)):
self._build_iterable(value, get_args(type_)[0], ans)
@@ -60,7 +60,7 @@ def _build(self, value: Any, type_: type, ans: dict[str, set[ModelRef]]) -> None
self._build_iterable(value.keys(), get_args(type_)[0], ans)
self._build_iterable(value.values(), get_args(type_)[1], ans)
- elif isinstance(value, ModelRef):
+ elif isinstance(value, Ref):
cls = value.data_cls or get_args(type_)[0]
name = cls.__name__
ans[name].add(value)
@@ -70,6 +70,6 @@ def _build(self, value: Any, type_: type, ans: dict[str, set[ModelRef]]) -> None
for field in value.fields.values():
self._build(field.value, field.type, ans)
- def _build_iterable(self, value: Iterable, value_: type, ans: dict[str, set[ModelRef]]) -> None:
+ def _build_iterable(self, value: Iterable, value_: type, ans: dict[str, set[Ref]]) -> None:
for sub_value in value:
self._build(sub_value, value_, ans)
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/injectors.py b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/injectors.py
similarity index 97%
rename from packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/injectors.py
rename to packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/injectors.py
index f36214f74..06ed13f7a 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/injectors.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/injectors.py
@@ -11,7 +11,7 @@
)
-class ModelRefInjector:
+class RefInjector:
"""Model Reference Injector class."""
def __init__(self, value: Any, mapper: dict[UUID, Model]):
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/models.py b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/models.py
similarity index 94%
rename from packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/models.py
rename to packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/models.py
index 31a9c86e2..6f3bb1f6b 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/models.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/models.py
@@ -20,6 +20,9 @@
inject,
)
+from minos.aggregate.contextvars import (
+ IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR,
+)
from minos.common import (
DataDecoder,
DataEncoder,
@@ -36,26 +39,10 @@
BrokerMessageV1Payload,
)
-from ...contextvars import (
- IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR,
-)
-from ..entities import (
- Entity,
-)
-
MT = TypeVar("MT", bound=Model)
-class AggregateRef(Entity):
- """Aggregate Ref class."""
-
- version: int
-
- def __init__(self, uuid: UUID, *args, **kwargs):
- super().__init__(uuid=uuid, *args, **kwargs)
-
-
-class ModelRef(DeclarativeModel, UUID, Generic[MT]):
+class Ref(DeclarativeModel, UUID, Generic[MT]):
"""Model Reference."""
data: Union[MT, UUID]
@@ -131,7 +118,7 @@ def encode_data(encoder: DataEncoder, target: Any, **kwargs) -> Any:
return encoder.build(target, **kwargs)
@classmethod
- def decode_data(cls, decoder: DataDecoder, target: Any, type_: ModelType, **kwargs) -> ModelRef:
+ def decode_data(cls, decoder: DataDecoder, target: Any, type_: ModelType, **kwargs) -> Ref:
"""Decode data with the given decoder.
:param decoder: The decoder instance.
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/resolvers.py b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/resolvers.py
similarity index 87%
rename from packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/resolvers.py
rename to packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/resolvers.py
index 5bd227148..72b51fccd 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/models/refs/resolvers.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/entities/refs/resolvers.py
@@ -30,15 +30,15 @@
)
from .extractors import (
- ModelRefExtractor,
+ RefExtractor,
)
from .injectors import (
- ModelRefInjector,
+ RefInjector,
)
-class ModelRefResolver:
- """ModelRef Resolver class."""
+class RefResolver:
+ """Ref Resolver class."""
# noinspection PyUnusedLocal
@inject
@@ -47,20 +47,20 @@ def __init__(self, broker_pool: BrokerClientPool = Provide["broker_pool"], **kwa
# noinspection PyUnusedLocal
async def resolve(self, data: Any, **kwargs) -> Any:
- """Resolve ModelRef instances.
+ """Resolve Ref instances.
:param data: The data to be resolved.
:param kwargs: Additional named arguments.
:return: The data instance with model references already resolved.
"""
- missing = ModelRefExtractor(data).build()
+ missing = RefExtractor(data).build()
if not len(missing):
return data
recovered = await self._query(missing)
- return ModelRefInjector(data, recovered).build()
+ return RefInjector(data, recovered).build()
async def _query(self, references: dict[str, set[UUID]]) -> dict[UUID, Model]:
async with self.broker_pool.acquire() as broker:
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/events/__init__.py b/packages/core/minos-microservice-aggregate/minos/aggregate/events/__init__.py
index 641eb9679..7dcf102ef 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/events/__init__.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/events/__init__.py
@@ -1,6 +1,14 @@
from .entries import (
EventEntry,
)
+from .fields import (
+ FieldDiff,
+ FieldDiffContainer,
+ IncrementalFieldDiff,
+)
+from .models import (
+ Event,
+)
from .repositories import (
EventRepository,
InMemoryEventRepository,
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/events/entries.py b/packages/core/minos-microservice-aggregate/minos/aggregate/events/entries.py
index 57eaf6cf7..2d33a57f7 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/events/entries.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/events/entries.py
@@ -10,7 +10,6 @@
Any,
Iterable,
Optional,
- Type,
Union,
)
from uuid import (
@@ -22,12 +21,19 @@
import_module,
)
+from ..actions import (
+ Action,
+)
+from .fields import (
+ FieldDiffContainer,
+)
+from .models import (
+ Event,
+)
+
if TYPE_CHECKING:
- from ..models import (
- Action,
- Aggregate,
- AggregateDiff,
- FieldDiffContainer,
+ from ..entities import (
+ RootEntity,
)
from ..transactions import (
TransactionEntry,
@@ -35,11 +41,11 @@
class EventEntry:
- """Class that represents an entry (or row) on the events repository database which stores the aggregate changes."""
+ """Class that represents an entry (or row) on the event repository database which stores the root entity changes."""
__slots__ = (
- "aggregate_uuid",
- "aggregate_name",
+ "uuid",
+ "name",
"version",
"data",
"id",
@@ -51,8 +57,8 @@ class EventEntry:
# noinspection PyShadowingBuiltins
def __init__(
self,
- aggregate_uuid: UUID,
- aggregate_name: str,
+ uuid: UUID,
+ name: str,
version: Optional[int] = None,
data: Union[bytes, memoryview] = bytes(),
id: Optional[int] = None,
@@ -63,14 +69,10 @@ def __init__(
if isinstance(data, memoryview):
data = data.tobytes()
if action is not None and isinstance(action, str):
- from ..models import (
- Action,
- )
-
action = Action.value_of(action)
- self.aggregate_uuid = aggregate_uuid
- self.aggregate_name = aggregate_name
+ self.uuid = uuid
+ self.name = name
self.version = version
self.data = data
@@ -80,12 +82,10 @@ def __init__(
self.transaction_uuid = transaction_uuid
@classmethod
- def from_aggregate_diff(
- cls, aggregate_diff: AggregateDiff, *, transaction: Optional[TransactionEntry] = None, **kwargs
- ) -> EventEntry:
- """Build a new instance from an ``Aggregate``.
+ def from_event(cls, event: Event, *, transaction: Optional[TransactionEntry] = None, **kwargs) -> EventEntry:
+ """Build a new instance from a ``RootEntity``.
- :param aggregate_diff: The aggregate difference.
+ :param event: The event.
:param transaction: Optional transaction.
:param kwargs: Additional named arguments.
:return: A new ``EventEntry`` instance.
@@ -95,10 +95,10 @@ def from_aggregate_diff(
# noinspection PyTypeChecker
return cls(
- aggregate_uuid=aggregate_diff.uuid,
- aggregate_name=aggregate_diff.name,
- data=aggregate_diff.fields_diff.avro_bytes,
- action=aggregate_diff.action,
+ uuid=event.uuid,
+ name=event.name,
+ data=event.fields_diff.avro_bytes,
+ action=event.action,
**kwargs,
)
@@ -118,8 +118,8 @@ def as_raw(self) -> dict[str, Any]:
:return: A dictionary in which the keys are attribute names and values the attribute contents.
"""
return {
- "aggregate_uuid": self.aggregate_uuid,
- "aggregate_name": self.aggregate_name,
+ "uuid": self.uuid,
+ "name": self.name,
"version": self.version,
"data": self.data,
"id": self.id,
@@ -129,27 +129,23 @@ def as_raw(self) -> dict[str, Any]:
}
@property
- def aggregate_cls(self) -> Type[Aggregate]:
- """Load the concrete ``Aggregate`` class.
+ def type_(self) -> type[RootEntity]:
+ """Load the concrete ``RootEntity`` class.
:return: A ``Type`` object.
"""
# noinspection PyTypeChecker
- return import_module(self.aggregate_name)
+ return import_module(self.name)
@property
- def aggregate_diff(self) -> AggregateDiff:
- """Get the stored ``AggregateDiff`` instance.
+ def event(self) -> Event:
+ """Get the stored ``Event`` instance.
- :return: An ``AggregateDiff`` instance.
+ :return: An ``Event`` instance.
"""
- from ..models import (
- AggregateDiff,
- )
-
- return AggregateDiff(
- self.aggregate_uuid,
- self.aggregate_name,
+ return Event(
+ self.uuid,
+ self.name,
self.version,
self.action,
self.created_at,
@@ -162,10 +158,6 @@ def field_diff_container(self) -> FieldDiffContainer:
:return: A ``FieldDiffContainer`` instance.
"""
- from ..models import (
- FieldDiffContainer,
- )
-
if not self.data:
return FieldDiffContainer.empty()
@@ -179,8 +171,8 @@ def __hash__(self) -> int:
def __iter__(self) -> Iterable:
yield from (
- self.aggregate_uuid,
- self.aggregate_name,
+ self.uuid,
+ self.name,
self.version,
self.data,
self.id,
@@ -192,7 +184,7 @@ def __iter__(self) -> Iterable:
def __repr__(self):
return (
f"{type(self).__name__}("
- f"aggregate_uuid={self.aggregate_uuid!r}, aggregate_name={self.aggregate_name!r}, "
+ f"uuid={self.uuid!r}, name={self.name!r}, "
f"version={self.version!r}, len(data)={len(self.data)!r}, "
f"id={self.id!r}, action={self.action!r}, created_at={self.created_at!r}, "
f"transaction_uuid={self.transaction_uuid!r})"
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/diffs/fields.py b/packages/core/minos-microservice-aggregate/minos/aggregate/events/fields.py
similarity index 98%
rename from packages/core/minos-microservice-aggregate/minos/aggregate/models/diffs/fields.py
rename to packages/core/minos-microservice-aggregate/minos/aggregate/events/fields.py
index c55af6a21..14eb43938 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/models/diffs/fields.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/events/fields.py
@@ -22,6 +22,12 @@
uuid4,
)
+from minos.aggregate.actions import (
+ Action,
+)
+from minos.aggregate.collections import (
+ IncrementalSet,
+)
from minos.common import (
BucketModel,
Field,
@@ -29,13 +35,6 @@
ModelType,
)
-from ..actions import (
- Action,
-)
-from ..collections import (
- IncrementalSet,
-)
-
logger = logging.getLogger(__name__)
T = TypeVar("T")
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/diffs/aggregates.py b/packages/core/minos-microservice-aggregate/minos/aggregate/events/models.py
similarity index 61%
rename from packages/core/minos-microservice-aggregate/minos/aggregate/models/diffs/aggregates.py
rename to packages/core/minos-microservice-aggregate/minos/aggregate/events/models.py
index f0a1e69e3..ecf7afd30 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/models/diffs/aggregates.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/events/models.py
@@ -21,29 +21,29 @@
UUID,
)
+from minos.aggregate.actions import (
+ Action,
+)
from minos.common import (
DeclarativeModel,
)
-from ..actions import (
- Action,
-)
from .fields import (
FieldDiff,
FieldDiffContainer,
)
if TYPE_CHECKING:
- from ..aggregates import (
- Aggregate,
+ from minos.aggregate.entities import (
+ RootEntity,
)
logger = logging.getLogger(__name__)
@total_ordering
-class AggregateDiff(DeclarativeModel):
- """Aggregate Diff class."""
+class Event(DeclarativeModel):
+ """Event class."""
uuid: UUID
name: str
@@ -55,7 +55,7 @@ class AggregateDiff(DeclarativeModel):
@property
def simplified_name(self) -> str:
- """Get the Aggregate's simplified name.
+ """Get the RootEntity's simplified name.
:return: An string value.
"""
@@ -95,20 +95,19 @@ def get_all(self, return_diff: bool = False) -> dict[str, Union[FieldDiff, Any,
return self.fields_diff.get_all(return_diff)
@classmethod
- def from_difference(cls, a: Aggregate, b: Aggregate, action: Action = Action.UPDATE) -> AggregateDiff:
- """Build an ``AggregateDiff`` instance from the difference of two aggregates.
+ def from_difference(cls, a: RootEntity, b: RootEntity, action: Action = Action.UPDATE) -> Event:
+ """Build an ``Event`` instance from the difference of two instances.
- :param a: One ``Aggregate`` instance.
- :param b: Another ``Aggregate`` instance.
- :param action: The action to that generates the aggregate difference.
- :return: An ``AggregateDiff`` instance.
+ :param a: One ``RootEntity`` instance.
+ :param b: Another ``RootEntity`` instance.
+ :param action: The action that generates the ``RootEntity`` difference.
+ :return: An ``Event`` instance.
"""
logger.debug(f"Computing the {cls!r} between {a!r} and {b!r}...")
if a.uuid != b.uuid:
raise ValueError(
- f"To compute aggregate differences, both arguments must have same identifier. "
- f"Obtained: {a.uuid!r} vs {b.uuid!r}"
+ f"To compute differences, both arguments must have same identifier. Obtained: {a.uuid!r} vs {b.uuid!r}"
)
old, new = sorted([a, b], key=attrgetter("version"))
@@ -125,45 +124,45 @@ def from_difference(cls, a: Aggregate, b: Aggregate, action: Action = Action.UPD
)
@classmethod
- def from_aggregate(cls, aggregate: Aggregate, action: Action = Action.CREATE) -> AggregateDiff:
- """Build an ``AggregateDiff`` from an ``Aggregate`` (considering all fields as differences).
+ def from_root_entity(cls, instance: RootEntity, action: Action = Action.CREATE) -> Event:
+ """Build an ``Event`` from a ``RootEntity`` (considering all fields as differences).
- :param aggregate: An ``Aggregate`` instance.
- :param action: The action to that generates the aggregate difference.
- :return: An ``AggregateDiff`` instance.
+ :param instance: A ``RootEntity`` instance.
+ :param action: The action that generates the event.
+ :return: An ``Event`` instance.
"""
- fields_diff = FieldDiffContainer.from_model(aggregate, ignore={"uuid", "version", "created_at", "updated_at"})
+ fields_diff = FieldDiffContainer.from_model(instance, ignore={"uuid", "version", "created_at", "updated_at"})
return cls(
- uuid=aggregate.uuid,
- name=aggregate.classname,
- version=aggregate.version,
+ uuid=instance.uuid,
+ name=instance.classname,
+ version=instance.version,
action=action,
- created_at=aggregate.updated_at,
+ created_at=instance.updated_at,
fields_diff=fields_diff,
)
@classmethod
- def from_deleted_aggregate(cls, aggregate: Aggregate, action: Action = Action.DELETE) -> AggregateDiff:
- """Build an ``AggregateDiff`` from an ``Aggregate`` (considering all fields as differences).
+ def from_deleted_root_entity(cls, instance: RootEntity, action: Action = Action.DELETE) -> Event:
+ """Build an ``Event`` from a ``RootEntity`` (considering all fields as differences).
- :param aggregate: An ``Aggregate`` instance.
- :param action: The action to that generates the aggregate difference.
- :return: An ``AggregateDiff`` instance.
+ :param instance: A ``RootEntity`` instance.
+ :param action: The action that generates the event.
+ :return: An ``Event`` instance.
"""
return cls(
- uuid=aggregate.uuid,
- name=aggregate.classname,
- version=aggregate.version,
+ uuid=instance.uuid,
+ name=instance.classname,
+ version=instance.version,
action=action,
- created_at=aggregate.updated_at,
+ created_at=instance.updated_at,
fields_diff=FieldDiffContainer.empty(),
)
- def decompose(self) -> list[AggregateDiff]:
- """Decompose AggregateDiff Fields into AggregateDiff with once Field.
+ def decompose(self) -> list[Event]:
+ """Decompose the ``Event`` fields into multiple ``Event`` instances with once Field.
- :return: An list of``AggregateDiff`` instances.
+ :return: An list of``Event`` instances.
"""
return [
type(self)(
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/events/repositories/abc.py b/packages/core/minos-microservice-aggregate/minos/aggregate/events/repositories/abc.py
index 36588812f..b42c67b88 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/events/repositories/abc.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/events/repositories/abc.py
@@ -13,7 +13,6 @@
suppress,
)
from typing import (
- TYPE_CHECKING,
AsyncIterator,
Awaitable,
Optional,
@@ -42,6 +41,9 @@
BrokerPublisher,
)
+from ...actions import (
+ Action,
+)
from ...contextvars import (
IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR,
)
@@ -58,11 +60,12 @@
from ..entries import (
EventEntry,
)
-
-if TYPE_CHECKING:
- from ...models import (
- AggregateDiff,
- )
+from ..fields import (
+ IncrementalFieldDiff,
+)
+from ..models import (
+ Event,
+)
class EventRepository(ABC, MinosSetup):
@@ -100,63 +103,50 @@ def transaction(self, **kwargs) -> TransactionEntry:
"""
return TransactionEntry(event_repository=self, transaction_repository=self._transaction_repository, **kwargs)
- async def create(self, entry: Union[AggregateDiff, EventEntry]) -> EventEntry:
+ async def create(self, entry: Union[Event, EventEntry]) -> EventEntry:
"""Store new creation entry into the repository.
:param entry: Entry to be stored.
:return: The repository entry containing the stored information.
"""
- from ...models import (
- Action,
- )
entry.action = Action.CREATE
return await self.submit(entry)
- async def update(self, entry: Union[AggregateDiff, EventEntry]) -> EventEntry:
+ async def update(self, entry: Union[Event, EventEntry]) -> EventEntry:
"""Store new update entry into the repository.
:param entry: Entry to be stored.
:return: The repository entry containing the stored information.
"""
- from ...models import (
- Action,
- )
entry.action = Action.UPDATE
return await self.submit(entry)
- async def delete(self, entry: Union[AggregateDiff, EventEntry]) -> EventEntry:
+ async def delete(self, entry: Union[Event, EventEntry]) -> EventEntry:
"""Store new deletion entry into the repository.
:param entry: Entry to be stored.
:return: The repository entry containing the stored information.
"""
- from ...models import (
- Action,
- )
entry.action = Action.DELETE
return await self.submit(entry)
- async def submit(self, entry: Union[AggregateDiff, EventEntry], **kwargs) -> EventEntry:
+ async def submit(self, entry: Union[Event, EventEntry], **kwargs) -> EventEntry:
"""Store new entry into the repository.
:param entry: The entry to be stored.
:param kwargs: Additional named arguments.
:return: The repository entry containing the stored information.
"""
- from ...models import (
- Action,
- AggregateDiff,
- )
token = IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR.set(True)
try:
transaction = TRANSACTION_CONTEXT_VAR.get()
- if isinstance(entry, AggregateDiff):
- entry = EventEntry.from_aggregate_diff(entry, transaction=transaction)
+ if isinstance(entry, Event):
+ entry = EventEntry.from_event(entry, transaction=transaction)
if not isinstance(entry.action, Action):
raise EventRepositoryException("The 'EventEntry.action' attribute must be an 'Action' instance.")
@@ -168,7 +158,7 @@ async def submit(self, entry: Union[AggregateDiff, EventEntry], **kwargs) -> Eve
entry = await self._submit(entry, **kwargs)
if entry.transaction_uuid == NULL_UUID:
- await self._send_events(entry.aggregate_diff)
+ await self._send_events(entry.event)
finally:
IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR.reset(token)
@@ -194,9 +184,7 @@ async def validate(self, entry: EventEntry, transaction_uuid_ne: Optional[UUID]
if len(transaction_uuids):
with suppress(StopAsyncIteration):
- iterable = self.select(
- aggregate_uuid=entry.aggregate_uuid, transaction_uuid_in=tuple(transaction_uuids), **kwargs
- )
+ iterable = self.select(uuid=entry.uuid, transaction_uuid_in=tuple(transaction_uuids), **kwargs)
await iterable.__anext__() # Will raise a `StopAsyncIteration` exception if not any item.
@@ -208,38 +196,30 @@ async def validate(self, entry: EventEntry, transaction_uuid_ne: Optional[UUID]
async def _submit(self, entry: EventEntry, **kwargs) -> EventEntry:
raise NotImplementedError
- async def _send_events(self, aggregate_diff: AggregateDiff):
- from ...models import (
- Action,
- )
-
+ async def _send_events(self, event: Event):
suffix_mapper = {
Action.CREATE: "Created",
Action.UPDATE: "Updated",
Action.DELETE: "Deleted",
}
- topic = f"{aggregate_diff.simplified_name}{suffix_mapper[aggregate_diff.action]}"
+ topic = f"{event.simplified_name}{suffix_mapper[event.action]}"
message = BrokerMessageV1(
topic=topic,
- payload=BrokerMessageV1Payload(content=aggregate_diff),
+ payload=BrokerMessageV1Payload(content=event),
strategy=BrokerMessageV1Strategy.MULTICAST,
)
futures = [self._broker_publisher.send(message)]
- if aggregate_diff.action == Action.UPDATE:
- from ...models import (
- IncrementalFieldDiff,
- )
-
- for decomposed_aggregate_diff in aggregate_diff.decompose():
- diff = next(iter(decomposed_aggregate_diff.fields_diff.flatten_values()))
+ if event.action == Action.UPDATE:
+ for decomposed_event in event.decompose():
+ diff = next(iter(decomposed_event.fields_diff.flatten_values()))
composed_topic = f"{topic}.{diff.name}"
if isinstance(diff, IncrementalFieldDiff):
composed_topic += f".{diff.action.value}"
message = BrokerMessageV1(
topic=composed_topic,
- payload=BrokerMessageV1Payload(content=decomposed_aggregate_diff),
+ payload=BrokerMessageV1Payload(content=decomposed_event),
strategy=BrokerMessageV1Strategy.MULTICAST,
)
futures.append(self._broker_publisher.send(message))
@@ -249,8 +229,8 @@ async def _send_events(self, aggregate_diff: AggregateDiff):
# noinspection PyShadowingBuiltins
async def select(
self,
- aggregate_uuid: Optional[UUID] = None,
- aggregate_name: Optional[str] = None,
+ uuid: Optional[UUID] = None,
+ name: Optional[str] = None,
version: Optional[int] = None,
version_lt: Optional[int] = None,
version_gt: Optional[int] = None,
@@ -268,26 +248,26 @@ async def select(
) -> AsyncIterator[EventEntry]:
"""Perform a selection query of entries stored in to the repository.
- :param aggregate_uuid: Aggregate identifier.
- :param aggregate_name: Aggregate name.
- :param version: Aggregate version.
- :param version_lt: Aggregate version lower than the given value.
- :param version_gt: Aggregate version greater than the given value.
- :param version_le: Aggregate version lower or equal to the given value.
- :param version_ge: Aggregate version greater or equal to the given value.
- :param id: Entry identifier.
- :param id_lt: Entry identifier lower than the given value.
- :param id_gt: Entry identifier greater than the given value.
- :param id_le: Entry identifier lower or equal to the given value.
- :param id_ge: Entry identifier greater or equal to the given value.
- :param transaction_uuid: Transaction identifier.
- :param transaction_uuid_ne: Transaction identifier distinct of the given value.
- :param transaction_uuid_in: Destination Transaction identifier equal to one of the given values.
+ :param uuid: The identifier must be equal to the given value.
+ :param name: The classname must be equal to the given value.
+ :param version: The version must be equal to the given value.
+ :param version_lt: The version must be lower than the given value.
+ :param version_gt: The version must be greater than the given value.
+ :param version_le: The version must be lower or equal to the given value.
+ :param version_ge: The version must be greater or equal to the given value.
+ :param id: The entry identifier must be equal to the given value.
+ :param id_lt: The entry identifier must be lower than the given value.
+ :param id_gt: The entry identifier must be greater than the given value.
+ :param id_le: The entry identifier must be lower or equal to the given value.
+ :param id_ge: The entry identifier must be greater or equal to the given value.
+ :param transaction_uuid: The transaction identifier must be equal to the given value.
+ :param transaction_uuid_ne: The transaction identifier must be distinct of the given value.
+ :param transaction_uuid_in: The destination transaction identifier must be equal to one of the given values.
:return: A list of entries.
"""
generator = self._select(
- aggregate_uuid=aggregate_uuid,
- aggregate_name=aggregate_name,
+ uuid=uuid,
+ name=name,
version=version,
version_lt=version_lt,
version_gt=version_gt,
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/events/repositories/memory.py b/packages/core/minos-microservice-aggregate/minos/aggregate/events/repositories/memory.py
index 737fa787c..73dcd74f0 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/events/repositories/memory.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/events/repositories/memory.py
@@ -43,8 +43,8 @@ def __init__(self, *args, **kwargs):
self._next_versions = defaultdict(int)
async def _submit(self, entry: EventEntry, **kwargs) -> EventEntry:
- if entry.aggregate_uuid == NULL_UUID:
- entry.aggregate_uuid = uuid4()
+ if entry.uuid == NULL_UUID:
+ entry.uuid = uuid4()
next_version = self._get_next_version_id(entry)
if entry.version is None:
@@ -66,14 +66,14 @@ def _generate_next_id(self) -> int:
return next(self._id_generator) + 1
def _get_next_version_id(self, entry: EventEntry) -> int:
- key = (entry.aggregate_name, entry.aggregate_uuid, entry.transaction_uuid)
+ key = (entry.name, entry.uuid, entry.transaction_uuid)
self._next_versions[key] += 1
return self._next_versions[key]
async def _select(
self,
- aggregate_uuid: Optional[int] = None,
- aggregate_name: Optional[str] = None,
+ uuid: Optional[int] = None,
+ name: Optional[str] = None,
version: Optional[int] = None,
version_lt: Optional[int] = None,
version_gt: Optional[int] = None,
@@ -93,9 +93,9 @@ async def _select(
# noinspection DuplicatedCode
def _fn_filter(entry: EventEntry) -> bool:
- if aggregate_uuid is not None and aggregate_uuid != entry.aggregate_uuid:
+ if uuid is not None and uuid != entry.uuid:
return False
- if aggregate_name is not None and aggregate_name != entry.aggregate_name:
+ if name is not None and name != entry.name:
return False
if version is not None and version != entry.version:
return False
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/events/repositories/pg.py b/packages/core/minos-microservice-aggregate/minos/aggregate/events/repositories/pg.py
index 834c6a2fd..c70bcac64 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/events/repositories/pg.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/events/repositories/pg.py
@@ -58,8 +58,8 @@ async def _setup(self):
async def _submit(self, entry: EventEntry, **kwargs) -> EventEntry:
lock = None
- if entry.aggregate_uuid != NULL_UUID:
- lock = entry.aggregate_uuid.int & (1 << 32) - 1
+ if entry.uuid != NULL_UUID:
+ lock = entry.uuid.int & (1 << 32) - 1
query, params = await self._build_query(entry)
@@ -71,7 +71,7 @@ async def _submit(self, entry: EventEntry, **kwargs) -> EventEntry:
await self.offset,
)
- entry.id, entry.aggregate_uuid, entry.version, entry.created_at = response
+ entry.id, entry.uuid, entry.version, entry.created_at = response
return entry
async def _build_query(self, entry: EventEntry) -> tuple[Composable, dict[str, UUID]]:
@@ -105,8 +105,8 @@ async def _select(self, **kwargs) -> AsyncIterator[EventEntry]:
# noinspection PyUnusedLocal
@staticmethod
def _build_select_query(
- aggregate_uuid: Optional[UUID] = None,
- aggregate_name: Optional[str] = None,
+ uuid: Optional[UUID] = None,
+ name: Optional[str] = None,
version: Optional[int] = None,
version_lt: Optional[int] = None,
version_gt: Optional[int] = None,
@@ -124,10 +124,10 @@ def _build_select_query(
) -> str:
conditions = list()
- if aggregate_uuid is not None:
- conditions.append("aggregate_uuid = %(aggregate_uuid)s")
- if aggregate_name is not None:
- conditions.append("aggregate_name = %(aggregate_name)s")
+ if uuid is not None:
+ conditions.append("uuid = %(uuid)s")
+ if name is not None:
+ conditions.append("name = %(name)s")
if version is not None:
conditions.append("version = %(version)s")
if version_lt is not None:
@@ -186,51 +186,51 @@ async def _offset(self) -> int:
CREATE TABLE IF NOT EXISTS aggregate_event (
id BIGSERIAL PRIMARY KEY,
action ACTION_TYPE NOT NULL,
- aggregate_uuid UUID NOT NULL,
- aggregate_name TEXT NOT NULL,
+ uuid UUID NOT NULL,
+ name TEXT NOT NULL,
version INT NOT NULL,
data BYTEA NOT NULL,
created_at TIMESTAMPTZ NOT NULL,
transaction_uuid UUID NOT NULL DEFAULT uuid_nil(),
- UNIQUE (aggregate_uuid, version, transaction_uuid)
+ UNIQUE (uuid, version, transaction_uuid)
);
""".strip()
_INSERT_VALUES_QUERY = SQL(
"""
-INSERT INTO aggregate_event (id, action, aggregate_uuid, aggregate_name, version, data, created_at, transaction_uuid)
+INSERT INTO aggregate_event (id, action, uuid, name, version, data, created_at, transaction_uuid)
VALUES (
default,
%(action)s,
- CASE %(aggregate_uuid)s WHEN uuid_nil() THEN uuid_generate_v4() ELSE %(aggregate_uuid)s END,
- %(aggregate_name)s,
+ CASE %(uuid)s WHEN uuid_nil() THEN uuid_generate_v4() ELSE %(uuid)s END,
+ %(name)s,
(
SELECT (CASE WHEN %(version)s IS NULL THEN 1 + COALESCE(MAX(t2.version), 0) ELSE %(version)s END)
FROM (
- SELECT DISTINCT ON (t1.aggregate_uuid) t1.version
+ SELECT DISTINCT ON (t1.uuid) t1.version
FROM ( {from_parts} ) AS t1
- ORDER BY t1.aggregate_uuid, t1.transaction_index DESC
+ ORDER BY t1.uuid, t1.transaction_index DESC
) AS t2
),
%(data)s,
(CASE WHEN %(created_at)s IS NULL THEN NOW() ELSE %(created_at)s END),
%(transaction_uuid)s
)
-RETURNING id, aggregate_uuid, version, created_at;
+RETURNING id, uuid, version, created_at;
"""
)
_SELECT_TRANSACTION_CHUNK = SQL(
"""
-SELECT {index} AS transaction_index, aggregate_uuid, MAX(version) AS version
+SELECT {index} AS transaction_index, uuid, MAX(version) AS version
FROM aggregate_event
-WHERE aggregate_uuid = %(aggregate_uuid)s AND transaction_uuid = {transaction_uuid}
-GROUP BY aggregate_uuid
+WHERE uuid = %(uuid)s AND transaction_uuid = {transaction_uuid}
+GROUP BY uuid
"""
)
_SELECT_ALL_ENTRIES_QUERY = """
-SELECT aggregate_uuid, aggregate_name, version, data, id, action, created_at, transaction_uuid
+SELECT uuid, name, version, data, id, action, created_at, transaction_uuid
FROM aggregate_event
""".strip()
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/exceptions.py b/packages/core/minos-microservice-aggregate/minos/aggregate/exceptions.py
index 3f317c4e3..0b39bab65 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/exceptions.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/exceptions.py
@@ -11,9 +11,11 @@
)
if TYPE_CHECKING:
+ from .entities import (
+ RootEntity,
+ )
from .models import (
- Aggregate,
- AggregateDiff,
+ Event,
)
@@ -52,21 +54,21 @@ class SnapshotRepositoryException(AggregateException):
class SnapshotRepositoryConflictException(SnapshotRepositoryException):
"""Exception to be raised when current version is newer than the one to be processed."""
- def __init__(self, previous: Aggregate, aggregate_diff: AggregateDiff):
+ def __init__(self, previous: RootEntity, event: Event):
self.previous = previous
- self.aggregate_diff = aggregate_diff
+ self.event = event
super().__init__(
- f"Version for {repr(previous.classname)} aggregate must be "
- f"greater than {previous.version}. Obtained: {aggregate_diff.version}"
+ f"Version for {repr(previous.classname)} root entity must be "
+ f"greater than {previous.version}. Obtained: {event.version}"
)
-class AggregateNotFoundException(SnapshotRepositoryException):
- """Exception to be raised when some aggregate is not found on the repository."""
+class NotFoundException(SnapshotRepositoryException):
+ """Exception to be raised when a ``RootEntity`` is not found on the repository."""
-class DeletedAggregateException(SnapshotRepositoryException):
- """Exception to be raised when some aggregate is already deleted from the repository."""
+class AlreadyDeletedException(SnapshotRepositoryException):
+ """Exception to be raised when a ``RootEntity`` is already deleted from the repository."""
class ValueObjectException(AggregateException):
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/__init__.py b/packages/core/minos-microservice-aggregate/minos/aggregate/models/__init__.py
deleted file mode 100644
index d05225f1d..000000000
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/models/__init__.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from .actions import (
- Action,
-)
-from .aggregates import (
- Aggregate,
-)
-from .collections import (
- IncrementalSet,
- IncrementalSetDiff,
- IncrementalSetDiffEntry,
-)
-from .diffs import (
- AggregateDiff,
- FieldDiff,
- FieldDiffContainer,
- IncrementalFieldDiff,
-)
-from .entities import (
- Entity,
- EntitySet,
-)
-from .refs import (
- AggregateRef,
- ModelRef,
- ModelRefExtractor,
- ModelRefInjector,
- ModelRefResolver,
-)
-from .value_objects import (
- ValueObject,
- ValueObjectSet,
-)
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/diffs/__init__.py b/packages/core/minos-microservice-aggregate/minos/aggregate/models/diffs/__init__.py
deleted file mode 100644
index 2543280c3..000000000
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/models/diffs/__init__.py
+++ /dev/null
@@ -1,8 +0,0 @@
-from .aggregates import (
- AggregateDiff,
-)
-from .fields import (
- FieldDiff,
- FieldDiffContainer,
- IncrementalFieldDiff,
-)
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/abc.py b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/abc.py
index 082a0dbb0..ec090eb03 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/abc.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/abc.py
@@ -30,55 +30,54 @@
)
if TYPE_CHECKING:
- from ..models import (
- Aggregate,
+ from ..entities import (
+ RootEntity,
)
class SnapshotRepository(ABC, MinosSetup):
"""Base Snapshot class.
- The snapshot provides a direct accessor to the aggregate instances stored as events by the event repository class.
+ The snapshot provides a direct accessor to the ``RootEntity`` instances stored as events by the event repository
+ class.
"""
- async def get(
- self, aggregate_name: str, uuid: UUID, transaction: Optional[TransactionEntry] = None, **kwargs
- ) -> Aggregate:
- """Get an aggregate instance from its identifier.
+ async def get(self, name: str, uuid: UUID, transaction: Optional[TransactionEntry] = None, **kwargs) -> RootEntity:
+ """Get a ``RootEntity`` instance from its identifier.
- :param aggregate_name: Class name of the ``Aggregate``.
- :param uuid: Identifier of the ``Aggregate``.
+ :param name: Class name of the ``RootEntity``.
+ :param uuid: Identifier of the ``RootEntity``.
:param transaction: The transaction within the operation is performed. If not any value is provided, then the
transaction is extracted from the context var. If not any transaction is being scoped then the query is
performed to the global snapshot.
:param kwargs: Additional named arguments.
- :return: The ``Aggregate`` instance.
+ :return: The ``RootEntity`` instance.
"""
if transaction is None:
transaction = TRANSACTION_CONTEXT_VAR.get()
await self.synchronize(**kwargs)
- return await self._get(aggregate_name=aggregate_name, uuid=uuid, transaction=transaction, **kwargs)
+ return await self._get(name=name, uuid=uuid, transaction=transaction, **kwargs)
@abstractmethod
- async def _get(self, *args, **kwargs) -> Aggregate:
+ async def _get(self, *args, **kwargs) -> RootEntity:
raise NotImplementedError
async def find(
self,
- aggregate_name: str,
+ name: str,
condition: _Condition,
ordering: Optional[_Ordering] = None,
limit: Optional[int] = None,
streaming_mode: bool = False,
transaction: Optional[TransactionEntry] = None,
**kwargs,
- ) -> AsyncIterator[Aggregate]:
- """Find a collection of ``Aggregate`` instances based on a ``Condition``.
+ ) -> AsyncIterator[RootEntity]:
+ """Find a collection of ``RootEntity`` instances based on a ``Condition``.
- :param aggregate_name: Class name of the ``Aggregate``.
- :param condition: The condition that must be satisfied by the ``Aggregate`` instances.
+ :param name: Class name of the ``RootEntity``.
+ :param condition: The condition that must be satisfied by the ``RootEntity`` instances.
:param ordering: Optional argument to return the instance with specific ordering strategy. The default behaviour
is to retrieve them without any order pattern.
:param limit: Optional argument to return only a subset of instances. The default behaviour is to return all the
@@ -89,7 +88,7 @@ async def find(
transaction is extracted from the context var. If not any transaction is being scoped then the query is
performed to the global snapshot.
:param kwargs: Additional named arguments.
- :return: An asynchronous iterator that containing the ``Aggregate`` instances.
+ :return: An asynchronous iterator that containing the ``RootEntity`` instances.
"""
if transaction is None:
transaction = TRANSACTION_CONTEXT_VAR.get()
@@ -97,7 +96,7 @@ async def find(
await self.synchronize(**kwargs)
iterable = self._find(
- aggregate_name=aggregate_name,
+ name=name,
condition=condition,
ordering=ordering,
limit=limit,
@@ -106,11 +105,11 @@ async def find(
**kwargs,
)
- async for aggregate in iterable:
- yield aggregate
+ async for instance in iterable:
+ yield instance
@abstractmethod
- def _find(self, *args, **kwargs) -> AsyncIterator[Aggregate]:
+ def _find(self, *args, **kwargs) -> AsyncIterator[RootEntity]:
raise NotImplementedError
def synchronize(self, **kwargs) -> Awaitable[None]:
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/entries.py b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/entries.py
index 41d1e234c..73b8afab1 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/entries.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/entries.py
@@ -11,7 +11,6 @@
Any,
Iterable,
Optional,
- Type,
Union,
)
from uuid import (
@@ -28,12 +27,12 @@
EventEntry,
)
from ..exceptions import (
- DeletedAggregateException,
+ AlreadyDeletedException,
)
if TYPE_CHECKING:
- from ..models import (
- Aggregate,
+ from ..entities import (
+ RootEntity,
)
@@ -44,8 +43,8 @@ class SnapshotEntry:
"""
__slots__ = (
- "aggregate_uuid",
- "aggregate_name",
+ "uuid",
+ "name",
"version",
"schema",
"data",
@@ -57,8 +56,8 @@ class SnapshotEntry:
# noinspection PyShadowingBuiltins
def __init__(
self,
- aggregate_uuid: UUID,
- aggregate_name: str,
+ uuid: UUID,
+ name: str,
version: int,
schema: Optional[Union[list[dict[str, Any]], dict[str, Any]]] = None,
data: Optional[dict[str, Any]] = None,
@@ -71,8 +70,8 @@ def __init__(
if isinstance(schema, bytes):
schema = MinosJsonBinaryProtocol.decode(schema)
- self.aggregate_uuid = aggregate_uuid
- self.aggregate_name = aggregate_name
+ self.uuid = uuid
+ self.name = name
self.version = version
self.schema = schema
@@ -84,25 +83,23 @@ def __init__(
self.transaction_uuid = transaction_uuid
@classmethod
- def from_aggregate(cls, aggregate: Aggregate, **kwargs) -> SnapshotEntry:
- """Build a new instance from an ``Aggregate``.
+ def from_root_entity(cls, instance: RootEntity, **kwargs) -> SnapshotEntry:
+ """Build a new instance from a ``RootEntity``.
- :param aggregate: The aggregate instance.
- :return: A new ``MinosSnapshotEntry`` instance.
+ :param instance: The ``RootEntity`` instance.
+ :return: A new ``SnapshotEntry`` instance.
"""
- data = {
- k: v for k, v in aggregate.avro_data.items() if k not in {"uuid", "version", "created_at", "updated_at"}
- }
+ data = {k: v for k, v in instance.avro_data.items() if k not in {"uuid", "version", "created_at", "updated_at"}}
# noinspection PyTypeChecker
return cls(
- aggregate_uuid=aggregate.uuid,
- aggregate_name=aggregate.classname,
- version=aggregate.version,
- schema=aggregate.avro_schema,
+ uuid=instance.uuid,
+ name=instance.classname,
+ version=instance.version,
+ schema=instance.avro_schema,
data=data,
- created_at=aggregate.created_at,
- updated_at=aggregate.updated_at,
+ created_at=instance.created_at,
+ updated_at=instance.updated_at,
**kwargs,
)
@@ -114,8 +111,8 @@ def from_event_entry(cls, entry: EventEntry) -> SnapshotEntry:
:return: A new ``SnapshotEntry`` instance.
"""
return cls(
- aggregate_uuid=entry.aggregate_uuid,
- aggregate_name=entry.aggregate_name,
+ uuid=entry.uuid,
+ name=entry.name,
version=entry.version,
created_at=entry.created_at,
updated_at=entry.created_at,
@@ -128,8 +125,8 @@ def as_raw(self) -> dict[str, Any]:
:return: A dictionary in which the keys are attribute names and values the attribute contents.
"""
return {
- "aggregate_uuid": self.aggregate_uuid,
- "aggregate_name": self.aggregate_name,
+ "uuid": self.uuid,
+ "name": self.name,
"version": self.version,
"schema": self.encoded_schema,
"data": self.encoded_data,
@@ -160,37 +157,37 @@ def encoded_data(self) -> Optional[str]:
return json.dumps(self.data)
- def build_aggregate(self, **kwargs) -> Aggregate:
- """Rebuild the stored ``Aggregate`` object instance from the internal state.
+ def build(self, **kwargs) -> RootEntity:
+ """Rebuild the stored ``RootEntity`` object instance from the internal state.
:param kwargs: Additional named arguments.
- :return: A ``Aggregate`` instance.
+ :return: A ``RootEntity`` instance.
"""
- from ..models import (
- Aggregate,
+ from ..entities import (
+ RootEntity,
)
if self.data is None:
- raise DeletedAggregateException(f"The {self.aggregate_uuid!r} id points to an already deleted aggregate.")
+ raise AlreadyDeletedException(f"The {self.uuid!r} identifier belongs to an already deleted instance.")
data = dict(self.data)
data |= {
- "uuid": self.aggregate_uuid,
+ "uuid": self.uuid,
"version": self.version,
"created_at": self.created_at,
"updated_at": self.updated_at,
}
data |= kwargs
- instance = Aggregate.from_avro(self.schema, data)
+ instance = RootEntity.from_avro(self.schema, data)
return instance
@property
- def aggregate_cls(self) -> Type[Aggregate]:
- """Load the concrete ``Aggregate`` class.
+ def type_(self) -> type[RootEntity]:
+ """Load the concrete ``RootEntity`` class.
:return: A ``Type`` object.
"""
# noinspection PyTypeChecker
- return import_module(self.aggregate_name)
+ return import_module(self.name)
def __eq__(self, other: SnapshotEntry) -> bool:
return type(self) == type(other) and tuple(self) == tuple(other)
@@ -198,7 +195,7 @@ def __eq__(self, other: SnapshotEntry) -> bool:
def __iter__(self) -> Iterable:
# noinspection PyRedundantParentheses
yield from (
- self.aggregate_name,
+ self.name,
self.version,
self.schema,
self.data,
@@ -210,7 +207,7 @@ def __iter__(self) -> Iterable:
def __repr__(self):
name = type(self).__name__
return (
- f"{name}(aggregate_uuid={self.aggregate_uuid!r}, aggregate_name={self.aggregate_name!r}, "
+ f"{name}(uuid={self.uuid!r}, name={self.name!r}, "
f"version={self.version!r}, schema={self.schema!r}, data={self.data!r}, "
f"created_at={self.created_at!r}, updated_at={self.updated_at!r}, "
f"transaction_uuid={self.transaction_uuid!r})"
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/memory.py b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/memory.py
index 3dec8858e..174cc9372 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/memory.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/memory.py
@@ -29,8 +29,8 @@
EventRepository,
)
from ..exceptions import (
- AggregateNotFoundException,
- DeletedAggregateException,
+ AlreadyDeletedException,
+ NotFoundException,
)
from ..queries import (
_Condition,
@@ -46,15 +46,16 @@
)
if TYPE_CHECKING:
- from ..models import (
- Aggregate,
+ from ..entities import (
+ RootEntity,
)
class InMemorySnapshotRepository(SnapshotRepository):
"""InMemory Snapshot class.
- The snapshot provides a direct accessor to the aggregate instances stored as events by the event repository class.
+ The snapshot provides a direct accessor to the ``RootEntity`` instances stored as events by the event repository
+ class.
"""
@inject
@@ -78,47 +79,45 @@ def __init__(
async def _find(
self,
- aggregate_name: str,
+ name: str,
condition: _Condition,
ordering: Optional[_Ordering] = None,
limit: Optional[int] = None,
**kwargs,
- ) -> AsyncIterator[Aggregate]:
- uuids = {v.aggregate_uuid async for v in self._event_repository.select(aggregate_name=aggregate_name)}
+ ) -> AsyncIterator[RootEntity]:
+ uuids = {v.uuid async for v in self._event_repository.select(name=name)}
- aggregates = list()
+ instances = list()
for uuid in uuids:
try:
- aggregate = await self.get(aggregate_name, uuid, **kwargs)
- except DeletedAggregateException:
+ instance = await self.get(name, uuid, **kwargs)
+ except AlreadyDeletedException:
continue
- if condition.evaluate(aggregate):
- aggregates.append(aggregate)
+ if condition.evaluate(instance):
+ instances.append(instance)
if ordering is not None:
- aggregates.sort(key=attrgetter(ordering.by), reverse=ordering.reverse)
+ instances.sort(key=attrgetter(ordering.by), reverse=ordering.reverse)
if limit is not None:
- aggregates = aggregates[:limit]
+ instances = instances[:limit]
- for aggregate in aggregates:
- yield aggregate
+ for instance in instances:
+ yield instance
# noinspection PyMethodOverriding
- async def _get(
- self, aggregate_name: str, uuid: UUID, transaction: Optional[TransactionEntry] = None, **kwargs
- ) -> Aggregate:
+ async def _get(self, name: str, uuid: UUID, transaction: Optional[TransactionEntry] = None, **kwargs) -> RootEntity:
transaction_uuids = await self._get_transaction_uuids(transaction)
- entries = await self._get_event_entries(aggregate_name, uuid, transaction_uuids)
+ entries = await self._get_event_entries(name, uuid, transaction_uuids)
if not len(entries):
- raise AggregateNotFoundException(f"Not found any entries for the {uuid!r} id.")
+ raise NotFoundException(f"Not found any entries for the {uuid!r} id.")
if entries[-1].action.is_delete:
- raise DeletedAggregateException(f"The {uuid!r} id points to an already deleted aggregate.")
+ raise AlreadyDeletedException(f"The {uuid!r} identifier belongs to an already deleted instance.")
- return self._build_aggregate(entries, **kwargs)
+ return self._build_instance(entries, **kwargs)
async def _get_transaction_uuids(self, transaction: Optional[TransactionEntry]) -> tuple[UUID, ...]:
if transaction is None:
@@ -134,12 +133,10 @@ async def _get_transaction_uuids(self, transaction: Optional[TransactionEntry])
return transaction_uuids
- async def _get_event_entries(
- self, aggregate_name: str, uuid: UUID, transaction_uuids: tuple[UUID, ...]
- ) -> list[EventEntry]:
+ async def _get_event_entries(self, name: str, uuid: UUID, transaction_uuids: tuple[UUID, ...]) -> list[EventEntry]:
entries = [
v
- async for v in self._event_repository.select(aggregate_name=aggregate_name, aggregate_uuid=uuid)
+ async for v in self._event_repository.select(name=name, uuid=uuid)
if v.transaction_uuid in transaction_uuids
]
@@ -154,12 +151,12 @@ async def _get_event_entries(
return entries
@staticmethod
- def _build_aggregate(entries: list[EventEntry], **kwargs) -> Aggregate:
- cls = entries[0].aggregate_cls
- aggregate = cls.from_diff(entries[0].aggregate_diff, **kwargs)
+ def _build_instance(entries: list[EventEntry], **kwargs) -> RootEntity:
+ cls = entries[0].type_
+ instance = cls.from_diff(entries[0].event, **kwargs)
for entry in entries[1:]:
- aggregate.apply_diff(entry.aggregate_diff)
- return aggregate
+ instance.apply_diff(entry.event)
+ return instance
async def _synchronize(self, **kwargs) -> None:
pass
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/abc.py b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/abc.py
index 8ace62d08..36fcb5f42 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/abc.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/abc.py
@@ -30,15 +30,15 @@ async def _setup(self) -> None:
_CREATE_TABLE_QUERY = """
CREATE TABLE IF NOT EXISTS snapshot (
- aggregate_uuid UUID NOT NULL,
- aggregate_name TEXT NOT NULL,
+ uuid UUID NOT NULL,
+ name TEXT NOT NULL,
version INT NOT NULL,
schema BYTEA,
data JSONB,
created_at TIMESTAMPTZ NOT NULL,
updated_at TIMESTAMPTZ NOT NULL,
transaction_uuid UUID NOT NULL DEFAULT uuid_nil(),
- PRIMARY KEY (aggregate_uuid, transaction_uuid)
+ PRIMARY KEY (uuid, transaction_uuid)
);
""".strip()
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/api.py b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/api.py
index 9d0d12975..9b5aec9f7 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/api.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/api.py
@@ -23,15 +23,16 @@
)
if TYPE_CHECKING:
- from ...models import (
- Aggregate,
+ from ...entities import (
+ RootEntity,
)
class PostgreSqlSnapshotRepository(SnapshotRepository):
"""PostgreSQL Snapshot class.
- The snapshot provides a direct accessor to the aggregate instances stored as events by the event repository class.
+ The snapshot provides a direct accessor to the ``RootEntity`` instances stored as events by the event repository
+ class.
"""
reader: PostgreSqlSnapshotReader
@@ -62,10 +63,10 @@ async def _destroy(self) -> None:
await self.reader.destroy()
await self.writer.destroy()
- def _get(self, *args, **kwargs) -> Awaitable[Aggregate]:
+ def _get(self, *args, **kwargs) -> Awaitable[RootEntity]:
return self.reader.get(*args, **kwargs)
- def _find(self, *args, **kwargs) -> AsyncIterator[Aggregate]:
+ def _find(self, *args, **kwargs) -> AsyncIterator[RootEntity]:
return self.reader.find(*args, **kwargs)
def _synchronize(self, *args, **kwargs) -> Awaitable[None]:
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/queries.py b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/queries.py
index 48bc4a118..8dc95af38 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/queries.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/queries.py
@@ -59,14 +59,14 @@ class PostgreSqlSnapshotQueryBuilder:
def __init__(
self,
- aggregate_name: str,
+ name: str,
condition: _Condition,
ordering: Optional[_Ordering] = None,
limit: Optional[int] = None,
transaction_uuids: tuple[UUID, ...] = (NULL_UUID,),
exclude_deleted: bool = False,
):
- self.aggregate_name = aggregate_name
+ self.name = name
self.condition = condition
self.ordering = ordering
self.limit = limit
@@ -93,7 +93,7 @@ def build(self) -> tuple[Composable, dict[str, Any]]:
return query, parameters
def _build(self) -> Composable:
- self._parameters["aggregate_name"] = self.aggregate_name
+ self._parameters["name"] = self.name
query = SQL(" WHERE ").join([self._build_select_from(), self._build_condition(self.condition)])
@@ -213,7 +213,7 @@ def generate_random_str() -> str:
}
_FIXED_FIELDS_MAPPER = {
- "uuid": Identifier("aggregate_uuid"),
+ "uuid": Identifier("uuid"),
"version": Identifier("version"),
"created_at": Identifier("created_at"),
"updated_at": Identifier("updated_at"),
@@ -226,8 +226,8 @@ def generate_random_str() -> str:
_SELECT_ENTRIES_QUERY = SQL(
"SELECT "
- " t2.aggregate_uuid, "
- " t2.aggregate_name, "
+ " t2.uuid, "
+ " t2.name, "
" t2.version, "
" t2.schema, "
" t2.data, "
@@ -235,16 +235,16 @@ def generate_random_str() -> str:
" t2.updated_at, "
" t2.transaction_uuid "
"FROM ("
- " SELECT DISTINCT ON (aggregate_uuid) t1.* "
+ " SELECT DISTINCT ON (uuid) t1.* "
" FROM ( {from_parts} ) AS t1 "
- " ORDER BY aggregate_uuid, transaction_index DESC "
+ " ORDER BY uuid, transaction_index DESC "
") AS t2"
)
_SELECT_TRANSACTION_CHUNK = SQL(
"SELECT {index} AS transaction_index, * "
"FROM snapshot "
- "WHERE aggregate_name = %(aggregate_name)s AND transaction_uuid = {transaction_uuid} "
+ "WHERE name = %(name)s AND transaction_uuid = {transaction_uuid} "
)
_EXCLUDE_DELETED_CONDITION = SQL("(data IS NOT NULL)")
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/readers.py b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/readers.py
index 2cef349b1..9793b7ddc 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/readers.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/readers.py
@@ -17,7 +17,7 @@
)
from ...exceptions import (
- AggregateNotFoundException,
+ NotFoundException,
)
from ...queries import (
_Condition,
@@ -38,8 +38,8 @@
)
if TYPE_CHECKING:
- from ...models import (
- Aggregate,
+ from ...entities import (
+ RootEntity,
)
logger = logging.getLogger(__name__)
@@ -48,51 +48,52 @@
class PostgreSqlSnapshotReader(PostgreSqlSnapshotSetup):
"""PostgreSQL Snapshot class.
- The snapshot provides a direct accessor to the aggregate instances stored as events by the event repository class.
+ The snapshot provides a direct accessor to the ``RootEntity`` instances stored as events by the event repository
+ class.
"""
- async def get(self, aggregate_name: str, uuid: UUID, **kwargs) -> Aggregate:
- """Get an aggregate instance from its identifier.
+ async def get(self, name: str, uuid: UUID, **kwargs) -> RootEntity:
+ """Get a ``RootEntity`` instance from its identifier.
- :param aggregate_name: Class name of the ``Aggregate``.
- :param uuid: Identifier of the ``Aggregate``.
+ :param name: Class name of the ``RootEntity``.
+ :param uuid: Identifier of the ``RootEntity``.
:param kwargs: Additional named arguments.
- :return: The ``Aggregate`` instance.
+ :return: The ``RootEntity`` instance.
"""
- snapshot_entry = await self.get_entry(aggregate_name, uuid, **kwargs)
- aggregate = snapshot_entry.build_aggregate(**kwargs)
- return aggregate
+ snapshot_entry = await self.get_entry(name, uuid, **kwargs)
+ instance = snapshot_entry.build(**kwargs)
+ return instance
# noinspection PyUnusedLocal
- async def get_entry(self, aggregate_name: str, uuid: UUID, **kwargs) -> SnapshotEntry:
+ async def get_entry(self, name: str, uuid: UUID, **kwargs) -> SnapshotEntry:
"""Get a ``SnapshotEntry`` from its identifier.
- :param aggregate_name: Class name of the ``Aggregate``.
- :param uuid: Identifier of the ``Aggregate``.
+ :param name: Class name of the ``RootEntity``.
+ :param uuid: Identifier of the ``RootEntity``.
:param kwargs: Additional named arguments.
:return: The ``SnapshotEntry`` instance.
"""
try:
return await self.find_entries(
- aggregate_name, _EqualCondition("uuid", uuid), **kwargs | {"exclude_deleted": False}
+ name, _EqualCondition("uuid", uuid), **kwargs | {"exclude_deleted": False}
).__anext__()
except StopAsyncIteration:
- raise AggregateNotFoundException(f"Some aggregates could not be found: {uuid!s}")
+ raise NotFoundException(f"The instance could not be found: {uuid!s}")
- async def find(self, *args, **kwargs) -> AsyncIterator[Aggregate]:
- """Find a collection of ``Aggregate`` instances based on a ``Condition``.
+ async def find(self, *args, **kwargs) -> AsyncIterator[RootEntity]:
+ """Find a collection of ``RootEntity`` instances based on a ``Condition``.
:param args: Additional positional arguments.
:param kwargs: Additional named arguments.
- :return: An asynchronous iterator that containing the ``Aggregate`` instances.
+ :return: An asynchronous iterator that containing the ``RootEntity`` instances.
"""
async for snapshot_entry in self.find_entries(*args, **kwargs):
- yield snapshot_entry.build_aggregate(**kwargs)
+ yield snapshot_entry.build(**kwargs)
async def find_entries(
self,
- aggregate_name: str,
+ name: str,
condition: _Condition,
ordering: Optional[_Ordering] = None,
limit: Optional[int] = None,
@@ -103,8 +104,8 @@ async def find_entries(
) -> AsyncIterator[SnapshotEntry]:
"""Find a collection of ``SnapshotEntry`` instances based on a ``Condition``.
- :param aggregate_name: Class name of the ``Aggregate``.
- :param condition: The condition that must be satisfied by the ``Aggregate`` instances.
+ :param name: Class name of the ``RootEntity``.
+ :param condition: The condition that must be satisfied by the ``RootEntity`` instances.
:param ordering: Optional argument to return the instance with specific ordering strategy. The default behaviour
is to retrieve them without any order pattern.
:param limit: Optional argument to return only a subset of instances. The default behaviour is to return all the
@@ -114,19 +115,17 @@ async def find_entries(
:param transaction: The transaction within the operation is performed. If not any value is provided, then the
transaction is extracted from the context var. If not any transaction is being scoped then the query is
performed to the global snapshot.
- :param exclude_deleted: If ``True``, deleted ``Aggregate`` entries are included, otherwise deleted ``Aggregate``
- entries are filtered.
+ :param exclude_deleted: If ``True``, deleted ``RootEntity`` entries are included, otherwise deleted
+ ``RootEntity`` entries are filtered.
:param kwargs: Additional named arguments.
- :return: An asynchronous iterator that containing the ``Aggregate`` instances.
+ :return: An asynchronous iterator that containing the ``RootEntity`` instances.
"""
if transaction is None:
transaction_uuids = (NULL_UUID,)
else:
transaction_uuids = await transaction.uuids
- qb = PostgreSqlSnapshotQueryBuilder(
- aggregate_name, condition, ordering, limit, transaction_uuids, exclude_deleted
- )
+ qb = PostgreSqlSnapshotQueryBuilder(name, condition, ordering, limit, transaction_uuids, exclude_deleted)
query, parameters = qb.build()
async with self.cursor() as cursor:
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/writers.py b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/writers.py
index 0c3197ed4..99b62eba4 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/writers.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/pg/writers.py
@@ -21,11 +21,12 @@
)
from ...events import (
+ Event,
EventEntry,
EventRepository,
)
from ...exceptions import (
- AggregateNotFoundException,
+ NotFoundException,
SnapshotRepositoryConflictException,
TransactionNotFoundException,
)
@@ -41,9 +42,8 @@
)
if TYPE_CHECKING:
- from ...models import (
- Aggregate,
- AggregateDiff,
+ from ...entities import (
+ RootEntity,
)
from .readers import (
PostgreSqlSnapshotReader,
@@ -60,7 +60,7 @@ def __init__(
reader: PostgreSqlSnapshotReader,
event_repository: EventRepository = Provide["event_repository"],
transaction_repository: TransactionRepository = Provide["transaction_repository"],
- **kwargs
+ **kwargs,
):
super().__init__(*args, **kwargs)
@@ -74,14 +74,14 @@ def __init__(
self._event_repository = event_repository
self._transaction_repository = transaction_repository
- async def is_synced(self, aggregate_name: str, **kwargs) -> bool:
- """Check if the snapshot has the latest version of an ``Aggregate`` instance.
+ async def is_synced(self, name: str, **kwargs) -> bool:
+ """Check if the snapshot has the latest version of a ``RootEntity`` instance.
- :param aggregate_name: Class name of the ``Aggregate`` to be checked.
+ :param name: Class name of the ``RootEntity`` to be checked.
:return: ``True`` if it has the latest version for the identifier or ``False`` otherwise.
"""
offset = await self._load_offset(**kwargs)
- iterable = self._event_repository.select(id_gt=offset, aggregate_name=aggregate_name, **kwargs)
+ iterable = self._event_repository.select(id_gt=offset, name=name, **kwargs)
try:
await iterable.__anext__()
return False
@@ -131,42 +131,42 @@ async def _submit_delete(self, event_entry: EventEntry, **kwargs) -> SnapshotEnt
return snapshot_entry
async def _submit_update_or_create(self, event_entry: EventEntry, **kwargs) -> SnapshotEntry:
- aggregate = await self._build_aggregate(event_entry, **kwargs)
+ instance = await self._build_instance(event_entry, **kwargs)
- snapshot_entry = SnapshotEntry.from_aggregate(aggregate, transaction_uuid=event_entry.transaction_uuid)
+ snapshot_entry = SnapshotEntry.from_root_entity(instance, transaction_uuid=event_entry.transaction_uuid)
snapshot_entry = await self._submit_entry(snapshot_entry, **kwargs)
return snapshot_entry
- async def _build_aggregate(self, event_entry: EventEntry, **kwargs) -> Aggregate:
- diff = event_entry.aggregate_diff
+ async def _build_instance(self, event_entry: EventEntry, **kwargs) -> RootEntity:
+ diff = event_entry.event
try:
transaction = await self._transaction_repository.get(uuid=event_entry.transaction_uuid)
except TransactionNotFoundException:
transaction = None
- aggregate = await self._update_if_exists(diff, transaction=transaction, **kwargs)
- return aggregate
+ instance = await self._update_instance_if_exists(diff, transaction=transaction, **kwargs)
+ return instance
- async def _update_if_exists(self, aggregate_diff: AggregateDiff, **kwargs) -> Aggregate:
+ async def _update_instance_if_exists(self, event: Event, **kwargs) -> RootEntity:
# noinspection PyBroadException
try:
# noinspection PyTypeChecker
- previous = await self._select_one_aggregate(aggregate_diff.uuid, aggregate_diff.name, **kwargs)
- except AggregateNotFoundException:
+ previous = await self._select_one_instance(event.name, event.uuid, **kwargs)
+ except NotFoundException:
# noinspection PyTypeChecker
- aggregate_cls: Type[Aggregate] = import_module(aggregate_diff.name)
- return aggregate_cls.from_diff(aggregate_diff, **kwargs)
+ cls: Type[RootEntity] = import_module(event.name)
+ return cls.from_diff(event, **kwargs)
- if previous.version >= aggregate_diff.version:
- raise SnapshotRepositoryConflictException(previous, aggregate_diff)
+ if previous.version >= event.version:
+ raise SnapshotRepositoryConflictException(previous, event)
- previous.apply_diff(aggregate_diff)
+ previous.apply_diff(event)
return previous
- async def _select_one_aggregate(self, aggregate_uuid: UUID, aggregate_name: str, **kwargs) -> Aggregate:
- snapshot_entry = await self._reader.get_entry(aggregate_name, aggregate_uuid, **kwargs)
- return snapshot_entry.build_aggregate(**kwargs)
+ async def _select_one_instance(self, name: str, uuid: UUID, **kwargs) -> RootEntity:
+ snapshot_entry = await self._reader.get_entry(name, uuid, **kwargs)
+ return snapshot_entry.build(**kwargs)
async def _submit_entry(self, snapshot_entry: SnapshotEntry, **kwargs) -> SnapshotEntry:
params = snapshot_entry.as_raw()
@@ -186,10 +186,10 @@ async def _clean_transactions(self, offset: int, **kwargs) -> None:
_INSERT_ONE_SNAPSHOT_ENTRY_QUERY = """
-INSERT INTO snapshot (aggregate_uuid, aggregate_name, version, schema, data, created_at, updated_at, transaction_uuid)
+INSERT INTO snapshot (uuid, name, version, schema, data, created_at, updated_at, transaction_uuid)
VALUES (
- %(aggregate_uuid)s,
- %(aggregate_name)s,
+ %(uuid)s,
+ %(name)s,
%(version)s,
%(schema)s,
%(data)s,
@@ -197,7 +197,7 @@ async def _clean_transactions(self, offset: int, **kwargs) -> None:
%(updated_at)s,
%(transaction_uuid)s
)
-ON CONFLICT (aggregate_uuid, transaction_uuid)
+ON CONFLICT (uuid, transaction_uuid)
DO
UPDATE SET version = %(version)s, schema = %(schema)s, data = %(data)s, updated_at = %(updated_at)s
RETURNING created_at, updated_at;
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/services.py b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/services.py
index d4e60a931..c36c2774d 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/services.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/snapshots/services.py
@@ -8,7 +8,6 @@
)
from typing import (
TYPE_CHECKING,
- Type,
)
from uuid import (
UUID,
@@ -40,8 +39,8 @@
)
if TYPE_CHECKING:
- from ..models import (
- Aggregate,
+ from ..entities import (
+ RootEntity,
)
logger = logging.getLogger(__name__)
@@ -64,18 +63,18 @@ def __init__(
@classmethod
def __get_enroute__(cls, config: MinosConfig) -> dict[str, set[EnrouteDecorator]]:
- aggregate_name = config.service.aggregate.rsplit(".", 1)[-1]
+ simplified_name = config.service.aggregate.rsplit(".", 1)[-1]
return {
- cls.__get_one__.__name__: {enroute.broker.command(f"Get{aggregate_name}")},
- cls.__get_many__.__name__: {enroute.broker.command(f"Get{aggregate_name}s")},
+ cls.__get_one__.__name__: {enroute.broker.command(f"Get{simplified_name}")},
+ cls.__get_many__.__name__: {enroute.broker.command(f"Get{simplified_name}s")},
cls.__synchronize__.__name__: {enroute.periodic.event("* * * * *")},
}
async def __get_one__(self, request: Request) -> Response:
- """Get aggregate.
+ """Get one ``RootEntity`` instance.
- :param request: The ``Request`` instance that contains the aggregate identifier.
- :return: A ``Response`` instance containing the requested aggregate.
+ :param request: The ``Request`` instance that contains the instance identifier.
+ :return: A ``Response`` instance containing the requested instances.
"""
try:
content = await request.content(model_type=ModelType.build("Query", {"uuid": UUID}))
@@ -83,17 +82,17 @@ async def __get_one__(self, request: Request) -> Response:
raise ResponseException(f"There was a problem while parsing the given request: {exc!r}")
try:
- aggregate = await self.__aggregate_cls__.get(content["uuid"])
+ instance = await self.type_.get(content["uuid"])
except Exception as exc:
- raise ResponseException(f"There was a problem while getting the aggregate: {exc!r}")
+ raise ResponseException(f"There was a problem while getting the instance: {exc!r}")
- return Response(aggregate)
+ return Response(instance)
async def __get_many__(self, request: Request) -> Response:
- """Get aggregates.
+ """Get many ``RootEntity`` instances.
- :param request: The ``Request`` instance that contains the product identifiers.
- :return: A ``Response`` instance containing the requested aggregates.
+ :param request: The ``Request`` instance that contains the instance identifiers.
+ :return: A ``Response`` instance containing the requested instances.
"""
try:
content = await request.content(model_type=ModelType.build("Query", {"uuids": list[UUID]}))
@@ -101,14 +100,18 @@ async def __get_many__(self, request: Request) -> Response:
raise ResponseException(f"There was a problem while parsing the given request: {exc!r}")
try:
- aggregates = await gather(*(self.__aggregate_cls__.get(uuid) for uuid in content["uuids"]))
+ instances = await gather(*(self.type_.get(uuid) for uuid in content["uuids"]))
except Exception as exc:
- raise ResponseException(f"There was a problem while getting aggregates: {exc!r}")
+ raise ResponseException(f"There was a problem while getting the instances: {exc!r}")
- return Response(aggregates)
+ return Response(instances)
@cached_property
- def __aggregate_cls__(self) -> Type[Aggregate]:
+ def type_(self) -> type[RootEntity]:
+ """Load the concrete ``RootEntity`` class.
+
+ :return: A ``Type`` object.
+ """
# noinspection PyTypeChecker
return import_module(self.config.service.aggregate)
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/transactions/entries.py b/packages/core/minos-microservice-aggregate/minos/aggregate/transactions/entries.py
index 66d4df90d..e8aeb9528 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/transactions/entries.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/transactions/entries.py
@@ -192,13 +192,13 @@ async def validate(self) -> bool:
entries = dict()
async for entry in self._event_repository.select(transaction_uuid=self.uuid):
- if entry.aggregate_uuid in entries and entry.version < entries[entry.aggregate_uuid]:
+ if entry.uuid in entries and entry.version < entries[entry.uuid]:
continue
- entries[entry.aggregate_uuid] = entry.version
+ entries[entry.uuid] = entry.version
transaction_uuids = set()
- for aggregate_uuid, version in entries.items():
- async for entry in self._event_repository.select(aggregate_uuid=aggregate_uuid, version=version):
+ for uuid, version in entries.items():
+ async for entry in self._event_repository.select(uuid=uuid, version=version):
if entry.transaction_uuid == self.destination_uuid:
return False
if entry.transaction_uuid != self.uuid:
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/transactions/repositories/abc.py b/packages/core/minos-microservice-aggregate/minos/aggregate/transactions/repositories/abc.py
index d58af3467..bdeffee3b 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/transactions/repositories/abc.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/transactions/repositories/abc.py
@@ -62,7 +62,7 @@ async def _submit(self, transaction: TransactionEntry) -> TransactionEntry:
async def get(self, uuid: UUID, **kwargs) -> TransactionEntry:
"""Get a ``TransactionEntry`` from its identifier.
- :param uuid: Identifier of the ``Aggregate``.
+ :param uuid: Identifier of the ``RootEntity``.
:param kwargs: Additional named arguments.
:return: The ``TransactionEntry`` instance.
"""
@@ -140,7 +140,7 @@ async def _select(self, **kwargs) -> AsyncIterator[TransactionEntry]:
raise NotImplementedError
def write_lock(self) -> Lock:
- """Get a write lock.
+ """Get write lock.
:return: An asynchronous context manager.
"""
diff --git a/packages/core/minos-microservice-aggregate/minos/aggregate/models/value_objects.py b/packages/core/minos-microservice-aggregate/minos/aggregate/value_objects.py
similarity index 88%
rename from packages/core/minos-microservice-aggregate/minos/aggregate/models/value_objects.py
rename to packages/core/minos-microservice-aggregate/minos/aggregate/value_objects.py
index d204d497f..1ab7ca389 100644
--- a/packages/core/minos-microservice-aggregate/minos/aggregate/models/value_objects.py
+++ b/packages/core/minos-microservice-aggregate/minos/aggregate/value_objects.py
@@ -7,16 +7,15 @@
TypeVar,
)
-from minos.common import (
- DeclarativeModel,
- Model,
+from minos.aggregate.collections import (
+ IncrementalSet,
)
-
-from ..exceptions import (
+from minos.aggregate.exceptions import (
ValueObjectException,
)
-from .collections import (
- IncrementalSet,
+from minos.common import (
+ DeclarativeModel,
+ Model,
)
diff --git a/packages/core/minos-microservice-aggregate/poetry.lock b/packages/core/minos-microservice-aggregate/poetry.lock
index 65c2942b1..c48dbc0f7 100644
--- a/packages/core/minos-microservice-aggregate/poetry.lock
+++ b/packages/core/minos-microservice-aggregate/poetry.lock
@@ -130,28 +130,24 @@ pytz = ">=2015.7"
[[package]]
name = "black"
-version = "21.12b0"
+version = "22.1.0"
description = "The uncompromising code formatter."
category = "dev"
optional = false
python-versions = ">=3.6.2"
[package.dependencies]
-click = ">=7.1.2"
+click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
-pathspec = ">=0.9.0,<1"
+pathspec = ">=0.9.0"
platformdirs = ">=2"
-tomli = ">=0.2.6,<2.0.0"
-typing-extensions = [
- {version = ">=3.10.0.0", markers = "python_version < \"3.10\""},
- {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""},
-]
+tomli = ">=1.1.0"
+typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
[package.extras]
colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.7.4)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
-python2 = ["typed-ast (>=1.4.3)"]
uvloop = ["uvloop (>=0.15.2)"]
[[package]]
@@ -449,7 +445,7 @@ python-versions = "*"
[[package]]
name = "minos-microservice-common"
-version = "0.4.0"
+version = "0.4.1"
description = "Python Package with common Classes and Utilities used in Minos Microservices."
category = "main"
optional = false
@@ -472,7 +468,7 @@ url = "../minos-microservice-common"
[[package]]
name = "minos-microservice-networks"
-version = "0.4.0"
+version = "0.4.1"
description = "Python Package with the common network classes and utilities used in Minos Microservice."
category = "main"
optional = false
@@ -949,7 +945,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
-content-hash = "0ef4d2ebc5573e712d02eb7a4e38c1db284ae4964c89c5fad6110cf15042b3c9"
+content-hash = "7780ec62aa832682987ee33f4fac9973fc1cc8c815dc1790d98c74e840cf5b22"
[metadata.files]
aiohttp = [
@@ -1082,8 +1078,29 @@ babel = [
{file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"},
]
black = [
- {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"},
- {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"},
+ {file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"},
+ {file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"},
+ {file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"},
+ {file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"},
+ {file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"},
+ {file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"},
+ {file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"},
+ {file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"},
+ {file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"},
+ {file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"},
+ {file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"},
+ {file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"},
+ {file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"},
+ {file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"},
+ {file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"},
+ {file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"},
+ {file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"},
+ {file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"},
+ {file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"},
+ {file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"},
+ {file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"},
+ {file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"},
+ {file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"},
]
cached-property = [
{file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"},
diff --git a/packages/core/minos-microservice-aggregate/pyproject.toml b/packages/core/minos-microservice-aggregate/pyproject.toml
index 7511f763e..077039bf5 100644
--- a/packages/core/minos-microservice-aggregate/pyproject.toml
+++ b/packages/core/minos-microservice-aggregate/pyproject.toml
@@ -1,14 +1,14 @@
[tool.poetry]
name = "minos-microservice-aggregate"
-version = "0.4.0"
-description = "Python Package for Minos Microservices containing all the Aggregate stuff"
+version = "0.5.0"
+description = "The Aggregate pattern of the Minos Framework"
readme = "README.md"
repository = "https://github.com/minos-framework/minos-python"
homepage = "http://www.minos.run/"
authors = ["Minos Framework Devs "]
license = "MIT"
classifiers = [
- "Development Status :: 2 - Pre-Alpha",
+ "Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Natural Language :: English",
"Programming Language :: Python :: 3",
@@ -37,7 +37,7 @@ minos-microservice-networks = "^0.4.0"
[tool.poetry.dev-dependencies]
minos-microservice-common = { path = "../minos-microservice-common", develop = true }
minos-microservice-networks = { path = "../minos-microservice-networks", develop = true }
-black = "^21.12b0"
+black = "^22.1"
isort = "^5.8.0"
pytest = "^6.2.4"
coverage = "^6.3"
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_actions.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_actions.py
similarity index 100%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_actions.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_actions.py
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_aggregate.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_aggregate.py
new file mode 100644
index 000000000..89e6fd82a
--- /dev/null
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_aggregate.py
@@ -0,0 +1,50 @@
+import unittest
+from uuid import (
+ UUID,
+)
+
+from minos.aggregate import (
+ Aggregate,
+)
+from minos.common import (
+ NotProvidedException,
+)
+from tests.utils import (
+ CONFIG_FILE_PATH,
+ MinosTestCase,
+ Order,
+ OrderAggregate,
+)
+
+
+class TestAggregate(MinosTestCase):
+ async def test_root(self):
+ async with OrderAggregate.from_config(CONFIG_FILE_PATH) as aggregate:
+ self.assertEqual(Order, aggregate.root)
+
+ def test_root_raises(self):
+ with self.assertRaises(TypeError):
+ Aggregate.from_config(CONFIG_FILE_PATH)
+
+ async def test_from_config(self):
+ async with OrderAggregate.from_config(CONFIG_FILE_PATH) as aggregate:
+ self.assertTrue(self.transaction_repository, aggregate.transaction_repository)
+ self.assertTrue(self.event_repository, aggregate.event_repository)
+ self.assertTrue(self.snapshot_repository, aggregate.snapshot_repository)
+
+ def test_from_config_raises(self):
+ with self.assertRaises(NotProvidedException):
+ OrderAggregate.from_config(CONFIG_FILE_PATH, transaction_repository=None)
+ with self.assertRaises(NotProvidedException):
+ OrderAggregate.from_config(CONFIG_FILE_PATH, event_repository=None)
+ with self.assertRaises(NotProvidedException):
+ OrderAggregate.from_config(CONFIG_FILE_PATH, snapshot_repository=None)
+
+ async def test_call(self):
+ async with OrderAggregate.from_config(CONFIG_FILE_PATH) as aggregate:
+ uuid = await aggregate.create_order()
+ self.assertIsInstance(uuid, UUID)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_collections.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_collections.py
similarity index 93%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_collections.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_collections.py
index fb368b8f8..c475c4a3d 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_collections.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_collections.py
@@ -82,18 +82,14 @@ def test_data_cls(self):
def test_from_avro(self):
expected = IncrementalSet([1, 2])
- schema = [
- {"items": "int", "logicalType": "minos.aggregate.models.collections.IncrementalSet", "type": "array"},
- ]
+ schema = [{"items": "int", "logicalType": "minos.aggregate.collections.IncrementalSet", "type": "array"}]
data = [1, 2]
observed = Model.from_avro(schema, data)
self.assertEqual(expected, observed)
def test_avro_schema(self):
- expected = [
- {"items": "int", "logicalType": "minos.aggregate.models.collections.IncrementalSet", "type": "array"},
- ]
+ expected = [{"items": "int", "logicalType": "minos.aggregate.collections.IncrementalSet", "type": "array"}]
observed = IncrementalSet([1, 2]).avro_schema
self.assertEqual(expected, observed)
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_diffs/__init__.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/__init__.py
similarity index 100%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_diffs/__init__.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/__init__.py
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_entities.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_collections.py
similarity index 71%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_entities.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_collections.py
index d1d627e44..9a655318f 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_entities.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_collections.py
@@ -5,92 +5,67 @@
from unittest.mock import (
patch,
)
-from uuid import (
- UUID,
- uuid4,
-)
from minos.aggregate import (
Action,
- Entity,
EntitySet,
IncrementalSetDiff,
IncrementalSetDiffEntry,
)
from minos.common import (
- NULL_UUID,
- DeclarativeModel,
Model,
)
-
-
-class _Entity(Entity):
- """For testing purposes."""
-
- name: str
-
-
-class TestEntity(unittest.TestCase):
- def test_default(self):
- entity = Entity()
- self.assertIsInstance(entity, DeclarativeModel)
- self.assertIsNot(entity.uuid, NULL_UUID)
- self.assertIsInstance(entity.uuid, UUID)
-
- def test_uuid(self):
- uuid = uuid4()
- entity = Entity(uuid=uuid)
- self.assertIsInstance(entity, DeclarativeModel)
- self.assertIsNot(entity.uuid, NULL_UUID)
- self.assertEqual(uuid, entity.uuid)
+from tests.utils import (
+ OrderItem,
+)
class TestEntitySet(unittest.TestCase):
def test_data(self):
- raw = {_Entity("John"), _Entity("Michael")}
+ raw = {OrderItem("John"), OrderItem("Michael")}
entities = EntitySet(raw)
self.assertEqual({str(v.uuid): v for v in raw}, entities.data)
def test_eq_true(self):
- raw = {_Entity("John"), _Entity("Michael")}
+ raw = {OrderItem("John"), OrderItem("Michael")}
observed = EntitySet(raw)
self.assertEqual(EntitySet(raw), observed)
self.assertEqual(raw, observed)
self.assertEqual({str(v.uuid): v for v in raw}, observed)
def test_eq_false(self):
- raw = {_Entity("John"), _Entity("Michael")}
+ raw = {OrderItem("John"), OrderItem("Michael")}
observed = EntitySet(raw)
- other = {_Entity("Charlie")}
+ other = {OrderItem("Charlie")}
self.assertNotEqual(EntitySet(other), observed)
self.assertNotEqual(other, observed)
self.assertNotEqual({str(v.uuid): v for v in other}, observed)
self.assertNotEqual(list(raw), observed)
def test_len(self):
- raw = {_Entity("John"), _Entity("Michael")}
+ raw = {OrderItem("John"), OrderItem("Michael")}
entities = EntitySet(raw)
self.assertEqual(2, len(entities))
def test_iter(self):
- raw = {_Entity("John"), _Entity("Michael")}
+ raw = {OrderItem("John"), OrderItem("Michael")}
entities = EntitySet(raw)
self.assertEqual(raw, set(entities))
def test_contains(self):
- raw = [_Entity("John")]
+ raw = [OrderItem("John")]
entities = EntitySet(raw)
self.assertIn(raw[0], entities)
- self.assertNotIn(_Entity("Charlie"), entities)
+ self.assertNotIn(OrderItem("Charlie"), entities)
self.assertNotIn(1234, entities)
def test_add(self):
- raw = _Entity("John")
+ raw = OrderItem("John")
entities = EntitySet()
entities.add(raw)
@@ -98,14 +73,14 @@ def test_add(self):
self.assertEqual({raw}, entities)
def test_get(self):
- raw = _Entity("John")
+ raw = OrderItem("John")
entities = EntitySet()
entities.add(raw)
self.assertEqual(raw, entities.get(raw.uuid))
def test_remove(self):
- raw = [_Entity("John"), _Entity("Michael")]
+ raw = [OrderItem("John"), OrderItem("Michael")]
entities = EntitySet(raw)
entities.remove(raw[1])
@@ -113,7 +88,7 @@ def test_remove(self):
self.assertEqual({raw[0]}, entities)
def test_diff(self):
- raw = [_Entity("John"), _Entity("Michael")]
+ raw = [OrderItem("John"), OrderItem("Michael")]
entities = EntitySet(raw)
observed = entities.diff(EntitySet([raw[0]]))
@@ -122,18 +97,18 @@ def test_diff(self):
self.assertEqual(observed, expected)
def test_data_cls(self):
- raw = [_Entity("John"), _Entity("Michael")]
+ raw = [OrderItem("John"), OrderItem("Michael")]
entities = EntitySet(raw)
- self.assertEqual(_Entity, entities.data_cls)
+ self.assertEqual(OrderItem, entities.data_cls)
def test_from_avro(self):
- values = {_Entity("John"), _Entity("Michael")}
+ values = {OrderItem("John"), OrderItem("Michael")}
expected = EntitySet(values)
schema = [
{
- "logicalType": "minos.aggregate.models.entities.EntitySet",
+ "logicalType": "minos.aggregate.entities.EntitySet",
"type": "array",
- "items": _Entity.avro_schema[0],
+ "items": OrderItem.avro_schema[0],
},
]
data = [v.avro_data for v in values]
@@ -145,36 +120,36 @@ def test_avro_schema(self):
with patch("minos.common.AvroSchemaEncoder.generate_random_str", return_value="hello"):
expected = [
{
- "logicalType": "minos.aggregate.models.entities.EntitySet",
+ "logicalType": "minos.aggregate.entities.collections.EntitySet",
"type": "array",
- "items": _Entity.avro_schema[0],
+ "items": OrderItem.avro_schema[0],
},
]
- observed = EntitySet({_Entity("John"), _Entity("Michael")}).avro_schema
+ observed = EntitySet({OrderItem("John"), OrderItem("Michael")}).avro_schema
self.assertEqual(expected, observed)
def test_avro_data(self):
- values = {_Entity("John"), _Entity("Michael")}
+ values = {OrderItem("John"), OrderItem("Michael")}
expected = sorted([v.avro_data for v in values], key=lambda v: v["uuid"])
observed = EntitySet(values).avro_data
self.assertIsInstance(observed, list)
self.assertEqual(expected, sorted([v.avro_data for v in values], key=lambda v: v["uuid"]))
def test_avro_bytes(self):
- expected = EntitySet({_Entity("John"), _Entity("Michael")})
+ expected = EntitySet({OrderItem("John"), OrderItem("Michael")})
self.assertEqual(expected, Model.from_avro_bytes(expected.avro_bytes))
class TestEntitySetDiff(unittest.TestCase):
def setUp(self) -> None:
- self.raw = [_Entity("John"), _Entity("Michael")]
+ self.raw = [OrderItem("John"), OrderItem("Michael")]
self.old = EntitySet(self.raw)
- self.clone = [_Entity(name=entity.name, uuid=entity.uuid) for entity in self.raw]
+ self.clone = [OrderItem(name=entity.name, uuid=entity.uuid) for entity in self.raw]
def test_from_difference_create(self):
entities = EntitySet(self.clone)
- new = _Entity("Charlie")
+ new = OrderItem("Charlie")
entities.add(new)
observed = IncrementalSetDiff.from_difference(entities, self.old, get_fn=attrgetter("uuid"))
@@ -201,7 +176,7 @@ def test_from_difference_update(self):
def test_from_difference_combined(self):
entities = EntitySet(self.clone)
- new = _Entity("Charlie")
+ new = OrderItem("Charlie")
entities.add(new)
removed = self.clone[1]
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/__init__.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/__init__.py
similarity index 100%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/__init__.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/__init__.py
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_base.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_base.py
new file mode 100644
index 000000000..69dafbb8b
--- /dev/null
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_base.py
@@ -0,0 +1,40 @@
+import unittest
+from uuid import (
+ UUID,
+ uuid4,
+)
+
+from minos.aggregate import (
+ Entity,
+)
+from minos.common import (
+ NULL_UUID,
+ DeclarativeModel,
+)
+from tests.utils import (
+ OrderItem,
+)
+
+
+class TestEntity(unittest.TestCase):
+ def test_subclass(self):
+ self.assertTrue(issubclass(Entity, DeclarativeModel))
+
+ def test_default(self):
+ entity = OrderItem("foo")
+ self.assertIsInstance(entity, DeclarativeModel)
+ self.assertIsNot(entity.uuid, NULL_UUID)
+ self.assertIsInstance(entity.uuid, UUID)
+ self.assertEqual("foo", entity.name)
+
+ def test_uuid(self):
+ uuid = uuid4()
+ entity = OrderItem("foo", uuid=uuid)
+ self.assertIsInstance(entity, DeclarativeModel)
+ self.assertIsNot(entity.uuid, NULL_UUID)
+ self.assertEqual(uuid, entity.uuid)
+ self.assertEqual("foo", entity.name)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_external.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_external.py
new file mode 100644
index 000000000..74eb0180d
--- /dev/null
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_external.py
@@ -0,0 +1,23 @@
+import unittest
+from uuid import (
+ uuid4,
+)
+
+from tests.utils import (
+ Product,
+)
+
+
+class TestExternalEntity(unittest.TestCase):
+ def test_values(self):
+ uuid = uuid4()
+ product = Product(uuid, 3, "apple", 3028)
+
+ self.assertEqual(uuid, product.uuid)
+ self.assertEqual(3, product.version)
+ self.assertEqual("apple", product.title)
+ self.assertEqual(3028, product.quantity)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/__init__.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/__init__.py
similarity index 100%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/__init__.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/__init__.py
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_base.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_base.py
similarity index 95%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_base.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_base.py
index 23104e279..3cfe81c00 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_base.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_base.py
@@ -7,10 +7,10 @@
)
from minos.aggregate import (
- AggregateNotFoundException,
+ AlreadyDeletedException,
Condition,
- DeletedAggregateException,
EventRepositoryException,
+ NotFoundException,
Ordering,
)
from minos.common import (
@@ -23,7 +23,7 @@
)
-class TestAggregate(MinosTestCase):
+class TestRootEntity(MinosTestCase):
def setUp(self) -> None:
super().setUp()
self.kwargs = {"_repository": self.event_repository, "_snapshot": self.snapshot_repository}
@@ -77,7 +77,7 @@ async def test_get(self):
self.assertEqual(original, recovered)
async def test_get_raises(self):
- with self.assertRaises(AggregateNotFoundException):
+ with self.assertRaises(NotFoundException):
await Car.get(NULL_UUID, **self.kwargs)
async def test_update(self):
@@ -138,7 +138,7 @@ async def test_save_create(self):
car.color = "red"
car.doors = 5
- with self.assertRaises(AggregateNotFoundException):
+ with self.assertRaises(NotFoundException):
await car.refresh()
await car.save()
@@ -182,7 +182,7 @@ async def test_save_raises(self):
async def test_delete(self):
car = await Car.create(doors=3, color="blue", **self.kwargs)
await car.delete()
- with self.assertRaises(DeletedAggregateException):
+ with self.assertRaises(AlreadyDeletedException):
await Car.get(car.uuid, **self.kwargs)
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_broker.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_broker.py
similarity index 92%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_broker.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_broker.py
index 2ec9a3515..f94810954 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_broker.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_broker.py
@@ -5,10 +5,10 @@
from minos.aggregate import (
Action,
- AggregateDiff,
+ Event,
FieldDiff,
FieldDiffContainer,
- ModelRef,
+ Ref,
)
from minos.networks import (
BrokerMessageV1,
@@ -20,7 +20,7 @@
)
-class TestAggregate(MinosTestCase):
+class TestRootEntityBroker(MinosTestCase):
async def test_create(self):
car = await Car.create(doors=3, color="blue")
@@ -30,7 +30,7 @@ async def test_create(self):
self.assertIsInstance(observed[0], BrokerMessageV1)
self.assertEqual("CarCreated", observed[0].topic)
self.assertEqual(
- AggregateDiff(
+ Event(
uuid=car.uuid,
name=Car.classname,
version=1,
@@ -40,7 +40,7 @@ async def test_create(self):
[
FieldDiff("doors", int, 3),
FieldDiff("color", str, "blue"),
- FieldDiff("owner", Optional[ModelRef[Owner]], None),
+ FieldDiff("owner", Optional[Ref[Owner]], None),
]
),
),
@@ -59,7 +59,7 @@ async def test_update(self):
self.assertIsInstance(observed[0], BrokerMessageV1)
self.assertEqual("CarUpdated", observed[0].topic)
self.assertEqual(
- AggregateDiff(
+ Event(
uuid=car.uuid,
name=Car.classname,
version=2,
@@ -72,7 +72,7 @@ async def test_update(self):
self.assertIsInstance(observed[1], BrokerMessageV1)
self.assertEqual("CarUpdated.color", observed[1].topic)
self.assertEqual(
- AggregateDiff(
+ Event(
uuid=car.uuid,
name=Car.classname,
version=2,
@@ -95,7 +95,7 @@ async def test_delete(self):
self.assertIsInstance(observed[0], BrokerMessageV1)
self.assertEqual("CarDeleted", observed[0].topic)
self.assertEqual(
- AggregateDiff(
+ Event(
uuid=car.uuid,
name=Car.classname,
version=2,
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_differences.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_differences.py
similarity index 93%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_differences.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_differences.py
index 83769a090..8fb49716e 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_differences.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_differences.py
@@ -5,7 +5,7 @@
from minos.aggregate import (
Action,
- AggregateDiff,
+ Event,
FieldDiff,
FieldDiffContainer,
)
@@ -18,7 +18,7 @@
)
-class TestAggregateDifferences(MinosTestCase):
+class TestRootEntityDifferences(MinosTestCase):
async def asyncSetUp(self) -> None:
self.uuid = uuid4()
self.uuid_another = uuid4()
@@ -43,7 +43,7 @@ async def asyncSetUp(self) -> None:
)
def test_diff(self):
- expected = AggregateDiff(
+ expected = Event(
uuid=self.uuid,
name=Car.classname,
version=3,
@@ -55,7 +55,7 @@ def test_diff(self):
self.assertEqual(expected, observed)
def test_apply_diff(self):
- diff = AggregateDiff(
+ diff = Event(
uuid=self.uuid,
name=Car.classname,
version=3,
@@ -67,7 +67,7 @@ def test_apply_diff(self):
self.assertEqual(self.final, self.initial)
def test_apply_diff_raises(self):
- diff = AggregateDiff(
+ diff = Event(
uuid=self.uuid_another,
name=Car.classname,
version=3,
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_not_provided.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_not_provided.py
similarity index 95%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_not_provided.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_not_provided.py
index 1acd9bedb..1d7ed117d 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_not_provided.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_not_provided.py
@@ -15,7 +15,7 @@
)
-class TestAggregateNotProvided(MinosTestCase):
+class TestRootEntityNotProvided(MinosTestCase):
async def test_create_raises(self):
with self.assertRaises(NotProvidedException):
await Car.create(doors=3, color="blue", _repository=None)
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_with_postgresql.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_with_postgresql.py
similarity index 91%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_with_postgresql.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_with_postgresql.py
index ef878482b..726e7cae2 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/test_with_postgresql.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_models/test_root/test_with_postgresql.py
@@ -1,7 +1,7 @@
import unittest
from minos.aggregate import (
- DeletedAggregateException,
+ AlreadyDeletedException,
EntitySet,
PostgreSqlEventRepository,
PostgreSqlSnapshotRepository,
@@ -21,7 +21,7 @@
)
-class TestAggregateWithPostgreSql(MinosTestCase, PostgresAsyncTestCase):
+class TestExternalEntityWithPostgreSql(MinosTestCase, PostgresAsyncTestCase):
CONFIG_FILE_PATH = BASE_PATH / "test_config.yml"
def setUp(self):
@@ -51,7 +51,7 @@ async def test_create_update_delete(self):
self.assertEqual(car, await Car.get(car.uuid))
await car.delete()
- with self.assertRaises(DeletedAggregateException):
+ with self.assertRaises(AlreadyDeletedException):
await Car.get(car.uuid)
car = await Car.create(doors=3, color="blue")
@@ -62,12 +62,12 @@ async def test_create_update_delete(self):
self.assertEqual(expected, await Car.get(car.uuid))
await car.delete()
- with self.assertRaises(DeletedAggregateException):
+ with self.assertRaises(AlreadyDeletedException):
await Car.get(car.uuid)
async def test_entity_set_value_object_set(self):
order = await Order.create(products=EntitySet(), reviews=ValueObjectSet())
- item = OrderItem(24)
+ item = OrderItem("foo")
order.products.add(item)
await order.save()
@@ -75,7 +75,7 @@ async def test_entity_set_value_object_set(self):
recovered = await Order.get(order.uuid)
self.assertEqual(order, recovered)
- item.amount = 36
+ item.name = "bar"
order.products.add(item)
await order.save()
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/__init__.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/test_extractors.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/test_extractors.py
similarity index 62%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/test_extractors.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/test_extractors.py
index 7fe3262fe..5de4171fb 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/test_extractors.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/test_extractors.py
@@ -8,82 +8,82 @@
)
from minos.aggregate import (
- ModelRef,
- ModelRefExtractor,
+ Ref,
+ RefExtractor,
)
from minos.common import (
ModelType,
)
-class TestModelRefExtractor(unittest.TestCase):
+class TestRefExtractor(unittest.TestCase):
def test_simple(self):
mt_foo = ModelType.build("Foo", {"uuid": UUID, "version": int})
- value = ModelRef(uuid4())
+ value = Ref(uuid4())
expected = {"Foo": {value}}
- observed = ModelRefExtractor(value, ModelRef[mt_foo]).build()
+ observed = RefExtractor(value, Ref[mt_foo]).build()
self.assertEqual(expected, observed)
def test_list(self):
mt_foo = ModelType.build("Foo", {"uuid": UUID, "version": int})
- value = [ModelRef(uuid4()), ModelRef(uuid4())]
+ value = [Ref(uuid4()), Ref(uuid4())]
expected = {"Foo": set(value)}
- observed = ModelRefExtractor(value, list[ModelRef[mt_foo]]).build()
+ observed = RefExtractor(value, list[Ref[mt_foo]]).build()
self.assertEqual(expected, observed)
def test_dict(self):
mt_key = ModelType.build("Key", {"uuid": UUID, "version": int})
mt_value = ModelType.build("Value", {"uuid": UUID, "version": int})
- value = {ModelRef(uuid4()): ModelRef(uuid4()), ModelRef(uuid4()): ModelRef(uuid4())}
+ value = {Ref(uuid4()): Ref(uuid4()), Ref(uuid4()): Ref(uuid4())}
expected = {"Key": set(value.keys()), "Value": set(value.values())}
- observed = ModelRefExtractor(value, dict[ModelRef[mt_key], ModelRef[mt_value]]).build()
+ observed = RefExtractor(value, dict[Ref[mt_key], Ref[mt_value]]).build()
self.assertEqual(expected, observed)
def test_model(self):
mt_bar = ModelType.build("Bar", {"uuid": UUID, "version": int})
- mt_foo = ModelType.build("Foo", {"uuid": UUID, "version": int, "another": ModelRef[mt_bar]})
+ mt_foo = ModelType.build("Foo", {"uuid": UUID, "version": int, "another": Ref[mt_bar]})
- value = mt_foo(uuid=uuid4(), version=1, another=ModelRef(uuid4()))
+ value = mt_foo(uuid=uuid4(), version=1, another=Ref(uuid4()))
expected = {"Bar": {value.another}}
- observed = ModelRefExtractor(value, mt_foo).build()
+ observed = RefExtractor(value, mt_foo).build()
self.assertEqual(expected, observed)
def test_model_without_kind(self):
mt_bar = ModelType.build("Bar", {"uuid": UUID, "version": int})
- mt_foo = ModelType.build("Foo", {"uuid": UUID, "version": int, "another": ModelRef[mt_bar]})
+ mt_foo = ModelType.build("Foo", {"uuid": UUID, "version": int, "another": Ref[mt_bar]})
- value = mt_foo(uuid=uuid4(), version=1, another=ModelRef(uuid4()))
+ value = mt_foo(uuid=uuid4(), version=1, another=Ref(uuid4()))
- expected = ModelRefExtractor(value, mt_foo).build()
- observed = ModelRefExtractor(value).build()
+ expected = RefExtractor(value, mt_foo).build()
+ observed = RefExtractor(value).build()
self.assertEqual(expected, observed)
def test_optional(self):
mt_foo = ModelType.build("Foo", {"uuid": UUID, "version": int})
- value = ModelRef(uuid4())
+ value = Ref(uuid4())
expected = {"Foo": {value}}
- observed = ModelRefExtractor(value, Optional[ModelRef[mt_foo]]).build()
+ observed = RefExtractor(value, Optional[Ref[mt_foo]]).build()
self.assertEqual(expected, observed)
def test_model_cls_by_type_hints(self):
mt_foo = ModelType.build("Foo", {"uuid": UUID, "version": int})
- value = ModelRef(mt_foo(uuid4(), 1))
+ value = Ref(mt_foo(uuid4(), 1))
self.assertEqual(mt_foo, value.data_cls)
def test_model_cls_none(self):
- value = ModelRef(uuid4())
+ value = Ref(uuid4())
self.assertEqual(None, value.data_cls)
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/test_injectors.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/test_injectors.py
similarity index 75%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/test_injectors.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/test_injectors.py
index 202d04617..f88b5d0a7 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/test_injectors.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/test_injectors.py
@@ -5,8 +5,8 @@
)
from minos.aggregate import (
- ModelRef,
- ModelRefInjector,
+ Ref,
+ RefInjector,
)
from minos.common import (
ModelType,
@@ -17,13 +17,13 @@
)
-class TestModelRefInjector(MinosTestCase):
+class TestRefInjector(MinosTestCase):
async def test_simple(self):
model = await Car.create(3, "test")
mapper = {model.uuid: model}
expected = model
- observed = ModelRefInjector(model.uuid, mapper).build()
+ observed = RefInjector(model.uuid, mapper).build()
self.assertEqual(expected, observed)
@@ -32,7 +32,7 @@ async def test_list(self):
mapper = {model.uuid: model}
expected = [model, model, model]
- observed = ModelRefInjector([model.uuid, model.uuid, model.uuid], mapper).build()
+ observed = RefInjector([model.uuid, model.uuid, model.uuid], mapper).build()
self.assertEqual(expected, observed)
@@ -41,20 +41,20 @@ async def test_dict(self):
mapper = {model.uuid: model}
expected = {model: model}
- observed = ModelRefInjector({model.uuid: model.uuid}, mapper).build()
+ observed = RefInjector({model.uuid: model.uuid}, mapper).build()
self.assertEqual(expected, observed)
def test_model(self):
mt_bar = ModelType.build("Bar", {"uuid": UUID, "version": int})
- mt_foo = ModelType.build("Foo", {"uuid": UUID, "version": int, "another": ModelRef[mt_bar]})
+ mt_foo = ModelType.build("Foo", {"uuid": UUID, "version": int, "another": Ref[mt_bar]})
model = mt_bar(uuid=uuid4(), version=1)
mapper = {model.uuid: model}
value = mt_foo(uuid=uuid4(), version=1, another=model.uuid)
expected = mt_foo(uuid=value.uuid, version=1, another=model)
- observed = ModelRefInjector(value, mapper).build()
+ observed = RefInjector(value, mapper).build()
self.assertEqual(expected, observed)
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/test_models.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/test_models.py
similarity index 71%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/test_models.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/test_models.py
index 71e279dc4..50215e863 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/test_models.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/test_models.py
@@ -11,8 +11,7 @@
from minos.aggregate import (
IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR,
- AggregateRef,
- ModelRef,
+ Ref,
)
from minos.common import (
DeclarativeModel,
@@ -28,56 +27,37 @@
MinosTestCase,
)
-
-class Product(AggregateRef):
- """For testing purposes."""
-
- title: str
- quantity: int
-
-
-class TestSubAggregate(unittest.TestCase):
- def test_values(self):
- uuid = uuid4()
- product = Product(uuid, 3, "apple", 3028)
-
- self.assertEqual(uuid, product.uuid)
- self.assertEqual(3, product.version)
- self.assertEqual("apple", product.title)
- self.assertEqual(3028, product.quantity)
-
-
FakeMessage = ModelType.build("FakeMessage", {"content": Any})
Bar = ModelType.build("Bar", {"uuid": UUID, "age": int})
-Foo = ModelType.build("Foo", {"another": ModelRef[Bar]})
+Foo = ModelType.build("Foo", {"another": Ref[Bar]})
-class TestModelRef(MinosTestCase):
+class TestRef(MinosTestCase):
def test_subclass(self):
# noinspection PyTypeHints
- self.assertTrue(issubclass(ModelRef, (DeclarativeModel, UUID, Generic)))
+ self.assertTrue(issubclass(Ref, (DeclarativeModel, UUID, Generic)))
def test_raises(self):
with self.assertRaises(ValueError):
# noinspection PyTypeChecker
- ModelRef(56)
+ Ref(56)
def test_uuid(self):
uuid = uuid4()
- value = ModelRef(uuid)
+ value = Ref(uuid)
self.assertEqual(uuid, value)
def test_uuid_int(self):
uuid = uuid4()
- value = ModelRef(uuid)
+ value = Ref(uuid)
self.assertEqual(uuid.int, value.int)
def test_uuid_is_safe(self):
uuid = uuid4()
- value = ModelRef(uuid)
+ value = Ref(uuid)
self.assertEqual(uuid.is_safe, value.is_safe)
@@ -89,46 +69,46 @@ def test_model(self):
def test_model_uuid(self):
uuid = uuid4()
- value = ModelRef(Bar(uuid, 1))
+ value = Ref(Bar(uuid, 1))
self.assertEqual(uuid, value.uuid)
def test_model_attribute(self):
- value = ModelRef(Bar(uuid4(), 1))
+ value = Ref(Bar(uuid4(), 1))
self.assertEqual(1, value.age)
def test_model_attribute_raises(self):
- value = ModelRef(Bar(uuid4(), 1))
+ value = Ref(Bar(uuid4(), 1))
with self.assertRaises(AttributeError):
value.year
def test_fields(self):
- value = ModelRef(Bar(uuid4(), 1))
+ value = Ref(Bar(uuid4(), 1))
self.assertEqual({"data": Field("data", Union[Bar, UUID], value)}, value.fields)
def test_model_avro_data(self):
value = Bar(uuid4(), 1)
- self.assertEqual(value.avro_data, ModelRef(value).avro_data)
+ self.assertEqual(value.avro_data, Ref(value).avro_data)
def test_uuid_avro_data(self):
value = uuid4()
- self.assertEqual(str(value), ModelRef(value).avro_data)
+ self.assertEqual(str(value), Ref(value).avro_data)
async def test_model_avro_data_submitting(self):
uuid = uuid4()
value = Bar(uuid, 1)
IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR.set(True)
- self.assertEqual(str(uuid), ModelRef(value).avro_data)
+ self.assertEqual(str(uuid), Ref(value).avro_data)
async def test_uuid_avro_data_submitting(self):
value = uuid4()
IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR.set(True)
- self.assertEqual(str(value), ModelRef(value).avro_data)
+ self.assertEqual(str(value), Ref(value).avro_data)
def test_model_avro_schema(self):
another = Bar(uuid4(), 1)
@@ -143,13 +123,13 @@ def test_model_avro_schema(self):
"name": "Bar",
"namespace": "",
"type": "record",
- "logicalType": "minos.aggregate.models.refs.models.ModelRef",
+ "logicalType": "minos.aggregate.entities.refs.models.Ref",
},
- {"logicalType": "minos.aggregate.models.refs.models.ModelRef", "type": "string"},
+ {"logicalType": "minos.aggregate.entities.refs.models.Ref", "type": "string"},
]
]
- self.assertEqual(expected, ModelRef(another).avro_schema)
+ self.assertEqual(expected, Ref(another).avro_schema)
def test_uuid_avro_schema(self):
another = uuid4()
@@ -162,12 +142,12 @@ def test_uuid_avro_schema(self):
{"name": "uuid", "type": {"logicalType": "uuid", "type": "string"}},
{"name": "age", "type": "int"},
],
- "logicalType": "minos.aggregate.models.refs.models.ModelRef",
+ "logicalType": "minos.aggregate.entities.refs.models.Ref",
"name": "Bar",
"namespace": "",
"type": "record",
},
- {"logicalType": "minos.aggregate.models.refs.models.ModelRef", "type": "string"},
+ {"logicalType": "minos.aggregate.entities.refs.models.Ref", "type": "string"},
]
]
self.assertEqual(expected, ref.avro_schema)
@@ -177,13 +157,13 @@ def test_model_from_avro(self):
expected = Foo(another).another # FIXME: This should not be needed to set the type hint properly
schema = [
- {"logicalType": "minos.aggregate.models.refs.models.ModelRef", "type": "string"},
+ {"logicalType": "minos.aggregate.entities.refs.models.Ref", "type": "string"},
{
"fields": [
{"name": "uuid", "type": {"logicalType": "uuid", "type": "string"}},
{"name": "age", "type": "int"},
],
- "logicalType": "minos.aggregate.models.refs.models.ModelRef",
+ "logicalType": "minos.aggregate.entities.refs.models.Ref",
"name": "Bar",
"namespace": "",
"type": "record",
@@ -204,12 +184,12 @@ def test_uuid_from_avro(self):
{"name": "uuid", "type": {"logicalType": "uuid", "type": "string"}},
{"name": "age", "type": "int"},
],
- "logicalType": "minos.aggregate.models.refs.models.ModelRef",
+ "logicalType": "minos.aggregate.entities.refs.models.Ref",
"name": "Bar",
"namespace": "",
"type": "record",
},
- {"logicalType": "minos.aggregate.models.refs.models.ModelRef", "type": "string"},
+ {"logicalType": "minos.aggregate.entities.refs.models.Ref", "type": "string"},
]
data = str(another)
@@ -238,7 +218,7 @@ async def test_resolve(self):
async def test_resolve_already(self):
uuid = uuid4()
- ref = ModelRef(Bar(uuid, 1))
+ ref = Ref(Bar(uuid, 1))
await ref.resolve()
@@ -246,20 +226,20 @@ async def test_resolve_already(self):
self.assertEqual(0, len(observed))
async def test_resolved(self):
- self.assertFalse(ModelRef(uuid4()).resolved)
- self.assertTrue(ModelRef(Bar(uuid4(), 4)).resolved)
+ self.assertFalse(Ref(uuid4()).resolved)
+ self.assertTrue(Ref(Bar(uuid4(), 4)).resolved)
def test_avro_model(self):
another = Bar(uuid4(), 1)
ref = Foo(another).another # FIXME: This should not be needed to set the type hint properly
- self.assertEqual(ref, ModelRef.from_avro_bytes(ref.avro_bytes))
+ self.assertEqual(ref, Ref.from_avro_bytes(ref.avro_bytes))
def test_avro_uuid(self):
another = uuid4()
ref = Foo(another).another # FIXME: This should not be needed to set the type hint properly
- self.assertEqual(ref, ModelRef.from_avro_bytes(ref.avro_bytes))
+ self.assertEqual(ref, Ref.from_avro_bytes(ref.avro_bytes))
if __name__ == "__main__":
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/test_resolvers.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/test_resolvers.py
similarity index 80%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/test_resolvers.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/test_resolvers.py
index bf842d3a5..1b74cc24e 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_refs/test_resolvers.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_entities/test_refs/test_resolvers.py
@@ -5,8 +5,8 @@
)
from minos.aggregate import (
- ModelRef,
- ModelRefResolver,
+ Ref,
+ RefResolver,
)
from minos.common import (
ModelType,
@@ -20,17 +20,17 @@
)
Bar = ModelType.build("Bar", {"uuid": UUID, "version": int})
-Foo = ModelType.build("Foo", {"uuid": UUID, "version": int, "another": ModelRef[Bar]})
+Foo = ModelType.build("Foo", {"uuid": UUID, "version": int, "another": Ref[Bar]})
-class TestModelRefResolver(MinosTestCase):
+class TestRefResolver(MinosTestCase):
def setUp(self) -> None:
super().setUp()
- self.resolver = ModelRefResolver()
+ self.resolver = RefResolver()
self.uuid = uuid4()
self.another_uuid = uuid4()
- self.value = Foo(self.uuid, 1, another=ModelRef(self.another_uuid))
+ self.value = Foo(self.uuid, 1, another=Ref(self.another_uuid))
async def test_resolve(self):
self.broker_subscriber_builder.with_messages(
@@ -46,7 +46,7 @@ async def test_resolve(self):
self.assertEqual("GetBars", observed[0].topic)
self.assertEqual({"uuids": {self.another_uuid}}, observed[0].content)
- self.assertEqual(Foo(self.uuid, 1, another=ModelRef(Bar(self.another_uuid, 1))), resolved)
+ self.assertEqual(Foo(self.uuid, 1, another=Ref(Bar(self.another_uuid, 1))), resolved)
async def test_resolve_already(self):
self.assertEqual(34, await self.resolver.resolve(34))
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_entries.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_entries.py
index b6ac965e9..a2941bdfc 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_entries.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_entries.py
@@ -8,7 +8,7 @@
from minos.aggregate import (
Action,
- AggregateDiff,
+ Event,
EventEntry,
FieldDiff,
FieldDiffContainer,
@@ -30,8 +30,8 @@ def setUp(self) -> None:
def test_constructor(self):
entry = EventEntry(self.uuid, "example.Car", 0, bytes("car", "utf-8"))
- self.assertEqual(self.uuid, entry.aggregate_uuid)
- self.assertEqual("example.Car", entry.aggregate_name)
+ self.assertEqual(self.uuid, entry.uuid)
+ self.assertEqual("example.Car", entry.name)
self.assertEqual(0, entry.version)
self.assertEqual(bytes("car", "utf-8"), entry.data)
self.assertEqual(None, entry.id)
@@ -41,8 +41,8 @@ def test_constructor(self):
def test_constructor_extended(self):
entry = EventEntry(
- aggregate_uuid=self.uuid,
- aggregate_name="example.Car",
+ uuid=self.uuid,
+ name="example.Car",
version=0,
data=bytes("car", "utf-8"),
id=5678,
@@ -50,8 +50,8 @@ def test_constructor_extended(self):
created_at=datetime(2020, 10, 13, 8, 45, 32),
transaction_uuid=self.transaction_uuid,
)
- self.assertEqual(self.uuid, entry.aggregate_uuid)
- self.assertEqual("example.Car", entry.aggregate_name)
+ self.assertEqual(self.uuid, entry.uuid)
+ self.assertEqual("example.Car", entry.name)
self.assertEqual(0, entry.version)
self.assertEqual(bytes("car", "utf-8"), entry.data)
self.assertEqual(5678, entry.id)
@@ -59,14 +59,14 @@ def test_constructor_extended(self):
self.assertEqual(datetime(2020, 10, 13, 8, 45, 32), entry.created_at)
self.assertEqual(self.transaction_uuid, entry.transaction_uuid)
- async def test_from_aggregate_diff(self):
+ async def test_from_event(self):
fields_diff = FieldDiffContainer([FieldDiff("doors", int, 3), FieldDiff("color", str, "blue")])
created_at = current_datetime()
- aggregate_diff = AggregateDiff(self.uuid, Car.classname, 1, Action.CREATE, created_at, fields_diff)
+ event = Event(self.uuid, Car.classname, 1, Action.CREATE, created_at, fields_diff)
- entry = EventEntry.from_aggregate_diff(aggregate_diff)
- self.assertEqual(self.uuid, entry.aggregate_uuid)
- self.assertEqual("tests.utils.Car", entry.aggregate_name)
+ entry = EventEntry.from_event(event)
+ self.assertEqual(self.uuid, entry.uuid)
+ self.assertEqual("tests.utils.Car", entry.name)
self.assertEqual(None, entry.version)
self.assertEqual(fields_diff, FieldDiffContainer.from_avro_bytes(entry.data))
self.assertEqual(None, entry.id)
@@ -74,15 +74,15 @@ async def test_from_aggregate_diff(self):
self.assertEqual(None, entry.created_at)
self.assertEqual(NULL_UUID, entry.transaction_uuid)
- async def test_from_aggregate_diff_with_transaction(self):
+ async def test_from_event_with_transaction(self):
transaction = TransactionEntry(self.transaction_uuid)
fields_diff = FieldDiffContainer([FieldDiff("doors", int, 3), FieldDiff("color", str, "blue")])
created_at = current_datetime()
- aggregate_diff = AggregateDiff(self.uuid, Car.classname, 1, Action.CREATE, created_at, fields_diff)
+ event = Event(self.uuid, Car.classname, 1, Action.CREATE, created_at, fields_diff)
- entry = EventEntry.from_aggregate_diff(aggregate_diff, transaction=transaction)
- self.assertEqual(self.uuid, entry.aggregate_uuid)
- self.assertEqual("tests.utils.Car", entry.aggregate_name)
+ entry = EventEntry.from_event(event, transaction=transaction)
+ self.assertEqual(self.uuid, entry.uuid)
+ self.assertEqual("tests.utils.Car", entry.name)
self.assertEqual(None, entry.version)
self.assertEqual(fields_diff, FieldDiffContainer.from_avro_bytes(entry.data))
self.assertEqual(None, entry.id)
@@ -93,8 +93,8 @@ async def test_from_aggregate_diff_with_transaction(self):
async def test_from_another(self):
created_at = datetime(2020, 10, 13, 8, 45, 32)
another = EventEntry(
- aggregate_uuid=self.uuid,
- aggregate_name="example.Car",
+ uuid=self.uuid,
+ name="example.Car",
version=0,
data=bytes("car", "utf-8"),
id=5678,
@@ -105,8 +105,8 @@ async def test_from_another(self):
transaction_uuid = uuid4()
entry = EventEntry.from_another(another, transaction_uuid=transaction_uuid)
- self.assertEqual(self.uuid, entry.aggregate_uuid)
- self.assertEqual("example.Car", entry.aggregate_name)
+ self.assertEqual(self.uuid, entry.uuid)
+ self.assertEqual("example.Car", entry.name)
self.assertEqual(0, entry.version)
self.assertEqual(bytes("car", "utf-8"), entry.data)
self.assertEqual(None, entry.id)
@@ -114,19 +114,19 @@ async def test_from_another(self):
self.assertEqual(created_at, entry.created_at)
self.assertEqual(transaction_uuid, entry.transaction_uuid)
- def test_aggregate_diff(self):
+ def test_event(self):
field_diff_container = FieldDiffContainer([FieldDiff("doors", int, 3), FieldDiff("color", str, "blue")])
version = 1
now = current_datetime()
- aggregate_diff = AggregateDiff(self.uuid, Car.classname, version, Action.CREATE, now, field_diff_container)
+ event = Event(self.uuid, Car.classname, version, Action.CREATE, now, field_diff_container)
- entry = EventEntry.from_aggregate_diff(aggregate_diff)
+ entry = EventEntry.from_event(event)
entry.version = version
entry.created_at = now
- self.assertEqual(aggregate_diff, entry.aggregate_diff)
+ self.assertEqual(event, entry.event)
def test_field_diff_container(self):
field_diff_container = FieldDiffContainer([FieldDiff("doors", int, 3), FieldDiff("color", str, "blue")])
@@ -163,14 +163,14 @@ def test_hash(self):
def test_repr(self):
id_ = 5678
version = 0
- aggregate_name = "example.Car"
+ name = "example.Car"
data = bytes("car", "utf-8")
action = Action.CREATE
created_at = datetime(2020, 10, 13, 8, 45, 32)
transaction_uuid = uuid4()
entry = EventEntry(
- aggregate_uuid=self.uuid,
- aggregate_name=aggregate_name,
+ uuid=self.uuid,
+ name=name,
version=version,
data=data,
id=id_,
@@ -179,7 +179,7 @@ def test_repr(self):
transaction_uuid=transaction_uuid,
)
expected = (
- f"EventEntry(aggregate_uuid={self.uuid!r}, aggregate_name={aggregate_name!r}, "
+ f"EventEntry(uuid={self.uuid!r}, name={name!r}, "
f"version={version!r}, len(data)={len(data)!r}, id={id_!r}, action={action!r}, created_at={created_at!r}, "
f"transaction_uuid={transaction_uuid!r})"
)
@@ -188,14 +188,14 @@ def test_repr(self):
def test_as_raw(self):
id_ = 5678
version = 0
- aggregate_name = "example.Car"
+ name = "example.Car"
data = bytes("car", "utf-8")
action = Action.CREATE
created_at = datetime(2020, 10, 13, 8, 45, 32)
transaction_uuid = uuid4()
entry = EventEntry(
- aggregate_uuid=self.uuid,
- aggregate_name=aggregate_name,
+ uuid=self.uuid,
+ name=name,
version=version,
data=data,
id=id_,
@@ -204,8 +204,8 @@ def test_as_raw(self):
transaction_uuid=transaction_uuid,
)
expected = {
- "aggregate_uuid": self.uuid,
- "aggregate_name": aggregate_name,
+ "uuid": self.uuid,
+ "name": name,
"version": version,
"data": data,
"id": id_,
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_diffs/test_fields.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_fields.py
similarity index 96%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_diffs/test_fields.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_fields.py
index 1fc01894a..6a878096f 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_diffs/test_fields.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_fields.py
@@ -17,7 +17,7 @@
FieldDiff,
FieldDiffContainer,
IncrementalFieldDiff,
- ModelRef,
+ Ref,
)
from minos.common import (
NULL_DATETIME,
@@ -76,7 +76,7 @@ def test_from_model(self):
FieldDiff("updated_at", datetime, NULL_DATETIME),
FieldDiff("doors", int, 5),
FieldDiff("color", str, "red"),
- FieldDiff("owner", Optional[ModelRef[Owner]], None),
+ FieldDiff("owner", Optional[Ref[Owner]], None),
]
)
observed = FieldDiffContainer.from_model(self.car_two)
@@ -87,7 +87,7 @@ def test_from_model_with_ignore(self):
[
FieldDiff("doors", int, 5),
FieldDiff("color", str, "red"),
- FieldDiff("owner", Optional[ModelRef[Owner]], None),
+ FieldDiff("owner", Optional[Ref[Owner]], None),
]
)
observed = FieldDiffContainer.from_model(self.car_two, ignore={"uuid", "version", "created_at", "updated_at"})
@@ -102,7 +102,7 @@ def test_avro_schema(self):
"type": {
"fields": [{"name": "name", "type": "string"}, {"name": "value", "type": "int"}],
"name": "FieldDiff",
- "namespace": "minos.aggregate.models.diffs.fields.hola",
+ "namespace": "minos.aggregate.events.fields.hola",
"type": "record",
},
},
@@ -111,13 +111,13 @@ def test_avro_schema(self):
"type": {
"fields": [{"name": "name", "type": "string"}, {"name": "value", "type": "string"}],
"name": "FieldDiff",
- "namespace": "minos.aggregate.models.diffs.fields.adios",
+ "namespace": "minos.aggregate.events.fields.adios",
"type": "record",
},
},
],
"name": "FieldDiffContainer",
- "namespace": "minos.aggregate.models.diffs.fields.uno",
+ "namespace": "minos.aggregate.events.fields.uno",
"type": "record",
}
]
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_diffs/test_aggregates.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_models.py
similarity index 80%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_diffs/test_aggregates.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_models.py
index fe6fef6ad..1a8583bad 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_diffs/test_aggregates.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_models.py
@@ -8,11 +8,11 @@
from minos.aggregate import (
Action,
- AggregateDiff,
+ Event,
FieldDiff,
FieldDiffContainer,
IncrementalFieldDiff,
- ModelRef,
+ Ref,
)
from minos.common import (
current_datetime,
@@ -24,7 +24,7 @@
)
-class TestAggregateDiff(MinosTestCase):
+class TestEvent(MinosTestCase):
async def asyncSetUp(self) -> None:
await super().asyncSetUp()
@@ -35,7 +35,7 @@ async def asyncSetUp(self) -> None:
self.final = Car(5, "yellow", uuid=self.uuid, version=3)
self.another = Car(3, "blue", uuid=self.uuid_another, version=1)
- self.diff = AggregateDiff(
+ self.diff = Event(
uuid=self.uuid,
name=Car.classname,
version=1,
@@ -45,7 +45,7 @@ async def asyncSetUp(self) -> None:
[
FieldDiff("doors", int, 3),
FieldDiff("color", str, "blue"),
- FieldDiff("owner", Optional[ModelRef[Owner]], None),
+ FieldDiff("owner", Optional[Ref[Owner]], None),
]
),
)
@@ -55,27 +55,27 @@ def test_simplified_name(self):
def test_total_ordering(self):
observed = [
- AggregateDiff.from_aggregate(Car(3, "blue", version=4)),
- AggregateDiff.from_aggregate(Car(3, "blue", version=1)),
- AggregateDiff.from_aggregate(Car(3, "blue", version=3)),
- AggregateDiff.from_aggregate(Car(3, "blue", version=2)),
+ Event.from_root_entity(Car(3, "blue", version=4)),
+ Event.from_root_entity(Car(3, "blue", version=1)),
+ Event.from_root_entity(Car(3, "blue", version=3)),
+ Event.from_root_entity(Car(3, "blue", version=2)),
]
observed.sort()
expected = [
- AggregateDiff.from_aggregate(Car(3, "blue", version=1)),
- AggregateDiff.from_aggregate(Car(3, "blue", version=2)),
- AggregateDiff.from_aggregate(Car(3, "blue", version=3)),
- AggregateDiff.from_aggregate(Car(3, "blue", version=4)),
+ Event.from_root_entity(Car(3, "blue", version=1)),
+ Event.from_root_entity(Car(3, "blue", version=2)),
+ Event.from_root_entity(Car(3, "blue", version=3)),
+ Event.from_root_entity(Car(3, "blue", version=4)),
]
self.assertEqual(expected, observed)
- def test_from_aggregate(self):
- observed = AggregateDiff.from_aggregate(self.initial)
+ def test_from_root_entity(self):
+ observed = Event.from_root_entity(self.initial)
self.assertEqual(self.diff, observed)
- def test_from_deleted_aggregate(self):
- expected = AggregateDiff(
+ def test_from_deleted_root_entity(self):
+ expected = Event(
uuid=self.uuid,
name=Car.classname,
version=1,
@@ -83,11 +83,11 @@ def test_from_deleted_aggregate(self):
created_at=self.initial.updated_at,
fields_diff=FieldDiffContainer.empty(),
)
- observed = AggregateDiff.from_deleted_aggregate(self.initial)
+ observed = Event.from_deleted_root_entity(self.initial)
self.assertEqual(expected, observed)
def test_from_difference(self):
- expected = AggregateDiff(
+ expected = Event(
uuid=self.uuid,
name=Car.classname,
version=3,
@@ -95,22 +95,22 @@ def test_from_difference(self):
created_at=self.final.updated_at,
fields_diff=FieldDiffContainer([FieldDiff("doors", int, 5), FieldDiff("color", str, "yellow")]),
)
- observed = AggregateDiff.from_difference(self.final, self.initial)
+ observed = Event.from_difference(self.final, self.initial)
self.assertEqual(expected, observed)
def test_from_difference_raises(self):
with self.assertRaises(ValueError):
- AggregateDiff.from_difference(self.initial, self.another)
+ Event.from_difference(self.initial, self.another)
def test_avro_serialization(self):
serialized = self.diff.avro_bytes
self.assertIsInstance(serialized, bytes)
- deserialized = AggregateDiff.from_avro_bytes(serialized)
+ deserialized = Event.from_avro_bytes(serialized)
self.assertEqual(self.diff, deserialized)
def test_decompose(self):
- aggr = AggregateDiff(
+ aggr = Event(
uuid=self.uuid,
name=Car.classname,
version=3,
@@ -120,7 +120,7 @@ def test_decompose(self):
)
expected = [
- AggregateDiff(
+ Event(
uuid=self.uuid,
name=Car.classname,
version=3,
@@ -128,7 +128,7 @@ def test_decompose(self):
created_at=aggr.created_at,
fields_diff=FieldDiffContainer([FieldDiff("doors", int, 5)]),
),
- AggregateDiff(
+ Event(
uuid=self.uuid,
name=Car.classname,
version=3,
@@ -142,9 +142,9 @@ def test_decompose(self):
self.assertEqual(expected, observed)
-class TestAggregateDiffAccessors(unittest.TestCase):
+class TestEventAccessors(unittest.TestCase):
def setUp(self) -> None:
- self.diff = AggregateDiff(
+ self.diff = Event(
uuid=uuid4(),
name="src.domain.Car",
version=1,
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_repositories/test_abc.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_repositories/test_abc.py
index af08bda6e..004072357 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_repositories/test_abc.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_events/test_repositories/test_abc.py
@@ -20,7 +20,7 @@
IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR,
TRANSACTION_CONTEXT_VAR,
Action,
- AggregateDiff,
+ Event,
EventEntry,
EventRepository,
EventRepositoryConflictException,
@@ -151,7 +151,7 @@ async def _fn(e: EventEntry) -> EventEntry:
self.event_repository._send_events = send_events_mock
uuid = uuid4()
- aggregate_diff = AggregateDiff(
+ event = Event(
uuid=uuid,
name="example.Car",
version=2,
@@ -163,13 +163,13 @@ async def _fn(e: EventEntry) -> EventEntry:
validate_mock = AsyncMock(return_value=True)
self.event_repository.validate = validate_mock
- observed = await self.event_repository.submit(aggregate_diff)
+ observed = await self.event_repository.submit(event)
self.assertEqual(1, send_events_mock.call_count)
self.assertIsInstance(observed, EventEntry)
- self.assertEqual(uuid, observed.aggregate_uuid)
- self.assertEqual("example.Car", observed.aggregate_name)
+ self.assertEqual(uuid, observed.uuid)
+ self.assertEqual("example.Car", observed.name)
self.assertEqual(56, observed.version)
self.assertEqual(field_diff_container, FieldDiffContainer.from_avro_bytes(observed.data))
self.assertEqual(12, observed.id)
@@ -197,7 +197,7 @@ async def _fn(e: EventEntry) -> EventEntry:
self.event_repository._send_events = send_events_mock
uuid = uuid4()
- aggregate_diff = AggregateDiff(
+ event = Event(
uuid=uuid,
name="example.Car",
version=2,
@@ -209,13 +209,13 @@ async def _fn(e: EventEntry) -> EventEntry:
validate_mock = AsyncMock(return_value=True)
self.event_repository.validate = validate_mock
- observed = await self.event_repository.submit(aggregate_diff)
+ observed = await self.event_repository.submit(event)
self.assertEqual(0, send_events_mock.call_count)
self.assertIsInstance(observed, EventEntry)
- self.assertEqual(uuid, observed.aggregate_uuid)
- self.assertEqual("example.Car", observed.aggregate_name)
+ self.assertEqual(uuid, observed.uuid)
+ self.assertEqual("example.Car", observed.name)
self.assertEqual(56, observed.version)
self.assertEqual(field_diff_container, FieldDiffContainer.from_avro_bytes(observed.data))
self.assertEqual(12, observed.id)
@@ -238,7 +238,7 @@ async def _fn(e: EventEntry) -> EventEntry:
self.event_repository._submit = submit_mock
uuid = uuid4()
- aggregate_diff = AggregateDiff(
+ event = Event(
uuid=uuid,
name="example.Car",
version=2,
@@ -250,7 +250,7 @@ async def _fn(e: EventEntry) -> EventEntry:
validate_mock = AsyncMock(return_value=True)
self.event_repository.validate = validate_mock
- await self.event_repository.submit(aggregate_diff)
+ await self.event_repository.submit(event)
observed = self.broker_publisher.messages
@@ -258,7 +258,7 @@ async def _fn(e: EventEntry) -> EventEntry:
self.assertIsInstance(observed[0], BrokerMessageV1)
self.assertEqual("CarUpdated", observed[0].topic)
self.assertEqual(
- AggregateDiff(
+ Event(
uuid=uuid,
name="example.Car",
version=56,
@@ -271,7 +271,7 @@ async def _fn(e: EventEntry) -> EventEntry:
self.assertEqual("CarUpdated.colors.create", observed[1].topic)
self.assertIsInstance(observed[1], BrokerMessageV1)
self.assertEqual(
- AggregateDiff(
+ Event(
uuid=uuid,
name="example.Car",
version=56,
@@ -297,8 +297,8 @@ async def _fn(e: EventEntry) -> EventEntry:
self.event_repository._submit = submit_mock
uuid = uuid4()
- aggregate_diff = EventEntry.from_aggregate_diff(
- AggregateDiff(
+ event = EventEntry.from_event(
+ Event(
uuid=uuid,
name="example.Car",
version=2,
@@ -312,7 +312,7 @@ async def _fn(e: EventEntry) -> EventEntry:
validate_mock = AsyncMock(return_value=True)
self.event_repository.validate = validate_mock
- await self.event_repository.submit(aggregate_diff)
+ await self.event_repository.submit(event)
observed = self.broker_publisher.messages
@@ -333,8 +333,8 @@ async def test_submit_raises_conflict(self):
await self.event_repository.submit(entry)
async def test_submit_context_var(self):
- mocked_aggregate_diff = AsyncMock()
- mocked_aggregate_diff.action = Action.CREATE
+ mocked_event = AsyncMock()
+ mocked_event.action = Action.CREATE
async def _fn(entry):
self.assertEqual(True, IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR.get())
@@ -344,13 +344,13 @@ async def _fn(entry):
self.event_repository._submit = mocked_submit
self.assertEqual(False, IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR.get())
- await self.event_repository.submit(mocked_aggregate_diff)
+ await self.event_repository.submit(mocked_event)
self.assertEqual(False, IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR.get())
self.assertEqual(1, mocked_submit.call_count)
async def test_validate_true(self):
- aggregate_uuid = uuid4()
+ uuid = uuid4()
transaction_uuid = uuid4()
events = []
@@ -362,12 +362,12 @@ async def test_validate_true(self):
select_transaction_mock = MagicMock(return_value=FakeAsyncIterator(transactions))
self.transaction_repository.select = select_transaction_mock
- entry = EventEntry(aggregate_uuid, "example.Car")
+ entry = EventEntry(uuid, "example.Car")
self.assertTrue(await self.event_repository.validate(entry))
self.assertEqual(
- [call(aggregate_uuid=aggregate_uuid, transaction_uuid_in=(transaction_uuid,))],
+ [call(uuid=uuid, transaction_uuid_in=(transaction_uuid,))],
select_event_mock.call_args_list,
)
@@ -383,7 +383,7 @@ async def test_validate_true(self):
)
async def test_validate_with_skip(self):
- aggregate_uuid = uuid4()
+ uuid = uuid4()
transaction_uuid = uuid4()
another_transaction_uuid = uuid4()
@@ -396,7 +396,7 @@ async def test_validate_with_skip(self):
select_transaction_mock = MagicMock(return_value=FakeAsyncIterator(transactions))
self.transaction_repository.select = select_transaction_mock
- entry = EventEntry(aggregate_uuid, "example.Car")
+ entry = EventEntry(uuid, "example.Car")
self.assertTrue(await self.event_repository.validate(entry, transaction_uuid_ne=transaction_uuid))
self.assertEqual(
@@ -411,17 +411,17 @@ async def test_validate_with_skip(self):
)
self.assertEqual(
- [call(aggregate_uuid=aggregate_uuid, transaction_uuid_in=(another_transaction_uuid,))],
+ [call(uuid=uuid, transaction_uuid_in=(another_transaction_uuid,))],
select_event_mock.call_args_list,
)
async def test_validate_false(self):
- aggregate_uuid = uuid4()
+ uuid = uuid4()
transaction_uuid = uuid4()
events = [
- EventEntry(aggregate_uuid, "example.Car", 1),
- EventEntry(aggregate_uuid, "example.Car", 2, transaction_uuid=transaction_uuid),
+ EventEntry(uuid, "example.Car", 1),
+ EventEntry(uuid, "example.Car", 2, transaction_uuid=transaction_uuid),
]
transactions = [TransactionEntry(transaction_uuid, TransactionStatus.RESERVED)]
@@ -431,12 +431,12 @@ async def test_validate_false(self):
select_transaction_mock = MagicMock(return_value=FakeAsyncIterator(transactions))
self.transaction_repository.select = select_transaction_mock
- entry = EventEntry(aggregate_uuid, "example.Car")
+ entry = EventEntry(uuid, "example.Car")
self.assertFalse(await self.event_repository.validate(entry))
self.assertEqual(
- [call(aggregate_uuid=aggregate_uuid, transaction_uuid_in=(transaction_uuid,))],
+ [call(uuid=uuid, transaction_uuid_in=(transaction_uuid,))],
select_event_mock.call_args_list,
)
@@ -464,20 +464,18 @@ async def test_select(self):
mock = MagicMock(return_value=FakeAsyncIterator(range(5)))
self.event_repository._select = mock
- aggregate_uuid = uuid4()
- aggregate_name = "path.to.Aggregate"
+ uuid = uuid4()
+ name = "path.to.Product"
transaction_uuid = uuid4()
- iterable = self.event_repository.select(
- aggregate_uuid=aggregate_uuid, aggregate_name=aggregate_name, id_gt=56, transaction_uuid=transaction_uuid
- )
+ iterable = self.event_repository.select(uuid=uuid, name=name, id_gt=56, transaction_uuid=transaction_uuid)
observed = [a async for a in iterable]
self.assertEqual(list(range(5)), observed)
self.assertEqual(1, mock.call_count)
args = call(
- aggregate_uuid=aggregate_uuid,
- aggregate_name="path.to.Aggregate",
+ uuid=uuid,
+ name=name,
version=None,
version_lt=None,
version_gt=None,
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_exceptions.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_exceptions.py
index 9b0ec8e17..d41042910 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_exceptions.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_exceptions.py
@@ -2,9 +2,9 @@
from minos.aggregate import (
AggregateException,
- AggregateNotFoundException,
- DeletedAggregateException,
+ AlreadyDeletedException,
EventRepositoryException,
+ NotFoundException,
SnapshotRepositoryException,
)
from minos.common import (
@@ -22,11 +22,11 @@ def test_repository(self):
def test_snapshot(self):
self.assertTrue(issubclass(SnapshotRepositoryException, AggregateException))
- def test_snapshot_aggregate_not_found(self):
- self.assertTrue(issubclass(AggregateNotFoundException, SnapshotRepositoryException))
+ def test_snapshot_not_found(self):
+ self.assertTrue(issubclass(NotFoundException, SnapshotRepositoryException))
- def test_snapshot_deleted_aggregate(self):
- self.assertTrue(issubclass(DeletedAggregateException, SnapshotRepositoryException))
+ def test_snapshot_already_deleted(self):
+ self.assertTrue(issubclass(AlreadyDeletedException, SnapshotRepositoryException))
if __name__ == "__main__":
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/__init__.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/__init__.py
deleted file mode 100644
index 8b1378917..000000000
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_aggregates/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_abc.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_abc.py
index 7c754dc6d..c3501d154 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_abc.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_abc.py
@@ -16,9 +16,9 @@
from minos.aggregate import (
TRANSACTION_CONTEXT_VAR,
- Aggregate,
Condition,
Ordering,
+ RootEntity,
SnapshotRepository,
TransactionEntry,
)
@@ -33,10 +33,10 @@
class _SnapshotRepository(SnapshotRepository):
"""For testing purposes."""
- async def _get(self, *args, **kwargs) -> Aggregate:
+ async def _get(self, *args, **kwargs) -> RootEntity:
"""For testing purposes."""
- def _find(self, *args, **kwargs) -> AsyncIterator[Aggregate]:
+ def _find(self, *args, **kwargs) -> AsyncIterator[RootEntity]:
"""For testing purposes."""
async def _synchronize(self, **kwargs) -> None:
@@ -57,6 +57,8 @@ def setUp(self) -> None:
self.snapshot_repository._find = self.find_mock
self.snapshot_repository._synchronize = self.synchronize_mock
+ self.classname = "path.to.Product"
+
def test_subclass(self):
self.assertTrue(issubclass(SnapshotRepository, (ABC, MinosSetup)))
@@ -67,18 +69,18 @@ def test_abstract(self):
async def test_get(self):
transaction = TransactionEntry()
uuid = uuid4()
- observed = await self.snapshot_repository.get("path.to.Aggregate", uuid, transaction)
+ observed = await self.snapshot_repository.get(self.classname, uuid, transaction)
self.assertEqual(1, observed)
self.assertEqual(1, self.synchronize_mock.call_count)
self.assertEqual(call(), self.synchronize_mock.call_args)
self.assertEqual(1, self.get_mock.call_count)
- args = call(aggregate_name="path.to.Aggregate", uuid=uuid, transaction=transaction)
+ args = call(name=self.classname, uuid=uuid, transaction=transaction)
self.assertEqual(args, self.get_mock.call_args)
async def test_get_transaction_null(self):
- await self.snapshot_repository.get("path.to.Aggregate", uuid4())
+ await self.snapshot_repository.get(self.classname, uuid4())
self.assertEqual(1, self.get_mock.call_count)
self.assertEqual(None, self.get_mock.call_args.kwargs["transaction"])
@@ -86,7 +88,7 @@ async def test_get_transaction_null(self):
async def test_get_transaction_context(self):
transaction = TransactionEntry()
TRANSACTION_CONTEXT_VAR.set(transaction)
- await self.snapshot_repository.get("path.to.Aggregate", uuid4())
+ await self.snapshot_repository.get(self.classname, uuid4())
self.assertEqual(1, self.get_mock.call_count)
self.assertEqual(transaction, self.get_mock.call_args.kwargs["transaction"])
@@ -94,7 +96,7 @@ async def test_get_transaction_context(self):
async def test_find(self):
transaction = TransactionEntry()
iterable = self.snapshot_repository.find(
- "path.to.Aggregate", Condition.TRUE, Ordering.ASC("name"), 10, True, transaction
+ self.classname, Condition.TRUE, Ordering.ASC("name"), 10, True, transaction
)
observed = [a async for a in iterable]
self.assertEqual(list(range(5)), observed)
@@ -104,7 +106,7 @@ async def test_find(self):
self.assertEqual(1, self.find_mock.call_count)
args = call(
- aggregate_name="path.to.Aggregate",
+ name=self.classname,
condition=Condition.TRUE,
ordering=Ordering.ASC("name"),
limit=10,
@@ -114,7 +116,7 @@ async def test_find(self):
self.assertEqual(args, self.find_mock.call_args)
async def test_find_transaction_null(self):
- [a async for a in self.snapshot_repository.find("path.to.Aggregate", Condition.TRUE)]
+ [a async for a in self.snapshot_repository.find(self.classname, Condition.TRUE)]
self.assertEqual(1, self.find_mock.call_count)
self.assertEqual(None, self.find_mock.call_args.kwargs["transaction"])
@@ -122,7 +124,7 @@ async def test_find_transaction_null(self):
async def test_find_transaction_context(self):
transaction = TransactionEntry()
TRANSACTION_CONTEXT_VAR.set(transaction)
- [a async for a in self.snapshot_repository.find("path.to.Aggregate", Condition.TRUE)]
+ [a async for a in self.snapshot_repository.find(self.classname, Condition.TRUE)]
self.assertEqual(1, self.find_mock.call_count)
self.assertEqual(transaction, self.find_mock.call_args.kwargs["transaction"])
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_entries.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_entries.py
index 2224ee51b..8e2ee0367 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_entries.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_entries.py
@@ -36,8 +36,8 @@ def tearDown(self) -> None:
def test_constructor(self):
entry = SnapshotEntry(self.uuid, "example.Car", 0, self.schema, self.data)
- self.assertEqual(self.uuid, entry.aggregate_uuid)
- self.assertEqual("example.Car", entry.aggregate_name)
+ self.assertEqual(self.uuid, entry.uuid)
+ self.assertEqual("example.Car", entry.name)
self.assertEqual(0, entry.version)
self.assertEqual(self.schema, entry.schema)
self.assertEqual(self.data, entry.data)
@@ -54,20 +54,20 @@ def test_constructor_extended(self):
datetime(2020, 1, 10, 4, 23),
datetime(2020, 1, 10, 4, 25),
)
- self.assertEqual(self.uuid, entry.aggregate_uuid)
- self.assertEqual("example.Car", entry.aggregate_name)
+ self.assertEqual(self.uuid, entry.uuid)
+ self.assertEqual("example.Car", entry.name)
self.assertEqual(0, entry.version)
self.assertEqual(self.schema, entry.schema)
self.assertEqual(self.data, entry.data)
self.assertEqual(datetime(2020, 1, 10, 4, 23), entry.created_at)
self.assertEqual(datetime(2020, 1, 10, 4, 25), entry.updated_at)
- def test_from_aggregate(self):
+ def test_from_root_entity(self):
car = Car(3, "blue", uuid=self.uuid, version=1)
with patch("minos.common.AvroSchemaEncoder.generate_random_str", return_value="hello"):
- entry = SnapshotEntry.from_aggregate(car)
- self.assertEqual(car.uuid, entry.aggregate_uuid)
- self.assertEqual(car.classname, entry.aggregate_name)
+ entry = SnapshotEntry.from_root_entity(car)
+ self.assertEqual(car.uuid, entry.uuid)
+ self.assertEqual(car.classname, entry.name)
self.assertEqual(car.version, entry.version)
self.assertEqual(car.avro_schema, entry.schema)
self.assertEqual({"color": "blue", "doors": 3, "owner": None}, entry.data)
@@ -79,26 +79,26 @@ def test_equals(self):
b = SnapshotEntry(self.uuid, "example.Car", 0, self.schema, self.data)
self.assertEqual(a, b)
- def test_aggregate_cls(self):
+ def test_type_(self):
car = Car(3, "blue", uuid=self.uuid, version=1)
- entry = SnapshotEntry.from_aggregate(car)
- self.assertEqual(Car, entry.aggregate_cls)
+ entry = SnapshotEntry.from_root_entity(car)
+ self.assertEqual(Car, entry.type_)
- def test_aggregate(self):
+ def test_build(self):
car = Car(3, "blue", uuid=self.uuid, version=1)
- entry = SnapshotEntry.from_aggregate(car)
- self.assertEqual(car, entry.build_aggregate())
+ entry = SnapshotEntry.from_root_entity(car)
+ self.assertEqual(car, entry.build())
def test_repr(self):
- aggregate_name = "example.Car"
+ name = "example.Car"
version = 0
created_at = datetime(2020, 1, 10, 4, 23)
updated_at = datetime(2020, 1, 10, 4, 25)
transaction_uuid = uuid4()
entry = SnapshotEntry(
- aggregate_uuid=self.uuid,
- aggregate_name=aggregate_name,
+ uuid=self.uuid,
+ name=name,
version=version,
schema=self.schema,
data=self.data,
@@ -108,7 +108,7 @@ def test_repr(self):
)
expected = (
- f"SnapshotEntry(aggregate_uuid={self.uuid!r}, aggregate_name={aggregate_name!r}, version={version!r}, "
+ f"SnapshotEntry(uuid={self.uuid!r}, name={name!r}, version={version!r}, "
f"schema={self.schema!r}, data={self.data!r}, created_at={created_at!r}, updated_at={updated_at!r}, "
f"transaction_uuid={transaction_uuid!r})"
)
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_memory.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_memory.py
index 190da794a..c37257891 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_memory.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_memory.py
@@ -7,13 +7,13 @@
)
from minos.aggregate import (
- AggregateNotFoundException,
+ AlreadyDeletedException,
Condition,
- DeletedAggregateException,
EventEntry,
FieldDiff,
FieldDiffContainer,
InMemorySnapshotRepository,
+ NotFoundException,
Ordering,
SnapshotEntry,
SnapshotRepository,
@@ -49,25 +49,25 @@ async def asyncSetUp(self):
async def _populate(self):
diff = FieldDiffContainer([FieldDiff("doors", int, 3), FieldDiff("color", str, "blue")])
# noinspection PyTypeChecker
- aggregate_name: str = Car.classname
- await self.event_repository.create(EventEntry(self.uuid_1, aggregate_name, 1, diff.avro_bytes))
- await self.event_repository.update(EventEntry(self.uuid_1, aggregate_name, 2, diff.avro_bytes))
- await self.event_repository.create(EventEntry(self.uuid_2, aggregate_name, 1, diff.avro_bytes))
- await self.event_repository.update(EventEntry(self.uuid_1, aggregate_name, 3, diff.avro_bytes))
- await self.event_repository.delete(EventEntry(self.uuid_1, aggregate_name, 4))
- await self.event_repository.update(EventEntry(self.uuid_2, aggregate_name, 2, diff.avro_bytes))
+ name: str = Car.classname
+ await self.event_repository.create(EventEntry(self.uuid_1, name, 1, diff.avro_bytes))
+ await self.event_repository.update(EventEntry(self.uuid_1, name, 2, diff.avro_bytes))
+ await self.event_repository.create(EventEntry(self.uuid_2, name, 1, diff.avro_bytes))
+ await self.event_repository.update(EventEntry(self.uuid_1, name, 3, diff.avro_bytes))
+ await self.event_repository.delete(EventEntry(self.uuid_1, name, 4))
+ await self.event_repository.update(EventEntry(self.uuid_2, name, 2, diff.avro_bytes))
await self.event_repository.update(
- EventEntry(self.uuid_2, aggregate_name, 3, diff.avro_bytes, transaction_uuid=self.transaction_1)
+ EventEntry(self.uuid_2, name, 3, diff.avro_bytes, transaction_uuid=self.transaction_1)
)
await self.event_repository.delete(
- EventEntry(self.uuid_2, aggregate_name, 3, bytes(), transaction_uuid=self.transaction_2)
+ EventEntry(self.uuid_2, name, 3, bytes(), transaction_uuid=self.transaction_2)
)
await self.event_repository.update(
- EventEntry(self.uuid_2, aggregate_name, 4, diff.avro_bytes, transaction_uuid=self.transaction_1)
+ EventEntry(self.uuid_2, name, 4, diff.avro_bytes, transaction_uuid=self.transaction_1)
)
- await self.event_repository.create(EventEntry(self.uuid_3, aggregate_name, 1, diff.avro_bytes))
+ await self.event_repository.create(EventEntry(self.uuid_3, name, 1, diff.avro_bytes))
await self.event_repository.delete(
- EventEntry(self.uuid_2, aggregate_name, 3, bytes(), transaction_uuid=self.transaction_3)
+ EventEntry(self.uuid_2, name, 3, bytes(), transaction_uuid=self.transaction_3)
)
await self.transaction_repository.submit(
TransactionEntry(self.transaction_1, TransactionStatus.PENDING, await self.event_repository.offset)
@@ -282,13 +282,13 @@ async def test_get_with_transaction(self):
self.assertEqual(expected, observed)
async def test_get_raises(self):
- with self.assertRaises(DeletedAggregateException):
+ with self.assertRaises(AlreadyDeletedException):
await self.snapshot_repository.get("tests.utils.Car", self.uuid_1)
- with self.assertRaises(AggregateNotFoundException):
+ with self.assertRaises(NotFoundException):
await self.snapshot_repository.get("tests.utils.Car", uuid4())
async def test_get_with_transaction_raises(self):
- with self.assertRaises(DeletedAggregateException):
+ with self.assertRaises(AlreadyDeletedException):
await self.snapshot_repository.get(
"tests.utils.Car", self.uuid_2, transaction=TransactionEntry(self.transaction_2)
)
@@ -346,11 +346,11 @@ def _assert_equal_snapshot_entries(self, expected: list[SnapshotEntry], observed
self.assertEqual(len(expected), len(observed))
for exp, obs in zip(expected, observed):
if exp.data is None:
- with self.assertRaises(DeletedAggregateException):
+ with self.assertRaises(AlreadyDeletedException):
# noinspection PyStatementEffect
- obs.build_aggregate()
+ obs.build()
else:
- self.assertEqual(exp.build_aggregate(), obs.build_aggregate())
+ self.assertEqual(exp.build(), obs.build())
self.assertIsInstance(obs.created_at, datetime)
self.assertIsInstance(obs.updated_at, datetime)
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_api.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_api.py
index c2e41acdb..3e6bcb4bc 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_api.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_api.py
@@ -41,6 +41,8 @@ def setUp(self) -> None:
self.snapshot_repository.reader.find = self.find_mock
self.snapshot_repository.writer.dispatch = self.dispatch_mock
+ self.classname = "path.to.Product"
+
def test_from_config(self):
self.assertIsInstance(self.snapshot_repository.reader, PostgreSqlSnapshotReader)
self.assertIsInstance(self.snapshot_repository.writer, PostgreSqlSnapshotWriter)
@@ -48,20 +50,20 @@ def test_from_config(self):
async def test_get(self):
transaction = TransactionEntry()
uuid = uuid4()
- observed = await self.snapshot_repository.get("path.to.Aggregate", uuid, transaction)
+ observed = await self.snapshot_repository.get(self.classname, uuid, transaction)
self.assertEqual(1, observed)
self.assertEqual(1, self.dispatch_mock.call_count)
self.assertEqual(call(), self.dispatch_mock.call_args)
self.assertEqual(1, self.get_mock.call_count)
- args = call(aggregate_name="path.to.Aggregate", uuid=uuid, transaction=transaction)
+ args = call(name=self.classname, uuid=uuid, transaction=transaction)
self.assertEqual(args, self.get_mock.call_args)
async def test_find(self):
transaction = TransactionEntry()
iterable = self.snapshot_repository.find(
- "path.to.Aggregate", Condition.TRUE, Ordering.ASC("name"), 10, True, transaction
+ self.classname, Condition.TRUE, Ordering.ASC("name"), 10, True, transaction
)
observed = [a async for a in iterable]
self.assertEqual(list(range(5)), observed)
@@ -71,7 +73,7 @@ async def test_find(self):
self.assertEqual(1, self.find_mock.call_count)
args = call(
- aggregate_name="path.to.Aggregate",
+ name=self.classname,
condition=Condition.TRUE,
ordering=Ordering.ASC("name"),
limit=10,
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_queries.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_queries.py
index 01615a959..b9afa3ef8 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_queries.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_queries.py
@@ -43,8 +43,9 @@ class TestPostgreSqlSnapshotQueryBuilder(PostgresAsyncTestCase):
def setUp(self) -> None:
super().setUp()
+ self.classname = "path.to.Product"
self.base_parameters = {
- "aggregate_name": "path.to.Aggregate",
+ "name": self.classname,
"transaction_uuid_1": NULL_UUID,
}
self.base_select = _SELECT_ENTRIES_QUERY.format(
@@ -54,8 +55,8 @@ def setUp(self) -> None:
)
def test_constructor(self):
- qb = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", Condition.TRUE)
- self.assertEqual("path.to.Aggregate", qb.aggregate_name)
+ qb = PostgreSqlSnapshotQueryBuilder(self.classname, Condition.TRUE)
+ self.assertEqual(self.classname, qb.name)
self.assertEqual(Condition.TRUE, qb.condition)
self.assertEqual(None, qb.ordering)
self.assertEqual(None, qb.limit)
@@ -64,9 +65,9 @@ def test_constructor(self):
def test_constructor_full(self):
transaction_uuids = (NULL_UUID, uuid4())
qb = PostgreSqlSnapshotQueryBuilder(
- "path.to.Aggregate", Condition.TRUE, Ordering.ASC("name"), 10, transaction_uuids, True
+ self.classname, Condition.TRUE, Ordering.ASC("name"), 10, transaction_uuids, True
)
- self.assertEqual("path.to.Aggregate", qb.aggregate_name)
+ self.assertEqual(self.classname, qb.name)
self.assertEqual(Condition.TRUE, qb.condition)
self.assertEqual(Ordering.ASC("name"), qb.ordering)
self.assertEqual(10, qb.limit)
@@ -74,7 +75,7 @@ def test_constructor_full(self):
self.assertTrue(qb.exclude_deleted)
def test_build_submitting_context_var(self):
- builder = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", Condition.TRUE)
+ builder = PostgreSqlSnapshotQueryBuilder(self.classname, Condition.TRUE)
def _fn():
self.assertEqual(True, IS_REPOSITORY_SERIALIZATION_CONTEXT_VAR.get())
@@ -91,12 +92,12 @@ def _fn():
def test_build_raises(self):
with self.assertRaises(ValueError):
# noinspection PyTypeChecker
- PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", True).build()
+ PostgreSqlSnapshotQueryBuilder(self.classname, True).build()
async def test_build_with_transactions(self):
transaction_uuids = (NULL_UUID, uuid4())
observed = PostgreSqlSnapshotQueryBuilder(
- "path.to.Aggregate", Condition.TRUE, transaction_uuids=transaction_uuids
+ self.classname, Condition.TRUE, transaction_uuids=transaction_uuids
).build()
expected_query = SQL(" WHERE ").join(
@@ -123,7 +124,7 @@ async def test_build_with_transactions(self):
async def test_build_true(self):
condition = Condition.TRUE
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("TRUE")])
expected_parameters = self.base_parameters
@@ -133,7 +134,7 @@ async def test_build_true(self):
async def test_build_false(self):
condition = Condition.FALSE
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("FALSE")])
expected_parameters = self.base_parameters
self.assertEqual(await self._flatten_query(expected_query), await self._flatten_query(observed[0]))
@@ -143,9 +144,9 @@ async def test_build_fixed_uuid(self):
uuid = uuid4()
condition = Condition.EQUAL("uuid", uuid)
with patch("minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello"]):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
- expected_query = SQL(" WHERE ").join([self.base_select, SQL('("aggregate_uuid" = %(hello)s)')])
+ expected_query = SQL(" WHERE ").join([self.base_select, SQL('("uuid" = %(hello)s)')])
expected_parameters = {"hello": str(uuid)} | self.base_parameters
self.assertEqual(await self._flatten_query(expected_query), await self._flatten_query(observed[0]))
@@ -154,7 +155,7 @@ async def test_build_fixed_uuid(self):
async def test_build_fixed_version(self):
condition = Condition.EQUAL("version", 1)
with patch("minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello"]):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL('("version" = %(hello)s)')])
expected_parameters = {"hello": 1} | self.base_parameters
@@ -165,7 +166,7 @@ async def test_build_fixed_version(self):
async def test_build_fixed_created_at(self):
condition = Condition.EQUAL("created_at", 1)
with patch("minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello"]):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL('("created_at" = %(hello)s)')])
expected_parameters = {"hello": 1} | self.base_parameters
@@ -176,7 +177,7 @@ async def test_build_fixed_created_at(self):
async def test_build_fixed_updated_at(self):
condition = Condition.EQUAL("updated_at", 1)
with patch("minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello"]):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL('("updated_at" = %(hello)s)')])
expected_parameters = {"hello": 1} | self.base_parameters
@@ -187,7 +188,7 @@ async def test_build_fixed_updated_at(self):
async def test_build_lower(self):
condition = Condition.LOWER("age", 1)
with patch("minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello"]):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("(data#>'{age}' < %(hello)s::jsonb)")])
expected_parameters = {"hello": 1} | self.base_parameters
@@ -198,7 +199,7 @@ async def test_build_lower(self):
async def test_build_lower_equal(self):
condition = Condition.LOWER_EQUAL("age", 1)
with patch("minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello"]):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("(data#>'{age}' <= %(hello)s::jsonb)")])
expected_parameters = {"hello": 1} | self.base_parameters
@@ -209,7 +210,7 @@ async def test_build_lower_equal(self):
async def test_build_greater(self):
condition = Condition.GREATER("age", 1)
with patch("minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello"]):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("(data#>'{age}' > %(hello)s::jsonb)")])
expected_parameters = {"hello": 1} | self.base_parameters
@@ -220,7 +221,7 @@ async def test_build_greater(self):
async def test_build_greater_equal(self):
condition = Condition.GREATER_EQUAL("age", 1)
with patch("minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello"]):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("(data#>'{age}' >= %(hello)s::jsonb)")])
expected_parameters = {"hello": 1} | self.base_parameters
@@ -231,7 +232,7 @@ async def test_build_greater_equal(self):
async def test_build_equal(self):
condition = Condition.EQUAL("age", 1)
with patch("minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello"]):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("(data#>'{age}' = %(hello)s::jsonb)")])
expected_parameters = {"hello": 1} | self.base_parameters
@@ -242,7 +243,7 @@ async def test_build_equal(self):
async def test_build_not_equal(self):
condition = Condition.NOT_EQUAL("age", 1)
with patch("minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello"]):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("(data#>'{age}' <> %(hello)s::jsonb)")])
expected_parameters = {"hello": 1} | self.base_parameters
@@ -253,7 +254,7 @@ async def test_build_not_equal(self):
async def test_build_in(self):
condition = Condition.IN("age", [1, 2, 3])
with patch("minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello"]):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("(data#>'{age}' IN %(hello)s::jsonb)")])
expected_parameters = {"hello": (1, 2, 3)} | self.base_parameters
@@ -264,7 +265,7 @@ async def test_build_in(self):
async def test_build_in_empty(self):
condition = Condition.IN("age", [])
with patch("minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello"]):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("FALSE")])
expected_parameters = self.base_parameters
@@ -275,7 +276,7 @@ async def test_build_in_empty(self):
async def test_build_not(self):
condition = Condition.NOT(Condition.LOWER("age", 1))
with patch("minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello"]):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("(NOT (data#>'{age}' < %(hello)s::jsonb))")])
expected_parameters = {"hello": 1} | self.base_parameters
@@ -288,7 +289,7 @@ async def test_build_and(self):
with patch(
"minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello", "goodbye"]
):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join(
[self.base_select, SQL("((data#>'{age}' < %(hello)s::jsonb) AND (data#>'{level}' < %(goodbye)s::jsonb))")]
@@ -303,7 +304,7 @@ async def test_build_or(self):
with patch(
"minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["hello", "goodbye"]
):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition).build()
expected_query = SQL(" WHERE ").join(
[self.base_select, SQL("((data#>'{age}' < %(hello)s::jsonb) OR (data#>'{level}' < %(goodbye)s::jsonb))")]
@@ -314,7 +315,7 @@ async def test_build_or(self):
self.assertEqual(self._flatten_parameters(expected_parameters), self._flatten_parameters(observed[1]))
async def test_build_exclude_deleted(self):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", Condition.TRUE, exclude_deleted=True).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, Condition.TRUE, exclude_deleted=True).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("TRUE AND (data IS NOT NULL)")])
expected_parameters = self.base_parameters
@@ -324,7 +325,7 @@ async def test_build_exclude_deleted(self):
async def test_build_fixed_ordering_asc(self):
ordering = Ordering.ASC("created_at")
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", Condition.TRUE, ordering).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, Condition.TRUE, ordering).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL('TRUE ORDER BY "created_at" ASC')])
@@ -335,7 +336,7 @@ async def test_build_fixed_ordering_asc(self):
async def test_build_fixed_ordering_desc(self):
ordering = Ordering.DESC("created_at")
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", Condition.TRUE, ordering).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, Condition.TRUE, ordering).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL('TRUE ORDER BY "created_at" DESC')])
expected_parameters = self.base_parameters
@@ -345,7 +346,7 @@ async def test_build_fixed_ordering_desc(self):
async def test_build_ordering_asc(self):
ordering = Ordering.ASC("name")
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", Condition.TRUE, ordering).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, Condition.TRUE, ordering).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("TRUE ORDER BY data#>'{name}' ASC")])
expected_parameters = self.base_parameters
@@ -355,7 +356,7 @@ async def test_build_ordering_asc(self):
async def test_build_ordering_desc(self):
ordering = Ordering.DESC("name")
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", Condition.TRUE, ordering).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, Condition.TRUE, ordering).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("TRUE ORDER BY data#>'{name}' DESC")])
@@ -365,7 +366,7 @@ async def test_build_ordering_desc(self):
self.assertEqual(self._flatten_parameters(expected_parameters), self._flatten_parameters(observed[1]))
async def test_build_limit(self):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", Condition.TRUE, limit=10).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, Condition.TRUE, limit=10).build()
expected_query = SQL(" WHERE ").join([self.base_select, SQL("TRUE LIMIT 10")])
@@ -385,7 +386,7 @@ async def test_build_complex(self):
with patch(
"minos.aggregate.PostgreSqlSnapshotQueryBuilder.generate_random_str", side_effect=["one", "two", "three"]
):
- observed = PostgreSqlSnapshotQueryBuilder("path.to.Aggregate", condition, ordering, limit).build()
+ observed = PostgreSqlSnapshotQueryBuilder(self.classname, condition, ordering, limit).build()
expected_query = SQL(" WHERE ").join(
[
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_readers.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_readers.py
index 0d6a10f08..032536e7b 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_readers.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_readers.py
@@ -7,12 +7,12 @@
)
from minos.aggregate import (
- AggregateNotFoundException,
+ AlreadyDeletedException,
Condition,
- DeletedAggregateException,
EventEntry,
FieldDiff,
FieldDiffContainer,
+ NotFoundException,
Ordering,
PostgreSqlSnapshotReader,
PostgreSqlSnapshotSetup,
@@ -59,26 +59,26 @@ async def asyncTearDown(self):
async def _populate(self):
diff = FieldDiffContainer([FieldDiff("doors", int, 3), FieldDiff("color", str, "blue")])
# noinspection PyTypeChecker
- aggregate_name: str = Car.classname
-
- await self.event_repository.create(EventEntry(self.uuid_1, aggregate_name, 1, diff.avro_bytes))
- await self.event_repository.update(EventEntry(self.uuid_1, aggregate_name, 2, diff.avro_bytes))
- await self.event_repository.create(EventEntry(self.uuid_2, aggregate_name, 1, diff.avro_bytes))
- await self.event_repository.update(EventEntry(self.uuid_1, aggregate_name, 3, diff.avro_bytes))
- await self.event_repository.delete(EventEntry(self.uuid_1, aggregate_name, 4))
- await self.event_repository.update(EventEntry(self.uuid_2, aggregate_name, 2, diff.avro_bytes))
+ name: str = Car.classname
+
+ await self.event_repository.create(EventEntry(self.uuid_1, name, 1, diff.avro_bytes))
+ await self.event_repository.update(EventEntry(self.uuid_1, name, 2, diff.avro_bytes))
+ await self.event_repository.create(EventEntry(self.uuid_2, name, 1, diff.avro_bytes))
+ await self.event_repository.update(EventEntry(self.uuid_1, name, 3, diff.avro_bytes))
+ await self.event_repository.delete(EventEntry(self.uuid_1, name, 4))
+ await self.event_repository.update(EventEntry(self.uuid_2, name, 2, diff.avro_bytes))
await self.event_repository.update(
- EventEntry(self.uuid_2, aggregate_name, 3, diff.avro_bytes, transaction_uuid=self.transaction_1)
+ EventEntry(self.uuid_2, name, 3, diff.avro_bytes, transaction_uuid=self.transaction_1)
)
await self.event_repository.delete(
- EventEntry(self.uuid_2, aggregate_name, 3, bytes(), transaction_uuid=self.transaction_2)
+ EventEntry(self.uuid_2, name, 3, bytes(), transaction_uuid=self.transaction_2)
)
await self.event_repository.update(
- EventEntry(self.uuid_2, aggregate_name, 4, diff.avro_bytes, transaction_uuid=self.transaction_1)
+ EventEntry(self.uuid_2, name, 4, diff.avro_bytes, transaction_uuid=self.transaction_1)
)
- await self.event_repository.create(EventEntry(self.uuid_3, aggregate_name, 1, diff.avro_bytes))
+ await self.event_repository.create(EventEntry(self.uuid_3, name, 1, diff.avro_bytes))
await self.event_repository.delete(
- EventEntry(self.uuid_2, aggregate_name, 3, bytes(), transaction_uuid=self.transaction_3)
+ EventEntry(self.uuid_2, name, 3, bytes(), transaction_uuid=self.transaction_3)
)
await self.transaction_repository.submit(
TransactionEntry(self.transaction_1, TransactionStatus.PENDING, await self.event_repository.offset)
@@ -295,14 +295,14 @@ async def test_get_with_transaction(self):
async def test_get_raises(self):
- with self.assertRaises(DeletedAggregateException):
+ with self.assertRaises(AlreadyDeletedException):
await self.reader.get("tests.utils.Car", self.uuid_1)
- with self.assertRaises(AggregateNotFoundException):
+ with self.assertRaises(NotFoundException):
await self.reader.get("tests.utils.Car", uuid4())
async def test_get_with_transaction_raises(self):
- with self.assertRaises(DeletedAggregateException):
+ with self.assertRaises(AlreadyDeletedException):
await self.reader.get("tests.utils.Car", self.uuid_2, transaction=TransactionEntry(self.transaction_2))
async def test_find(self):
@@ -360,11 +360,11 @@ def _assert_equal_snapshot_entries(self, expected: list[SnapshotEntry], observed
self.assertEqual(len(expected), len(observed))
for exp, obs in zip(expected, observed):
if exp.data is None:
- with self.assertRaises(DeletedAggregateException):
+ with self.assertRaises(AlreadyDeletedException):
# noinspection PyStatementEffect
- obs.build_aggregate()
+ obs.build()
else:
- self.assertEqual(exp.build_aggregate(), obs.build_aggregate())
+ self.assertEqual(exp.build(), obs.build())
self.assertIsInstance(obs.created_at, datetime)
self.assertIsInstance(obs.updated_at, datetime)
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_writers.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_writers.py
index 484961e52..ffebe4e14 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_writers.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_pg/test_writers.py
@@ -12,8 +12,8 @@
from minos.aggregate import (
Action,
+ AlreadyDeletedException,
Condition,
- DeletedAggregateException,
EventEntry,
FieldDiff,
FieldDiffContainer,
@@ -69,26 +69,26 @@ async def asyncTearDown(self):
async def _populate(self):
diff = FieldDiffContainer([FieldDiff("doors", int, 3), FieldDiff("color", str, "blue")])
# noinspection PyTypeChecker
- aggregate_name: str = Car.classname
-
- await self.event_repository.create(EventEntry(self.uuid_1, aggregate_name, 1, diff.avro_bytes))
- await self.event_repository.update(EventEntry(self.uuid_1, aggregate_name, 2, diff.avro_bytes))
- await self.event_repository.create(EventEntry(self.uuid_2, aggregate_name, 1, diff.avro_bytes))
- await self.event_repository.update(EventEntry(self.uuid_1, aggregate_name, 3, diff.avro_bytes))
- await self.event_repository.delete(EventEntry(self.uuid_1, aggregate_name, 4))
- await self.event_repository.update(EventEntry(self.uuid_2, aggregate_name, 2, diff.avro_bytes))
+ name: str = Car.classname
+
+ await self.event_repository.create(EventEntry(self.uuid_1, name, 1, diff.avro_bytes))
+ await self.event_repository.update(EventEntry(self.uuid_1, name, 2, diff.avro_bytes))
+ await self.event_repository.create(EventEntry(self.uuid_2, name, 1, diff.avro_bytes))
+ await self.event_repository.update(EventEntry(self.uuid_1, name, 3, diff.avro_bytes))
+ await self.event_repository.delete(EventEntry(self.uuid_1, name, 4))
+ await self.event_repository.update(EventEntry(self.uuid_2, name, 2, diff.avro_bytes))
await self.event_repository.update(
- EventEntry(self.uuid_2, aggregate_name, 3, diff.avro_bytes, transaction_uuid=self.transaction_1)
+ EventEntry(self.uuid_2, name, 3, diff.avro_bytes, transaction_uuid=self.transaction_1)
)
await self.event_repository.delete(
- EventEntry(self.uuid_2, aggregate_name, 3, bytes(), transaction_uuid=self.transaction_2)
+ EventEntry(self.uuid_2, name, 3, bytes(), transaction_uuid=self.transaction_2)
)
await self.event_repository.update(
- EventEntry(self.uuid_2, aggregate_name, 4, diff.avro_bytes, transaction_uuid=self.transaction_1)
+ EventEntry(self.uuid_2, name, 4, diff.avro_bytes, transaction_uuid=self.transaction_1)
)
- await self.event_repository.create(EventEntry(self.uuid_3, aggregate_name, 1, diff.avro_bytes))
+ await self.event_repository.create(EventEntry(self.uuid_3, name, 1, diff.avro_bytes))
await self.event_repository.delete(
- EventEntry(self.uuid_2, aggregate_name, 3, bytes(), transaction_uuid=self.transaction_3)
+ EventEntry(self.uuid_2, name, 3, bytes(), transaction_uuid=self.transaction_3)
)
await self.transaction_repository.submit(
TransactionEntry(self.transaction_1, TransactionStatus.PENDING, await self.event_repository.offset)
@@ -129,7 +129,7 @@ async def test_dispatch(self):
# noinspection PyTypeChecker
expected = [
SnapshotEntry(self.uuid_1, Car.classname, 4),
- SnapshotEntry.from_aggregate(
+ SnapshotEntry.from_root_entity(
Car(
3,
"blue",
@@ -139,7 +139,7 @@ async def test_dispatch(self):
updated_at=observed[1].updated_at,
)
),
- SnapshotEntry.from_aggregate(
+ SnapshotEntry.from_root_entity(
Car(
3,
"blue",
@@ -168,7 +168,7 @@ async def test_dispatch_first_transaction(self):
# noinspection PyTypeChecker
expected = [
SnapshotEntry(self.uuid_1, Car.classname, 4),
- SnapshotEntry.from_aggregate(
+ SnapshotEntry.from_root_entity(
Car(
3,
"blue",
@@ -178,7 +178,7 @@ async def test_dispatch_first_transaction(self):
updated_at=observed[1].updated_at,
)
),
- SnapshotEntry.from_aggregate(
+ SnapshotEntry.from_root_entity(
Car(
3,
"blue",
@@ -208,7 +208,7 @@ async def test_dispatch_second_transaction(self):
expected = [
SnapshotEntry(self.uuid_1, Car.classname, 4),
SnapshotEntry(self.uuid_2, Car.classname, 4),
- SnapshotEntry.from_aggregate(
+ SnapshotEntry.from_root_entity(
Car(
3,
"blue",
@@ -237,7 +237,7 @@ async def test_dispatch_third_transaction(self):
# noinspection PyTypeChecker
expected = [
SnapshotEntry(self.uuid_1, Car.classname, 4),
- SnapshotEntry.from_aggregate(
+ SnapshotEntry.from_root_entity(
Car(
3,
"blue",
@@ -247,7 +247,7 @@ async def test_dispatch_third_transaction(self):
updated_at=observed[1].updated_at,
)
),
- SnapshotEntry.from_aggregate(
+ SnapshotEntry.from_root_entity(
Car(
3,
"blue",
@@ -268,24 +268,24 @@ async def test_is_synced(self):
async def test_dispatch_ignore_previous_version(self):
diff = FieldDiffContainer([FieldDiff("doors", int, 3), FieldDiff("color", str, "blue")])
# noinspection PyTypeChecker
- aggregate_name: str = Car.classname
+ name: str = Car.classname
condition = Condition.EQUAL("uuid", self.uuid_1)
async def _fn(*args, **kwargs):
- yield EventEntry(self.uuid_1, aggregate_name, 1, diff.avro_bytes, 1, Action.CREATE, current_datetime())
- yield EventEntry(self.uuid_1, aggregate_name, 3, diff.avro_bytes, 2, Action.CREATE, current_datetime())
- yield EventEntry(self.uuid_1, aggregate_name, 2, diff.avro_bytes, 3, Action.CREATE, current_datetime())
+ yield EventEntry(self.uuid_1, name, 1, diff.avro_bytes, 1, Action.CREATE, current_datetime())
+ yield EventEntry(self.uuid_1, name, 3, diff.avro_bytes, 2, Action.CREATE, current_datetime())
+ yield EventEntry(self.uuid_1, name, 2, diff.avro_bytes, 3, Action.CREATE, current_datetime())
self.event_repository.select = MagicMock(side_effect=_fn)
await self.writer.dispatch()
- observed = [v async for v in self.reader.find_entries(aggregate_name, condition)]
+ observed = [v async for v in self.reader.find_entries(name, condition)]
# noinspection PyTypeChecker
expected = [
SnapshotEntry(
- aggregate_uuid=self.uuid_1,
- aggregate_name=aggregate_name,
+ uuid=self.uuid_1,
+ name=name,
version=3,
schema=Car.avro_schema,
data=Car(3, "blue", uuid=self.uuid_1, version=1).avro_data,
@@ -299,11 +299,11 @@ def _assert_equal_snapshot_entries(self, expected: list[SnapshotEntry], observed
self.assertEqual(len(expected), len(observed))
for exp, obs in zip(expected, observed):
if exp.data is None:
- with self.assertRaises(DeletedAggregateException):
+ with self.assertRaises(AlreadyDeletedException):
# noinspection PyStatementEffect
- obs.build_aggregate()
+ obs.build()
else:
- self.assertEqual(exp.build_aggregate(), obs.build_aggregate())
+ self.assertEqual(exp.build(), obs.build())
self.assertIsInstance(obs.created_at, datetime)
self.assertIsInstance(obs.updated_at, datetime)
@@ -318,8 +318,8 @@ async def test_dispatch_with_offset(self):
# noinspection PyTypeChecker
entry = EventEntry(
- aggregate_uuid=self.uuid_3,
- aggregate_name=Car.classname,
+ uuid=self.uuid_3,
+ name=Car.classname,
data=FieldDiffContainer([FieldDiff("doors", int, 3), FieldDiff("color", str, "blue")]).avro_bytes,
)
await self.event_repository.create(entry)
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_services.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_services.py
index a30247cb5..e3c98eeb9 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_services.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_snapshots/test_services.py
@@ -9,6 +9,7 @@
)
from minos.aggregate import (
+ RootEntity,
SnapshotService,
)
from minos.common import (
@@ -49,37 +50,37 @@ def test_get_enroute(self):
observed = SnapshotService.__get_enroute__(self.config)
self.assertEqual(expected, observed)
- async def test_get_aggregate(self):
+ async def test_get(self):
uuid = uuid4()
expected = Agg(uuid)
- with patch("minos.aggregate.Aggregate.get", return_value=expected):
+ with patch.object(RootEntity, "get", return_value=expected):
response = await self.service.__get_one__(InMemoryRequest({"uuid": uuid}))
self.assertEqual(expected, await response.content())
- async def test_get_aggregate_raises(self):
+ async def test_get_raises(self):
with self.assertRaises(ResponseException):
await self.service.__get_one__(InMemoryRequest())
- with patch("minos.aggregate.Aggregate.get", side_effect=ValueError):
+ with patch.object(RootEntity, "get", side_effect=ValueError):
with self.assertRaises(ResponseException):
await self.service.__get_one__(InMemoryRequest({"uuid": uuid4()}))
- async def test_get_aggregates(self):
+ async def test_get_many(self):
uuids = [uuid4(), uuid4()]
expected = [Agg(u) for u in uuids]
- with patch("minos.aggregate.Aggregate.get", side_effect=expected):
+ with patch.object(RootEntity, "get", side_effect=expected):
response = await self.service.__get_many__(InMemoryRequest({"uuids": uuids}))
self.assertEqual(expected, await response.content())
- async def test_get_aggregates_raises(self):
+ async def test_get_many_raises(self):
with self.assertRaises(ResponseException):
await self.service.__get_many__(InMemoryRequest())
- with patch("minos.aggregate.Aggregate.get", side_effect=ValueError):
+ with patch.object(RootEntity, "get", side_effect=ValueError):
with self.assertRaises(ResponseException):
await self.service.__get_many__(InMemoryRequest({"uuids": [uuid4()]}))
- def test_aggregate_cls(self):
- self.assertEqual(Order, self.service.__aggregate_cls__)
+ def test_type(self):
+ self.assertEqual(Order, self.service.type_)
async def test_synchronize(self):
mock = AsyncMock()
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_something.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_something.py
deleted file mode 100644
index b21589a59..000000000
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_something.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import unittest
-
-
-class TestSomething(unittest.TestCase):
- def test_something(self):
- self.assertEqual(True, True)
-
-
-if __name__ == "__main__":
- unittest.main()
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_transactions/test_entries.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_transactions/test_entries.py
index 7af58bb05..e6d387c6f 100644
--- a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_transactions/test_entries.py
+++ b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_transactions/test_entries.py
@@ -186,7 +186,7 @@ async def test_validate_true(self):
self.assertTrue(await transaction.validate())
self.assertEqual(
- [call(transaction_uuid=uuid), call(aggregate_uuid=agg_uuid, version=3)], select_event_mock.call_args_list
+ [call(transaction_uuid=uuid), call(uuid=agg_uuid, version=3)], select_event_mock.call_args_list
)
self.assertEqual(
[
@@ -295,7 +295,7 @@ async def test_validate_false_already_committed(self):
self.assertFalse(await transaction.validate())
self.assertEqual(
- [call(transaction_uuid=uuid), call(aggregate_uuid=agg_uuid, version=3)], select_event_mock.call_args_list
+ [call(transaction_uuid=uuid), call(uuid=agg_uuid, version=3)], select_event_mock.call_args_list
)
self.assertEqual(
[
@@ -347,7 +347,7 @@ async def test_validate_false_already_reserved(self):
self.assertFalse(await transaction.validate())
self.assertEqual(
- [call(transaction_uuid=uuid), call(aggregate_uuid=agg_uuid, version=3)], select_event_mock.call_args_list
+ [call(transaction_uuid=uuid), call(uuid=agg_uuid, version=3)], select_event_mock.call_args_list
)
self.assertEqual(
[
diff --git a/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_value_objects.py b/packages/core/minos-microservice-aggregate/tests/test_aggregate/test_value_objects.py
similarity index 100%
rename from packages/core/minos-microservice-aggregate/tests/test_aggregate/test_models/test_value_objects.py
rename to packages/core/minos-microservice-aggregate/tests/test_aggregate/test_value_objects.py
diff --git a/packages/core/minos-microservice-aggregate/tests/testcases/event_repository.py b/packages/core/minos-microservice-aggregate/tests/testcases/event_repository.py
index 89dd611d6..c97c85b42 100644
--- a/packages/core/minos-microservice-aggregate/tests/testcases/event_repository.py
+++ b/packages/core/minos-microservice-aggregate/tests/testcases/event_repository.py
@@ -60,8 +60,8 @@ def assert_equal_repository_entries(self, expected: list[EventEntry], observed:
for e, o in zip(expected, observed):
self.assertEqual(type(e), type(o))
- self.assertEqual(e.aggregate_uuid, o.aggregate_uuid)
- self.assertEqual(e.aggregate_name, o.aggregate_name)
+ self.assertEqual(e.uuid, o.uuid)
+ self.assertEqual(e.name, o.name)
self.assertEqual(e.version, o.version)
self.assertEqual(e.data, o.data)
self.assertEqual(e.id, o.id)
@@ -76,8 +76,8 @@ async def test_generate_uuid(self):
await self.event_repository.create(EventEntry(NULL_UUID, "example.Car", 1, bytes("foo", "utf-8")))
observed = [v async for v in self.event_repository.select()]
self.assertEqual(1, len(observed))
- self.assertIsInstance(observed[0].aggregate_uuid, UUID)
- self.assertNotEqual(NULL_UUID, observed[0].aggregate_uuid)
+ self.assertIsInstance(observed[0].uuid, UUID)
+ self.assertNotEqual(NULL_UUID, observed[0].uuid)
async def test_submit(self):
await self.event_repository.submit(EventEntry(self.uuid, "example.Car", action=Action.CREATE))
@@ -223,14 +223,14 @@ async def test_select_id_ge(self):
observed = [v async for v in self.event_repository.select(id_ge=5)]
self.assert_equal_repository_entries(expected, observed)
- async def test_select_aggregate_uuid(self):
+ async def test_select_uuid(self):
expected = [self.entries[2], self.entries[5], self.entries[7], self.entries[8], self.entries[9]]
- observed = [v async for v in self.event_repository.select(aggregate_uuid=self.uuid_2)]
+ observed = [v async for v in self.event_repository.select(uuid=self.uuid_2)]
self.assert_equal_repository_entries(expected, observed)
- async def test_select_aggregate_name(self):
+ async def test_select_name(self):
expected = [self.entries[6]]
- observed = [v async for v in self.event_repository.select(aggregate_name="example.MotorCycle")]
+ observed = [v async for v in self.event_repository.select(name="example.MotorCycle")]
self.assert_equal_repository_entries(expected, observed)
async def test_select_version(self):
@@ -301,7 +301,5 @@ async def test_select_transaction_uuid_in(self):
async def test_select_combined(self):
expected = [self.entries[2], self.entries[5], self.entries[7], self.entries[8], self.entries[9]]
- observed = [
- v async for v in self.event_repository.select(aggregate_name="example.Car", aggregate_uuid=self.uuid_2)
- ]
+ observed = [v async for v in self.event_repository.select(name="example.Car", uuid=self.uuid_2)]
self.assert_equal_repository_entries(expected, observed)
diff --git a/packages/core/minos-microservice-aggregate/tests/utils.py b/packages/core/minos-microservice-aggregate/tests/utils.py
index 9098ba5be..6c5ee14ea 100644
--- a/packages/core/minos-microservice-aggregate/tests/utils.py
+++ b/packages/core/minos-microservice-aggregate/tests/utils.py
@@ -13,6 +13,9 @@
from typing import (
Optional,
)
+from uuid import (
+ UUID,
+)
from dependency_injector import (
containers,
@@ -23,10 +26,12 @@
Aggregate,
Entity,
EntitySet,
+ ExternalEntity,
InMemoryEventRepository,
InMemorySnapshotRepository,
InMemoryTransactionRepository,
- ModelRef,
+ Ref,
+ RootEntity,
ValueObject,
ValueObjectSet,
)
@@ -135,23 +140,23 @@ async def _destroy_instance(self, instance) -> None:
"""For testing purposes."""
-class Owner(Aggregate):
- """Aggregate ``Owner`` class for testing purposes."""
+class Owner(RootEntity):
+ """For testing purposes"""
name: str
surname: str
age: Optional[int]
-class Car(Aggregate):
- """Aggregate ``Car`` class for testing purposes."""
+class Car(RootEntity):
+ """For testing purposes"""
doors: int
color: str
- owner: Optional[ModelRef[Owner]]
+ owner: Optional[Ref[Owner]]
-class Order(Aggregate):
+class Order(RootEntity):
"""For testing purposes"""
products: EntitySet[OrderItem]
@@ -161,10 +166,28 @@ class Order(Aggregate):
class OrderItem(Entity):
"""For testing purposes"""
- amount: int
+ name: str
class Review(ValueObject):
"""For testing purposes."""
message: str
+
+
+class Product(ExternalEntity):
+ """For testing purposes."""
+
+ title: str
+ quantity: int
+
+
+class OrderAggregate(Aggregate[Order]):
+ """For testing purposes."""
+
+ @staticmethod
+ async def create_order() -> UUID:
+ """For testing purposes."""
+
+ order = await Order.create(products=EntitySet(), reviews=ValueObjectSet())
+ return order.uuid
diff --git a/packages/core/minos-microservice-common/.pre-commit-config.yaml b/packages/core/minos-microservice-common/.pre-commit-config.yaml
deleted file mode 100644
index c8808ff4e..000000000
--- a/packages/core/minos-microservice-common/.pre-commit-config.yaml
+++ /dev/null
@@ -1,38 +0,0 @@
-repos:
- - repo: local
- hooks:
- - id: install
- pass_filenames: false
- name: Install dependencies
- entry: make install
- language: system
-
- - id: reformat
- pass_filenames: false
- name: Reformat package
- entry: make reformat
- language: system
-
- - id: lint
- pass_filenames: false
- name: Lint package
- entry: make lint
- language: system
-
- - id: test
- pass_filenames: false
- name: Test package
- entry: make test
- language: system
-
- - id: docs
- pass_filenames: false
- name: Generate documentation
- entry: make docs
- language: system
-
- - id: build
- pass_filenames: false
- entry: make dist
- name: Generate build
- language: system
diff --git a/packages/core/minos-microservice-common/HISTORY.md b/packages/core/minos-microservice-common/HISTORY.md
index 310fc2c8e..80a7423be 100644
--- a/packages/core/minos-microservice-common/HISTORY.md
+++ b/packages/core/minos-microservice-common/HISTORY.md
@@ -269,3 +269,13 @@ History
------------------
* Add waiting time before destroying the `minos.common.MinosPool` acquired instances.
+
+0.4.1 (2022-01-31)
+------------------
+
+* Update `README.md`.
+
+0.5.0 (2022-02-03)
+------------------
+
+* Minor changes.
\ No newline at end of file
diff --git a/packages/core/minos-microservice-common/Makefile b/packages/core/minos-microservice-common/Makefile
index 9b3b57da2..854bc90bc 100644
--- a/packages/core/minos-microservice-common/Makefile
+++ b/packages/core/minos-microservice-common/Makefile
@@ -32,3 +32,11 @@ install:
update:
poetry update
+
+check:
+ $(MAKE) install
+ $(MAKE) reformat
+ $(MAKE) lint
+ $(MAKE) test
+ $(MAKE) docs
+ $(MAKE) dist
diff --git a/packages/core/minos-microservice-common/README.md b/packages/core/minos-microservice-common/README.md
index 1ae766b80..3837018db 100644
--- a/packages/core/minos-microservice-common/README.md
+++ b/packages/core/minos-microservice-common/README.md
@@ -1,7 +1,16 @@
-# Minos Microservice Common
+
+
+
-[](https://codecov.io/gh/Clariteia/minos_microservice_common)
-
+## minos-microservice-common
+
+[](https://pypi.org/project/minos-microservice-common/)
+[](https://minos-framework.github.io/minos-python)
+[](https://github.com/minos-framework/minos-python/blob/main/LICENSE)
+[](https://codecov.io/gh/minos-framework/minos-python)
+[](https://stackoverflow.com/questions/tagged/minos)
+
+## Summary
Minos is a framework which helps you create [reactive](https://www.reactivemanifesto.org/) microservices in Python.
Internally, it leverages Event Sourcing, CQRS and a message driven architecture to fulfil the commitments of an
@@ -9,76 +18,19 @@ asynchronous environment.
## Documentation
-The official documentation as well as the API you can find it under https://clariteia.github.io/minos_microservice_common/.
-Please, submit any issue regarding documentation as well!
-
-## Set up a development environment
-
-Minos uses `poetry` as its default package manager. Please refer to the
-[Poetry installation guide](https://python-poetry.org/docs/#installation) for instructions on how to install it.
-
-Now you con install all the dependencies by running
-```bash
-make install
-```
-
-In order to make the pre-commits checks available to git, run
-```bash
-pre-commit install
-```
-
-Make yourself sure you are able to run the tests. Refer to the appropriate section in this guide.
-
-## Run the tests
-
-In order to run the tests, please make sure you have the [Docker Engine](https://docs.docker.com/engine/install/)
-and [Docker Compose](https://docs.docker.com/compose/install/) installed.
-
-Move into `tests/` directory
-
-```bash
-cd tests/
-```
-Run service dependencies:
-
-```bash
-docker-compose up -d
-```
-
-Install library dependencies:
-
-```bash
-make install
-```
-
-Run tests:
-
-```bash
-make test
-```
-
-## How to contribute
-
-Minos being an open-source project, we are looking forward to having your contributions. No matter whether it is a pull
-request with new features, or the creation of an issue related to a bug you have found.
-
-Please consider these guidelines before you submit any modification.
+The official API Reference is publicly available at the [GitHub Pages](https://minos-framework.github.io/minos-python).
-### Create an issue
+## Source Code
-1. If you happen to find a bug, please file a new issue filling the 'Bug report' template.
-2. Set the appropriate labels, so we can categorise it easily.
-3. Wait for any core developer's feedback on it.
+The source code of this project is hosted at the [GitHub Repository](https://github.com/minos-framework/minos-python).
-### Submit a Pull Request
+## Getting Help
-1. Create an issue following the previous steps.
-2. Fork the project.
-3. Push your changes to a local branch.
-4. Run the tests!
-5. Submit a pull request from your fork's branch.
+For usage questions, the best place to go to is [StackOverflow](https://stackoverflow.com/questions/tagged/minos).
-## Credits
+## Discussion and Development
+Most development discussions take place over the [GitHub Issues](https://github.com/minos-framework/minos-python/issues). In addition, a [Gitter channel](https://gitter.im/minos-framework/community) is available for development-related questions.
-This package was created with  and the  project template.
+## License
+This project is distributed under the [MIT](https://raw.githubusercontent.com/minos-framework/minos-python/main/LICENSE) license.
diff --git a/packages/core/minos-microservice-common/minos/common/__init__.py b/packages/core/minos-microservice-common/minos/common/__init__.py
index b30086083..441e8c580 100644
--- a/packages/core/minos-microservice-common/minos/common/__init__.py
+++ b/packages/core/minos-microservice-common/minos/common/__init__.py
@@ -1,6 +1,6 @@
__author__ = "Minos Framework Devs"
__email__ = "hey@minos.run"
-__version__ = "0.4.0"
+__version__ = "0.5.0"
from .configuration import (
BROKER,
diff --git a/packages/core/minos-microservice-common/minos/common/launchers.py b/packages/core/minos-microservice-common/minos/common/launchers.py
index 620b03378..14e7c3e5c 100644
--- a/packages/core/minos-microservice-common/minos/common/launchers.py
+++ b/packages/core/minos-microservice-common/minos/common/launchers.py
@@ -79,7 +79,7 @@ def __init__(
log_date_format: Union[str, DateFormat] = DateFormat["color"],
external_modules: Optional[list[ModuleType]] = None,
*args,
- **kwargs
+ **kwargs,
):
if external_modules is None:
external_modules = list()
diff --git a/packages/core/minos-microservice-common/poetry.lock b/packages/core/minos-microservice-common/poetry.lock
index 741f945a4..59b0cdb43 100644
--- a/packages/core/minos-microservice-common/poetry.lock
+++ b/packages/core/minos-microservice-common/poetry.lock
@@ -85,28 +85,24 @@ pytz = ">=2015.7"
[[package]]
name = "black"
-version = "21.12b0"
+version = "22.1.0"
description = "The uncompromising code formatter."
category = "dev"
optional = false
python-versions = ">=3.6.2"
[package.dependencies]
-click = ">=7.1.2"
+click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
-pathspec = ">=0.9.0,<1"
+pathspec = ">=0.9.0"
platformdirs = ">=2"
-tomli = ">=0.2.6,<2.0.0"
-typing-extensions = [
- {version = ">=3.10.0.0", markers = "python_version < \"3.10\""},
- {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""},
-]
+tomli = ">=1.1.0"
+typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
[package.extras]
colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.7.4)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
-python2 = ["typed-ast (>=1.4.3)"]
uvloop = ["uvloop (>=0.15.2)"]
[[package]]
@@ -190,7 +186,7 @@ toml = ["tomli"]
[[package]]
name = "dependency-injector"
-version = "4.37.0"
+version = "4.38.0"
description = "Dependency injection framework for Python"
category = "main"
optional = false
@@ -811,7 +807,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
-content-hash = "820cf0b3e427d6b50179bf3ddfd3c37edad1858cb61c0ad3319488bd3567cf1b"
+content-hash = "6d2e61afb5b2cf90183a61ffe5fab62c065f3586603a70284571b91fa7dc359b"
[metadata.files]
aiomisc = [
@@ -843,8 +839,29 @@ babel = [
{file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"},
]
black = [
- {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"},
- {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"},
+ {file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"},
+ {file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"},
+ {file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"},
+ {file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"},
+ {file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"},
+ {file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"},
+ {file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"},
+ {file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"},
+ {file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"},
+ {file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"},
+ {file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"},
+ {file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"},
+ {file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"},
+ {file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"},
+ {file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"},
+ {file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"},
+ {file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"},
+ {file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"},
+ {file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"},
+ {file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"},
+ {file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"},
+ {file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"},
+ {file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"},
]
cached-property = [
{file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"},
@@ -921,42 +938,42 @@ coverage = [
{file = "coverage-6.3.tar.gz", hash = "sha256:987a84ff98a309994ca77ed3cc4b92424f824278e48e4bf7d1bb79a63cfe2099"},
]
dependency-injector = [
- {file = "dependency-injector-4.37.0.tar.gz", hash = "sha256:8881c65ecc133d4b0af1cf35215a7bfab8d907e10ee1452d2dfef27cc3ca23d3"},
- {file = "dependency_injector-4.37.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6fdabe9dd14259fe14eb4c65f5bf244524a5cc43a474cb448528daeda4453573"},
- {file = "dependency_injector-4.37.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a184b71e8aa2fffd6c3d3828c2db045a14c3bc1ac9ca7945db76b9ac93efca81"},
- {file = "dependency_injector-4.37.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0cc2cb5b85a587f9b95505391ab4f1ef02432a590807f2230f445666d0bd3984"},
- {file = "dependency_injector-4.37.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:985570539c2703c6c009077026042a05b05474e75bec585607a556c1970bdeee"},
- {file = "dependency_injector-4.37.0-cp310-cp310-win32.whl", hash = "sha256:b73bd0dd82b42950fb78baae68750ecb5c943d39cbfacea8dbee9d6df6535427"},
- {file = "dependency_injector-4.37.0-cp310-cp310-win_amd64.whl", hash = "sha256:a944c1bbbb81dbeca8c30001bc8b7e061ca52cf291bf0dd35005863484e6ea8a"},
- {file = "dependency_injector-4.37.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d15b6fe1be06bffecf9b5f28fd972596f1ef6b7553d884c317b6d472ca0fb040"},
- {file = "dependency_injector-4.37.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbf05aefcb3cd856624e2203f69a61ad54ffa0541a23a8e6d136c178b7a37153"},
- {file = "dependency_injector-4.37.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ededd0f6f7abe153030f3f50959abf5cb65bf7e5215a59b9333e027d6262d161"},
- {file = "dependency_injector-4.37.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a3c5312fa1854eb45ed78a720ac5e1e354769e55a2fb42ca142b5dd612e8f0da"},
- {file = "dependency_injector-4.37.0-cp36-cp36m-win32.whl", hash = "sha256:6446bd95a80a487893e162eeb8aa2f3029ab47bb4641a9e5d431f3c024b459c9"},
- {file = "dependency_injector-4.37.0-cp36-cp36m-win_amd64.whl", hash = "sha256:fb29620e8249d66e8328d30c44d2f788d773132cdb6d0d62be4f1dd4343fc748"},
- {file = "dependency_injector-4.37.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c9fad82e44a34c83a0b522692aace49f3149d44b3ff826197a131a27a8df51df"},
- {file = "dependency_injector-4.37.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bfbcaa71ea2fd3a54e46d5038e6cedbb66d7c1319ac638f935f6cbba348ffc9"},
- {file = "dependency_injector-4.37.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d550f4e9e81e87ae23c5086e5b3b08f2331a02e9dc7a2553ce16275ba9921817"},
- {file = "dependency_injector-4.37.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a5242bca4f404c4918ba00b48fa1780c42903a9ff850956e04134bfc8b423d04"},
- {file = "dependency_injector-4.37.0-cp37-cp37m-win32.whl", hash = "sha256:59f557f1f1f7fe856759fdc59b5f2c012e4caaf05b4f848cbb1f250bdf4d8541"},
- {file = "dependency_injector-4.37.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c69196827505288a8f94f9d36d4b4829fb23d5a62f0898e0aa7d5ad1fce0505e"},
- {file = "dependency_injector-4.37.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7639c601288417352af3318d683e96f034ffb685de2cfb8d79a75f982c262302"},
- {file = "dependency_injector-4.37.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b607090446e697b77d36be523ed845021d2379d62fcaf152998127066b70d80"},
- {file = "dependency_injector-4.37.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c9f31a7b3806098476767531b40f8a59dac726ce7602158a6e093f9e2be46f1a"},
- {file = "dependency_injector-4.37.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:86c4e918064de9e300152233da096797c4de7bb8e33ce86a7c6a398daf760c57"},
- {file = "dependency_injector-4.37.0-cp38-cp38-win32.whl", hash = "sha256:9756873290abd53111f9a7edc055c62a7968ac67d0fc3f49e7dba5bdda5c78a3"},
- {file = "dependency_injector-4.37.0-cp38-cp38-win_amd64.whl", hash = "sha256:35ac330fc1ed6ba0751f3eaa6a6f068c4e88cb1069bbe0c10568847db00dc62d"},
- {file = "dependency_injector-4.37.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6dc75b54da62da105ea5d4541bc5f1d0d1edb1be3763d2e9e1184fd0f249f23b"},
- {file = "dependency_injector-4.37.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9f9572021c4ed1ae59d22437ba60c4d92d1a1ec1e5fee1f81ef0c58096b9ee8"},
- {file = "dependency_injector-4.37.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2c796ec1de86c5bd34ba6a96ea95409582ebc8e54d9a62f263c7c7852d593ae6"},
- {file = "dependency_injector-4.37.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b7fda0bd48b8b3d6f9e7227d872b7d0cc95b8d54f296213369867f7490e38d06"},
- {file = "dependency_injector-4.37.0-cp39-cp39-win32.whl", hash = "sha256:c80521fc43f2812fec10ab4b92e7168659e25b5b13e0e3d45da0260e959da24a"},
- {file = "dependency_injector-4.37.0-cp39-cp39-win_amd64.whl", hash = "sha256:8930da0c2a0bdc3d96863e9f9522abeeb106ee7bb5c670805e97e42838191998"},
- {file = "dependency_injector-4.37.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6001f91e67700479088763babe976354538344ca347abe2d4405f6f4bc40b803"},
- {file = "dependency_injector-4.37.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14ccce9356f161c42664b73085c7ead179186e6cb8434bf885fa64b213e32712"},
- {file = "dependency_injector-4.37.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:58be030a8b0f4a856523ce3799cecfcf686a545b79f1f897262cec43090a7fd3"},
- {file = "dependency_injector-4.37.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a3bc779fe3f1331299032c51ec66c01dfd49e1a052c7ac3ac96aef30313c2e80"},
- {file = "dependency_injector-4.37.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:7c781db928a6f02f5f373773dc1a263e1e9dfcce2a854b42c9c261db2eb0042f"},
+ {file = "dependency-injector-4.38.0.tar.gz", hash = "sha256:bab4c323d822d3fc9936e8eb3c2f5553d75e9efdadac11d5b293a016e31a1477"},
+ {file = "dependency_injector-4.38.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:025eb5f97021663715bff8e01feb83d5b2f66fc17ece1042a194f1aae88c0d85"},
+ {file = "dependency_injector-4.38.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3c61334b196ab767eae43af207764349287d5eb0283d8ed1ab24608121aea35"},
+ {file = "dependency_injector-4.38.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9bf4bfc52015e81c4f17647b7bbbe4e4549f041b3c6635b44a9ecede7594932c"},
+ {file = "dependency_injector-4.38.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7aeba5882b06baf78978f33228e4c44133dada9173e330da68fbccca98520848"},
+ {file = "dependency_injector-4.38.0-cp310-cp310-win32.whl", hash = "sha256:445dbf5324eee215a465d7f3b1965b05e199c31caa09e63abf0f02d982791306"},
+ {file = "dependency_injector-4.38.0-cp310-cp310-win_amd64.whl", hash = "sha256:880edbcb5d810faa0623112e2e652a7bec73d20ce0708d9db998a0a40b62cbb9"},
+ {file = "dependency_injector-4.38.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cd6f1c130462e7461a43f82fdc0d2ba25b5ef594db823dbd0e57f3d1b7c44f86"},
+ {file = "dependency_injector-4.38.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0be75905f7513886699d3ff5ed9aca233175c03808fc888da2a53b83af0a5d65"},
+ {file = "dependency_injector-4.38.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d7f1a7d27de6295ce8b7ca69d1177817bf36c7cbaf73819e4bab04f87c5e962"},
+ {file = "dependency_injector-4.38.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e9c1ff387d7b7d814e9d29a531c6804acc67b1cca578c09abd3590fa7ec6bf06"},
+ {file = "dependency_injector-4.38.0-cp36-cp36m-win32.whl", hash = "sha256:7770efcbc6915dabbb31ea0bdeee1105dabf76e1c8e31a454cb1983dcf19ecf1"},
+ {file = "dependency_injector-4.38.0-cp36-cp36m-win_amd64.whl", hash = "sha256:9e89a9c88317ad237abfb374c410e1466476ffefe6c44f3caeca3dce747a635c"},
+ {file = "dependency_injector-4.38.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb75cd29c132bfaf03a11a6ac4f459dddb7a6526669543de57d2bb5fddf78def"},
+ {file = "dependency_injector-4.38.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d116c56e7fc3b59b3afa6078163b5f6ff4680ebf27800dd4032de7a04f7ef777"},
+ {file = "dependency_injector-4.38.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9df330ef9e24b6f94e6764d23180350c2fb99785257233ee4738e066b876fa7f"},
+ {file = "dependency_injector-4.38.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7a46639038313f64eca2dc858ac4cd9e0aca5ea21bb005f5d754aadd6446ba4b"},
+ {file = "dependency_injector-4.38.0-cp37-cp37m-win32.whl", hash = "sha256:d0d983b269b657744058b5858afc3c59443db53afe9c3e709e316daa9f9b9454"},
+ {file = "dependency_injector-4.38.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1446df58169c166a5a2d5644ba9eeb3b7f2f679f260596f78d012c58ff140d92"},
+ {file = "dependency_injector-4.38.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:307396f2d9d2f532fe92079a56d40af5fc60dacb1d766e3f9cd04c3802a1c251"},
+ {file = "dependency_injector-4.38.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dd96b6c454ab86648f57f37b895c1c976b1a82b76f835011f607ee8a78ebc0e"},
+ {file = "dependency_injector-4.38.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fb44b17e649cabcfd1f370ecfd492ac7a93216776d91954b31598eecb36cdb13"},
+ {file = "dependency_injector-4.38.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ab8ebe728dd9b3be23c40ca5a5dbe195050d9ad35d42d7e9fdaea816f7134584"},
+ {file = "dependency_injector-4.38.0-cp38-cp38-win32.whl", hash = "sha256:1da3bad1452212bab76e87fbf7a71d3675190a1a909f345aaf8bae2fa97b878f"},
+ {file = "dependency_injector-4.38.0-cp38-cp38-win_amd64.whl", hash = "sha256:2918776e88de88be0e2be036261180ca0605c8f64ead43d835ce852f16a9efd2"},
+ {file = "dependency_injector-4.38.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:493be62561218624380d4eca9243a46753444f677217db6292a7b715cf429172"},
+ {file = "dependency_injector-4.38.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a70511db88f84ac4228b27e37e12ea0e04a9c2a32cae3602b9af9a27c0db992"},
+ {file = "dependency_injector-4.38.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e3e1cfe41a5ada0ff71889563441f538caff0399e41d3ee377b60fa50a858bf"},
+ {file = "dependency_injector-4.38.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:116cc679a2c6d40c6a4f968aefe68535e596e88e96315dbd0d0ad2ff76654e3d"},
+ {file = "dependency_injector-4.38.0-cp39-cp39-win32.whl", hash = "sha256:f703c2c161de067ba9893b56743d24fb4c9dbff92eb504bc082c2d2cfeab4c01"},
+ {file = "dependency_injector-4.38.0-cp39-cp39-win_amd64.whl", hash = "sha256:6821a864d6405dc0d5f794ac1b10da4a8c7e8731c6a0651a9682a0b76f5a5b3e"},
+ {file = "dependency_injector-4.38.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6c9e8dc91aa5831bd3a58fec1b94ed8c52f78f601f5ab91135b5ad44325beef7"},
+ {file = "dependency_injector-4.38.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b4eedadef0c84295b70803a79a3ce5a10a59dddd8f306876f6fa6bfc4de8e00"},
+ {file = "dependency_injector-4.38.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2e88b5d09c80e20d6b3d985cc360f39a81e748667c20f6bc7eee9f4b832176ed"},
+ {file = "dependency_injector-4.38.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b1fcd71ff46e097f4e47917ccdf6aa388b6a6372557f7d9f83db1e879e95f8bb"},
+ {file = "dependency_injector-4.38.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:9633d6366282e83a3f21543c5c78299787948333d9fe6649b020cfac93d8b7ca"},
]
distlib = [
{file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"},
diff --git a/packages/core/minos-microservice-common/pyproject.toml b/packages/core/minos-microservice-common/pyproject.toml
index 60ef02bbb..47b0e67f1 100644
--- a/packages/core/minos-microservice-common/pyproject.toml
+++ b/packages/core/minos-microservice-common/pyproject.toml
@@ -1,14 +1,14 @@
[tool.poetry]
name = "minos-microservice-common"
-version = "0.4.0"
-description = "Python Package with common Classes and Utilities used in Minos Microservices."
+version = "0.5.0"
+description = "The common core of the Minos Framework"
readme = "README.md"
repository = "https://github.com/minos-framework/minos-python"
homepage = "http://www.minos.run/"
authors = ["Minos Framework Devs "]
license = "MIT"
classifiers = [
- "Development Status :: 2 - Pre-Alpha",
+ "Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Natural Language :: English",
"Programming Language :: Python :: 3",
@@ -41,7 +41,7 @@ dependency-injector = "^4.32.2"
cached-property = "^1.5.2"
[tool.poetry.dev-dependencies]
-black = "^21.12b0"
+black = "^22.1"
isort = "^5.8.0"
pytest = "^6.2.4"
coverage = "^6.3"
diff --git a/packages/core/minos-microservice-cqrs/.pre-commit-config.yaml b/packages/core/minos-microservice-cqrs/.pre-commit-config.yaml
deleted file mode 100644
index c8808ff4e..000000000
--- a/packages/core/minos-microservice-cqrs/.pre-commit-config.yaml
+++ /dev/null
@@ -1,38 +0,0 @@
-repos:
- - repo: local
- hooks:
- - id: install
- pass_filenames: false
- name: Install dependencies
- entry: make install
- language: system
-
- - id: reformat
- pass_filenames: false
- name: Reformat package
- entry: make reformat
- language: system
-
- - id: lint
- pass_filenames: false
- name: Lint package
- entry: make lint
- language: system
-
- - id: test
- pass_filenames: false
- name: Test package
- entry: make test
- language: system
-
- - id: docs
- pass_filenames: false
- name: Generate documentation
- entry: make docs
- language: system
-
- - id: build
- pass_filenames: false
- entry: make dist
- name: Generate build
- language: system
diff --git a/packages/core/minos-microservice-cqrs/HISTORY.md b/packages/core/minos-microservice-cqrs/HISTORY.md
index 7707bd8f0..929911aaf 100644
--- a/packages/core/minos-microservice-cqrs/HISTORY.md
+++ b/packages/core/minos-microservice-cqrs/HISTORY.md
@@ -56,3 +56,11 @@
* Be compatible with `minos-microservice-common~=0.4.0`.
* Be compatible with `minos-microservice-aggregate~=0.4.0`.
* Be compatible with `minos-microservice-networks~=0.4.0`.
+
+# 0.4.1 (2022-01-31)
+
+* Update `README.md`.
+
+# 0.5.0 (2022-02-03)
+
+* Minor changes.
\ No newline at end of file
diff --git a/packages/core/minos-microservice-cqrs/Makefile b/packages/core/minos-microservice-cqrs/Makefile
index 9b3b57da2..854bc90bc 100644
--- a/packages/core/minos-microservice-cqrs/Makefile
+++ b/packages/core/minos-microservice-cqrs/Makefile
@@ -32,3 +32,11 @@ install:
update:
poetry update
+
+check:
+ $(MAKE) install
+ $(MAKE) reformat
+ $(MAKE) lint
+ $(MAKE) test
+ $(MAKE) docs
+ $(MAKE) dist
diff --git a/packages/core/minos-microservice-cqrs/README.md b/packages/core/minos-microservice-cqrs/README.md
index b1323fe95..e14b9b739 100644
--- a/packages/core/minos-microservice-cqrs/README.md
+++ b/packages/core/minos-microservice-cqrs/README.md
@@ -1,7 +1,16 @@
-# Minos Microservice CQRS
+
+
+
-[](https://codecov.io/gh/Clariteia/minos_microservice_cqrs)
-
+## minos-microservice-cqrs
+
+[](https://pypi.org/project/minos-microservice-cqrs/)
+[](https://minos-framework.github.io/minos-python)
+[](https://github.com/minos-framework/minos-python/blob/main/LICENSE)
+[](https://codecov.io/gh/minos-framework/minos-python)
+[](https://stackoverflow.com/questions/tagged/minos)
+
+## Summary
Minos is a framework which helps you create [reactive](https://www.reactivemanifesto.org/) microservices in Python.
Internally, it leverages Event Sourcing, CQRS and a message driven architecture to fulfil the commitments of an
@@ -9,76 +18,19 @@ asynchronous environment.
## Documentation
-The official documentation as well as the API you can find it under https://clariteia.github.io/minos_microservice_cqrs/.
-Please, submit any issue regarding documentation as well!
-
-## Set up a development environment
-
-Minos uses `poetry` as its default package manager. Please refer to the
-[Poetry installation guide](https://python-poetry.org/docs/#installation) for instructions on how to install it.
-
-Now you con install all the dependencies by running
-```bash
-make install
-```
-
-In order to make the pre-commits checks available to git, run
-```bash
-pre-commit install
-```
-
-Make yourself sure you are able to run the tests. Refer to the appropriate section in this guide.
-
-## Run the tests
-
-In order to run the tests, please make sure you have the [Docker Engine](https://docs.docker.com/engine/install/)
-and [Docker Compose](https://docs.docker.com/compose/install/) installed.
-
-Move into `tests/` directory
-
-```bash
-cd tests/
-```
-Run service dependencies:
-
-```bash
-docker-compose up -d
-```
-
-Install library dependencies:
-
-```bash
-make install
-```
-
-Run tests:
-
-```bash
-make test
-```
-
-## How to contribute
-
-Minos being an open-source project, we are looking forward to having your contributions. No matter whether it is a pull
-request with new features, or the creation of an issue related to a bug you have found.
-
-Please consider these guidelines before you submit any modification.
+The official API Reference is publicly available at the [GitHub Pages](https://minos-framework.github.io/minos-python).
-### Create an issue
+## Source Code
-1. If you happen to find a bug, please file a new issue filling the 'Bug report' template.
-2. Set the appropriate labels, so we can categorise it easily.
-3. Wait for any core developer's feedback on it.
+The source code of this project is hosted at the [GitHub Repository](https://github.com/minos-framework/minos-python).
-### Submit a Pull Request
+## Getting Help
-1. Create an issue following the previous steps.
-2. Fork the project.
-3. Push your changes to a local branch.
-4. Run the tests!
-5. Submit a pull request from your fork's branch.
+For usage questions, the best place to go to is [StackOverflow](https://stackoverflow.com/questions/tagged/minos).
-## Credits
+## Discussion and Development
+Most development discussions take place over the [GitHub Issues](https://github.com/minos-framework/minos-python/issues). In addition, a [Gitter channel](https://gitter.im/minos-framework/community) is available for development-related questions.
-This package was created with  and the  project template.
+## License
+This project is distributed under the [MIT](https://raw.githubusercontent.com/minos-framework/minos-python/main/LICENSE) license.
diff --git a/packages/core/minos-microservice-cqrs/minos/cqrs/__init__.py b/packages/core/minos-microservice-cqrs/minos/cqrs/__init__.py
index 66d93ace3..be82395ea 100644
--- a/packages/core/minos-microservice-cqrs/minos/cqrs/__init__.py
+++ b/packages/core/minos-microservice-cqrs/minos/cqrs/__init__.py
@@ -1,6 +1,6 @@
__author__ = "Minos Framework Devs"
__email__ = "hey@minos.run"
-__version__ = "0.4.0"
+__version__ = "0.5.0"
from .exceptions import (
MinosCqrsException,
diff --git a/packages/core/minos-microservice-cqrs/minos/cqrs/handlers.py b/packages/core/minos-microservice-cqrs/minos/cqrs/handlers.py
index 93d3c7ab5..300d9c042 100644
--- a/packages/core/minos-microservice-cqrs/minos/cqrs/handlers.py
+++ b/packages/core/minos-microservice-cqrs/minos/cqrs/handlers.py
@@ -8,8 +8,8 @@
)
from minos.aggregate import (
- AggregateDiff,
- ModelRefResolver,
+ Event,
+ RefResolver,
)
logger = logging.getLogger(__name__)
@@ -20,18 +20,18 @@ class PreEventHandler:
@classmethod
async def handle(cls, diff: T, resolve_references: bool = True, **kwargs) -> T:
- """Handle ModelRef resolution for Events.
+ """Handle Ref resolution for Events.
- :param diff: The instance containing ``ModelRef`` instances.
+ :param diff: The instance containing ``Ref`` instances.
:param resolve_references: If ``True`` the resolution is performed, otherwise it is skipped.
:param kwargs: Additional named arguments.
- :return: The original instance with the ``ModelRef`` references already resolved.
+ :return: The original instance with the ``Ref`` references already resolved.
"""
- if not isinstance(diff, AggregateDiff) or not resolve_references:
+ if not isinstance(diff, Event) or not resolve_references:
return diff
try:
- return await ModelRefResolver(**kwargs).resolve(diff)
+ return await RefResolver(**kwargs).resolve(diff)
except Exception as exc:
logger.warning(f"An exception was raised while trying to resolve model references: {exc!r}")
return diff
diff --git a/packages/core/minos-microservice-cqrs/minos/cqrs/services.py b/packages/core/minos-microservice-cqrs/minos/cqrs/services.py
index 46c229838..267d85f85 100644
--- a/packages/core/minos-microservice-cqrs/minos/cqrs/services.py
+++ b/packages/core/minos-microservice-cqrs/minos/cqrs/services.py
@@ -26,6 +26,7 @@
)
from minos.networks import (
EnrouteDecorator,
+ HandlerWrapper,
Request,
WrappedRequest,
)
@@ -59,9 +60,9 @@ def __getattr__(self, item: str) -> Any:
def __get_enroute__(cls, config: MinosConfig) -> dict[str, set[EnrouteDecorator]]:
result = dict()
for name, fn in getmembers(cls, predicate=lambda x: ismethod(x) or isfunction(x)):
- if not hasattr(fn, "__decorators__"):
+ if not isinstance(fn, HandlerWrapper):
continue
- result[name] = fn.__decorators__
+ result[name] = fn.meta.decorators
return result
@staticmethod
diff --git a/packages/core/minos-microservice-cqrs/poetry.lock b/packages/core/minos-microservice-cqrs/poetry.lock
index 208d8c7a9..99bafd38c 100644
--- a/packages/core/minos-microservice-cqrs/poetry.lock
+++ b/packages/core/minos-microservice-cqrs/poetry.lock
@@ -130,28 +130,24 @@ pytz = ">=2015.7"
[[package]]
name = "black"
-version = "21.12b0"
+version = "22.1.0"
description = "The uncompromising code formatter."
category = "dev"
optional = false
python-versions = ">=3.6.2"
[package.dependencies]
-click = ">=7.1.2"
+click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
-pathspec = ">=0.9.0,<1"
+pathspec = ">=0.9.0"
platformdirs = ">=2"
-tomli = ">=0.2.6,<2.0.0"
-typing-extensions = [
- {version = ">=3.10.0.0", markers = "python_version < \"3.10\""},
- {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""},
-]
+tomli = ">=1.1.0"
+typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
[package.extras]
colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.7.4)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
-python2 = ["typed-ast (>=1.4.3)"]
uvloop = ["uvloop (>=0.15.2)"]
[[package]]
@@ -243,7 +239,7 @@ python-versions = "*"
[[package]]
name = "dependency-injector"
-version = "4.37.0"
+version = "4.38.0"
description = "Dependency injection framework for Python"
category = "main"
optional = false
@@ -449,7 +445,7 @@ python-versions = "*"
[[package]]
name = "minos-microservice-aggregate"
-version = "0.4.0"
+version = "0.4.1"
description = "Python Package for Minos Microservices containing all the Aggregate stuff"
category = "main"
optional = false
@@ -466,7 +462,7 @@ url = "../minos-microservice-aggregate"
[[package]]
name = "minos-microservice-common"
-version = "0.4.0"
+version = "0.4.1"
description = "Python Package with common Classes and Utilities used in Minos Microservices."
category = "main"
optional = false
@@ -489,7 +485,7 @@ url = "../minos-microservice-common"
[[package]]
name = "minos-microservice-networks"
-version = "0.4.0"
+version = "0.4.1"
description = "Python Package with the common network classes and utilities used in Minos Microservice."
category = "main"
optional = false
@@ -966,7 +962,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-
[metadata]
lock-version = "1.1"
python-versions = "^3.9"
-content-hash = "bec0d6c2fbf3ab06a59d617d379e59136374f00de999a130e8df511bcefc485d"
+content-hash = "da5928149e0d3787d4d29665728c6e66db783900a95f01664333096a04edd9f8"
[metadata.files]
aiohttp = [
@@ -1099,8 +1095,29 @@ babel = [
{file = "Babel-2.9.1.tar.gz", hash = "sha256:bc0c176f9f6a994582230df350aa6e05ba2ebe4b3ac317eab29d9be5d2768da0"},
]
black = [
- {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"},
- {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"},
+ {file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"},
+ {file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"},
+ {file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"},
+ {file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"},
+ {file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"},
+ {file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"},
+ {file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"},
+ {file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"},
+ {file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"},
+ {file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"},
+ {file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"},
+ {file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"},
+ {file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"},
+ {file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"},
+ {file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"},
+ {file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"},
+ {file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"},
+ {file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"},
+ {file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"},
+ {file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"},
+ {file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"},
+ {file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"},
+ {file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"},
]
cached-property = [
{file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"},
@@ -1180,42 +1197,42 @@ crontab = [
{file = "crontab-0.23.0.tar.gz", hash = "sha256:ca79dede9c2f572bb32f38703e8fddcf3427e86edc838f2ffe7ae4b9ee2b0733"},
]
dependency-injector = [
- {file = "dependency-injector-4.37.0.tar.gz", hash = "sha256:8881c65ecc133d4b0af1cf35215a7bfab8d907e10ee1452d2dfef27cc3ca23d3"},
- {file = "dependency_injector-4.37.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6fdabe9dd14259fe14eb4c65f5bf244524a5cc43a474cb448528daeda4453573"},
- {file = "dependency_injector-4.37.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a184b71e8aa2fffd6c3d3828c2db045a14c3bc1ac9ca7945db76b9ac93efca81"},
- {file = "dependency_injector-4.37.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0cc2cb5b85a587f9b95505391ab4f1ef02432a590807f2230f445666d0bd3984"},
- {file = "dependency_injector-4.37.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:985570539c2703c6c009077026042a05b05474e75bec585607a556c1970bdeee"},
- {file = "dependency_injector-4.37.0-cp310-cp310-win32.whl", hash = "sha256:b73bd0dd82b42950fb78baae68750ecb5c943d39cbfacea8dbee9d6df6535427"},
- {file = "dependency_injector-4.37.0-cp310-cp310-win_amd64.whl", hash = "sha256:a944c1bbbb81dbeca8c30001bc8b7e061ca52cf291bf0dd35005863484e6ea8a"},
- {file = "dependency_injector-4.37.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d15b6fe1be06bffecf9b5f28fd972596f1ef6b7553d884c317b6d472ca0fb040"},
- {file = "dependency_injector-4.37.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbf05aefcb3cd856624e2203f69a61ad54ffa0541a23a8e6d136c178b7a37153"},
- {file = "dependency_injector-4.37.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ededd0f6f7abe153030f3f50959abf5cb65bf7e5215a59b9333e027d6262d161"},
- {file = "dependency_injector-4.37.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a3c5312fa1854eb45ed78a720ac5e1e354769e55a2fb42ca142b5dd612e8f0da"},
- {file = "dependency_injector-4.37.0-cp36-cp36m-win32.whl", hash = "sha256:6446bd95a80a487893e162eeb8aa2f3029ab47bb4641a9e5d431f3c024b459c9"},
- {file = "dependency_injector-4.37.0-cp36-cp36m-win_amd64.whl", hash = "sha256:fb29620e8249d66e8328d30c44d2f788d773132cdb6d0d62be4f1dd4343fc748"},
- {file = "dependency_injector-4.37.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c9fad82e44a34c83a0b522692aace49f3149d44b3ff826197a131a27a8df51df"},
- {file = "dependency_injector-4.37.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bfbcaa71ea2fd3a54e46d5038e6cedbb66d7c1319ac638f935f6cbba348ffc9"},
- {file = "dependency_injector-4.37.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d550f4e9e81e87ae23c5086e5b3b08f2331a02e9dc7a2553ce16275ba9921817"},
- {file = "dependency_injector-4.37.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a5242bca4f404c4918ba00b48fa1780c42903a9ff850956e04134bfc8b423d04"},
- {file = "dependency_injector-4.37.0-cp37-cp37m-win32.whl", hash = "sha256:59f557f1f1f7fe856759fdc59b5f2c012e4caaf05b4f848cbb1f250bdf4d8541"},
- {file = "dependency_injector-4.37.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c69196827505288a8f94f9d36d4b4829fb23d5a62f0898e0aa7d5ad1fce0505e"},
- {file = "dependency_injector-4.37.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7639c601288417352af3318d683e96f034ffb685de2cfb8d79a75f982c262302"},
- {file = "dependency_injector-4.37.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b607090446e697b77d36be523ed845021d2379d62fcaf152998127066b70d80"},
- {file = "dependency_injector-4.37.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c9f31a7b3806098476767531b40f8a59dac726ce7602158a6e093f9e2be46f1a"},
- {file = "dependency_injector-4.37.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:86c4e918064de9e300152233da096797c4de7bb8e33ce86a7c6a398daf760c57"},
- {file = "dependency_injector-4.37.0-cp38-cp38-win32.whl", hash = "sha256:9756873290abd53111f9a7edc055c62a7968ac67d0fc3f49e7dba5bdda5c78a3"},
- {file = "dependency_injector-4.37.0-cp38-cp38-win_amd64.whl", hash = "sha256:35ac330fc1ed6ba0751f3eaa6a6f068c4e88cb1069bbe0c10568847db00dc62d"},
- {file = "dependency_injector-4.37.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6dc75b54da62da105ea5d4541bc5f1d0d1edb1be3763d2e9e1184fd0f249f23b"},
- {file = "dependency_injector-4.37.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9f9572021c4ed1ae59d22437ba60c4d92d1a1ec1e5fee1f81ef0c58096b9ee8"},
- {file = "dependency_injector-4.37.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2c796ec1de86c5bd34ba6a96ea95409582ebc8e54d9a62f263c7c7852d593ae6"},
- {file = "dependency_injector-4.37.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b7fda0bd48b8b3d6f9e7227d872b7d0cc95b8d54f296213369867f7490e38d06"},
- {file = "dependency_injector-4.37.0-cp39-cp39-win32.whl", hash = "sha256:c80521fc43f2812fec10ab4b92e7168659e25b5b13e0e3d45da0260e959da24a"},
- {file = "dependency_injector-4.37.0-cp39-cp39-win_amd64.whl", hash = "sha256:8930da0c2a0bdc3d96863e9f9522abeeb106ee7bb5c670805e97e42838191998"},
- {file = "dependency_injector-4.37.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6001f91e67700479088763babe976354538344ca347abe2d4405f6f4bc40b803"},
- {file = "dependency_injector-4.37.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14ccce9356f161c42664b73085c7ead179186e6cb8434bf885fa64b213e32712"},
- {file = "dependency_injector-4.37.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:58be030a8b0f4a856523ce3799cecfcf686a545b79f1f897262cec43090a7fd3"},
- {file = "dependency_injector-4.37.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a3bc779fe3f1331299032c51ec66c01dfd49e1a052c7ac3ac96aef30313c2e80"},
- {file = "dependency_injector-4.37.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:7c781db928a6f02f5f373773dc1a263e1e9dfcce2a854b42c9c261db2eb0042f"},
+ {file = "dependency-injector-4.38.0.tar.gz", hash = "sha256:bab4c323d822d3fc9936e8eb3c2f5553d75e9efdadac11d5b293a016e31a1477"},
+ {file = "dependency_injector-4.38.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:025eb5f97021663715bff8e01feb83d5b2f66fc17ece1042a194f1aae88c0d85"},
+ {file = "dependency_injector-4.38.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3c61334b196ab767eae43af207764349287d5eb0283d8ed1ab24608121aea35"},
+ {file = "dependency_injector-4.38.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9bf4bfc52015e81c4f17647b7bbbe4e4549f041b3c6635b44a9ecede7594932c"},
+ {file = "dependency_injector-4.38.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7aeba5882b06baf78978f33228e4c44133dada9173e330da68fbccca98520848"},
+ {file = "dependency_injector-4.38.0-cp310-cp310-win32.whl", hash = "sha256:445dbf5324eee215a465d7f3b1965b05e199c31caa09e63abf0f02d982791306"},
+ {file = "dependency_injector-4.38.0-cp310-cp310-win_amd64.whl", hash = "sha256:880edbcb5d810faa0623112e2e652a7bec73d20ce0708d9db998a0a40b62cbb9"},
+ {file = "dependency_injector-4.38.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cd6f1c130462e7461a43f82fdc0d2ba25b5ef594db823dbd0e57f3d1b7c44f86"},
+ {file = "dependency_injector-4.38.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0be75905f7513886699d3ff5ed9aca233175c03808fc888da2a53b83af0a5d65"},
+ {file = "dependency_injector-4.38.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d7f1a7d27de6295ce8b7ca69d1177817bf36c7cbaf73819e4bab04f87c5e962"},
+ {file = "dependency_injector-4.38.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e9c1ff387d7b7d814e9d29a531c6804acc67b1cca578c09abd3590fa7ec6bf06"},
+ {file = "dependency_injector-4.38.0-cp36-cp36m-win32.whl", hash = "sha256:7770efcbc6915dabbb31ea0bdeee1105dabf76e1c8e31a454cb1983dcf19ecf1"},
+ {file = "dependency_injector-4.38.0-cp36-cp36m-win_amd64.whl", hash = "sha256:9e89a9c88317ad237abfb374c410e1466476ffefe6c44f3caeca3dce747a635c"},
+ {file = "dependency_injector-4.38.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cb75cd29c132bfaf03a11a6ac4f459dddb7a6526669543de57d2bb5fddf78def"},
+ {file = "dependency_injector-4.38.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d116c56e7fc3b59b3afa6078163b5f6ff4680ebf27800dd4032de7a04f7ef777"},
+ {file = "dependency_injector-4.38.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9df330ef9e24b6f94e6764d23180350c2fb99785257233ee4738e066b876fa7f"},
+ {file = "dependency_injector-4.38.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7a46639038313f64eca2dc858ac4cd9e0aca5ea21bb005f5d754aadd6446ba4b"},
+ {file = "dependency_injector-4.38.0-cp37-cp37m-win32.whl", hash = "sha256:d0d983b269b657744058b5858afc3c59443db53afe9c3e709e316daa9f9b9454"},
+ {file = "dependency_injector-4.38.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1446df58169c166a5a2d5644ba9eeb3b7f2f679f260596f78d012c58ff140d92"},
+ {file = "dependency_injector-4.38.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:307396f2d9d2f532fe92079a56d40af5fc60dacb1d766e3f9cd04c3802a1c251"},
+ {file = "dependency_injector-4.38.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dd96b6c454ab86648f57f37b895c1c976b1a82b76f835011f607ee8a78ebc0e"},
+ {file = "dependency_injector-4.38.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fb44b17e649cabcfd1f370ecfd492ac7a93216776d91954b31598eecb36cdb13"},
+ {file = "dependency_injector-4.38.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ab8ebe728dd9b3be23c40ca5a5dbe195050d9ad35d42d7e9fdaea816f7134584"},
+ {file = "dependency_injector-4.38.0-cp38-cp38-win32.whl", hash = "sha256:1da3bad1452212bab76e87fbf7a71d3675190a1a909f345aaf8bae2fa97b878f"},
+ {file = "dependency_injector-4.38.0-cp38-cp38-win_amd64.whl", hash = "sha256:2918776e88de88be0e2be036261180ca0605c8f64ead43d835ce852f16a9efd2"},
+ {file = "dependency_injector-4.38.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:493be62561218624380d4eca9243a46753444f677217db6292a7b715cf429172"},
+ {file = "dependency_injector-4.38.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a70511db88f84ac4228b27e37e12ea0e04a9c2a32cae3602b9af9a27c0db992"},
+ {file = "dependency_injector-4.38.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e3e1cfe41a5ada0ff71889563441f538caff0399e41d3ee377b60fa50a858bf"},
+ {file = "dependency_injector-4.38.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:116cc679a2c6d40c6a4f968aefe68535e596e88e96315dbd0d0ad2ff76654e3d"},
+ {file = "dependency_injector-4.38.0-cp39-cp39-win32.whl", hash = "sha256:f703c2c161de067ba9893b56743d24fb4c9dbff92eb504bc082c2d2cfeab4c01"},
+ {file = "dependency_injector-4.38.0-cp39-cp39-win_amd64.whl", hash = "sha256:6821a864d6405dc0d5f794ac1b10da4a8c7e8731c6a0651a9682a0b76f5a5b3e"},
+ {file = "dependency_injector-4.38.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6c9e8dc91aa5831bd3a58fec1b94ed8c52f78f601f5ab91135b5ad44325beef7"},
+ {file = "dependency_injector-4.38.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b4eedadef0c84295b70803a79a3ce5a10a59dddd8f306876f6fa6bfc4de8e00"},
+ {file = "dependency_injector-4.38.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2e88b5d09c80e20d6b3d985cc360f39a81e748667c20f6bc7eee9f4b832176ed"},
+ {file = "dependency_injector-4.38.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b1fcd71ff46e097f4e47917ccdf6aa388b6a6372557f7d9f83db1e879e95f8bb"},
+ {file = "dependency_injector-4.38.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:9633d6366282e83a3f21543c5c78299787948333d9fe6649b020cfac93d8b7ca"},
]
distlib = [
{file = "distlib-0.3.4-py2.py3-none-any.whl", hash = "sha256:6564fe0a8f51e734df6333d08b8b94d4ea8ee6b99b5ed50613f731fd4089f34b"},
diff --git a/packages/core/minos-microservice-cqrs/pyproject.toml b/packages/core/minos-microservice-cqrs/pyproject.toml
index 3c0e02dfa..c8826041a 100644
--- a/packages/core/minos-microservice-cqrs/pyproject.toml
+++ b/packages/core/minos-microservice-cqrs/pyproject.toml
@@ -1,14 +1,14 @@
[tool.poetry]
name = "minos-microservice-cqrs"
-version = "0.4.0"
-description = "Minos Microservice CQRS package"
+version = "0.5.0"
+description = "The CQRS pattern of the Minos Framework"
readme = "README.md"
repository = "https://github.com/minos-framework/minos-python"
homepage = "http://www.minos.run/"
authors = ["Minos Framework Devs "]
license = "MIT"
classifiers = [
- "Development Status :: 2 - Pre-Alpha",
+ "Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"Natural Language :: English",
"Programming Language :: Python :: 3",
@@ -40,7 +40,7 @@ dependency-injector = "^4.34.0"
minos-microservice-common = { path = "../minos-microservice-common", develop = true }
minos-microservice-networks = { path = "../minos-microservice-networks", develop = true }
minos-microservice-aggregate = { path = "../minos-microservice-aggregate", develop = true }
-black = "^21.12b0"
+black = "^22.1"
isort = "^5.8.0"
pytest = "^6.2.4"
coverage = "^6.3"
diff --git a/packages/core/minos-microservice-cqrs/tests/test_cqrs/test_handlers.py b/packages/core/minos-microservice-cqrs/tests/test_cqrs/test_handlers.py
index e0d93deae..d28a1e459 100644
--- a/packages/core/minos-microservice-cqrs/tests/test_cqrs/test_handlers.py
+++ b/packages/core/minos-microservice-cqrs/tests/test_cqrs/test_handlers.py
@@ -8,10 +8,10 @@
from minos.aggregate import (
Action,
- AggregateDiff,
+ Event,
FieldDiff,
FieldDiffContainer,
- ModelRef,
+ Ref,
)
from minos.common import (
current_datetime,
@@ -29,35 +29,35 @@ def setUp(self) -> None:
self.uuid = uuid4()
self.bars = [Bar(uuid4(), 1, "hello"), Bar(uuid4(), 1, "world")]
self.now = current_datetime()
- self.diff = AggregateDiff(
+ self.diff = Event(
self.uuid,
"Foo",
1,
Action.CREATE,
self.now,
- FieldDiffContainer([FieldDiff("bars", list[ModelRef[Bar]], [b.uuid for b in self.bars])]),
+ FieldDiffContainer([FieldDiff("bars", list[Ref[Bar]], [b.uuid for b in self.bars])]),
)
async def test_handle(self):
- value = AggregateDiff(
+ value = Event(
self.uuid,
"Foo",
1,
Action.CREATE,
self.now,
- FieldDiffContainer([FieldDiff("bars", list[ModelRef[Bar]], self.bars)]),
+ FieldDiffContainer([FieldDiff("bars", list[Ref[Bar]], self.bars)]),
)
- with patch("minos.aggregate.ModelRefResolver.resolve", return_value=value):
+ with patch("minos.aggregate.RefResolver.resolve", return_value=value):
observed = await PreEventHandler.handle(self.diff)
- expected = AggregateDiff(
+ expected = Event(
self.uuid,
"Foo",
1,
Action.CREATE,
self.now,
- FieldDiffContainer([FieldDiff("bars", list[ModelRef[Bar]], self.bars)]),
+ FieldDiffContainer([FieldDiff("bars", list[Ref[Bar]], self.bars)]),
)
self.assertEqual(expected, observed)
@@ -70,16 +70,16 @@ async def test_handle_without_resolving_references(self):
self.assertEqual(self.diff, observed)
async def test_handle_raises(self):
- with patch("minos.aggregate.ModelRefResolver.resolve", side_effect=ValueError):
+ with patch("minos.aggregate.RefResolver.resolve", side_effect=ValueError):
observed = await PreEventHandler.handle(self.diff)
- expected = AggregateDiff(
+ expected = Event(
self.uuid,
"Foo",
1,
Action.CREATE,
self.now,
- FieldDiffContainer([FieldDiff("bars", list[ModelRef[Bar]], [b.uuid for b in self.bars])]),
+ FieldDiffContainer([FieldDiff("bars", list[Ref[Bar]], [b.uuid for b in self.bars])]),
)
self.assertEqual(expected, observed)
diff --git a/packages/core/minos-microservice-cqrs/tests/utils.py b/packages/core/minos-microservice-cqrs/tests/utils.py
index 133fafaa6..a70c6b4cf 100644
--- a/packages/core/minos-microservice-cqrs/tests/utils.py
+++ b/packages/core/minos-microservice-cqrs/tests/utils.py
@@ -7,9 +7,9 @@
)
from minos.aggregate import (
- Aggregate,
- AggregateRef,
- ModelRef,
+ ExternalEntity,
+ Ref,
+ RootEntity,
)
from minos.cqrs import (
CommandService,
@@ -45,13 +45,13 @@ async def create_foo(self, request: Request) -> Response:
"""For testing purpose"""
-class Foo(Aggregate):
+class Foo(RootEntity):
"""For testing purposes"""
- bar: ModelRef[Bar]
+ bar: Ref[Bar]
-class Bar(AggregateRef):
+class Bar(ExternalEntity):
"""For testing purposes"""
name: str
diff --git a/packages/core/minos-microservice-networks/.pre-commit-config.yaml b/packages/core/minos-microservice-networks/.pre-commit-config.yaml
deleted file mode 100644
index c8808ff4e..000000000
--- a/packages/core/minos-microservice-networks/.pre-commit-config.yaml
+++ /dev/null
@@ -1,38 +0,0 @@
-repos:
- - repo: local
- hooks:
- - id: install
- pass_filenames: false
- name: Install dependencies
- entry: make install
- language: system
-
- - id: reformat
- pass_filenames: false
- name: Reformat package
- entry: make reformat
- language: system
-
- - id: lint
- pass_filenames: false
- name: Lint package
- entry: make lint
- language: system
-
- - id: test
- pass_filenames: false
- name: Test package
- entry: make test
- language: system
-
- - id: docs
- pass_filenames: false
- name: Generate documentation
- entry: make docs
- language: system
-
- - id: build
- pass_filenames: false
- entry: make dist
- name: Generate build
- language: system
diff --git a/packages/core/minos-microservice-networks/HISTORY.md b/packages/core/minos-microservice-networks/HISTORY.md
index c2a69f6a8..a9d53e401 100644
--- a/packages/core/minos-microservice-networks/HISTORY.md
+++ b/packages/core/minos-microservice-networks/HISTORY.md
@@ -191,3 +191,16 @@ History
* Refactor `DynamicBroker` and `DynamicBrokerPool` as `BrokerClient` and `BrokerClientPool`. The new `BrokerClient` has a `send(message: BrokerMessage) -> Awaitable[None]` method for sending messages and a `receive() -> Awaitable[BrokerMessage]` to receive them.
* Implement a builder pattern on `BrokerPublisher`
* Be compatible with `minos-microservice-common~=0.4.0`.
+
+0.4.1 (2022-01-31)
+------------------
+
+* Update `README.md`.
+
+
+0.5.0 (2022-02-03)
+------------------
+
+* Extract `kafka` related code to the `minos-broker-kafka` plugin.
+* Extract `minos-discovery` related code to the `minos-discovery-minos` plugin.
+* Minor changes.
\ No newline at end of file
diff --git a/packages/core/minos-microservice-networks/Makefile b/packages/core/minos-microservice-networks/Makefile
index 9b3b57da2..854bc90bc 100644
--- a/packages/core/minos-microservice-networks/Makefile
+++ b/packages/core/minos-microservice-networks/Makefile
@@ -32,3 +32,11 @@ install:
update:
poetry update
+
+check:
+ $(MAKE) install
+ $(MAKE) reformat
+ $(MAKE) lint
+ $(MAKE) test
+ $(MAKE) docs
+ $(MAKE) dist
diff --git a/packages/core/minos-microservice-networks/README.md b/packages/core/minos-microservice-networks/README.md
index 6078b2d48..885fbc60b 100644
--- a/packages/core/minos-microservice-networks/README.md
+++ b/packages/core/minos-microservice-networks/README.md
@@ -1,7 +1,16 @@
-# Minos Microservice Network
+