eventsourcing 9.3.2__tar.gz → 9.3.4__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.3.2 → eventsourcing-9.3.4}/PKG-INFO +3 -8
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/postgres.py +2 -1
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/system.py +3 -1
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/pyproject.toml +14 -38
- eventsourcing-9.3.2/eventsourcing/examples/aggregate1/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/aggregate1/application.py +0 -27
- eventsourcing-9.3.2/eventsourcing/examples/aggregate1/domainmodel.py +0 -16
- eventsourcing-9.3.2/eventsourcing/examples/aggregate1/test_application.py +0 -37
- eventsourcing-9.3.2/eventsourcing/examples/aggregate2/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/aggregate2/application.py +0 -27
- eventsourcing-9.3.2/eventsourcing/examples/aggregate2/domainmodel.py +0 -22
- eventsourcing-9.3.2/eventsourcing/examples/aggregate2/test_application.py +0 -37
- eventsourcing-9.3.2/eventsourcing/examples/aggregate3/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/aggregate3/application.py +0 -27
- eventsourcing-9.3.2/eventsourcing/examples/aggregate3/domainmodel.py +0 -38
- eventsourcing-9.3.2/eventsourcing/examples/aggregate3/test_application.py +0 -37
- eventsourcing-9.3.2/eventsourcing/examples/aggregate4/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/aggregate4/application.py +0 -27
- eventsourcing-9.3.2/eventsourcing/examples/aggregate4/domainmodel.py +0 -114
- eventsourcing-9.3.2/eventsourcing/examples/aggregate4/test_application.py +0 -38
- eventsourcing-9.3.2/eventsourcing/examples/aggregate5/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/aggregate5/application.py +0 -27
- eventsourcing-9.3.2/eventsourcing/examples/aggregate5/domainmodel.py +0 -131
- eventsourcing-9.3.2/eventsourcing/examples/aggregate5/test_application.py +0 -38
- eventsourcing-9.3.2/eventsourcing/examples/aggregate6/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/aggregate6/application.py +0 -30
- eventsourcing-9.3.2/eventsourcing/examples/aggregate6/domainmodel.py +0 -123
- eventsourcing-9.3.2/eventsourcing/examples/aggregate6/test_application.py +0 -38
- eventsourcing-9.3.2/eventsourcing/examples/aggregate6a/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/aggregate6a/application.py +0 -40
- eventsourcing-9.3.2/eventsourcing/examples/aggregate6a/domainmodel.py +0 -149
- eventsourcing-9.3.2/eventsourcing/examples/aggregate6a/test_application.py +0 -45
- eventsourcing-9.3.2/eventsourcing/examples/aggregate7/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/aggregate7/application.py +0 -48
- eventsourcing-9.3.2/eventsourcing/examples/aggregate7/domainmodel.py +0 -144
- eventsourcing-9.3.2/eventsourcing/examples/aggregate7/persistence.py +0 -57
- eventsourcing-9.3.2/eventsourcing/examples/aggregate7/test_application.py +0 -38
- eventsourcing-9.3.2/eventsourcing/examples/aggregate7/test_compression_and_encryption.py +0 -45
- eventsourcing-9.3.2/eventsourcing/examples/aggregate7/test_snapshotting_intervals.py +0 -67
- eventsourcing-9.3.2/eventsourcing/examples/aggregate7a/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/aggregate7a/application.py +0 -56
- eventsourcing-9.3.2/eventsourcing/examples/aggregate7a/domainmodel.py +0 -170
- eventsourcing-9.3.2/eventsourcing/examples/aggregate7a/test_application.py +0 -46
- eventsourcing-9.3.2/eventsourcing/examples/aggregate7a/test_compression_and_encryption.py +0 -45
- eventsourcing-9.3.2/eventsourcing/examples/aggregate8/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/aggregate8/application.py +0 -47
- eventsourcing-9.3.2/eventsourcing/examples/aggregate8/domainmodel.py +0 -65
- eventsourcing-9.3.2/eventsourcing/examples/aggregate8/persistence.py +0 -57
- eventsourcing-9.3.2/eventsourcing/examples/aggregate8/test_application.py +0 -37
- eventsourcing-9.3.2/eventsourcing/examples/aggregate8/test_compression_and_encryption.py +0 -44
- eventsourcing-9.3.2/eventsourcing/examples/aggregate8/test_snapshotting_intervals.py +0 -38
- eventsourcing-9.3.2/eventsourcing/examples/bankaccounts/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/bankaccounts/application.py +0 -70
- eventsourcing-9.3.2/eventsourcing/examples/bankaccounts/domainmodel.py +0 -56
- eventsourcing-9.3.2/eventsourcing/examples/bankaccounts/test.py +0 -173
- eventsourcing-9.3.2/eventsourcing/examples/cargoshipping/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/cargoshipping/application.py +0 -126
- eventsourcing-9.3.2/eventsourcing/examples/cargoshipping/domainmodel.py +0 -330
- eventsourcing-9.3.2/eventsourcing/examples/cargoshipping/interface.py +0 -143
- eventsourcing-9.3.2/eventsourcing/examples/cargoshipping/test.py +0 -231
- eventsourcing-9.3.2/eventsourcing/examples/contentmanagement/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/contentmanagement/application.py +0 -118
- eventsourcing-9.3.2/eventsourcing/examples/contentmanagement/domainmodel.py +0 -69
- eventsourcing-9.3.2/eventsourcing/examples/contentmanagement/test.py +0 -180
- eventsourcing-9.3.2/eventsourcing/examples/contentmanagement/utils.py +0 -26
- eventsourcing-9.3.2/eventsourcing/examples/contentmanagementsystem/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/contentmanagementsystem/application.py +0 -54
- eventsourcing-9.3.2/eventsourcing/examples/contentmanagementsystem/postgres.py +0 -17
- eventsourcing-9.3.2/eventsourcing/examples/contentmanagementsystem/sqlite.py +0 -17
- eventsourcing-9.3.2/eventsourcing/examples/contentmanagementsystem/system.py +0 -14
- eventsourcing-9.3.2/eventsourcing/examples/contentmanagementsystem/test_system.py +0 -180
- eventsourcing-9.3.2/eventsourcing/examples/searchablecontent/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/searchablecontent/application.py +0 -45
- eventsourcing-9.3.2/eventsourcing/examples/searchablecontent/persistence.py +0 -23
- eventsourcing-9.3.2/eventsourcing/examples/searchablecontent/postgres.py +0 -118
- eventsourcing-9.3.2/eventsourcing/examples/searchablecontent/sqlite.py +0 -136
- eventsourcing-9.3.2/eventsourcing/examples/searchablecontent/test_application.py +0 -110
- eventsourcing-9.3.2/eventsourcing/examples/searchablecontent/test_recorder.py +0 -68
- eventsourcing-9.3.2/eventsourcing/examples/searchabletimestamps/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/examples/searchabletimestamps/application.py +0 -32
- eventsourcing-9.3.2/eventsourcing/examples/searchabletimestamps/persistence.py +0 -20
- eventsourcing-9.3.2/eventsourcing/examples/searchabletimestamps/postgres.py +0 -110
- eventsourcing-9.3.2/eventsourcing/examples/searchabletimestamps/sqlite.py +0 -99
- eventsourcing-9.3.2/eventsourcing/examples/searchabletimestamps/test_searchabletimestamps.py +0 -94
- eventsourcing-9.3.2/eventsourcing/examples/test_invoice.py +0 -176
- eventsourcing-9.3.2/eventsourcing/examples/test_parking_lot.py +0 -206
- eventsourcing-9.3.2/eventsourcing/tests/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/test_application_with_automatic_snapshotting.py +0 -55
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/test_application_with_popo.py +0 -22
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/test_application_with_postgres.py +0 -75
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/test_application_with_sqlite.py +0 -72
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/test_cache.py +0 -134
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/test_event_sourced_log.py +0 -162
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/test_notificationlog.py +0 -232
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/test_notificationlogreader.py +0 -126
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/test_processapplication.py +0 -110
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/test_processingpolicy.py +0 -109
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/test_repository.py +0 -504
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/test_snapshotting.py +0 -68
- eventsourcing-9.3.2/eventsourcing/tests/application_tests/test_upcasting.py +0 -459
- eventsourcing-9.3.2/eventsourcing/tests/docs_tests/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/tests/docs_tests/test_docs.py +0 -293
- eventsourcing-9.3.2/eventsourcing/tests/domain_tests/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/tests/domain_tests/test_aggregate.py +0 -1200
- eventsourcing-9.3.2/eventsourcing/tests/domain_tests/test_aggregate_decorators.py +0 -1604
- eventsourcing-9.3.2/eventsourcing/tests/domain_tests/test_domainevent.py +0 -80
- eventsourcing-9.3.2/eventsourcing/tests/interface_tests/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/tests/interface_tests/test_remotenotificationlog.py +0 -258
- eventsourcing-9.3.2/eventsourcing/tests/persistence_tests/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/tests/persistence_tests/test_aes.py +0 -93
- eventsourcing-9.3.2/eventsourcing/tests/persistence_tests/test_connection_pool.py +0 -722
- eventsourcing-9.3.2/eventsourcing/tests/persistence_tests/test_eventstore.py +0 -72
- eventsourcing-9.3.2/eventsourcing/tests/persistence_tests/test_infrastructure_factory.py +0 -21
- eventsourcing-9.3.2/eventsourcing/tests/persistence_tests/test_mapper.py +0 -113
- eventsourcing-9.3.2/eventsourcing/tests/persistence_tests/test_noninterleaving_notification_ids.py +0 -69
- eventsourcing-9.3.2/eventsourcing/tests/persistence_tests/test_popo.py +0 -124
- eventsourcing-9.3.2/eventsourcing/tests/persistence_tests/test_postgres.py +0 -1119
- eventsourcing-9.3.2/eventsourcing/tests/persistence_tests/test_sqlite.py +0 -348
- eventsourcing-9.3.2/eventsourcing/tests/persistence_tests/test_transcoder.py +0 -44
- eventsourcing-9.3.2/eventsourcing/tests/system_tests/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/tests/system_tests/test_runner.py +0 -935
- eventsourcing-9.3.2/eventsourcing/tests/system_tests/test_system.py +0 -284
- eventsourcing-9.3.2/eventsourcing/tests/utils_tests/__init__.py +0 -0
- eventsourcing-9.3.2/eventsourcing/tests/utils_tests/test_utils.py +0 -226
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/AUTHORS +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/LICENSE +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/README.md +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/__init__.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/application.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/cipher.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/compressor.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/dispatch.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/domain.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/interface.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/persistence.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/popo.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/py.typed +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/sqlite.py +0 -0
- {eventsourcing-9.3.2/eventsourcing/examples → eventsourcing-9.3.4/eventsourcing/tests}/__init__.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/tests/application.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/tests/domain.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/tests/persistence.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/tests/postgres_utils.py +0 -0
- {eventsourcing-9.3.2 → eventsourcing-9.3.4}/eventsourcing/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: eventsourcing
|
|
3
|
-
Version: 9.3.
|
|
3
|
+
Version: 9.3.4
|
|
4
4
|
Summary: Event sourcing in Python
|
|
5
5
|
Home-page: https://github.com/pyeventsourcing/eventsourcing
|
|
6
6
|
License: BSD 3-Clause
|
|
@@ -25,15 +25,10 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
25
25
|
Classifier: Programming Language :: Python :: 3.13
|
|
26
26
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
27
|
Provides-Extra: crypto
|
|
28
|
-
Provides-Extra: docs
|
|
29
28
|
Provides-Extra: postgres
|
|
30
|
-
Requires-Dist: Sphinx ; extra == "docs"
|
|
31
29
|
Requires-Dist: backports.zoneinfo ; python_version < "3.9"
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-Dist:
|
|
34
|
-
Requires-Dist: pycryptodome (>=3.20,<3.21) ; extra == "crypto"
|
|
35
|
-
Requires-Dist: pydantic ; extra == "docs"
|
|
36
|
-
Requires-Dist: sphinx_rtd_theme ; extra == "docs"
|
|
30
|
+
Requires-Dist: psycopg[c,pool] (<=3.2.99999) ; extra == "postgres"
|
|
31
|
+
Requires-Dist: pycryptodome (>=3.21,<3.22) ; extra == "crypto"
|
|
37
32
|
Requires-Dist: typing_extensions
|
|
38
33
|
Project-URL: Repository, https://github.com/pyeventsourcing/eventsourcing
|
|
39
34
|
Description-Content-Type: text/markdown
|
|
@@ -9,7 +9,6 @@ import psycopg.errors
|
|
|
9
9
|
import psycopg_pool
|
|
10
10
|
from psycopg import Connection, Cursor
|
|
11
11
|
from psycopg.rows import DictRow, dict_row
|
|
12
|
-
from typing_extensions import Self
|
|
13
12
|
|
|
14
13
|
from eventsourcing.persistence import (
|
|
15
14
|
AggregateRecorder,
|
|
@@ -34,6 +33,8 @@ from eventsourcing.utils import Environment, resolve_topic, retry, strtobool
|
|
|
34
33
|
if TYPE_CHECKING: # pragma: nocover
|
|
35
34
|
from uuid import UUID
|
|
36
35
|
|
|
36
|
+
from typing_extensions import Self
|
|
37
|
+
|
|
37
38
|
logging.getLogger("psycopg.pool").setLevel(logging.CRITICAL)
|
|
38
39
|
logging.getLogger("psycopg").setLevel(logging.CRITICAL)
|
|
39
40
|
|
|
@@ -8,6 +8,7 @@ from queue import Full, Queue
|
|
|
8
8
|
from threading import Event, Lock, RLock, Thread
|
|
9
9
|
from types import FrameType, ModuleType
|
|
10
10
|
from typing import (
|
|
11
|
+
TYPE_CHECKING,
|
|
11
12
|
Any,
|
|
12
13
|
ClassVar,
|
|
13
14
|
Dict,
|
|
@@ -22,7 +23,8 @@ from typing import (
|
|
|
22
23
|
cast,
|
|
23
24
|
)
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
if TYPE_CHECKING: # pragma: nocover
|
|
27
|
+
from typing_extensions import Self
|
|
26
28
|
|
|
27
29
|
from eventsourcing.application import (
|
|
28
30
|
Application,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "eventsourcing"
|
|
3
|
-
version = "9.3.
|
|
3
|
+
version = "9.3.4"
|
|
4
4
|
|
|
5
5
|
description = "Event sourcing in Python"
|
|
6
6
|
authors = [
|
|
@@ -30,10 +30,6 @@ readme = "README.md"
|
|
|
30
30
|
homepage = "https://github.com/pyeventsourcing/eventsourcing"
|
|
31
31
|
repository = "https://github.com/pyeventsourcing/eventsourcing"
|
|
32
32
|
include = ["eventsourcing/py.typed"]
|
|
33
|
-
packages = [
|
|
34
|
-
{ include = "eventsourcing" },
|
|
35
|
-
{ include = "eventsourcing/tests" },
|
|
36
|
-
]
|
|
37
33
|
keywords=[
|
|
38
34
|
"event sourcing",
|
|
39
35
|
"event store",
|
|
@@ -48,48 +44,27 @@ keywords=[
|
|
|
48
44
|
python = ">=3.8,<4.0"
|
|
49
45
|
typing_extensions = "*"
|
|
50
46
|
"backports.zoneinfo" = { version = "*", python = "<3.9" }
|
|
51
|
-
pycryptodome = { version = "~3.
|
|
52
|
-
|
|
53
|
-
psycopg = { version = "<=3.2.1", optional = true, extras = ["c", "pool"], python = "<=3.12.999999" }
|
|
54
|
-
|
|
55
|
-
Sphinx = { version = "*", optional = true }
|
|
56
|
-
sphinx_rtd_theme = { version = "*", optional = true }
|
|
57
|
-
pydantic = { version = "*", optional = true }
|
|
58
|
-
orjson = { version = "*", optional = true }
|
|
47
|
+
pycryptodome = { version = "~3.21", optional = true }
|
|
48
|
+
psycopg = { version = "<=3.2.99999", optional = true, extras=["c,pool"]}
|
|
59
49
|
|
|
60
50
|
[tool.poetry.extras]
|
|
61
51
|
crypto = ["pycryptodome"]
|
|
62
52
|
postgres = ["psycopg"]
|
|
63
|
-
docs = ["Sphinx", "sphinx_rtd_theme", "pydantic", "orjson"]
|
|
64
53
|
|
|
65
54
|
[tool.poetry.group.dev.dependencies]
|
|
66
55
|
black = { version = "*", allow-prereleases = true }
|
|
67
56
|
coverage = "^7.2.7"
|
|
68
|
-
flake8 = "*"
|
|
69
|
-
flake8-broken-line = "*"
|
|
70
|
-
flake8-bugbear = "*"
|
|
71
|
-
flake8-coding = "*"
|
|
72
|
-
flake8-isort = "*"
|
|
73
|
-
flake8-tidy-imports = "*"
|
|
74
57
|
isort = "*"
|
|
75
58
|
mypy = "*"
|
|
76
|
-
|
|
77
|
-
psycopg = [
|
|
78
|
-
{ version = "<=3.2.1", python = "<=3.12.999999" },
|
|
79
|
-
{ git = "https://github.com/psycopg/psycopg", branch="master", subdirectory = "psycopg", python = ">3.12.999999" }
|
|
80
|
-
]
|
|
81
|
-
psycopg-binary = [
|
|
82
|
-
{ version = "<=3.2.1", python = "<=3.12.999999" },
|
|
83
|
-
]
|
|
84
|
-
psycopg-c = [
|
|
85
|
-
{ git = "https://github.com/psycopg/psycopg", branch="master", subdirectory = "psycopg_c", python = ">3.12.999999" }
|
|
86
|
-
]
|
|
87
|
-
psycopg-pool = [
|
|
88
|
-
{ version = "<=3.2.2", python = "<=3.12.999999" },
|
|
89
|
-
{ git = "https://github.com/psycopg/psycopg", branch="master", subdirectory = "psycopg_pool", python = ">3.12.999999" }
|
|
90
|
-
]
|
|
59
|
+
psycopg = { version = "<=3.2.99999", extras = ["binary", "pool"] }
|
|
91
60
|
ruff = "^0.1.14"
|
|
92
61
|
|
|
62
|
+
[tool.poetry.group.docs.dependencies]
|
|
63
|
+
Sphinx = { version = "*"}
|
|
64
|
+
sphinx_rtd_theme = { version = "*"}
|
|
65
|
+
pydantic = { version = "~2.9"}
|
|
66
|
+
orjson = { version = "~3.10.11"}
|
|
67
|
+
|
|
93
68
|
|
|
94
69
|
[build-system]
|
|
95
70
|
requires = ["poetry-core>=1.0.0"]
|
|
@@ -118,9 +93,7 @@ exclude = '''
|
|
|
118
93
|
|
|
119
94
|
[tool.coverage.run]
|
|
120
95
|
branch = true
|
|
121
|
-
omit = [
|
|
122
|
-
"esdbclient/protos/*"
|
|
123
|
-
]
|
|
96
|
+
omit = []
|
|
124
97
|
|
|
125
98
|
[tool.coverage.report]
|
|
126
99
|
exclude_lines = [
|
|
@@ -218,6 +191,9 @@ unfixable = []
|
|
|
218
191
|
# Allow unused variables when underscore-prefixed.
|
|
219
192
|
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
|
|
220
193
|
|
|
194
|
+
[tool.ruff.lint.flake8-type-checking]
|
|
195
|
+
runtime-evaluated-base-classes = ["pydantic.BaseModel"]
|
|
196
|
+
|
|
221
197
|
[tool.ruff.format]
|
|
222
198
|
# Like Black, use double quotes for strings.
|
|
223
199
|
quote-style = "double"
|
|
File without changes
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Dict
|
|
4
|
-
|
|
5
|
-
from eventsourcing.application import Application
|
|
6
|
-
from eventsourcing.examples.aggregate1.domainmodel import Dog
|
|
7
|
-
|
|
8
|
-
if TYPE_CHECKING: # pragma: nocover
|
|
9
|
-
from uuid import UUID
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class DogSchool(Application):
|
|
13
|
-
is_snapshotting_enabled = True
|
|
14
|
-
|
|
15
|
-
def register_dog(self, name: str) -> UUID:
|
|
16
|
-
dog = Dog(name)
|
|
17
|
-
self.save(dog)
|
|
18
|
-
return dog.id
|
|
19
|
-
|
|
20
|
-
def add_trick(self, dog_id: UUID, trick: str) -> None:
|
|
21
|
-
dog: Dog = self.repository.get(dog_id)
|
|
22
|
-
dog.add_trick(trick)
|
|
23
|
-
self.save(dog)
|
|
24
|
-
|
|
25
|
-
def get_dog(self, dog_id: UUID) -> Dict[str, Any]:
|
|
26
|
-
dog: Dog = self.repository.get(dog_id)
|
|
27
|
-
return {"name": dog.name, "tricks": tuple(dog.tricks)}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import List
|
|
4
|
-
|
|
5
|
-
from eventsourcing.domain import Aggregate, event
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Dog(Aggregate):
|
|
9
|
-
@event("Registered")
|
|
10
|
-
def __init__(self, name: str) -> None:
|
|
11
|
-
self.name = name
|
|
12
|
-
self.tricks: List[str] = []
|
|
13
|
-
|
|
14
|
-
@event("TrickAdded")
|
|
15
|
-
def add_trick(self, trick: str) -> None:
|
|
16
|
-
self.tricks.append(trick)
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from unittest import TestCase
|
|
4
|
-
|
|
5
|
-
from eventsourcing.examples.aggregate1.application import DogSchool
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class TestDogSchool(TestCase):
|
|
9
|
-
def test_dog_school(self) -> None:
|
|
10
|
-
# Construct application object.
|
|
11
|
-
school = DogSchool()
|
|
12
|
-
|
|
13
|
-
# Evolve application state.
|
|
14
|
-
dog_id = school.register_dog("Fido")
|
|
15
|
-
school.add_trick(dog_id, "roll over")
|
|
16
|
-
school.add_trick(dog_id, "play dead")
|
|
17
|
-
|
|
18
|
-
# Query application state.
|
|
19
|
-
dog = school.get_dog(dog_id)
|
|
20
|
-
assert dog["name"] == "Fido"
|
|
21
|
-
assert dog["tricks"] == ("roll over", "play dead")
|
|
22
|
-
|
|
23
|
-
# Select notifications.
|
|
24
|
-
notifications = school.notification_log.select(start=1, limit=10)
|
|
25
|
-
assert len(notifications) == 3
|
|
26
|
-
|
|
27
|
-
# Take snapshot.
|
|
28
|
-
school.take_snapshot(dog_id, version=3)
|
|
29
|
-
dog = school.get_dog(dog_id)
|
|
30
|
-
assert dog["name"] == "Fido"
|
|
31
|
-
assert dog["tricks"] == ("roll over", "play dead")
|
|
32
|
-
|
|
33
|
-
# Continue with snapshotted aggregate.
|
|
34
|
-
school.add_trick(dog_id, "fetch ball")
|
|
35
|
-
dog = school.get_dog(dog_id)
|
|
36
|
-
assert dog["name"] == "Fido"
|
|
37
|
-
assert dog["tricks"] == ("roll over", "play dead", "fetch ball")
|
|
File without changes
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Dict
|
|
4
|
-
|
|
5
|
-
from eventsourcing.application import Application
|
|
6
|
-
from eventsourcing.examples.aggregate2.domainmodel import Dog
|
|
7
|
-
|
|
8
|
-
if TYPE_CHECKING: # pragma: nocover
|
|
9
|
-
from uuid import UUID
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class DogSchool(Application):
|
|
13
|
-
is_snapshotting_enabled = True
|
|
14
|
-
|
|
15
|
-
def register_dog(self, name: str) -> UUID:
|
|
16
|
-
dog = Dog(name)
|
|
17
|
-
self.save(dog)
|
|
18
|
-
return dog.id
|
|
19
|
-
|
|
20
|
-
def add_trick(self, dog_id: UUID, trick: str) -> None:
|
|
21
|
-
dog: Dog = self.repository.get(dog_id)
|
|
22
|
-
dog.add_trick(trick)
|
|
23
|
-
self.save(dog)
|
|
24
|
-
|
|
25
|
-
def get_dog(self, dog_id: UUID) -> Dict[str, Any]:
|
|
26
|
-
dog: Dog = self.repository.get(dog_id)
|
|
27
|
-
return {"name": dog.name, "tricks": tuple(dog.tricks)}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import List
|
|
4
|
-
|
|
5
|
-
from eventsourcing.domain import Aggregate, event
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Dog(Aggregate):
|
|
9
|
-
class Registered(Aggregate.Created):
|
|
10
|
-
name: str
|
|
11
|
-
|
|
12
|
-
class TrickAdded(Aggregate.Event):
|
|
13
|
-
trick: str
|
|
14
|
-
|
|
15
|
-
@event(Registered)
|
|
16
|
-
def __init__(self, name: str) -> None:
|
|
17
|
-
self.name = name
|
|
18
|
-
self.tricks: List[str] = []
|
|
19
|
-
|
|
20
|
-
@event(TrickAdded)
|
|
21
|
-
def add_trick(self, trick: str) -> None:
|
|
22
|
-
self.tricks.append(trick)
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from unittest import TestCase
|
|
4
|
-
|
|
5
|
-
from eventsourcing.examples.aggregate2.application import DogSchool
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class TestDogSchool(TestCase):
|
|
9
|
-
def test_dog_school(self) -> None:
|
|
10
|
-
# Construct application object.
|
|
11
|
-
school = DogSchool()
|
|
12
|
-
|
|
13
|
-
# Evolve application state.
|
|
14
|
-
dog_id = school.register_dog("Fido")
|
|
15
|
-
school.add_trick(dog_id, "roll over")
|
|
16
|
-
school.add_trick(dog_id, "play dead")
|
|
17
|
-
|
|
18
|
-
# Query application state.
|
|
19
|
-
dog = school.get_dog(dog_id)
|
|
20
|
-
assert dog["name"] == "Fido"
|
|
21
|
-
assert dog["tricks"] == ("roll over", "play dead")
|
|
22
|
-
|
|
23
|
-
# Select notifications.
|
|
24
|
-
notifications = school.notification_log.select(start=1, limit=10)
|
|
25
|
-
assert len(notifications) == 3
|
|
26
|
-
|
|
27
|
-
# Take snapshot.
|
|
28
|
-
school.take_snapshot(dog_id, version=3)
|
|
29
|
-
dog = school.get_dog(dog_id)
|
|
30
|
-
assert dog["name"] == "Fido"
|
|
31
|
-
assert dog["tricks"] == ("roll over", "play dead")
|
|
32
|
-
|
|
33
|
-
# Continue with snapshotted aggregate.
|
|
34
|
-
school.add_trick(dog_id, "fetch ball")
|
|
35
|
-
dog = school.get_dog(dog_id)
|
|
36
|
-
assert dog["name"] == "Fido"
|
|
37
|
-
assert dog["tricks"] == ("roll over", "play dead", "fetch ball")
|
|
File without changes
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Dict
|
|
4
|
-
|
|
5
|
-
from eventsourcing.application import Application
|
|
6
|
-
from eventsourcing.examples.aggregate3.domainmodel import Dog
|
|
7
|
-
|
|
8
|
-
if TYPE_CHECKING: # pragma: nocover
|
|
9
|
-
from uuid import UUID
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class DogSchool(Application):
|
|
13
|
-
is_snapshotting_enabled = True
|
|
14
|
-
|
|
15
|
-
def register_dog(self, name: str) -> UUID:
|
|
16
|
-
dog = Dog.register(name=name)
|
|
17
|
-
self.save(dog)
|
|
18
|
-
return dog.id
|
|
19
|
-
|
|
20
|
-
def add_trick(self, dog_id: UUID, trick: str) -> None:
|
|
21
|
-
dog: Dog = self.repository.get(dog_id)
|
|
22
|
-
dog.add_trick(trick)
|
|
23
|
-
self.save(dog)
|
|
24
|
-
|
|
25
|
-
def get_dog(self, dog_id: UUID) -> Dict[str, Any]:
|
|
26
|
-
dog: Dog = self.repository.get(dog_id)
|
|
27
|
-
return {"name": dog.name, "tricks": tuple(dog.tricks)}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import List, cast
|
|
4
|
-
|
|
5
|
-
from eventsourcing.dispatch import singledispatchmethod
|
|
6
|
-
from eventsourcing.domain import Aggregate
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class Dog(Aggregate):
|
|
10
|
-
class Event(Aggregate.Event):
|
|
11
|
-
def apply(self, aggregate: Aggregate) -> None:
|
|
12
|
-
cast(Dog, aggregate).apply(self)
|
|
13
|
-
|
|
14
|
-
class Registered(Event, Aggregate.Created):
|
|
15
|
-
name: str
|
|
16
|
-
|
|
17
|
-
class TrickAdded(Event):
|
|
18
|
-
trick: str
|
|
19
|
-
|
|
20
|
-
@classmethod
|
|
21
|
-
def register(cls, name: str) -> Dog:
|
|
22
|
-
return cls._create(cls.Registered, name=name)
|
|
23
|
-
|
|
24
|
-
def add_trick(self, trick: str) -> None:
|
|
25
|
-
self.trigger_event(self.TrickAdded, trick=trick)
|
|
26
|
-
|
|
27
|
-
@singledispatchmethod
|
|
28
|
-
def apply(self, event: Event) -> None:
|
|
29
|
-
"""Applies event to aggregate."""
|
|
30
|
-
|
|
31
|
-
@apply.register
|
|
32
|
-
def _(self, event: Dog.Registered) -> None:
|
|
33
|
-
self.name = event.name
|
|
34
|
-
self.tricks: List[str] = []
|
|
35
|
-
|
|
36
|
-
@apply.register
|
|
37
|
-
def _(self, event: Dog.TrickAdded) -> None:
|
|
38
|
-
self.tricks.append(event.trick)
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from unittest import TestCase
|
|
4
|
-
|
|
5
|
-
from eventsourcing.examples.aggregate3.application import DogSchool
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class TestDogSchool(TestCase):
|
|
9
|
-
def test_dog_school(self) -> None:
|
|
10
|
-
# Construct application object.
|
|
11
|
-
school = DogSchool()
|
|
12
|
-
|
|
13
|
-
# Evolve application state.
|
|
14
|
-
dog_id = school.register_dog("Fido")
|
|
15
|
-
school.add_trick(dog_id, "roll over")
|
|
16
|
-
school.add_trick(dog_id, "play dead")
|
|
17
|
-
|
|
18
|
-
# Query application state.
|
|
19
|
-
dog = school.get_dog(dog_id)
|
|
20
|
-
assert dog["name"] == "Fido"
|
|
21
|
-
assert dog["tricks"] == ("roll over", "play dead")
|
|
22
|
-
|
|
23
|
-
# Select notifications.
|
|
24
|
-
notifications = school.notification_log.select(start=1, limit=10)
|
|
25
|
-
assert len(notifications) == 3
|
|
26
|
-
|
|
27
|
-
# Take snapshot.
|
|
28
|
-
school.take_snapshot(dog_id, version=3)
|
|
29
|
-
dog = school.get_dog(dog_id)
|
|
30
|
-
assert dog["name"] == "Fido"
|
|
31
|
-
assert dog["tricks"] == ("roll over", "play dead")
|
|
32
|
-
|
|
33
|
-
# Continue with snapshotted aggregate.
|
|
34
|
-
school.add_trick(dog_id, "fetch ball")
|
|
35
|
-
dog = school.get_dog(dog_id)
|
|
36
|
-
assert dog["name"] == "Fido"
|
|
37
|
-
assert dog["tricks"] == ("roll over", "play dead", "fetch ball")
|
|
File without changes
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Dict
|
|
4
|
-
|
|
5
|
-
from eventsourcing.application import Application
|
|
6
|
-
from eventsourcing.examples.aggregate4.domainmodel import Dog
|
|
7
|
-
|
|
8
|
-
if TYPE_CHECKING: # pragma: nocover
|
|
9
|
-
from uuid import UUID
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class DogSchool(Application):
|
|
13
|
-
is_snapshotting_enabled = True
|
|
14
|
-
|
|
15
|
-
def register_dog(self, name: str) -> UUID:
|
|
16
|
-
dog = Dog.register(name)
|
|
17
|
-
self.save(dog)
|
|
18
|
-
return dog.id
|
|
19
|
-
|
|
20
|
-
def add_trick(self, dog_id: UUID, trick: str) -> None:
|
|
21
|
-
dog = self.repository.get(dog_id, projector_func=Dog.projector)
|
|
22
|
-
dog.add_trick(trick)
|
|
23
|
-
self.save(dog)
|
|
24
|
-
|
|
25
|
-
def get_dog(self, dog_id: UUID) -> Dict[str, Any]:
|
|
26
|
-
dog = self.repository.get(dog_id, projector_func=Dog.projector)
|
|
27
|
-
return {"name": dog.name, "tricks": tuple(dog.tricks)}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from datetime import datetime, timezone
|
|
5
|
-
from typing import Any, Iterable, List, Type, TypeVar, cast
|
|
6
|
-
from uuid import UUID, uuid4
|
|
7
|
-
|
|
8
|
-
from eventsourcing.dispatch import singledispatchmethod
|
|
9
|
-
from eventsourcing.domain import Snapshot
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@dataclass(frozen=True)
|
|
13
|
-
class DomainEvent:
|
|
14
|
-
originator_version: int
|
|
15
|
-
originator_id: UUID
|
|
16
|
-
timestamp: datetime
|
|
17
|
-
|
|
18
|
-
@staticmethod
|
|
19
|
-
def create_timestamp() -> datetime:
|
|
20
|
-
return datetime.now(tz=timezone.utc)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
TAggregate = TypeVar("TAggregate", bound="Aggregate")
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class Aggregate:
|
|
27
|
-
id: UUID
|
|
28
|
-
version: int
|
|
29
|
-
created_on: datetime
|
|
30
|
-
_pending_events: List[DomainEvent]
|
|
31
|
-
|
|
32
|
-
def __init__(self, event: DomainEvent):
|
|
33
|
-
self.id = event.originator_id
|
|
34
|
-
self.version = event.originator_version
|
|
35
|
-
self.created_on = event.timestamp
|
|
36
|
-
|
|
37
|
-
def trigger_event(
|
|
38
|
-
self,
|
|
39
|
-
event_class: Type[DomainEvent],
|
|
40
|
-
**kwargs: Any,
|
|
41
|
-
) -> None:
|
|
42
|
-
kwargs = kwargs.copy()
|
|
43
|
-
kwargs.update(
|
|
44
|
-
originator_id=self.id,
|
|
45
|
-
originator_version=self.version + 1,
|
|
46
|
-
timestamp=event_class.create_timestamp(),
|
|
47
|
-
)
|
|
48
|
-
new_event = event_class(**kwargs)
|
|
49
|
-
self._apply(new_event)
|
|
50
|
-
self._pending_events.append(new_event)
|
|
51
|
-
|
|
52
|
-
@singledispatchmethod
|
|
53
|
-
def _apply(self, event: DomainEvent) -> None:
|
|
54
|
-
"""Applies event to aggregate."""
|
|
55
|
-
|
|
56
|
-
def collect_events(self) -> List[DomainEvent]:
|
|
57
|
-
events, self._pending_events = self._pending_events, []
|
|
58
|
-
return events
|
|
59
|
-
|
|
60
|
-
@classmethod
|
|
61
|
-
def projector(
|
|
62
|
-
cls: Type[TAggregate],
|
|
63
|
-
_: TAggregate | None,
|
|
64
|
-
events: Iterable[DomainEvent],
|
|
65
|
-
) -> TAggregate | None:
|
|
66
|
-
aggregate: TAggregate = object.__new__(cls)
|
|
67
|
-
aggregate._pending_events = []
|
|
68
|
-
for event in events:
|
|
69
|
-
aggregate._apply(event)
|
|
70
|
-
return aggregate
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
class Dog(Aggregate):
|
|
74
|
-
@dataclass(frozen=True)
|
|
75
|
-
class Registered(DomainEvent):
|
|
76
|
-
name: str
|
|
77
|
-
|
|
78
|
-
@dataclass(frozen=True)
|
|
79
|
-
class TrickAdded(DomainEvent):
|
|
80
|
-
trick: str
|
|
81
|
-
|
|
82
|
-
@classmethod
|
|
83
|
-
def register(cls, name: str) -> Dog:
|
|
84
|
-
event = cls.Registered(
|
|
85
|
-
originator_id=uuid4(),
|
|
86
|
-
originator_version=1,
|
|
87
|
-
timestamp=DomainEvent.create_timestamp(),
|
|
88
|
-
name=name,
|
|
89
|
-
)
|
|
90
|
-
dog = cast(Dog, cls.projector(None, [event]))
|
|
91
|
-
dog._pending_events.append(event)
|
|
92
|
-
return dog
|
|
93
|
-
|
|
94
|
-
def add_trick(self, trick: str) -> None:
|
|
95
|
-
self.trigger_event(self.TrickAdded, trick=trick)
|
|
96
|
-
|
|
97
|
-
@singledispatchmethod
|
|
98
|
-
def _apply(self, event: DomainEvent) -> None:
|
|
99
|
-
"""Applies event to aggregate."""
|
|
100
|
-
|
|
101
|
-
@_apply.register(Registered)
|
|
102
|
-
def _(self, event: Registered) -> None:
|
|
103
|
-
super().__init__(event)
|
|
104
|
-
self.name = event.name
|
|
105
|
-
self.tricks: List[str] = []
|
|
106
|
-
|
|
107
|
-
@_apply.register(TrickAdded)
|
|
108
|
-
def _(self, event: TrickAdded) -> None:
|
|
109
|
-
self.tricks.append(event.trick)
|
|
110
|
-
self.version = event.originator_version
|
|
111
|
-
|
|
112
|
-
@_apply.register(Snapshot)
|
|
113
|
-
def _(self, event: Snapshot) -> None:
|
|
114
|
-
self.__dict__.update(event.state)
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from unittest import TestCase
|
|
4
|
-
|
|
5
|
-
from eventsourcing.examples.aggregate4.application import DogSchool
|
|
6
|
-
from eventsourcing.examples.aggregate4.domainmodel import Dog
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class TestDogSchool(TestCase):
|
|
10
|
-
def test_dog_school(self) -> None:
|
|
11
|
-
# Construct application object.
|
|
12
|
-
school = DogSchool()
|
|
13
|
-
|
|
14
|
-
# Evolve application state.
|
|
15
|
-
dog_id = school.register_dog("Fido")
|
|
16
|
-
school.add_trick(dog_id, "roll over")
|
|
17
|
-
school.add_trick(dog_id, "play dead")
|
|
18
|
-
|
|
19
|
-
# Query application state.
|
|
20
|
-
dog = school.get_dog(dog_id)
|
|
21
|
-
assert dog["name"] == "Fido"
|
|
22
|
-
assert dog["tricks"] == ("roll over", "play dead")
|
|
23
|
-
|
|
24
|
-
# Select notifications.
|
|
25
|
-
notifications = school.notification_log.select(start=1, limit=10)
|
|
26
|
-
assert len(notifications) == 3
|
|
27
|
-
|
|
28
|
-
# Take snapshot.
|
|
29
|
-
school.take_snapshot(dog_id, version=3, projector_func=Dog.projector)
|
|
30
|
-
dog = school.get_dog(dog_id)
|
|
31
|
-
assert dog["name"] == "Fido"
|
|
32
|
-
assert dog["tricks"] == ("roll over", "play dead")
|
|
33
|
-
|
|
34
|
-
# Continue with snapshotted aggregate.
|
|
35
|
-
school.add_trick(dog_id, "fetch ball")
|
|
36
|
-
dog = school.get_dog(dog_id)
|
|
37
|
-
assert dog["name"] == "Fido"
|
|
38
|
-
assert dog["tricks"] == ("roll over", "play dead", "fetch ball")
|
|
File without changes
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import TYPE_CHECKING, Any, Dict
|
|
4
|
-
|
|
5
|
-
from eventsourcing.application import Application
|
|
6
|
-
from eventsourcing.examples.aggregate5.domainmodel import Dog
|
|
7
|
-
|
|
8
|
-
if TYPE_CHECKING: # pragma: nocover
|
|
9
|
-
from uuid import UUID
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class DogSchool(Application):
|
|
13
|
-
is_snapshotting_enabled = True
|
|
14
|
-
|
|
15
|
-
def register_dog(self, name: str) -> UUID:
|
|
16
|
-
dog, event = Dog.register(name)
|
|
17
|
-
self.save(event)
|
|
18
|
-
return dog.id
|
|
19
|
-
|
|
20
|
-
def add_trick(self, dog_id: UUID, trick: str) -> None:
|
|
21
|
-
dog = self.repository.get(dog_id, projector_func=Dog.projector)
|
|
22
|
-
dog, event = dog.add_trick(trick)
|
|
23
|
-
self.save(event)
|
|
24
|
-
|
|
25
|
-
def get_dog(self, dog_id: UUID) -> Dict[str, Any]:
|
|
26
|
-
dog = self.repository.get(dog_id, projector_func=Dog.projector)
|
|
27
|
-
return {"name": dog.name, "tricks": dog.tricks}
|