diff options
-rw-r--r-- | backends/couch.py (renamed from backends/couchdb.py) | 52 | ||||
-rw-r--r-- | backends/leap.py | 1 | ||||
-rw-r--r-- | backends/objectstore.py | 43 | ||||
-rw-r--r-- | backends/openstack.py | 2 | ||||
-rw-r--r-- | tests/test_couchdb.py | 19 |
5 files changed, 80 insertions, 37 deletions
diff --git a/backends/couchdb.py b/backends/couch.py index 89b713f9..5586ea9c 100644 --- a/backends/couchdb.py +++ b/backends/couch.py @@ -1,7 +1,9 @@ from u1db import errors from u1db.remote.http_target import HTTPSyncTarget -from couchdb import * +from couchdb.client import Server, Document +from couchdb.http import ResourceNotFound from soledad.backends.objectstore import ObjectStore +from soledad.backends.leap import LeapDocument class CouchDatabase(ObjectStore): @@ -12,13 +14,18 @@ class CouchDatabase(ObjectStore): self._url = url self._full_commit = full_commit self._session = session - self._server = couchdb.Server(url=self._url, - full_commit=self._full_commit, - session=self._session) + self._server = Server(url=self._url, + full_commit=self._full_commit, + session=self._session) # this will ensure that transaction and sync logs exist and are # up-to-date. - super(CouchDatabase, self) - self._database = self._server[database] + self.set_document_factory(LeapDocument) + try: + self._database = self._server[database] + except ResourceNotFound: + self._server.create(database) + self._database = self._server[database] + super(CouchDatabase, self).__init__() #------------------------------------------------------------------------- # implemented methods from Database @@ -31,13 +38,14 @@ class CouchDatabase(ObjectStore): for them. """ cdoc = self._database.get(doc_id) - if cdoc is not None: - content = {} - for key, value in content: - if not key in ['_id', '_rev', '_u1db_rev']: - content[key] = value - doc = self._factory(doc_id=doc_id, rev=cdoc['_u1db_rev']) - doc.content = content + if cdoc is None: + return None + content = {} + for (key, value) in cdoc.items(): + if key not in ['_id', '_rev', 'u1db_rev']: + content[key] = value + doc = self._factory(doc_id=doc_id, rev=cdoc['u1db_rev']) + doc.content = content return doc def get_all_docs(self, include_deleted=False): @@ -51,12 +59,15 @@ class CouchDatabase(ObjectStore): results.append(doc) return (generation, results) - def _put_doc(self, doc, new_rev): + def _put_doc(self, doc): # map u1db metadata to couch content = doc.content - content['_id'] = doc.doc_id - content['_u1db_rev'] = new_rev - self._database.save(doc.content) + cdoc = Document() + cdoc['_id'] = doc.doc_id + cdoc['u1db_rev'] = doc.rev + for (key, value) in content.items(): + cdoc[key] = value + self._database.save(cdoc) def get_sync_target(self): return CouchSyncTarget(self) @@ -70,6 +81,13 @@ class CouchDatabase(ObjectStore): return Synchronizer(self, CouchSyncTarget(url, creds=creds)).sync( autocreate=autocreate) + def _get_u1db_data(self): + cdoc = self._database.get(self.U1DB_DATA_DOC_ID) + self._sync_log.log = cdoc['sync_log'] + self._transaction_log.log = cdoc['transaction_log'] + self._replica_uid = cdoc['replica_uid'] + self._couch_rev = cdoc['_rev'] + #------------------------------------------------------------------------- # Couch specific methods #------------------------------------------------------------------------- diff --git a/backends/leap.py b/backends/leap.py index 2c815632..ce00c8f3 100644 --- a/backends/leap.py +++ b/backends/leap.py @@ -7,6 +7,7 @@ from u1db import Document from u1db.remote.http_target import HTTPSyncTarget from u1db.remote.http_database import HTTPDatabase import base64 +from soledad import GPGWrapper class NoDefaultKey(Exception): diff --git a/backends/objectstore.py b/backends/objectstore.py index d9ab7cbd..5bd864c8 100644 --- a/backends/objectstore.py +++ b/backends/objectstore.py @@ -1,5 +1,7 @@ +import uuid from u1db.backends import CommonBackend from soledad import SyncLog, TransactionLog +from soledad.backends.leap import LeapDocument class ObjectStore(CommonBackend): @@ -45,15 +47,14 @@ class ObjectStore(CommonBackend): self._check_doc_id(doc.doc_id) self._check_doc_size(doc) # put the document - new_rev = self._allocate_doc_rev(doc.rev) - self._put_doc(doc, new_rev) - doc.rev = new_rev + doc.rev = self._allocate_doc_rev(doc.rev) + self._put_doc(doc) # update u1db generation and logs new_gen = self._get_generation() + 1 trans_id = self._allocate_transaction_id() self._transaction_log.append((new_gen, doc.doc_id, trans_id)) self._set_u1db_data() - return new_rev + return doc.rev def delete_doc(self, doc): old_doc = self._get_doc(doc.doc_id, check_for_conflicts=True) @@ -145,15 +146,16 @@ class ObjectStore(CommonBackend): """ if not self._is_initialized(): self._initialize() - u1db_data = self._get_doc('u1db_data') - self._sync_log.log = u1db_data.content['sync_log'] - self._transaction_log.log = u1db_data.content['transaction_log'] + self._get_u1db_data() + + U1DB_DATA_DOC_ID = 'u1db_data' def _is_initialized(self): """ Verify if u1db data exists in store. """ - if not self._get_doc('u1db_data'): + doc = self._get_doc(self.U1DB_DATA_DOC_ID) + if not self._get_doc(self.U1DB_DATA_DOC_ID): return False return True @@ -161,19 +163,22 @@ class ObjectStore(CommonBackend): """ Create u1db data object in store. """ - content = { 'transaction_log' : [], - 'sync_log' : [] } - doc = self.create_doc('u1db_data', content) + self._replica_uid = uuid.uuid4().hex + doc = self._factory(doc_id=self.U1DB_DATA_DOC_ID) + doc.content = { 'transaction_log' : [], + 'sync_log' : [], + 'replica_uid' : self._replica_uid } + self._put_doc(doc) - def _get_u1db_data(self): - data = self.get_doc('u1db_data').content - self._transaction_log = data['transaction_log'] - self._sync_log = data['sync_log'] + def _get_u1db_data(self, u1db_data_doc_id): + NotImplementedError(self._get_u1db_data) def _set_u1db_data(self): - doc = self._factory('u1db_data') - doc.content = { 'transaction_log' : self._transaction_log, - 'sync_log' : self._sync_log } - self.put_doc(doc) + doc = self._factory(doc_id=self.U1DB_DATA_DOC_ID) + doc.content = { 'transaction_log' : self._transaction_log.log, + 'sync_log' : self._sync_log.log, + 'replica_uid' : self._replica_uid, + '_rev' : self._couch_rev} + self._put_doc(doc) diff --git a/backends/openstack.py b/backends/openstack.py index 5f2a2771..c027231c 100644 --- a/backends/openstack.py +++ b/backends/openstack.py @@ -17,7 +17,7 @@ class OpenStackDatabase(ObjectStore): self._auth_key) self._get_auth() # this will ensure transaction and sync logs exist and are up-to-date. - super(OpenStackDatabase, self) + super(OpenStackDatabase, self).__init__() #------------------------------------------------------------------------- # implemented methods from Database diff --git a/tests/test_couchdb.py b/tests/test_couchdb.py new file mode 100644 index 00000000..58285086 --- /dev/null +++ b/tests/test_couchdb.py @@ -0,0 +1,19 @@ +import unittest +from soledad.backends.couch import CouchDatabase + +class CouchTestCase(unittest.TestCase): + + def setUp(self): + self._db = CouchDatabase('http://localhost:5984', 'u1db_tests') + + def test_create_get(self): + doc1 = self._db.create_doc({"key": "value"}, doc_id="testdoc") + doc2 = self._db.get_doc('testdoc') + self.assertEqual(doc1, doc2, 'error storing/retrieving document.') + self.assertEqual(self._db._get_generation(), 1) + + def tearDown(self): + self._db._server.delete('u1db_tests') + +if __name__ == '__main__': + unittest.main() |