Skip to content

Commit 575fc21

Browse files
authored
Merge pull request #17 from maxipavlovic/feature/LITE-17439
LITE-17439 Optimized CQRS sync to not make excessive queries to DB
2 parents bdc9b08 + ad2e35d commit 575fc21

File tree

4 files changed

+38
-11
lines changed

4 files changed

+38
-11
lines changed

dj_cqrs/mixins.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,18 @@ def _save_tracked_fields(self):
105105
tracker = getattr(self, FIELDS_TRACKER_FIELD_NAME)
106106
setattr(self, TRACKED_FIELDS_ATTR_NAME, tracker.changed())
107107

108-
def to_cqrs_dict(self, using=None):
108+
def to_cqrs_dict(self, using=None, sync=False):
109109
"""CQRS serialization for transport payload.
110110
111111
:param using: The using argument can be used to force the database
112112
to use, defaults to None
113113
:type using: str, optional
114+
:type sync: bool, optional
114115
:return: The serialized instance data.
115116
:rtype: dict
116117
"""
117118
if self.CQRS_SERIALIZER:
118-
data = self._class_serialization(using)
119+
data = self._class_serialization(using, sync=sync)
119120
else:
120121
self._refresh_f_expr_values(using)
121122
data = self._common_serialization(using)
@@ -230,13 +231,16 @@ def _common_serialization(self, using):
230231

231232
return data
232233

233-
def _class_serialization(self, using):
234-
db = using if using is not None else self._state.db
235-
qs = self.__class__._default_manager.using(db).filter(pk=self.pk)
234+
def _class_serialization(self, using, sync=False):
235+
if sync:
236+
instance = self
237+
else:
238+
db = using if using is not None else self._state.db
239+
qs = self.__class__._default_manager.using(db).filter(pk=self.pk)
236240

237-
instance = self.relate_cqrs_serialization(qs).first()
238-
if not instance:
239-
raise RuntimeError("Couldn't serialize CQRS class ({}).".format(self.CQRS_ID))
241+
instance = self.relate_cqrs_serialization(qs).first()
242+
if not instance:
243+
raise RuntimeError("Couldn't serialize CQRS class ({}).".format(self.CQRS_ID))
240244

241245
data = self._cqrs_serializer_cls(instance).data
242246
data['cqrs_revision'] = instance.cqrs_revision
@@ -264,8 +268,8 @@ def _refresh_f_expr_values(self, using):
264268
if value is not None and isinstance(value, CombinedExpression):
265269
fields_to_refresh.append(f.name)
266270

267-
if fields_to_refresh:
268-
self.refresh_from_db(fields=fields_to_refresh)
271+
if fields_to_refresh:
272+
self.refresh_from_db(fields=fields_to_refresh)
269273

270274
@property
271275
def _cqrs_serializer_cls(self):

dj_cqrs/signals.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def post_save(cls, sender, **kwargs):
5959
connection = transaction.get_connection(using)
6060
if not connection.in_atomic_block:
6161
instance.reset_cqrs_saves_count()
62-
instance_data = instance.to_cqrs_dict(using)
62+
instance_data = instance.to_cqrs_dict(using, sync=sync)
6363
previous_data = instance.get_tracked_fields_data()
6464
signal_type = SignalType.SYNC if sync else SignalType.SAVE
6565
payload = TransportPayload(

tests/test_flow.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ def test_sync_exists(mocker):
144144
author.save()
145145
mocker.stopall()
146146

147+
author.refresh_from_db()
147148
author.cqrs_sync()
148149

149150
assert replica_models.AuthorRef.objects.count() == 1

tests/test_master/test_mixin.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,28 @@ def test_cqrs_sync(mocker):
201201
)
202202

203203

204+
@pytest.mark.django_db(transaction=True)
205+
def test_cqrs_sync_optimized_for_class_serialization(mocker, django_assert_num_queries):
206+
models.Author.objects.create(
207+
id=5,
208+
name='hi',
209+
publisher=models.Publisher.objects.create(id=1, name='pub'),
210+
)
211+
m = models.Author.relate_cqrs_serialization(models.Author.objects.all()).first()
212+
213+
publisher_mock = mocker.patch('dj_cqrs.controller.producer.produce')
214+
with django_assert_num_queries(0):
215+
assert m.cqrs_sync()
216+
217+
assert_publisher_once_called_with_args(
218+
publisher_mock,
219+
SignalType.SYNC,
220+
models.Author.CQRS_ID,
221+
{'id': 5, 'name': 'hi', 'publisher': {'id': 1, 'name': 'pub'}},
222+
5,
223+
)
224+
225+
204226
@pytest.mark.django_db(transaction=True)
205227
def test_is_sync_instance(mocker):
206228
publisher_mock = mocker.patch('dj_cqrs.controller.producer.produce')

0 commit comments

Comments
 (0)