Skip to content

Commit b101c10

Browse files
authored
Merge pull request #9 from maxipavlovic/feature/LITE-16933
LITE-16933 Added CQRS_NO_DB_OPERATIONS flag to support models without DB tables
2 parents 51f81e1 + a8c0ab6 commit b101c10

File tree

5 files changed

+55
-13
lines changed

5 files changed

+55
-13
lines changed

dj_cqrs/controller/consumer.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# Copyright © 2020 Ingram Micro Inc. All rights reserved.
22

33
import logging
4+
from contextlib import ExitStack
45

56
from django.db import close_old_connections, transaction
67

78
from dj_cqrs.constants import SignalType
89
from dj_cqrs.registries import ReplicaRegistry
910

10-
1111
logger = logging.getLogger('django-cqrs')
1212

1313

@@ -29,26 +29,26 @@ def route_signal_to_replica_model(signal_type, cqrs_id, instance_data, previous_
2929
:param str cqrs_id: Replica model CQRS unique identifier.
3030
:param dict instance_data: Master model data.
3131
"""
32-
model_cls = ReplicaRegistry.get_model_by_cqrs_id(cqrs_id)
32+
if signal_type not in (SignalType.DELETE, SignalType.SAVE, SignalType.SYNC):
33+
logger.error('Bad signal type "{}" for CQRS_ID "{}".'.format(signal_type, cqrs_id))
34+
return
3335

36+
model_cls = ReplicaRegistry.get_model_by_cqrs_id(cqrs_id)
3437
if model_cls:
35-
close_old_connections()
38+
db_is_needed = not model_cls.CQRS_NO_DB_OPERATIONS
39+
if db_is_needed:
40+
close_old_connections()
3641

37-
if signal_type == SignalType.DELETE:
38-
with transaction.atomic(savepoint=False):
42+
with transaction.atomic(savepoint=False) if db_is_needed else ExitStack():
43+
if signal_type == SignalType.DELETE:
3944
return model_cls.cqrs_delete(instance_data)
4045

41-
elif signal_type == SignalType.SAVE:
42-
with transaction.atomic(savepoint=False):
46+
elif signal_type == SignalType.SAVE:
4347
return model_cls.cqrs_save(instance_data, previous_data=previous_data)
4448

45-
elif signal_type == SignalType.SYNC:
46-
with transaction.atomic(savepoint=False):
49+
elif signal_type == SignalType.SYNC:
4750
return model_cls.cqrs_save(
4851
instance_data,
4952
previous_data=previous_data,
5053
sync=True,
5154
)
52-
53-
else:
54-
logger.error('Bad signal type "{}" for CQRS_ID "{}".'.format(signal_type, cqrs_id))

dj_cqrs/mixins.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,9 @@ class ReplicaMixin(Model, metaclass=ReplicaMeta):
306306
CQRS_SELECT_FOR_UPDATE = False
307307
"""Set it to True to acquire lock on instance creation/update."""
308308

309+
CQRS_NO_DB_OPERATIONS = False
310+
"""Set it to True to disable any default DB operations for this model."""
311+
309312
objects = Manager()
310313

311314
cqrs = ReplicaManager()
@@ -328,6 +331,9 @@ def cqrs_save(cls, master_data, previous_data=None, sync=False):
328331
:return: Model instance.
329332
:rtype: django.db.models.Model
330333
"""
334+
if cls.CQRS_NO_DB_OPERATIONS:
335+
raise NotImplementedError
336+
331337
return cls.cqrs.save_instance(master_data, previous_data, sync)
332338

333339
@classmethod
@@ -367,4 +373,7 @@ def cqrs_delete(cls, master_data):
367373
:return: Flag, if delete operation is successful (even if nothing was deleted).
368374
:rtype: bool
369375
"""
376+
if cls.CQRS_NO_DB_OPERATIONS:
377+
raise NotImplementedError
378+
370379
return cls.cqrs.delete_instance(master_data)

tests/dj_replica/models.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ class LockModelRef(ReplicaMixin, models.Model):
5555
id = models.IntegerField(primary_key=True)
5656

5757

58+
class NoDBModelRef(ReplicaMixin):
59+
CQRS_ID = 'no_db'
60+
CQRS_NO_DB_OPERATIONS = True
61+
62+
id = models.IntegerField(primary_key=True)
63+
64+
class Meta:
65+
abstract = True
66+
67+
5868
class Event(models.Model):
5969
pid = models.IntegerField()
6070
cqrs_id = models.CharField(max_length=20)

tests/test_controller.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Copyright © 2020 Ingram Micro Inc. All rights reserved.
22

3-
from dj_cqrs.controller.consumer import consume
3+
import pytest
4+
5+
from dj_cqrs.constants import SignalType
6+
from dj_cqrs.controller.consumer import consume, route_signal_to_replica_model
47
from dj_cqrs.controller.producer import produce
58
from dj_cqrs.dataclasses import TransportPayload
69

@@ -24,3 +27,14 @@ def test_consumer(mocker):
2427
consume(TransportPayload('a', 'b', {}, 'c', previous_data={'e': 'f'}))
2528

2629
factory_mock.assert_called_once_with('a', 'b', {}, previous_data={'e': 'f'})
30+
31+
32+
@pytest.mark.django_db(transaction=True)
33+
def test_route_signal_to_replica_model_with_db(django_assert_num_queries):
34+
with django_assert_num_queries(1):
35+
route_signal_to_replica_model(SignalType.SAVE, 'lock', {})
36+
37+
38+
def test_route_signal_to_replica_model_without_db():
39+
with pytest.raises(NotImplementedError):
40+
route_signal_to_replica_model(SignalType.SAVE, 'no_db', {})

tests/test_replica/test_mixin.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,3 +485,12 @@ def test_select_for_update_lock(mocker):
485485

486486
assert instance.id == 1
487487
m.assert_called_once()
488+
489+
490+
@pytest.mark.django_db
491+
def test_nodb(mocker):
492+
with pytest.raises(NotImplementedError):
493+
models.NoDBModelRef.cqrs_save(None)
494+
495+
with pytest.raises(NotImplementedError):
496+
models.NoDBModelRef.cqrs_delete(None)

0 commit comments

Comments
 (0)