eventsourcing 9.3.3__py3-none-any.whl → 9.3.4__py3-none-any.whl

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.

Files changed (127) hide show
  1. {eventsourcing-9.3.3.dist-info → eventsourcing-9.3.4.dist-info}/METADATA +1 -1
  2. eventsourcing-9.3.4.dist-info/RECORD +24 -0
  3. eventsourcing/examples/__init__.py +0 -0
  4. eventsourcing/examples/aggregate1/__init__.py +0 -0
  5. eventsourcing/examples/aggregate1/application.py +0 -27
  6. eventsourcing/examples/aggregate1/domainmodel.py +0 -16
  7. eventsourcing/examples/aggregate1/test_application.py +0 -37
  8. eventsourcing/examples/aggregate2/__init__.py +0 -0
  9. eventsourcing/examples/aggregate2/application.py +0 -27
  10. eventsourcing/examples/aggregate2/domainmodel.py +0 -22
  11. eventsourcing/examples/aggregate2/test_application.py +0 -37
  12. eventsourcing/examples/aggregate3/__init__.py +0 -0
  13. eventsourcing/examples/aggregate3/application.py +0 -27
  14. eventsourcing/examples/aggregate3/domainmodel.py +0 -38
  15. eventsourcing/examples/aggregate3/test_application.py +0 -37
  16. eventsourcing/examples/aggregate4/__init__.py +0 -0
  17. eventsourcing/examples/aggregate4/application.py +0 -27
  18. eventsourcing/examples/aggregate4/domainmodel.py +0 -114
  19. eventsourcing/examples/aggregate4/test_application.py +0 -38
  20. eventsourcing/examples/aggregate5/__init__.py +0 -0
  21. eventsourcing/examples/aggregate5/application.py +0 -27
  22. eventsourcing/examples/aggregate5/domainmodel.py +0 -131
  23. eventsourcing/examples/aggregate5/test_application.py +0 -38
  24. eventsourcing/examples/aggregate6/__init__.py +0 -0
  25. eventsourcing/examples/aggregate6/application.py +0 -30
  26. eventsourcing/examples/aggregate6/domainmodel.py +0 -123
  27. eventsourcing/examples/aggregate6/test_application.py +0 -38
  28. eventsourcing/examples/aggregate6a/__init__.py +0 -0
  29. eventsourcing/examples/aggregate6a/application.py +0 -40
  30. eventsourcing/examples/aggregate6a/domainmodel.py +0 -149
  31. eventsourcing/examples/aggregate6a/test_application.py +0 -45
  32. eventsourcing/examples/aggregate7/__init__.py +0 -0
  33. eventsourcing/examples/aggregate7/application.py +0 -53
  34. eventsourcing/examples/aggregate7/domainmodel.py +0 -142
  35. eventsourcing/examples/aggregate7/persistence.py +0 -57
  36. eventsourcing/examples/aggregate7/test_application.py +0 -45
  37. eventsourcing/examples/aggregate7/test_compression_and_encryption.py +0 -45
  38. eventsourcing/examples/aggregate7/test_snapshotting_intervals.py +0 -67
  39. eventsourcing/examples/aggregate7a/__init__.py +0 -0
  40. eventsourcing/examples/aggregate7a/application.py +0 -56
  41. eventsourcing/examples/aggregate7a/domainmodel.py +0 -168
  42. eventsourcing/examples/aggregate7a/test_application.py +0 -46
  43. eventsourcing/examples/aggregate7a/test_compression_and_encryption.py +0 -45
  44. eventsourcing/examples/aggregate8/__init__.py +0 -0
  45. eventsourcing/examples/aggregate8/application.py +0 -47
  46. eventsourcing/examples/aggregate8/domainmodel.py +0 -71
  47. eventsourcing/examples/aggregate8/persistence.py +0 -57
  48. eventsourcing/examples/aggregate8/test_application.py +0 -44
  49. eventsourcing/examples/aggregate8/test_compression_and_encryption.py +0 -44
  50. eventsourcing/examples/aggregate8/test_snapshotting_intervals.py +0 -38
  51. eventsourcing/examples/bankaccounts/__init__.py +0 -0
  52. eventsourcing/examples/bankaccounts/application.py +0 -70
  53. eventsourcing/examples/bankaccounts/domainmodel.py +0 -56
  54. eventsourcing/examples/bankaccounts/test.py +0 -173
  55. eventsourcing/examples/cargoshipping/__init__.py +0 -0
  56. eventsourcing/examples/cargoshipping/application.py +0 -126
  57. eventsourcing/examples/cargoshipping/domainmodel.py +0 -330
  58. eventsourcing/examples/cargoshipping/interface.py +0 -143
  59. eventsourcing/examples/cargoshipping/test.py +0 -231
  60. eventsourcing/examples/contentmanagement/__init__.py +0 -0
  61. eventsourcing/examples/contentmanagement/application.py +0 -118
  62. eventsourcing/examples/contentmanagement/domainmodel.py +0 -69
  63. eventsourcing/examples/contentmanagement/test.py +0 -180
  64. eventsourcing/examples/contentmanagement/utils.py +0 -26
  65. eventsourcing/examples/contentmanagementsystem/__init__.py +0 -0
  66. eventsourcing/examples/contentmanagementsystem/application.py +0 -54
  67. eventsourcing/examples/contentmanagementsystem/postgres.py +0 -17
  68. eventsourcing/examples/contentmanagementsystem/sqlite.py +0 -17
  69. eventsourcing/examples/contentmanagementsystem/system.py +0 -14
  70. eventsourcing/examples/contentmanagementsystem/test_system.py +0 -180
  71. eventsourcing/examples/searchablecontent/__init__.py +0 -0
  72. eventsourcing/examples/searchablecontent/application.py +0 -45
  73. eventsourcing/examples/searchablecontent/persistence.py +0 -23
  74. eventsourcing/examples/searchablecontent/postgres.py +0 -118
  75. eventsourcing/examples/searchablecontent/sqlite.py +0 -136
  76. eventsourcing/examples/searchablecontent/test_application.py +0 -110
  77. eventsourcing/examples/searchablecontent/test_recorder.py +0 -68
  78. eventsourcing/examples/searchabletimestamps/__init__.py +0 -0
  79. eventsourcing/examples/searchabletimestamps/application.py +0 -32
  80. eventsourcing/examples/searchabletimestamps/persistence.py +0 -20
  81. eventsourcing/examples/searchabletimestamps/postgres.py +0 -110
  82. eventsourcing/examples/searchabletimestamps/sqlite.py +0 -99
  83. eventsourcing/examples/searchabletimestamps/test_searchabletimestamps.py +0 -94
  84. eventsourcing/examples/test_invoice.py +0 -176
  85. eventsourcing/examples/test_parking_lot.py +0 -206
  86. eventsourcing/tests/application_tests/__init__.py +0 -0
  87. eventsourcing/tests/application_tests/test_application_with_automatic_snapshotting.py +0 -55
  88. eventsourcing/tests/application_tests/test_application_with_popo.py +0 -22
  89. eventsourcing/tests/application_tests/test_application_with_postgres.py +0 -75
  90. eventsourcing/tests/application_tests/test_application_with_sqlite.py +0 -72
  91. eventsourcing/tests/application_tests/test_cache.py +0 -134
  92. eventsourcing/tests/application_tests/test_event_sourced_log.py +0 -162
  93. eventsourcing/tests/application_tests/test_notificationlog.py +0 -232
  94. eventsourcing/tests/application_tests/test_notificationlogreader.py +0 -126
  95. eventsourcing/tests/application_tests/test_processapplication.py +0 -110
  96. eventsourcing/tests/application_tests/test_processingpolicy.py +0 -109
  97. eventsourcing/tests/application_tests/test_repository.py +0 -504
  98. eventsourcing/tests/application_tests/test_snapshotting.py +0 -68
  99. eventsourcing/tests/application_tests/test_upcasting.py +0 -459
  100. eventsourcing/tests/docs_tests/__init__.py +0 -0
  101. eventsourcing/tests/docs_tests/test_docs.py +0 -293
  102. eventsourcing/tests/domain_tests/__init__.py +0 -0
  103. eventsourcing/tests/domain_tests/test_aggregate.py +0 -1200
  104. eventsourcing/tests/domain_tests/test_aggregate_decorators.py +0 -1604
  105. eventsourcing/tests/domain_tests/test_domainevent.py +0 -80
  106. eventsourcing/tests/interface_tests/__init__.py +0 -0
  107. eventsourcing/tests/interface_tests/test_remotenotificationlog.py +0 -258
  108. eventsourcing/tests/persistence_tests/__init__.py +0 -0
  109. eventsourcing/tests/persistence_tests/test_aes.py +0 -93
  110. eventsourcing/tests/persistence_tests/test_connection_pool.py +0 -722
  111. eventsourcing/tests/persistence_tests/test_eventstore.py +0 -72
  112. eventsourcing/tests/persistence_tests/test_infrastructure_factory.py +0 -21
  113. eventsourcing/tests/persistence_tests/test_mapper.py +0 -113
  114. eventsourcing/tests/persistence_tests/test_noninterleaving_notification_ids.py +0 -69
  115. eventsourcing/tests/persistence_tests/test_popo.py +0 -124
  116. eventsourcing/tests/persistence_tests/test_postgres.py +0 -1120
  117. eventsourcing/tests/persistence_tests/test_sqlite.py +0 -348
  118. eventsourcing/tests/persistence_tests/test_transcoder.py +0 -44
  119. eventsourcing/tests/system_tests/__init__.py +0 -0
  120. eventsourcing/tests/system_tests/test_runner.py +0 -935
  121. eventsourcing/tests/system_tests/test_system.py +0 -284
  122. eventsourcing/tests/utils_tests/__init__.py +0 -0
  123. eventsourcing/tests/utils_tests/test_utils.py +0 -226
  124. eventsourcing-9.3.3.dist-info/RECORD +0 -145
  125. {eventsourcing-9.3.3.dist-info → eventsourcing-9.3.4.dist-info}/AUTHORS +0 -0
  126. {eventsourcing-9.3.3.dist-info → eventsourcing-9.3.4.dist-info}/LICENSE +0 -0
  127. {eventsourcing-9.3.3.dist-info → eventsourcing-9.3.4.dist-info}/WHEEL +0 -0
