eventsourcing 9.2.22__tar.gz → 9.3.0a1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of eventsourcing might be problematic. Click here for more details.
- {eventsourcing-9.2.22/eventsourcing.egg-info → eventsourcing-9.3.0a1}/PKG-INFO +29 -13
- eventsourcing-9.3.0a1/eventsourcing/__init__.py +1 -0
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/application.py +106 -135
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/cipher.py +15 -12
- eventsourcing-9.3.0a1/eventsourcing/dispatch.py +38 -0
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/domain.py +138 -143
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate1/application.py +27 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate1/domainmodel.py +16 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate1/test_application.py +37 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate2/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate2/application.py +27 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate2/domainmodel.py +22 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate2/test_application.py +37 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate3/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate3/application.py +27 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate3/domainmodel.py +38 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate3/test_application.py +37 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate4/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate4/application.py +27 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate4/domainmodel.py +128 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate4/test_application.py +38 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate5/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate5/application.py +27 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate5/domainmodel.py +131 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate5/test_application.py +38 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate6/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate6/application.py +30 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate6/domainmodel.py +123 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate6/test_application.py +38 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate6a/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate6a/application.py +40 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate6a/domainmodel.py +149 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate6a/test_application.py +45 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate7/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate7/application.py +48 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate7/domainmodel.py +144 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate7/persistence.py +57 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate7/test_application.py +38 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate7/test_compression_and_encryption.py +45 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate7/test_snapshotting_intervals.py +67 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate7a/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate7a/application.py +56 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate7a/domainmodel.py +170 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate7a/test_application.py +46 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate7a/test_compression_and_encryption.py +45 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate8/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate8/application.py +47 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate8/domainmodel.py +65 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate8/persistence.py +57 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate8/test_application.py +37 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate8/test_compression_and_encryption.py +44 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/aggregate8/test_snapshotting_intervals.py +38 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/bankaccounts/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/bankaccounts/application.py +70 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/bankaccounts/domainmodel.py +56 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/bankaccounts/test.py +173 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/cargoshipping/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/cargoshipping/application.py +126 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/cargoshipping/domainmodel.py +330 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/cargoshipping/interface.py +143 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/cargoshipping/test.py +231 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/contentmanagement/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/contentmanagement/application.py +118 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/contentmanagement/domainmodel.py +69 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/contentmanagement/test.py +180 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/contentmanagement/utils.py +26 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/contentmanagementsystem/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/contentmanagementsystem/application.py +54 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/contentmanagementsystem/postgres.py +17 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/contentmanagementsystem/sqlite.py +17 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/contentmanagementsystem/system.py +14 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/contentmanagementsystem/test_system.py +174 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/searchablecontent/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/searchablecontent/application.py +45 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/searchablecontent/persistence.py +23 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/searchablecontent/postgres.py +118 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/searchablecontent/sqlite.py +136 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/searchablecontent/test_application.py +111 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/searchablecontent/test_recorder.py +69 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/searchabletimestamps/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/searchabletimestamps/application.py +32 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/searchabletimestamps/persistence.py +20 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/searchabletimestamps/postgres.py +110 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/searchabletimestamps/sqlite.py +99 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/searchabletimestamps/test_searchabletimestamps.py +91 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/test_invoice.py +176 -0
- eventsourcing-9.3.0a1/eventsourcing/examples/test_parking_lot.py +206 -0
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/interface.py +2 -2
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/persistence.py +85 -81
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/popo.py +30 -31
- eventsourcing-9.3.0a1/eventsourcing/postgres.py +794 -0
- eventsourcing-9.3.0a1/eventsourcing/py.typed +0 -0
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/sqlite.py +91 -99
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/system.py +42 -57
- eventsourcing-9.3.0a1/eventsourcing/tests/__init__.py +0 -0
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/tests/application.py +20 -32
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/test_application_with_automatic_snapshotting.py +55 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/test_application_with_popo.py +22 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/test_application_with_postgres.py +75 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/test_application_with_sqlite.py +72 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/test_cache.py +134 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/test_event_sourced_log.py +162 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/test_notificationlog.py +232 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/test_notificationlogreader.py +126 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/test_processapplication.py +110 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/test_processingpolicy.py +109 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/test_repository.py +504 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/test_snapshotting.py +68 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/application_tests/test_upcasting.py +459 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/docs_tests/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/docs_tests/test_docs.py +293 -0
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/tests/domain.py +1 -1
- eventsourcing-9.3.0a1/eventsourcing/tests/domain_tests/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/domain_tests/test_aggregate.py +1159 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/domain_tests/test_aggregate_decorators.py +1604 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/domain_tests/test_domainevent.py +80 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/interface_tests/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/interface_tests/test_remotenotificationlog.py +258 -0
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/tests/persistence.py +49 -50
- eventsourcing-9.3.0a1/eventsourcing/tests/persistence_tests/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/persistence_tests/test_aes.py +93 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/persistence_tests/test_connection_pool.py +722 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/persistence_tests/test_eventstore.py +72 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/persistence_tests/test_infrastructure_factory.py +21 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/persistence_tests/test_mapper.py +113 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/persistence_tests/test_noninterleaving_notification_ids.py +69 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/persistence_tests/test_popo.py +124 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/persistence_tests/test_postgres.py +1121 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/persistence_tests/test_sqlite.py +348 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/persistence_tests/test_transcoder.py +44 -0
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/tests/postgres_utils.py +7 -7
- eventsourcing-9.3.0a1/eventsourcing/tests/system_tests/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/system_tests/test_runner.py +935 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/system_tests/test_system.py +287 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/utils_tests/__init__.py +0 -0
- eventsourcing-9.3.0a1/eventsourcing/tests/utils_tests/test_utils.py +226 -0
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/utils.py +47 -50
- eventsourcing-9.3.0a1/pyproject.toml +266 -0
- eventsourcing-9.2.22/AUTHORS +0 -10
- eventsourcing-9.2.22/PKG-INFO +0 -228
- eventsourcing-9.2.22/eventsourcing/__init__.py +0 -1
- eventsourcing-9.2.22/eventsourcing/dispatch.py +0 -98
- eventsourcing-9.2.22/eventsourcing/postgres.py +0 -1011
- eventsourcing-9.2.22/eventsourcing.egg-info/SOURCES.txt +0 -30
- eventsourcing-9.2.22/eventsourcing.egg-info/dependency_links.txt +0 -1
- eventsourcing-9.2.22/eventsourcing.egg-info/not-zip-safe +0 -1
- eventsourcing-9.2.22/eventsourcing.egg-info/requires.txt +0 -82
- eventsourcing-9.2.22/eventsourcing.egg-info/top_level.txt +0 -1
- eventsourcing-9.2.22/setup.cfg +0 -41
- eventsourcing-9.2.22/setup.py +0 -128
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/LICENSE +0 -0
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/README.md +0 -0
- {eventsourcing-9.2.22 → eventsourcing-9.3.0a1}/eventsourcing/compressor.py +0 -0
- {eventsourcing-9.2.22/eventsourcing/tests → eventsourcing-9.3.0a1/eventsourcing/examples}/__init__.py +0 -0
- /eventsourcing-9.2.22/eventsourcing/py.typed → /eventsourcing-9.3.0a1/eventsourcing/examples/aggregate1/__init__.py +0 -0
|
@@ -1,36 +1,51 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: eventsourcing
|
|
3
|
-
Version: 9.
|
|
3
|
+
Version: 9.3.0a1
|
|
4
4
|
Summary: Event sourcing in Python
|
|
5
5
|
Home-page: https://github.com/pyeventsourcing/eventsourcing
|
|
6
|
+
License: BSD 3-Clause
|
|
7
|
+
Keywords: event sourcing,event store,domain driven design,domain-driven design,ddd,cqrs,cqs
|
|
6
8
|
Author: John Bywater
|
|
7
9
|
Author-email: john.bywater@appropriatesoftware.net
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Requires-Python: >=3.8,<4.0
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
12
|
Classifier: Intended Audience :: Developers
|
|
12
13
|
Classifier: Intended Audience :: Education
|
|
13
14
|
Classifier: Intended Audience :: Science/Research
|
|
14
15
|
Classifier: License :: OSI Approved :: BSD License
|
|
16
|
+
Classifier: License :: Other/Proprietary License
|
|
15
17
|
Classifier: Operating System :: OS Independent
|
|
16
18
|
Classifier: Programming Language :: Python
|
|
17
|
-
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
20
|
Classifier: Programming Language :: Python :: 3.8
|
|
19
21
|
Classifier: Programming Language :: Python :: 3.9
|
|
20
22
|
Classifier: Programming Language :: Python :: 3.10
|
|
21
23
|
Classifier: Programming Language :: Python :: 3.11
|
|
22
24
|
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
-
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
24
25
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
|
-
Requires-Python: >=3.7
|
|
26
|
-
Description-Content-Type: text/markdown
|
|
27
|
-
Provides-Extra: postgres
|
|
28
|
-
Provides-Extra: postgres_dev
|
|
29
26
|
Provides-Extra: crypto
|
|
30
27
|
Provides-Extra: docs
|
|
31
|
-
Provides-Extra:
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
Provides-Extra: postgres
|
|
29
|
+
Requires-Dist: Sphinx ; extra == "docs"
|
|
30
|
+
Requires-Dist: backports.zoneinfo ; python_version < "3.9"
|
|
31
|
+
Requires-Dist: orjson ; extra == "docs"
|
|
32
|
+
Requires-Dist: psycopg[c,pool] (<=3.9.99999) ; extra == "postgres"
|
|
33
|
+
Requires-Dist: pycryptodome (<=3.20.99999) ; extra == "crypto"
|
|
34
|
+
Requires-Dist: pydantic ; extra == "docs"
|
|
35
|
+
Requires-Dist: sphinx_rtd_theme ; extra == "docs"
|
|
36
|
+
Requires-Dist: typing_extensions ; python_version < "3.8"
|
|
37
|
+
Project-URL: Repository, https://github.com/pyeventsourcing/eventsourcing
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
[](https://github.com/pyeventsourcing/eventsourcing/tree/main)
|
|
41
|
+
[](https://coveralls.io/github/pyeventsourcing/eventsourcing?branch=main)
|
|
42
|
+
[](https://eventsourcing.readthedocs.io/en/stable/)
|
|
43
|
+
[](https://pypi.org/project/eventsourcing/)
|
|
44
|
+
[](https://pypistats.org/packages/eventsourcing)
|
|
45
|
+
[](https://github.com/psf/black)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# Event Sourcing in Python
|
|
34
49
|
|
|
35
50
|
A library for event sourcing in Python.
|
|
36
51
|
|
|
@@ -226,3 +241,4 @@ for this project, which you are [welcome to join](https://join.slack.com/t/event
|
|
|
226
241
|
|
|
227
242
|
Please refer to the [documentation](https://eventsourcing.readthedocs.io/) for installation and usage guides.
|
|
228
243
|
|
|
244
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "9.3.0dev0"
|
|
@@ -7,8 +7,10 @@ from dataclasses import dataclass
|
|
|
7
7
|
from itertools import chain
|
|
8
8
|
from threading import Event, Lock
|
|
9
9
|
from typing import (
|
|
10
|
+
TYPE_CHECKING,
|
|
10
11
|
Any,
|
|
11
12
|
Callable,
|
|
13
|
+
ClassVar,
|
|
12
14
|
Dict,
|
|
13
15
|
Generic,
|
|
14
16
|
Iterable,
|
|
@@ -19,16 +21,10 @@ from typing import (
|
|
|
19
21
|
Tuple,
|
|
20
22
|
Type,
|
|
21
23
|
TypeVar,
|
|
22
|
-
Union,
|
|
23
24
|
cast,
|
|
24
25
|
)
|
|
25
|
-
from uuid import UUID
|
|
26
26
|
from warnings import warn
|
|
27
27
|
|
|
28
|
-
# For backwards compatibility of import statements...
|
|
29
|
-
from eventsourcing.domain import LogEvent # noqa: F401
|
|
30
|
-
from eventsourcing.domain import TLogEvent # noqa: F401
|
|
31
|
-
from eventsourcing.domain import create_utc_datetime_now # noqa: F401
|
|
32
28
|
from eventsourcing.domain import (
|
|
33
29
|
Aggregate,
|
|
34
30
|
CanMutateProtocol,
|
|
@@ -41,6 +37,7 @@ from eventsourcing.domain import (
|
|
|
41
37
|
SnapshotProtocol,
|
|
42
38
|
TDomainEvent,
|
|
43
39
|
TMutableOrImmutableAggregate,
|
|
40
|
+
create_utc_datetime_now,
|
|
44
41
|
)
|
|
45
42
|
from eventsourcing.persistence import (
|
|
46
43
|
ApplicationRecorder,
|
|
@@ -57,6 +54,9 @@ from eventsourcing.persistence import (
|
|
|
57
54
|
)
|
|
58
55
|
from eventsourcing.utils import Environment, EnvType, strtobool
|
|
59
56
|
|
|
57
|
+
if TYPE_CHECKING: # pragma: nocover
|
|
58
|
+
from uuid import UUID
|
|
59
|
+
|
|
60
60
|
ProjectorFunction = Callable[
|
|
61
61
|
[Optional[TMutableOrImmutableAggregate], Iterable[TDomainEvent]],
|
|
62
62
|
Optional[TMutableOrImmutableAggregate],
|
|
@@ -69,9 +69,9 @@ MutatorFunction = Callable[
|
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
def project_aggregate(
|
|
72
|
-
aggregate:
|
|
72
|
+
aggregate: TMutableOrImmutableAggregate | None,
|
|
73
73
|
domain_events: Iterable[DomainEventProtocol],
|
|
74
|
-
) ->
|
|
74
|
+
) -> TMutableOrImmutableAggregate | None:
|
|
75
75
|
"""
|
|
76
76
|
Projector function for aggregate projections, which works
|
|
77
77
|
by successively calling aggregate mutator function mutate()
|
|
@@ -91,13 +91,12 @@ class Cache(Generic[S, T]):
|
|
|
91
91
|
def __init__(self) -> None:
|
|
92
92
|
self.cache: Dict[S, Any] = {}
|
|
93
93
|
|
|
94
|
-
def get(self, key: S, evict: bool = False) -> T:
|
|
94
|
+
def get(self, key: S, *, evict: bool = False) -> T:
|
|
95
95
|
if evict:
|
|
96
96
|
return self.cache.pop(key)
|
|
97
|
-
|
|
98
|
-
return self.cache[key]
|
|
97
|
+
return self.cache[key]
|
|
99
98
|
|
|
100
|
-
def put(self, key: S, value: T) ->
|
|
99
|
+
def put(self, key: S, value: T) -> T | None:
|
|
101
100
|
if value is not None:
|
|
102
101
|
self.cache[key] = value
|
|
103
102
|
return None
|
|
@@ -132,7 +131,7 @@ class LRUCache(Cache[S, T]):
|
|
|
132
131
|
None,
|
|
133
132
|
] # initialize by pointing to self
|
|
134
133
|
|
|
135
|
-
def get(self, key: S, evict: bool = False) -> T:
|
|
134
|
+
def get(self, key: S, *, evict: bool = False) -> T:
|
|
136
135
|
with self.lock:
|
|
137
136
|
link = self.cache.get(key)
|
|
138
137
|
if link is not None:
|
|
@@ -153,10 +152,9 @@ class LRUCache(Cache[S, T]):
|
|
|
153
152
|
self.full = self.cache.__len__() >= self.maxsize
|
|
154
153
|
|
|
155
154
|
return result
|
|
156
|
-
|
|
157
|
-
raise KeyError
|
|
155
|
+
raise KeyError
|
|
158
156
|
|
|
159
|
-
def put(self, key: S, value: T) ->
|
|
157
|
+
def put(self, key: S, value: T) -> Any | None:
|
|
160
158
|
evicted_key = None
|
|
161
159
|
evicted_value = None
|
|
162
160
|
with self.lock:
|
|
@@ -215,8 +213,9 @@ class Repository:
|
|
|
215
213
|
def __init__(
|
|
216
214
|
self,
|
|
217
215
|
event_store: EventStore,
|
|
218
|
-
|
|
219
|
-
|
|
216
|
+
*,
|
|
217
|
+
snapshot_store: EventStore | None = None,
|
|
218
|
+
cache_maxsize: int | None = None,
|
|
220
219
|
fastforward: bool = True,
|
|
221
220
|
fastforward_skipping: bool = False,
|
|
222
221
|
deepcopy_from_cache: bool = True,
|
|
@@ -233,7 +232,7 @@ class Repository:
|
|
|
233
232
|
self.snapshot_store = snapshot_store
|
|
234
233
|
|
|
235
234
|
if cache_maxsize is None:
|
|
236
|
-
self.cache:
|
|
235
|
+
self.cache: Cache[UUID, MutableOrImmutableAggregate] | None = None
|
|
237
236
|
elif cache_maxsize <= 0:
|
|
238
237
|
self.cache = Cache()
|
|
239
238
|
else:
|
|
@@ -252,7 +251,8 @@ class Repository:
|
|
|
252
251
|
def get(
|
|
253
252
|
self,
|
|
254
253
|
aggregate_id: UUID,
|
|
255
|
-
|
|
254
|
+
*,
|
|
255
|
+
version: int | None = None,
|
|
256
256
|
projector_func: ProjectorFunction[
|
|
257
257
|
TMutableOrImmutableAggregate, TDomainEvent
|
|
258
258
|
] = project_aggregate,
|
|
@@ -291,9 +291,8 @@ class Repository:
|
|
|
291
291
|
aggregate, cast(Iterable[TDomainEvent], new_events)
|
|
292
292
|
)
|
|
293
293
|
if _aggregate is None:
|
|
294
|
-
raise
|
|
295
|
-
|
|
296
|
-
aggregate = _aggregate
|
|
294
|
+
raise AggregateNotFoundError(aggregate_id)
|
|
295
|
+
aggregate = _aggregate
|
|
297
296
|
finally:
|
|
298
297
|
fastforward_lock.release()
|
|
299
298
|
finally:
|
|
@@ -312,10 +311,10 @@ class Repository:
|
|
|
312
311
|
def _reconstruct_aggregate(
|
|
313
312
|
self,
|
|
314
313
|
aggregate_id: UUID,
|
|
315
|
-
version:
|
|
314
|
+
version: int | None,
|
|
316
315
|
projector_func: ProjectorFunction[TMutableOrImmutableAggregate, TDomainEvent],
|
|
317
316
|
) -> TMutableOrImmutableAggregate:
|
|
318
|
-
gt:
|
|
317
|
+
gt: int | None = None
|
|
319
318
|
|
|
320
319
|
if self.snapshot_store is not None:
|
|
321
320
|
# Try to get a snapshot.
|
|
@@ -340,7 +339,7 @@ class Repository:
|
|
|
340
339
|
)
|
|
341
340
|
|
|
342
341
|
# Reconstruct the aggregate from its events.
|
|
343
|
-
initial:
|
|
342
|
+
initial: TMutableOrImmutableAggregate | None = None
|
|
344
343
|
aggregate = projector_func(
|
|
345
344
|
initial,
|
|
346
345
|
chain(
|
|
@@ -351,10 +350,9 @@ class Repository:
|
|
|
351
350
|
|
|
352
351
|
# Raise exception if "not found".
|
|
353
352
|
if aggregate is None:
|
|
354
|
-
raise
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
return aggregate
|
|
353
|
+
raise AggregateNotFoundError((aggregate_id, version))
|
|
354
|
+
# Return the aggregate.
|
|
355
|
+
return aggregate
|
|
358
356
|
|
|
359
357
|
def _use_fastforward_lock(self, aggregate_id: UUID) -> Lock:
|
|
360
358
|
with self._fastforward_locks_lock:
|
|
@@ -388,7 +386,7 @@ class Repository:
|
|
|
388
386
|
"""
|
|
389
387
|
try:
|
|
390
388
|
self.get(aggregate_id=item)
|
|
391
|
-
except
|
|
389
|
+
except AggregateNotFoundError:
|
|
392
390
|
return False
|
|
393
391
|
else:
|
|
394
392
|
return True
|
|
@@ -414,9 +412,9 @@ class Section:
|
|
|
414
412
|
:param Optional[str] next_id: section ID of the following section
|
|
415
413
|
"""
|
|
416
414
|
|
|
417
|
-
id:
|
|
415
|
+
id: str | None
|
|
418
416
|
items: List[Notification]
|
|
419
|
-
next_id:
|
|
417
|
+
next_id: str | None
|
|
420
418
|
|
|
421
419
|
|
|
422
420
|
class NotificationLog(ABC):
|
|
@@ -437,7 +435,7 @@ class NotificationLog(ABC):
|
|
|
437
435
|
self,
|
|
438
436
|
start: int,
|
|
439
437
|
limit: int,
|
|
440
|
-
stop:
|
|
438
|
+
stop: int | None = None,
|
|
441
439
|
topics: Sequence[str] = (),
|
|
442
440
|
) -> List[Notification]:
|
|
443
441
|
"""
|
|
@@ -497,8 +495,8 @@ class LocalNotificationLog(NotificationLog):
|
|
|
497
495
|
notifications = self.select(start, limit)
|
|
498
496
|
|
|
499
497
|
# Get next section ID.
|
|
500
|
-
actual_section_id:
|
|
501
|
-
next_id:
|
|
498
|
+
actual_section_id: str | None
|
|
499
|
+
next_id: str | None
|
|
502
500
|
if len(notifications):
|
|
503
501
|
last_notification_id = notifications[-1].id
|
|
504
502
|
actual_section_id = self.format_section_id(
|
|
@@ -525,7 +523,7 @@ class LocalNotificationLog(NotificationLog):
|
|
|
525
523
|
self,
|
|
526
524
|
start: int,
|
|
527
525
|
limit: int,
|
|
528
|
-
stop:
|
|
526
|
+
stop: int | None = None,
|
|
529
527
|
topics: Sequence[str] = (),
|
|
530
528
|
) -> List[Notification]:
|
|
531
529
|
"""
|
|
@@ -534,16 +532,17 @@ class LocalNotificationLog(NotificationLog):
|
|
|
534
532
|
from the notification log.
|
|
535
533
|
"""
|
|
536
534
|
if limit > self.section_size:
|
|
537
|
-
|
|
535
|
+
msg = (
|
|
538
536
|
f"Requested limit {limit} greater than section size {self.section_size}"
|
|
539
537
|
)
|
|
538
|
+
raise ValueError(msg)
|
|
540
539
|
return self.recorder.select_notifications(
|
|
541
540
|
start=start, limit=limit, stop=stop, topics=topics
|
|
542
541
|
)
|
|
543
542
|
|
|
544
543
|
@staticmethod
|
|
545
544
|
def format_section_id(first_id: int, last_id: int) -> str:
|
|
546
|
-
return "{},{}"
|
|
545
|
+
return f"{first_id},{last_id}"
|
|
547
546
|
|
|
548
547
|
|
|
549
548
|
class ProcessingEvent:
|
|
@@ -554,7 +553,7 @@ class ProcessingEvent:
|
|
|
554
553
|
new domain events that result from processing that notification.
|
|
555
554
|
"""
|
|
556
555
|
|
|
557
|
-
def __init__(self, tracking:
|
|
556
|
+
def __init__(self, tracking: Tracking | None = None):
|
|
558
557
|
"""
|
|
559
558
|
Initialises the process event with the given tracking object.
|
|
560
559
|
"""
|
|
@@ -565,7 +564,7 @@ class ProcessingEvent:
|
|
|
565
564
|
|
|
566
565
|
def collect_events(
|
|
567
566
|
self,
|
|
568
|
-
*objs:
|
|
567
|
+
*objs: MutableOrImmutableAggregate | DomainEventProtocol | None,
|
|
569
568
|
**kwargs: Any,
|
|
570
569
|
) -> None:
|
|
571
570
|
"""
|
|
@@ -574,7 +573,7 @@ class ProcessingEvent:
|
|
|
574
573
|
for obj in objs:
|
|
575
574
|
if obj is None:
|
|
576
575
|
continue
|
|
577
|
-
|
|
576
|
+
if isinstance(obj, DomainEventProtocol):
|
|
578
577
|
self.events.append(obj)
|
|
579
578
|
else:
|
|
580
579
|
if isinstance(obj, CollectEventsProtocol):
|
|
@@ -586,7 +585,7 @@ class ProcessingEvent:
|
|
|
586
585
|
|
|
587
586
|
def save(
|
|
588
587
|
self,
|
|
589
|
-
*aggregates:
|
|
588
|
+
*aggregates: MutableOrImmutableAggregate | DomainEventProtocol | None,
|
|
590
589
|
**kwargs: Any,
|
|
591
590
|
) -> None:
|
|
592
591
|
warn(
|
|
@@ -598,31 +597,12 @@ class ProcessingEvent:
|
|
|
598
597
|
self.collect_events(*aggregates, **kwargs)
|
|
599
598
|
|
|
600
599
|
|
|
601
|
-
class ProcessEvent(ProcessingEvent):
|
|
602
|
-
"""Deprecated, use :class:`ProcessingEvent` instead.
|
|
603
|
-
|
|
604
|
-
Keeps together a :class:`~eventsourcing.persistence.Tracking`
|
|
605
|
-
object, which represents the position of a domain event notification
|
|
606
|
-
in the notification log of a particular application, and the
|
|
607
|
-
new domain events that result from processing that notification.
|
|
608
|
-
"""
|
|
609
|
-
|
|
610
|
-
def __init__(self, tracking: Optional[Tracking] = None):
|
|
611
|
-
warn(
|
|
612
|
-
"'ProcessEvent' is deprecated, use 'ProcessingEvent' instead",
|
|
613
|
-
DeprecationWarning,
|
|
614
|
-
stacklevel=2,
|
|
615
|
-
)
|
|
616
|
-
|
|
617
|
-
super().__init__(tracking)
|
|
618
|
-
|
|
619
|
-
|
|
620
600
|
class RecordingEvent:
|
|
621
601
|
def __init__(
|
|
622
602
|
self,
|
|
623
603
|
application_name: str,
|
|
624
604
|
recordings: List[Recording],
|
|
625
|
-
previous_max_notification_id:
|
|
605
|
+
previous_max_notification_id: int | None,
|
|
626
606
|
):
|
|
627
607
|
self.application_name = application_name
|
|
628
608
|
self.recordings = recordings
|
|
@@ -635,13 +615,13 @@ class Application:
|
|
|
635
615
|
"""
|
|
636
616
|
|
|
637
617
|
name = "Application"
|
|
638
|
-
env:
|
|
618
|
+
env: ClassVar[Dict[str, str]] = {}
|
|
639
619
|
is_snapshotting_enabled: bool = False
|
|
640
|
-
snapshotting_intervals:
|
|
641
|
-
Dict[Type[MutableOrImmutableAggregate], int]
|
|
620
|
+
snapshotting_intervals: ClassVar[
|
|
621
|
+
Dict[Type[MutableOrImmutableAggregate], int] | None
|
|
642
622
|
] = None
|
|
643
|
-
snapshotting_projectors:
|
|
644
|
-
Dict[Type[MutableOrImmutableAggregate], ProjectorFunction[Any, Any]]
|
|
623
|
+
snapshotting_projectors: ClassVar[
|
|
624
|
+
Dict[Type[MutableOrImmutableAggregate], ProjectorFunction[Any, Any]] | None
|
|
645
625
|
] = None
|
|
646
626
|
snapshot_class: Type[SnapshotProtocol] = Snapshot
|
|
647
627
|
log_section_size = 10
|
|
@@ -656,7 +636,7 @@ class Application:
|
|
|
656
636
|
if "name" not in cls.__dict__:
|
|
657
637
|
cls.name = cls.__name__
|
|
658
638
|
|
|
659
|
-
def __init__(self, env:
|
|
639
|
+
def __init__(self, env: EnvType | None = None) -> None:
|
|
660
640
|
"""
|
|
661
641
|
Initialises an application with an
|
|
662
642
|
:class:`~eventsourcing.persistence.InfrastructureFactory`,
|
|
@@ -666,20 +646,20 @@ class Application:
|
|
|
666
646
|
a :class:`~eventsourcing.application.Repository`, and
|
|
667
647
|
a :class:`~eventsourcing.application.LocalNotificationLog`.
|
|
668
648
|
"""
|
|
669
|
-
self.env = self.construct_env(self.name, env)
|
|
649
|
+
self.env = self.construct_env(self.name, env) # type: ignore[misc]
|
|
670
650
|
self.factory = self.construct_factory(self.env)
|
|
671
651
|
self.mapper = self.construct_mapper()
|
|
672
652
|
self.recorder = self.construct_recorder()
|
|
673
653
|
self.events = self.construct_event_store()
|
|
674
|
-
self.snapshots:
|
|
654
|
+
self.snapshots: EventStore | None = None
|
|
675
655
|
if self.factory.is_snapshotting_enabled():
|
|
676
656
|
self.snapshots = self.construct_snapshot_store()
|
|
677
657
|
self._repository = self.construct_repository()
|
|
678
658
|
self._notification_log = self.construct_notification_log()
|
|
679
659
|
self.closing = Event()
|
|
680
|
-
self.previous_max_notification_id:
|
|
681
|
-
|
|
682
|
-
|
|
660
|
+
self.previous_max_notification_id: int | None = (
|
|
661
|
+
self.recorder.max_notification_id()
|
|
662
|
+
)
|
|
683
663
|
|
|
684
664
|
@property
|
|
685
665
|
def repository(self) -> Repository:
|
|
@@ -706,7 +686,7 @@ class Application:
|
|
|
706
686
|
)
|
|
707
687
|
return self._notification_log
|
|
708
688
|
|
|
709
|
-
def construct_env(self, name: str, env:
|
|
689
|
+
def construct_env(self, name: str, env: EnvType | None = None) -> Environment:
|
|
710
690
|
"""
|
|
711
691
|
Constructs environment from which application will be configured.
|
|
712
692
|
"""
|
|
@@ -785,10 +765,7 @@ class Application:
|
|
|
785
765
|
Constructs a :class:`Repository` for use by the application.
|
|
786
766
|
"""
|
|
787
767
|
cache_maxsize_envvar = self.env.get(self.AGGREGATE_CACHE_MAXSIZE)
|
|
788
|
-
if cache_maxsize_envvar
|
|
789
|
-
cache_maxsize = int(cache_maxsize_envvar)
|
|
790
|
-
else:
|
|
791
|
-
cache_maxsize = None
|
|
768
|
+
cache_maxsize = int(cache_maxsize_envvar) if cache_maxsize_envvar else None
|
|
792
769
|
return Repository(
|
|
793
770
|
event_store=self.events,
|
|
794
771
|
snapshot_store=self.snapshots,
|
|
@@ -810,7 +787,7 @@ class Application:
|
|
|
810
787
|
|
|
811
788
|
def save(
|
|
812
789
|
self,
|
|
813
|
-
*objs:
|
|
790
|
+
*objs: MutableOrImmutableAggregate | DomainEventProtocol | None,
|
|
814
791
|
**kwargs: Any,
|
|
815
792
|
) -> List[Recording]:
|
|
816
793
|
"""
|
|
@@ -848,43 +825,39 @@ class Application:
|
|
|
848
825
|
except KeyError:
|
|
849
826
|
continue
|
|
850
827
|
interval = self.snapshotting_intervals.get(type(aggregate))
|
|
851
|
-
if interval is not None:
|
|
852
|
-
if
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
)
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
" with class variable 'snapshotting_projectors', "
|
|
873
|
-
f"to be a dict that has {type(aggregate)} as a key "
|
|
874
|
-
"with the aggregate projector function for "
|
|
875
|
-
f"{type(aggregate)} as the value for that key."
|
|
876
|
-
)
|
|
877
|
-
)
|
|
878
|
-
self.take_snapshot(
|
|
879
|
-
aggregate_id=event.originator_id,
|
|
880
|
-
version=event.originator_version,
|
|
881
|
-
projector_func=projector_func,
|
|
828
|
+
if interval is not None and event.originator_version % interval == 0:
|
|
829
|
+
if (
|
|
830
|
+
self.snapshotting_projectors
|
|
831
|
+
and type(aggregate) in self.snapshotting_projectors
|
|
832
|
+
):
|
|
833
|
+
projector_func = self.snapshotting_projectors[type(aggregate)]
|
|
834
|
+
else:
|
|
835
|
+
projector_func = project_aggregate
|
|
836
|
+
if projector_func is project_aggregate and not isinstance(
|
|
837
|
+
event, CanMutateProtocol
|
|
838
|
+
):
|
|
839
|
+
msg = (
|
|
840
|
+
f"Cannot take snapshot for {type(aggregate)} with "
|
|
841
|
+
"default project_aggregate() function, because its "
|
|
842
|
+
f"domain event {type(event)} does not implement "
|
|
843
|
+
"the 'can mutate' protocol (see CanMutateProtocol)."
|
|
844
|
+
f" Please define application class {type(self)}"
|
|
845
|
+
" with class variable 'snapshotting_projectors', "
|
|
846
|
+
f"to be a dict that has {type(aggregate)} as a key "
|
|
847
|
+
"with the aggregate projector function for "
|
|
848
|
+
f"{type(aggregate)} as the value for that key."
|
|
882
849
|
)
|
|
850
|
+
raise ProgrammingError(msg)
|
|
851
|
+
self.take_snapshot(
|
|
852
|
+
aggregate_id=event.originator_id,
|
|
853
|
+
version=event.originator_version,
|
|
854
|
+
projector_func=projector_func,
|
|
855
|
+
)
|
|
883
856
|
|
|
884
857
|
def take_snapshot(
|
|
885
858
|
self,
|
|
886
859
|
aggregate_id: UUID,
|
|
887
|
-
version:
|
|
860
|
+
version: int | None = None,
|
|
888
861
|
projector_func: ProjectorFunction[
|
|
889
862
|
TMutableOrImmutableAggregate, TDomainEvent
|
|
890
863
|
] = project_aggregate,
|
|
@@ -894,22 +867,20 @@ class Application:
|
|
|
894
867
|
and puts the snapshot in the snapshot store.
|
|
895
868
|
"""
|
|
896
869
|
if self.snapshots is None:
|
|
897
|
-
|
|
870
|
+
msg = (
|
|
898
871
|
"Can't take snapshot without snapshots store. Please "
|
|
899
872
|
"set environment variable IS_SNAPSHOTTING_ENABLED to "
|
|
900
873
|
"a true value (e.g. 'y'), or set 'is_snapshotting_enabled' "
|
|
901
874
|
"on application class, or set 'snapshotting_intervals' on "
|
|
902
875
|
"application class."
|
|
903
876
|
)
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
snapshot = snapshot_class.take(aggregate)
|
|
912
|
-
self.snapshots.put([snapshot])
|
|
877
|
+
raise AssertionError(msg)
|
|
878
|
+
aggregate = self.repository.get(
|
|
879
|
+
aggregate_id, version=version, projector_func=projector_func
|
|
880
|
+
)
|
|
881
|
+
snapshot_class = getattr(type(aggregate), "Snapshot", type(self).snapshot_class)
|
|
882
|
+
snapshot = snapshot_class.take(aggregate)
|
|
883
|
+
self.snapshots.put([snapshot])
|
|
913
884
|
|
|
914
885
|
def notify(self, new_events: List[DomainEventProtocol]) -> None:
|
|
915
886
|
"""
|
|
@@ -937,7 +908,7 @@ class Application:
|
|
|
937
908
|
TApplication = TypeVar("TApplication", bound=Application)
|
|
938
909
|
|
|
939
910
|
|
|
940
|
-
class
|
|
911
|
+
class AggregateNotFoundError(EventSourcingError):
|
|
941
912
|
"""
|
|
942
913
|
Raised when an :class:`~eventsourcing.domain.Aggregate`
|
|
943
914
|
object is not found in a :class:`Repository`.
|
|
@@ -963,15 +934,15 @@ class EventSourcedLog(Generic[TDomainEvent]):
|
|
|
963
934
|
self,
|
|
964
935
|
events: EventStore,
|
|
965
936
|
originator_id: UUID,
|
|
966
|
-
logged_cls: Type[TDomainEvent], #
|
|
937
|
+
logged_cls: Type[TDomainEvent], # TODO: Rename to 'event_class' in v10.
|
|
967
938
|
):
|
|
968
939
|
self.events = events
|
|
969
940
|
self.originator_id = originator_id
|
|
970
|
-
self.logged_cls = logged_cls #
|
|
941
|
+
self.logged_cls = logged_cls # TODO: Rename to 'event_class' in v10.
|
|
971
942
|
|
|
972
943
|
def trigger_event(
|
|
973
944
|
self,
|
|
974
|
-
next_originator_version:
|
|
945
|
+
next_originator_version: int | None = None,
|
|
975
946
|
**kwargs: Any,
|
|
976
947
|
) -> TDomainEvent:
|
|
977
948
|
"""
|
|
@@ -985,8 +956,8 @@ class EventSourcedLog(Generic[TDomainEvent]):
|
|
|
985
956
|
|
|
986
957
|
def _trigger_event(
|
|
987
958
|
self,
|
|
988
|
-
logged_cls:
|
|
989
|
-
next_originator_version:
|
|
959
|
+
logged_cls: Type[T] | None,
|
|
960
|
+
next_originator_version: int | None = None,
|
|
990
961
|
**kwargs: Any,
|
|
991
962
|
) -> T:
|
|
992
963
|
"""
|
|
@@ -999,15 +970,14 @@ class EventSourcedLog(Generic[TDomainEvent]):
|
|
|
999
970
|
else:
|
|
1000
971
|
next_originator_version = last_logged.originator_version + 1
|
|
1001
972
|
|
|
1002
|
-
|
|
973
|
+
return logged_cls( # type: ignore
|
|
1003
974
|
originator_id=self.originator_id,
|
|
1004
975
|
originator_version=next_originator_version,
|
|
1005
976
|
timestamp=create_utc_datetime_now(),
|
|
1006
977
|
**kwargs,
|
|
1007
978
|
)
|
|
1008
|
-
return logged_event
|
|
1009
979
|
|
|
1010
|
-
def get_first(self) ->
|
|
980
|
+
def get_first(self) -> TDomainEvent | None:
|
|
1011
981
|
"""
|
|
1012
982
|
Selects the first logged event.
|
|
1013
983
|
"""
|
|
@@ -1016,7 +986,7 @@ class EventSourcedLog(Generic[TDomainEvent]):
|
|
|
1016
986
|
except StopIteration:
|
|
1017
987
|
return None
|
|
1018
988
|
|
|
1019
|
-
def get_last(self) ->
|
|
989
|
+
def get_last(self) -> TDomainEvent | None:
|
|
1020
990
|
"""
|
|
1021
991
|
Selects the last logged event.
|
|
1022
992
|
"""
|
|
@@ -1027,10 +997,11 @@ class EventSourcedLog(Generic[TDomainEvent]):
|
|
|
1027
997
|
|
|
1028
998
|
def get(
|
|
1029
999
|
self,
|
|
1030
|
-
|
|
1031
|
-
|
|
1000
|
+
*,
|
|
1001
|
+
gt: int | None = None,
|
|
1002
|
+
lte: int | None = None,
|
|
1032
1003
|
desc: bool = False,
|
|
1033
|
-
limit:
|
|
1004
|
+
limit: int | None = None,
|
|
1034
1005
|
) -> Iterator[TDomainEvent]:
|
|
1035
1006
|
"""
|
|
1036
1007
|
Selects a range of logged events with limit,
|