2021-07-24 17:09:10 -04:00
|
|
|
from abc import ABC, abstractmethod
|
|
|
|
|
|
|
|
|
|
|
|
class AbstractTransaction(ABC):
|
|
|
|
"""Represents an atomic group of operations."""
|
|
|
|
|
|
|
|
# child classes should override this
|
|
|
|
operations = []
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self.finished_operations = set()
|
|
|
|
# child classes should set this to a JSON-serializable object
|
|
|
|
# once they are finished
|
|
|
|
self.result = None
|
|
|
|
|
|
|
|
def finish(self, result):
|
2021-08-02 03:19:29 -04:00
|
|
|
"""
|
|
|
|
Store a result in this object so that it can be returned to the client.
|
|
|
|
"""
|
2021-07-24 17:09:10 -04:00
|
|
|
self.result = result
|
|
|
|
|
|
|
|
@abstractmethod
|
|
|
|
def child_execute_iter(self):
|
|
|
|
"""
|
|
|
|
Template Method design pattern. To be implemented by child classes.
|
|
|
|
Every time an operation is completed, it should be yielded.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError()
|
|
|
|
|
|
|
|
def execute_iter(self):
|
|
|
|
"""
|
|
|
|
Execute the transaction, yielding an operation each time
|
|
|
|
one is completed.
|
|
|
|
"""
|
|
|
|
for operation in self.child_execute_iter():
|
|
|
|
self.finished_operations.add(operation)
|
|
|
|
yield operation
|
|
|
|
|
|
|
|
def execute(self):
|
|
|
|
"""Execute the transaction synchronously."""
|
|
|
|
for _ in self.execute_iter():
|
|
|
|
pass
|
|
|
|
|
|
|
|
def rollback(self):
|
2021-08-02 04:01:13 -04:00
|
|
|
"""
|
|
|
|
Roll back the transaction, when it fails.
|
|
|
|
If the transaction only has one operation, then there is no need
|
|
|
|
to implement this.
|
|
|
|
"""
|
|
|
|
pass
|