Commits

Andriy Kornatskyy  committed 1363fb1

Added 'get or set/add' cache patterns.

  • Participants
  • Parent commits ae4ac41

Comments (0)

Files changed (2)

File src/wheezy/caching/patterns.py

 from time import time
 
 
+def get_or_add(key, create_factory, dependency_factory=None,
+               time=0, namespace=None, cache=None):
+    """ Cache Pattern: get an item by *key* from *cache* and
+        if it is not available use *create_factory* to aquire one.
+        If result is not `None` use cache `add` operation to store
+        result and if operation succeed use *dependency_factory*
+        to get an instance of `CacheDependency` to add *key* to it.
+    """
+    result = cache.get(key, namespace)
+    if result is not None:
+        return result
+    result = create_factory()
+    if result is not None:
+        succeed = cache.add(key, result, time, namespace)
+        if succeed and dependency_factory is not None:
+            dependency = dependency_factory()
+            dependency.add(key, namespace)
+    return result
+
+
+def get_or_set(key, create_factory, dependency_factory=None,
+               time=0, namespace=None, cache=None):
+    """ Cache Pattern: get an item by *key* from *cache* and
+        if it is not available use *create_factory* to aquire one.
+        If result is not `None` use cache `set` operation to store
+        result and use *dependency_factory* to get an instance of
+        `CacheDependency` to add *key* to it.
+    """
+    result = cache.get(key, namespace)
+    if result is not None:
+        return result
+    result = create_factory()
+    if result is not None:
+        cache.set(key, result, time, namespace)
+        if dependency_factory is not None:
+            dependency = dependency_factory()
+            dependency.add(key, namespace)
+    return result
+
+
 class OnePass(object):
     """ A solution to `Thundering Head` problem.
 

File src/wheezy/caching/tests/test_patterns.py

         assert not self.one_pass.acquired
         self.mock_cache.get.return_value = 1
         assert False == self.one_pass.wait()
+
+
+class GetOrAddTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.mock_cache = Mock()
+        self.mock_create_factory = Mock()
+
+    def get_or_add(self, dependency_factory=None):
+        from wheezy.caching.patterns import get_or_add as ga
+        return ga('key', self.mock_create_factory, dependency_factory,
+                  10, 'ns', self.mock_cache)
+
+    def test_found(self):
+        """ An item found in cache.
+        """
+        self.mock_cache.get.return_value = 'x'
+        assert 'x' == self.get_or_add()
+        self.mock_cache.get.assert_called_once_with('key', 'ns')
+        assert not self.mock_create_factory.called
+
+    def test_create_none(self):
+        """ Create factory returned None.
+        """
+        self.mock_cache.get.return_value = None
+        self.mock_create_factory.return_value = None
+
+        assert not self.get_or_add()
+        self.mock_cache.get.assert_called_once_with('key', 'ns')
+        self.mock_create_factory.assert_called_once_with()
+        assert not self.mock_cache.add.called
+
+    def test_add_failed(self):
+        """ Attempt to add a value to cache failed.
+        """
+        self.mock_cache.get.return_value = None
+        self.mock_create_factory.return_value = 'x'
+        self.mock_cache.add.return_value = False
+
+        assert 'x' == self.get_or_add()
+        self.mock_cache.get.assert_called_once_with('key', 'ns')
+        self.mock_cache.add.assert_called_once_with('key', 'x', 10, 'ns')
+
+    def test_has_dependency(self):
+        """ There is specified `dependency_factory`.
+        """
+        self.mock_cache.get.return_value = None
+        self.mock_create_factory.return_value = 'x'
+        self.mock_cache.add.return_value = True
+        mock_dependency_factory = Mock()
+
+        assert 'x' == self.get_or_add(mock_dependency_factory)
+        self.mock_cache.get.assert_called_once_with('key', 'ns')
+        self.mock_cache.add.assert_called_once_with('key', 'x', 10, 'ns')
+        mock_dependency_factory.return_value.add.assert_called_once_with(
+            'key', 'ns')
+
+
+class GetOrSetTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.mock_cache = Mock()
+        self.mock_create_factory = Mock()
+
+    def get_or_set(self, dependency_factory=None):
+        from wheezy.caching.patterns import get_or_set as gs
+        return gs('key', self.mock_create_factory, dependency_factory,
+                  10, 'ns', self.mock_cache)
+
+    def test_found(self):
+        """ An item found in cache.
+        """
+        self.mock_cache.get.return_value = 'x'
+        assert 'x' == self.get_or_set()
+        self.mock_cache.get.assert_called_once_with('key', 'ns')
+        assert not self.mock_create_factory.called
+
+    def test_create_none(self):
+        """ Create factory returned None.
+        """
+        self.mock_cache.get.return_value = None
+        self.mock_create_factory.return_value = None
+
+        assert not self.get_or_set()
+        self.mock_cache.get.assert_called_once_with('key', 'ns')
+        self.mock_create_factory.assert_called_once_with()
+        assert not self.mock_cache.add.called
+
+    def test_has_dependency(self):
+        """ There is specified `dependency_factory`.
+        """
+        self.mock_cache.get.return_value = None
+        self.mock_create_factory.return_value = 'x'
+        self.mock_cache.set.return_value = True
+        mock_dependency_factory = Mock()
+
+        assert 'x' == self.get_or_set(mock_dependency_factory)
+        self.mock_cache.get.assert_called_once_with('key', 'ns')
+        self.mock_cache.set.assert_called_once_with('key', 'x', 10, 'ns')
+        mock_dependency_factory.return_value.add.assert_called_once_with(
+            'key', 'ns')