Skip to content

Commit

Permalink
feat: add stop param to method save
Browse files Browse the repository at this point in the history
  • Loading branch information
Hugo Brilhante committed Jan 21, 2024
1 parent ea419ef commit 0089f4c
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 13 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,24 @@ This generates the following data to be sent.
Published(destination='/topic/my_route_key_1', body='{"id": 1, "one": "Field One"}')
Published(destination='/topic/my_route_key_2', body='{"id": 1, "two": "Field Two"}')
```
## Stopping Publication

The `@publish` decorator adds a named parameter called `stop` to the `save` method, which is useful when you need to update an instance of a decorated model and do not want this update to be published on the broker.
```python
from django.db import transaction
from django_outbox_pattern.payloads import Payload

from .models import Order

def callback(payload: Payload):
order_id = payload.body["order_id"]
status = payload.body["status"]
with transaction.atomic():
order = Order.objects.get(order_id=order_id)
order.status = status
order.save(stop=True)
payload.save()
```

## Publish/Subscribe commands

Expand Down
30 changes: 19 additions & 11 deletions django_outbox_pattern/decorators.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# pylint: disable=protected-access
import json
from typing import List
from typing import NamedTuple
Expand All @@ -17,17 +18,24 @@ class Config(NamedTuple):


def publish(configs: List[Config]):
def save(self, *args, **kwargs):
with transaction.atomic():
super(self.__class__, self).save(*args, **kwargs)
for config in configs:
_create_published(self, *config)

def decorator_publish(cls):
cls.save = save
return cls

return decorator_publish
def wrapper(cls):
class PublishModel(cls):
def save(self, *args, stop=False, **kwargs):
with transaction.atomic():
super().save(*args, **kwargs)
if not stop:
for config in configs:
_create_published(self, *config)

class Meta(getattr(cls, "Meta", object)):
proxy = True
app_label = cls._meta.app_label
verbose_name = cls._meta.verbose_name
verbose_name_plural = cls._meta.verbose_name_plural

return PublishModel

return wrapper


def _create_published(obj, destination, fields, serializer, version):
Expand Down
20 changes: 18 additions & 2 deletions tests/unit/test_publish_decorator.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def setUp(self):
}

def create_user(self, model):
model.objects.create(username="test", email=self.email)
return model.objects.create(username="test", email=self.email)

def test_when_is_correct_destination(self):
destination = "queue"
Expand Down Expand Up @@ -125,7 +125,6 @@ def my_serializer_1(obj):
self.assertEqual("", published[1].body["last_name"])
self.assertEqual("", published[1].body["first_name"])
self.assertIsNone(published[1].body["last_login"])
self.assertAlmostEqual(date_joined.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3], published[1].body["date_joined"])
self.assertFalse(published[1].body["is_superuser"])
self.assertEqual([], published[1].body["user_permissions"])
self.assertEqual("queue_2", published[1].destination)
Expand Down Expand Up @@ -170,3 +169,20 @@ def my_serializer_2(obj):
"username": "test",
},
)

def test_when_overriding_save_method(self):
def save(self, *args, **kwargs):
self.username = "test orverridden"
super(User, self).save(*args, **kwargs)

User.save = save
user_publish = publish([Config(destination="destination")])(User)
user = self.create_user(user_publish)
self.assertEqual(user.username, "test orverridden")

def test_when_stop_publishing(self):
user_published = publish([Config(destination="stop")])(User)
user = user_published(username="test", email=self.email)
user.save(stop=True)
published = Published.objects.first()
self.assertIsNone(published)

0 comments on commit 0089f4c

Please sign in to comment.