Skip to content

Commit

Permalink
Updated sqla to handle conflicting keys when inserting.
Browse files Browse the repository at this point in the history
  • Loading branch information
mmerickel committed Mar 16, 2012
1 parent c9eba8b commit e98075a
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 14 deletions.
11 changes: 9 additions & 2 deletions anykeystore/backends/sqla.py
Expand Up @@ -81,14 +81,21 @@ def retrieve(self, key):
c.close()
raise KeyError

def _insert_or_replace(self, c, key, value, expires):
try:
c.execute(
self.table.insert(), key=key, value=value, expires=expires)
except self.backend_api.exc.IntegrityError:
c.execute(
self.table.update(), key=key, value=value, expires=expires)

def store(self, key, value, expires=None):
expiration = None
if expires is not None:
expiration = datetime.utcnow() + coerce_timedelta(expires)
c = self._get_conn()
try:
c.execute(
self.table.insert(), key=key, value=value, expires=expiration)
self._insert_or_replace(c, key, value, expiration)
finally:
c.close()

Expand Down
66 changes: 54 additions & 12 deletions anykeystore/tests/test_backends/test_sqla.py
@@ -1,34 +1,76 @@
import unittest2 as unittest
from mock import MagicMock
from mock import MagicMock, patch

class TestSQLStore(unittest.TestCase):

def _getTargetClass(self):
from anykeystore.backends.sqla import SQLStore
return SQLStore

def _makeApi(self):
api = MagicMock(spec=[
'engine_from_config', 'MetaData',
'select', 'insert', 'delete'])
return api

def test_init_with_table(self):
cls = self._getTargetClass()
api = MagicMock(spec=['engine_from_config'])
api = self._makeApi()
result = cls('myurl', table='foo', backend_api=api)
self.assertEqual(result.table, 'foo')

def test_init_with_table_name(self):
cls = self._getTargetClass()
cls._make_table = MagicMock(return_value='some_table')
api = MagicMock(spec=['engine_from_config', 'MetaData'])
api = self._makeApi()
api.MetaData.return_value = 'a_meta'
result = cls(
'myurl', table_name='foo', backend_api=api)
with patch.object(cls, '_make_table') as _make_table:
_make_table.return_value = 'some_table'
result = cls(
'myurl', table_name='foo', backend_api=api)
self.assertEqual(result.table, 'some_table')
cls._make_table.assert_called_with('foo', 'a_meta')
_make_table.assert_called_with('foo', 'a_meta')

def test_init_with_table_name_and_metadata(self):
cls = self._getTargetClass()
cls._make_table = MagicMock(return_value='some_table')
api = MagicMock(spec=['engine_from_config', 'MetaData'])
api = self._makeApi()
api.MetaData.return_value = 'a_meta'
result = cls(
'myurl', table_name='foo', metadata='b_meta', backend_api=api)
with patch.object(cls, '_make_table') as _make_table:
_make_table.return_value = 'some_table'
result = cls(
'myurl', table_name='foo', metadata='b_meta', backend_api=api)
self.assertEqual(result.table, 'some_table')
cls._make_table.assert_called_with('foo', 'b_meta')
_make_table.assert_called_with('foo', 'b_meta')

def test__get_conn(self):
cls = self._getTargetClass()
api = self._makeApi()
engine = MagicMock()
engine.connect.return_value = 'myconn'
api.engine_from_config.return_value = engine
table = MagicMock()
store = cls('myurl', table=table, backend_api=api)
result = store._get_conn()
self.assertEqual(result, 'myconn')
self.assertTrue(store._created)
self.assertEqual(table.create.call_count, 1)
self.assertEqual(engine.connect.call_count, 1)

result = store._get_conn()
self.assertEqual(result, 'myconn')
self.assertEqual(table.create.call_count, 1)
self.assertEqual(engine.connect.call_count, 2)

def test_retrieve(self):
cls = self._getTargetClass()
api = self._makeApi()
table = MagicMock()
store = cls('myurl', table=table, backend_api=api)
with patch.object(store, '_get_conn') as get_conn:
get_conn.return_value = conn = MagicMock()

conn.execute.return_value.fetchone.return_value = ('bar', None)
result = store.retrieve('foo')
self.assertEqual(result, 'bar')

conn.execute.return_value.fetchone.return_value = None
self.assertRaises(KeyError, store.retrieve, 'foo')

0 comments on commit e98075a

Please sign in to comment.