full namespace support
3 files changed, 31 insertions(+), 32 deletions(-)

M dbcache/api.py
M test/conftest.py
M test/test_cache.py
M dbcache/api.py +18 -19
@@ 7,27 7,32 @@ import pytz
 
 
 class dbcache:
+    __slots__ = ('ns', 'engine')
 
-    def __init__(self, uri):
+    def __init__(self, uri, namespace='cache'):
         self.engine = create_engine(uri)
+        self.ns = namespace
 
     def _remove_expired(self, cn):
         cn.execute(
-            'delete from cache.things '
-            'where idate + validity < now()'
+            f'delete from "{self.ns}".things '
+            f'where idate + validity < now()'
+        )
+
+    def _txlock(self, cn, key):
+        lockid = hash(key + self.ns.encode('utf-8'))
+        cn.execute(
+            f'select pg_advisory_xact_lock({lockid})'
         )
 
     def get(self, key):
         with self.engine.begin() as cn:
-            lockid = hash(key)
-            cn.execute(
-                f'select pg_advisory_xact_lock({lockid})'
-            )
+            self._txlock(cn, key)
             self._remove_expired(cn)
             q = select(
                 'value'
             ).table(
-                'cache.things'
+                f'{self.ns}.things'
             ).where(
                 key=sha1(key).hexdigest()
             )

          
@@ 37,7 42,7 @@ class dbcache:
 
     def _set(self, cn, hkey, value, lifetime):
         sql = (
-            'insert into cache.things (key, value, validity) '
+            f'insert into {self.ns}.things (key, value, validity) '
             'values (%(key)s, %(value)s, %(validity)s) '
             'on conflict (key) do update set '
             ' value = %(value)s, '

          
@@ 54,10 59,7 @@ class dbcache:
 
     def set(self, key, value, lifetime=timedelta(minutes=10)):
         with self.engine.begin() as cn:
-            lockid = hash(key)
-            cn.execute(
-                f'select pg_advisory_xact_lock({lockid})'
-            )
+            self._txlock(cn, key)
             self._remove_expired(cn)
             hkey = sha1(key).hexdigest()
             self._set(cn, hkey, value, lifetime)

          
@@ 65,16 67,13 @@ class dbcache:
     def getorset(self, key, valuemaker, lifetime=timedelta(minutes=10)):
         assert callable(valuemaker)
         with self.engine.begin() as cn:
-            lockid = hash(key)
+            self._txlock(cn, key)
+            self._remove_expired(cn)
             hkey = sha1(key).hexdigest()
-            cn.execute(
-                f'select pg_advisory_xact_lock({lockid})'
-            )
-            self._remove_expired(cn)
             q = select(
                 'value'
             ).table(
-                'cache.things'
+                f'{self.ns}.things'
             ).where(
                 key=hkey
             )

          
M test/conftest.py +10 -4
@@ 5,17 5,23 @@ from sqlalchemy import create_engine
 from pytest_sa_pg import db
 
 from dbcache import schema
+from dbcache.api import dbcache
 
 
 DATADIR = Path(__file__).parent / 'data'
 PORT = 2346
 
-@pytest.fixture(scope='session')
-def dburi(request):
+
+@pytest.fixture(
+    scope='session',
+    params=('cache', 'fancyns')
+)
+def cache(request):
     db.setup_local_pg_cluster(request, DATADIR, PORT, {
         'timezone': 'UTC',
         'log_timezone': 'UTC'
     })
+    ns = request.param
     e = create_engine('postgresql://localhost:{}/postgres'.format(PORT))
-    schema.init(e, drop=True)
-    return e.url
+    schema.init(e, ns=ns, drop=True)
+    yield dbcache(e.url, ns)

          
M test/test_cache.py +3 -9
@@ 5,9 5,7 @@ import pickle
 from dbcache.api import dbcache
 
 
-def test_cache(dburi):
-    cache = dbcache(dburi)
-
+def test_cache(cache):
     assert cache.get(b'a') is None
     cache.set(b'a', b'aaa')
     assert cache.get(b'a') == b'aaa'

          
@@ 15,18 13,14 @@ def test_cache(dburi):
     assert cache.get(b'a') == b'newvalue'
 
 
-def test_invalidation(dburi):
-    cache = dbcache(dburi)
-
+def test_invalidation(cache):
     cache.set(b'b', b'bbb', lifetime=timedelta(seconds=1))
     assert cache.get(b'b') == b'bbb'
     sleep(1)
     assert cache.get(b'b') is None
 
 
-def test_getorset(dburi):
-    cache = dbcache(dburi)
-
+def test_getorset(cache):
     def stuff(x):
         return x