@@ -1,118 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING, Any, ClassVar, Dict, Iterator, Type, Union, cast
4
- from uuid import NAMESPACE_URL, UUID, uuid5
5
-
6
- from eventsourcing.application import (
7
- AggregateNotFoundError,
8
- Application,
9
- EventSourcedLog,
10
- )
11
- from eventsourcing.examples.contentmanagement.domainmodel import Index, Page, PageLogged
12
-
13
- if TYPE_CHECKING: # pragma: nocover
14
- from eventsourcing.domain import MutableOrImmutableAggregate
15
- from eventsourcing.utils import EnvType
16
-
17
- PageDetailsType = Dict[str, Union[str, Any]]
18
-
19
-
20
- class ContentManagementApplication(Application):
21
- env: ClassVar[Dict[str, str]] = {"COMPRESSOR_TOPIC": "gzip"}
22
- snapshotting_intervals: ClassVar[Dict[Type[MutableOrImmutableAggregate], int]] = {
23
- Page: 5
24
- }
25
-
26
- def __init__(self, env: EnvType | None = None) -> None:
27
- super().__init__(env)
28
- self.page_log: EventSourcedLog[PageLogged] = EventSourcedLog(
29
- self.events, uuid5(NAMESPACE_URL, "/page_log"), PageLogged
30
- )
31
-
32
- def create_page(self, title: str, slug: str) -> None:
33
- page = Page(title=title, slug=slug)
34
- page_logged = self.page_log.trigger_event(page_id=page.id)
35
- index_entry = Index(slug, ref=page.id)
36
- self.save(page, page_logged, index_entry)
37
-
38
- def get_page_by_slug(self, slug: str) -> PageDetailsType:
39
- page = self._get_page_by_slug(slug)
40
- return self._details_from_page(page)
41
-
42
- def get_page_by_id(self, page_id: UUID) -> PageDetailsType:
43
- page = self._get_page_by_id(page_id)
44
- return self._details_from_page(page)
45
-
46
- def _details_from_page(self, page: Page) -> PageDetailsType:
47
- return {
48
- "title": page.title,
49
- "slug": page.slug,
50
- "body": page.body,
51
- "modified_by": page.modified_by,
52
- }
53
-
54
- def update_title(self, slug: str, title: str) -> None:
55
- page = self._get_page_by_slug(slug)
56
- page.update_title(title=title)
57
- self.save(page)
58
-
59
- def update_slug(self, old_slug: str, new_slug: str) -> None:
60
- page = self._get_page_by_slug(old_slug)
61
- page.update_slug(new_slug)
62
- old_index = self._get_index(old_slug)
63
- old_index.update_ref(None)
64
- try:
65
- new_index = self._get_index(new_slug)
66
- except AggregateNotFoundError:
67
- new_index = Index(new_slug, page.id)
68
- else:
69
- if new_index.ref is None:
70
- new_index.update_ref(page.id)
71
- else:
72
- raise SlugConflictError
73
- self.save(page, old_index, new_index)
74
-
75
- def update_body(self, slug: str, body: str) -> None:
76
- page = self._get_page_by_slug(slug)
77
- page.update_body(body)
78
- self.save(page)
79
-
80
- def _get_page_by_slug(self, slug: str) -> Page:
81
- try:
82
- index = self._get_index(slug)
83
- except AggregateNotFoundError:
84
- raise PageNotFoundError(slug) from None
85
- if index.ref is None:
86
- raise PageNotFoundError(slug)
87
- page_id = index.ref
88
- return self._get_page_by_id(page_id)
89
-
90
- def _get_page_by_id(self, page_id: UUID) -> Page:
91
- return cast(Page, self.repository.get(page_id))
92
-
93
- def _get_index(self, slug: str) -> Index:
94
- return cast(Index, self.repository.get(Index.create_id(slug)))
95
-
96
- def get_pages(
97
- self,
98
- *,
99
- gt: int | None = None,
100
- lte: int | None = None,
101
- desc: bool = False,
102
- limit: int | None = None,
103
- ) -> Iterator[PageDetailsType]:
104
- for page_logged in self.page_log.get(gt=gt, lte=lte, desc=desc, limit=limit):
105
- page = self._get_page_by_id(page_logged.page_id)
106
- yield self._details_from_page(page)
107
-
108
-
109
- class PageNotFoundError(Exception):
110
- """
111
- Raised when a page is not found.
112
- """
113
-
114
-
115
- class SlugConflictError(Exception):
116
- """
117
- Raised when updating a page to a slug used by another page.
118
- """
@@ -1,69 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from contextvars import ContextVar
4
- from dataclasses import dataclass, field
5
- from typing import cast
6
- from uuid import NAMESPACE_URL, UUID, uuid5
7
-
8
- from eventsourcing.domain import Aggregate, DomainEvent, event
9
- from eventsourcing.examples.contentmanagement.utils import apply_patch, create_diff
10
-
11
- user_id_cvar: ContextVar[UUID | None] = ContextVar("user_id", default=None)
12
-
13
-
14
- class Page(Aggregate):
15
- class Event(Aggregate.Event):
16
- user_id: UUID | None = field(default_factory=user_id_cvar.get, init=False)
17
-
18
- def apply(self, aggregate: Aggregate) -> None:
19
- cast(Page, aggregate).modified_by = self.user_id
20
-
21
- class Created(Event, Aggregate.Created):
22
- title: str
23
- slug: str
24
- body: str
25
-
26
- def __init__(self, title: str, slug: str, body: str = ""):
27
- self.title = title
28
- self.slug = slug
29
- self.body = body
30
- self.modified_by: UUID | None = None
31
-
32
- @event("SlugUpdated")
33
- def update_slug(self, slug: str) -> None:
34
- self.slug = slug
35
-
36
- @event("TitleUpdated")
37
- def update_title(self, title: str) -> None:
38
- self.title = title
39
-
40
- def update_body(self, body: str) -> None:
41
- self._update_body(create_diff(old=self.body, new=body))
42
-
43
- class BodyUpdated(Event):
44
- diff: str
45
-
46
- @event(BodyUpdated)
47
- def _update_body(self, diff: str) -> None:
48
- self.body = apply_patch(old=self.body, diff=diff)
49
-
50
-
51
- @dataclass
52
- class Index(Aggregate):
53
- slug: str
54
- ref: UUID | None
55
-
56
- class Event(Aggregate.Event):
57
- pass
58
-
59
- @staticmethod
60
- def create_id(slug: str) -> UUID:
61
- return uuid5(NAMESPACE_URL, f"/slugs/{slug}")
62
-
63
- @event("RefChanged")
64
- def update_ref(self, ref: UUID | None) -> None:
65
- self.ref = ref
66
-
67
-
68
- class PageLogged(DomainEvent):
69
- page_id: UUID
@@ -1,180 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import cast
4
- from unittest import TestCase
5
- from uuid import uuid4
6
-
7
- from eventsourcing.examples.contentmanagement.application import (
8
- ContentManagementApplication,
9
- PageNotFoundError,
10
- SlugConflictError,
11
- )
12
- from eventsourcing.examples.contentmanagement.domainmodel import (
13
- Index,
14
- Page,
15
- user_id_cvar,
16
- )
17
- from eventsourcing.system import NotificationLogReader
18
-
19
-
20
- class TestContentManagement(TestCase):
21
- def test(self) -> None:
22
- # Set user_id context variable.
23
- user_id = uuid4()
24
- user_id_cvar.set(user_id)
25
-
26
- # Construct application.
27
- app = ContentManagementApplication()
28
-
29
- # Check the page doesn't exist.
30
- with self.assertRaises(PageNotFoundError):
31
- app.get_page_by_slug(slug="welcome")
32
-
33
- # Check the list of pages is empty.
34
- pages = list(app.get_pages())
35
- self.assertEqual(len(pages), 0)
36
-
37
- # Create a page.
38
- app.create_page(title="Welcome", slug="welcome")
39
-
40
- # Present page identified by the given slug.
41
- page = app.get_page_by_slug(slug="welcome")
42
-
43
- # Check we got a dict that has the given title and slug.
44
- self.assertEqual(page["title"], "Welcome")
45
- self.assertEqual(page["slug"], "welcome")
46
- self.assertEqual(page["body"], "")
47
- self.assertEqual(page["modified_by"], user_id)
48
-
49
- # Update the title.
50
- app.update_title(slug="welcome", title="Welcome Visitors")
51
-
52
- # Check the title was updated.
53
- page = app.get_page_by_slug(slug="welcome")
54
- self.assertEqual(page["title"], "Welcome Visitors")
55
- self.assertEqual(page["modified_by"], user_id)
56
-
57
- # Update the slug.
58
- app.update_slug(old_slug="welcome", new_slug="welcome-visitors")
59
-
60
- # Check the index was updated.
61
- with self.assertRaises(PageNotFoundError):
62
- app.get_page_by_slug(slug="welcome")
63
-
64
- # Check we can get the page by the new slug.
65
- page = app.get_page_by_slug(slug="welcome-visitors")
66
- self.assertEqual(page["title"], "Welcome Visitors")
67
- self.assertEqual(page["slug"], "welcome-visitors")
68
-
69
- # Update the body.
70
- app.update_body(slug="welcome-visitors", body="Welcome to my wiki")
71
-
72
- # Check the body was updated.
73
- page = app.get_page_by_slug(slug="welcome-visitors")
74
- self.assertEqual(page["body"], "Welcome to my wiki")
75
-
76
- # Update the body.
77
- app.update_body(slug="welcome-visitors", body="Welcome to this wiki")
78
-
79
- # Check the body was updated.
80
- page = app.get_page_by_slug(slug="welcome-visitors")
81
- self.assertEqual(page["body"], "Welcome to this wiki")
82
-
83
- # Update the body.
84
- app.update_body(
85
- slug="welcome-visitors",
86
- body="""
87
- Welcome to this wiki!
88
-
89
- This is a wiki about...
90
- """,
91
- )
92
-
93
- # Check the body was updated.
94
- page = app.get_page_by_slug(slug="welcome-visitors")
95
- self.assertEqual(
96
- page["body"],
97
- """
98
- Welcome to this wiki!
99
-
100
- This is a wiki about...
101
- """,
102
- )
103
-
104
- # Check all the Page events have the user_id.
105
- for notification in NotificationLogReader(app.notification_log).read(start=1):
106
- domain_event = app.mapper.to_domain_event(notification)
107
- if isinstance(domain_event, Page.Event):
108
- self.assertEqual(domain_event.user_id, user_id)
109
-
110
- # Change user_id context variable.
111
- user_id = uuid4()
112
- user_id_cvar.set(user_id)
113
-
114
- # Update the body.
115
- app.update_body(
116
- slug="welcome-visitors",
117
- body="""
118
- Welcome to this wiki!
119
-
120
- This is a wiki about us!
121
- """,
122
- )
123
-
124
- # Check 'modified_by' changed.
125
- page = app.get_page_by_slug(slug="welcome-visitors")
126
- self.assertEqual(page["title"], "Welcome Visitors")
127
- self.assertEqual(page["modified_by"], user_id)
128
-
129
- # Check a snapshot was created by now.
130
- assert app.snapshots
131
- index = cast(Index, app.repository.get(Index.create_id("welcome-visitors")))
132
- assert index.ref
133
- self.assertTrue(len(list(app.snapshots.get(index.ref))))
134
-
135
- # Create some more pages and list all the pages.
136
- app.create_page("Page 2", "page-2")
137
- app.create_page("Page 3", "page-3")
138
- app.create_page("Page 4", "page-4")
139
- app.create_page("Page 5", "page-5")
140
-
141
- pages = list(app.get_pages(desc=True))
142
- self.assertEqual(pages[0]["title"], "Page 5")
143
- self.assertEqual(pages[0]["slug"], "page-5")
144
- self.assertEqual(pages[1]["title"], "Page 4")
145
- self.assertEqual(pages[1]["slug"], "page-4")
146
- self.assertEqual(pages[2]["title"], "Page 3")
147
- self.assertEqual(pages[2]["slug"], "page-3")
148
- self.assertEqual(pages[3]["title"], "Page 2")
149
- self.assertEqual(pages[3]["slug"], "page-2")
150
- self.assertEqual(pages[4]["title"], "Welcome Visitors")
151
- self.assertEqual(pages[4]["slug"], "welcome-visitors")
152
-
153
- pages = list(app.get_pages(desc=True, limit=3))
154
- self.assertEqual(len(pages), 3)
155
- self.assertEqual(pages[0]["slug"], "page-5")
156
- self.assertEqual(pages[1]["slug"], "page-4")
157
- self.assertEqual(pages[2]["slug"], "page-3")
158
-
159
- pages = list(app.get_pages(desc=True, limit=3, lte=2))
160
- self.assertEqual(len(pages), 2)
161
- self.assertEqual(pages[0]["slug"], "page-2")
162
- self.assertEqual(pages[1]["slug"], "welcome-visitors")
163
-
164
- pages = list(app.get_pages(desc=True, lte=2))
165
- self.assertEqual(len(pages), 2)
166
- self.assertEqual(pages[0]["slug"], "page-2")
167
- self.assertEqual(pages[1]["slug"], "welcome-visitors")
168
-
169
- # Check we can't change the slug of a page to one
170
- # that is being used by another page.
171
- with self.assertRaises(SlugConflictError):
172
- app.update_slug("page-2", "page-3")
173
-
174
- # Check we can change the slug of a page to one
175
- # that was previously being used.
176
- app.update_slug("welcome-visitors", "welcome")
177
-
178
- page = app.get_page_by_slug(slug="welcome")
179
- self.assertEqual(page["title"], "Welcome Visitors")
180
- self.assertEqual(page["modified_by"], user_id)
@@ -1,26 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import os
4
- from tempfile import TemporaryDirectory
5
-
6
-
7
- def create_diff(old: str, new: str) -> str:
8
- return run("diff %s %s > %s", old, new)
9
-
10
-
11
- def apply_patch(old: str, diff: str) -> str:
12
- return run("patch -s %s %s -o %s", old, diff)
13
-
14
-
15
- def run(cmd: str, a: str, b: str) -> str:
16
- with TemporaryDirectory() as td:
17
- a_path = os.path.join(td, "a")
18
- b_path = os.path.join(td, "b")
19
- c_path = os.path.join(td, "c")
20
- with open(a_path, "w") as a_file:
21
- a_file.write(a)
22
- with open(b_path, "w") as b_file:
23
- b_file.write(b)
24
- os.system(cmd % (a_path, b_path, c_path)) # noqa: S605
25
- with open(c_path) as c_file:
26
- return c_file.read()
@@ -1,54 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import TYPE_CHECKING, ClassVar, Dict, List, cast
4
-
5
- from eventsourcing.examples.contentmanagement.domainmodel import Page
6
- from eventsourcing.examples.contentmanagement.utils import apply_patch
7
- from eventsourcing.examples.searchablecontent.persistence import (
8
- SearchableContentRecorder,
9
- )
10
- from eventsourcing.system import ProcessApplication
11
-
12
- if TYPE_CHECKING: # pragma: nocover
13
- from uuid import UUID
14
-
15
- from eventsourcing.application import ProcessingEvent
16
- from eventsourcing.domain import DomainEventProtocol
17
-
18
-
19
- class SearchIndexApplication(ProcessApplication):
20
- env: ClassVar[Dict[str, str]] = {
21
- "COMPRESSOR_TOPIC": "gzip",
22
- }
23
-
24
- def policy(
25
- self,
26
- domain_event: DomainEventProtocol,
27
- processing_event: ProcessingEvent,
28
- ) -> None:
29
- if isinstance(domain_event, Page.Created):
30
- processing_event.saved_kwargs["insert_pages"] = [
31
- (
32
- domain_event.originator_id,
33
- domain_event.slug,
34
- domain_event.title,
35
- domain_event.body,
36
- )
37
- ]
38
- elif isinstance(domain_event, Page.BodyUpdated):
39
- recorder = cast(SearchableContentRecorder, self.recorder)
40
- page_id = domain_event.originator_id
41
- page_slug, page_title, page_body = recorder.select_page(page_id)
42
- page_body = apply_patch(page_body, domain_event.diff)
43
- processing_event.saved_kwargs["update_pages"] = [
44
- (
45
- page_id,
46
- page_slug,
47
- page_title,
48
- page_body,
49
- )
50
- ]
51
-
52
- def search(self, query: str) -> List[UUID]:
53
- recorder = cast(SearchableContentRecorder, self.recorder)
54
- return recorder.search_pages(query)
@@ -1,17 +0,0 @@
1
- from eventsourcing.examples.searchablecontent.postgres import (
2
- PostgresSearchableContentRecorder,
3
- )
4
- from eventsourcing.postgres import Factory, PostgresProcessRecorder
5
-
6
-
7
- class SearchableContentProcessRecorder(
8
- PostgresSearchableContentRecorder, PostgresProcessRecorder
9
- ):
10
- pass
11
-
12
-
13
- class SearchableContentInfrastructureFactory(Factory):
14
- process_recorder_class = SearchableContentProcessRecorder
15
-
16
-
17
- del Factory
@@ -1,17 +0,0 @@
1
- from eventsourcing.examples.searchablecontent.sqlite import (
2
- SQLiteSearchableContentRecorder,
3
- )
4
- from eventsourcing.sqlite import Factory, SQLiteProcessRecorder
5
-
6
-
7
- class SearchableContentProcessRecorder(
8
- SQLiteSearchableContentRecorder, SQLiteProcessRecorder
9
- ):
10
- pass
11
-
12
-
13
- class SearchableContentInfrastructureFactory(Factory):
14
- process_recorder_class = SearchableContentProcessRecorder
15
-
16
-
17
- del Factory
@@ -1,14 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from eventsourcing.examples.contentmanagement.application import (
4
- ContentManagementApplication,
5
- )
6
- from eventsourcing.examples.contentmanagementsystem.application import (
7
- SearchIndexApplication,
8
- )
9
- from eventsourcing.system import System
10
-
11
-
12
- class ContentManagementSystem(System):
13
- def __init__(self) -> None:
14
- super().__init__(pipes=[[ContentManagementApplication, SearchIndexApplication]])
@@ -1,180 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import ClassVar, Dict
4
- from unittest import TestCase
5
- from uuid import uuid4
6
-
7
- from eventsourcing.examples.contentmanagement.application import (
8
- ContentManagementApplication,
9
- )
10
- from eventsourcing.examples.contentmanagement.domainmodel import user_id_cvar
11
- from eventsourcing.examples.contentmanagementsystem.application import (
12
- SearchIndexApplication,
13
- )
14
- from eventsourcing.examples.contentmanagementsystem.system import (
15
- ContentManagementSystem,
16
- )
17
- from eventsourcing.postgres import PostgresDatastore
18
- from eventsourcing.system import SingleThreadedRunner
19
- from eventsourcing.tests.postgres_utils import drop_postgres_table
20
-
21
-
22
- class ContentManagementSystemTestCase(TestCase):
23
- env: ClassVar[Dict[str, str]] = {}
24
-
25
- def test_system(self) -> None:
26
- with SingleThreadedRunner(
27
- system=ContentManagementSystem(), env=self.env
28
- ) as runner:
29
-
30
- content_management_app = runner.get(ContentManagementApplication)
31
- search_index_app = runner.get(SearchIndexApplication)
32
-
33
- # Set user_id context variable.
34
- user_id = uuid4()
35
- user_id_cvar.set(user_id)
36
-
37
- # Create empty pages.
38
- content_management_app.create_page(title="Animals", slug="animals")
39
- content_management_app.create_page(title="Plants", slug="plants")
40
- content_management_app.create_page(title="Minerals", slug="minerals")
41
-
42
- # Search, expect no results.
43
- self.assertEqual(0, len(search_index_app.search("cat")))
44
- self.assertEqual(0, len(search_index_app.search("rose")))
45
- self.assertEqual(0, len(search_index_app.search("calcium")))
46
-
47
- # Update the pages.
48
- content_management_app.update_body(slug="animals", body="cat")
49
- content_management_app.update_body(slug="plants", body="rose")
50
- content_management_app.update_body(slug="minerals", body="calcium")
51
-
52
- # Search for single words.
53
- page_ids = search_index_app.search("cat")
54
- self.assertEqual(1, len(page_ids))
55
- page = content_management_app.get_page_by_id(page_ids[0])
56
- self.assertEqual(page["slug"], "animals")
57
- self.assertEqual(page["body"], "cat")
58
-
59
- page_ids = search_index_app.search("rose")
60
- self.assertEqual(1, len(page_ids))
61
- page = content_management_app.get_page_by_id(page_ids[0])
62
- self.assertEqual(page["slug"], "plants")
63
- self.assertEqual(page["body"], "rose")
64
-
65
- page_ids = search_index_app.search("calcium")
66
- self.assertEqual(1, len(page_ids))
67
- page = content_management_app.get_page_by_id(page_ids[0])
68
- self.assertEqual(page["slug"], "minerals")
69
- self.assertEqual(page["body"], "calcium")
70
-
71
- self.assertEqual(len(search_index_app.search("dog")), 0)
72
- self.assertEqual(len(search_index_app.search("bluebell")), 0)
73
- self.assertEqual(len(search_index_app.search("zinc")), 0)
74
-
75
- # Update the pages again.
76
- content_management_app.update_body(slug="animals", body="cat dog zebra")
77
- content_management_app.update_body(
78
- slug="plants", body="bluebell rose jasmine"
79
- )
80
- content_management_app.update_body(
81
- slug="minerals", body="iron zinc calcium"
82
- )
83
-
84
- # Search for single words.
85
- page_ids = search_index_app.search("cat")
86
- self.assertEqual(1, len(page_ids))
87
- page = content_management_app.get_page_by_id(page_ids[0])
88
- self.assertEqual(page["slug"], "animals")
89
- self.assertEqual(page["body"], "cat dog zebra")
90
-
91
- page_ids = search_index_app.search("rose")
92
- self.assertEqual(1, len(page_ids))
93
- page = content_management_app.get_page_by_id(page_ids[0])
94
- self.assertEqual(page["slug"], "plants")
95
- self.assertEqual(page["body"], "bluebell rose jasmine")
96
-
97
- page_ids = search_index_app.search("calcium")
98
- self.assertEqual(1, len(page_ids))
99
- page = content_management_app.get_page_by_id(page_ids[0])
100
- self.assertEqual(page["slug"], "minerals")
101
- self.assertEqual(page["body"], "iron zinc calcium")
102
-
103
- page_ids = search_index_app.search("dog")
104
- self.assertEqual(1, len(page_ids))
105
- page = content_management_app.get_page_by_id(page_ids[0])
106
- self.assertEqual(page["slug"], "animals")
107
- self.assertEqual(page["body"], "cat dog zebra")
108
-
109
- page_ids = search_index_app.search("bluebell")
110
- self.assertEqual(1, len(page_ids))
111
- page = content_management_app.get_page_by_id(page_ids[0])
112
- self.assertEqual(page["slug"], "plants")
113
- self.assertEqual(page["body"], "bluebell rose jasmine")
114
-
115
- page_ids = search_index_app.search("zinc")
116
- self.assertEqual(1, len(page_ids))
117
- page = content_management_app.get_page_by_id(page_ids[0])
118
- self.assertEqual(page["slug"], "minerals")
119
- self.assertEqual(page["body"], "iron zinc calcium")
120
-
121
- # Search for multiple words in same page.
122
- page_ids = search_index_app.search("dog cat")
123
- self.assertEqual(1, len(page_ids))
124
- page = content_management_app.get_page_by_id(page_ids[0])
125
- self.assertEqual(page["slug"], "animals")
126
- self.assertEqual(page["body"], "cat dog zebra")
127
-
128
- # Search for multiple words in same page, expect no results.
129
- page_ids = search_index_app.search("rose zebra")
130
- self.assertEqual(0, len(page_ids))
131
-
132
- # Search for alternative words, expect two results.
133
- page_ids = search_index_app.search("rose OR zebra")
134
- pages = [
135
- content_management_app.get_page_by_id(page_id) for page_id in page_ids
136
- ]
137
- self.assertEqual(2, len(pages))
138
- self.assertEqual(["animals", "plants"], sorted(p["slug"] for p in pages))
139
-
140
-
141
- class TestWithSQLite(ContentManagementSystemTestCase):
142
- env: ClassVar[Dict[str, str]] = {
143
- "PERSISTENCE_MODULE": "eventsourcing.examples.contentmanagementsystem.sqlite",
144
- "SQLITE_DBNAME": ":memory:",
145
- }
146
-
147
-
148
- class TestWithPostgres(ContentManagementSystemTestCase):
149
- env: ClassVar[Dict[str, str]] = {
150
- "PERSISTENCE_MODULE": "eventsourcing.examples.contentmanagementsystem.postgres",
151
- "POSTGRES_DBNAME": "eventsourcing",
152
- "POSTGRES_HOST": "127.0.0.1",
153
- "POSTGRES_PORT": "5432",
154
- "POSTGRES_USER": "eventsourcing",
155
- "POSTGRES_PASSWORD": "eventsourcing",
156
- }
157
-
158
- def setUp(self) -> None:
159
- super().setUp()
160
- self.drop_tables()
161
-
162
- def tearDown(self) -> None:
163
- self.drop_tables()
164
- super().tearDown()
165
-
166
- def drop_tables(self) -> None:
167
- with PostgresDatastore(
168
- self.env["POSTGRES_DBNAME"],
169
- self.env["POSTGRES_HOST"],
170
- self.env["POSTGRES_PORT"],
171
- self.env["POSTGRES_USER"],
172
- self.env["POSTGRES_PASSWORD"],
173
- ) as datastore:
174
- drop_postgres_table(datastore, "public.contentmanagementapplication_events")
175
- drop_postgres_table(datastore, "public.pages_projection_example")
176
- drop_postgres_table(datastore, "public.searchindexapplication_events")
177
- drop_postgres_table(datastore, "public.searchindexapplication_tracking")
178
-
179
-
180
- del ContentManagementSystemTestCase
File without changes