From 142cd2a9ff2602067eb887693606ad20b1f0b0c7 Mon Sep 17 00:00:00 2001
From: inso <insomniak.fr@gmaiL.com>
Date: Tue, 6 Sep 2016 23:14:41 +0200
Subject: [PATCH] Implement Meta DB

---
 src/sakia/data/entities/identity.py           |  4 --
 src/sakia/data/repositories/__init__.py       |  3 +-
 src/sakia/data/repositories/identities.py     | 34 ++-------
 src/sakia/data/repositories/meta.py           | 70 +++++++++++++++++++
 .../tests/unit/data/test_identies_repo.py     |  6 +-
 5 files changed, 83 insertions(+), 34 deletions(-)
 create mode 100644 src/sakia/data/repositories/meta.py

diff --git a/src/sakia/data/entities/identity.py b/src/sakia/data/entities/identity.py
index 3637edef..8fa1a565 100644
--- a/src/sakia/data/entities/identity.py
+++ b/src/sakia/data/entities/identity.py
@@ -13,7 +13,3 @@ class Identity:
     member = attr.ib(validator=attr.validators.instance_of(bool))
     membership_buid = attr.ib(convert=block_uid)
     membership_timestamp = attr.ib(convert=int)
-    
-    def astuple(self):
-        return (self.currency, self.pubkey, self.uid, self.signature, self.blockstamp, self.timestamp,
-         self.member, self.membership_buid, self.membership_timestamp)
\ No newline at end of file
diff --git a/src/sakia/data/repositories/__init__.py b/src/sakia/data/repositories/__init__.py
index 43de57a0..ea239c6e 100644
--- a/src/sakia/data/repositories/__init__.py
+++ b/src/sakia/data/repositories/__init__.py
@@ -1 +1,2 @@
-from .identities import IdentitiesRepo
\ No newline at end of file
+from .identities import IdentitiesRepo
+from .meta import MetaDatabase
\ No newline at end of file
diff --git a/src/sakia/data/repositories/identities.py b/src/sakia/data/repositories/identities.py
index 4df5b994..c9615450 100644
--- a/src/sakia/data/repositories/identities.py
+++ b/src/sakia/data/repositories/identities.py
@@ -1,32 +1,12 @@
-import sqlite3
+import attr
 from ..entities import Identity
 
 
+@attr.s
 class IdentitiesRepo:
-    def __init__(self, conn):
-        """
-        :param sqlite3.Connection conn: the cursor
-        """
-        self._conn = conn
-
-    def prepare(self):
-        """
-        Prepares the database if the table is missing
-        """
-        with self._conn:
-            self._conn.execute("create table if not exists identities("
-                               "CURRENCY varchar(30), "
-                               "PUBKEY varchar(50),"
-                               "UID varchar(255),"
-                               "SIGNATURE varchar(100),"
-                               "BLOCKSTAMP varchar(100),"
-                               "TS int,"
-                               "MEMBER boolean,"
-                               "MS_BUID varchar(100),"
-                               "MS_TIMESTAMP int,"
-                               "PRIMARY KEY (CURRENCY, PUBKEY)"
-                               ")"
-                               )
+    """The repository for Identities entities.
+    """
+    _conn = attr.ib()  # :type sqlite3.Connection
 
     def insert(self, identity):
         """
@@ -34,7 +14,7 @@ class IdentitiesRepo:
         :param sakia.data.entities.Identity identity: the identity to commit
         """
         with self._conn:
-            self._conn.execute("INSERT INTO identities VALUES (?,?,?,?,?,?,?,?,?)", identity.astuple())
+            self._conn.execute("INSERT INTO identities VALUES (?,?,?,?,?,?,?,?,?)", attr.astuple(identity))
 
     def update(self, identity):
         """
@@ -50,7 +30,7 @@ class IdentitiesRepo:
                               "MEMBER=?,"
                               "MS_BUID=?,"
                               "MS_TIMESTAMP=?"
-                              "WHERE CURRENCY=? AND PUBKEY=?", identity.astuple()[2:] + (identity.currency,
+                              "WHERE CURRENCY=? AND PUBKEY=?", attr.astuple(identity)[2:] + (identity.currency,
                                                                                          identity.pubkey)
                               )
 
diff --git a/src/sakia/data/repositories/meta.py b/src/sakia/data/repositories/meta.py
new file mode 100644
index 00000000..1d831c5c
--- /dev/null
+++ b/src/sakia/data/repositories/meta.py
@@ -0,0 +1,70 @@
+import attr
+from ..entities import Identity
+
+
+@attr.s(frozen=True)
+class MetaDatabase:
+    """The repository for Identities entities.
+    """
+
+    _conn = attr.ib()  # :type sqlite3.Connection
+
+    def prepare(self):
+        """
+        Prepares the database if the table is missing
+        """
+        with self._conn:
+            self._conn.execute("create table if not exists meta("
+                               "id integer not null,"
+                               "version integer not null,"
+                               "primary key (id)"
+                               ")"
+                               )
+
+    @property
+    def upgrades(self):
+        return [
+            self.create_all_tables,
+        ]
+
+    def upgrade_database(self):
+        """
+        Execute the migrations
+        """
+        version = self.version()
+        nb_versions = len(self.upgrades)
+        for v in range(version, nb_versions):
+            self.upgrades[v]()
+            with self._conn:
+                self._conn.execute("UPDATE meta SET version=? WHERE id=1", (version + 1,))
+
+    def create_all_tables(self):
+        """
+        Init all the tables
+        :return:
+        """
+        with self._conn:
+            self._conn.execute("create table if not exists identities("
+                               "CURRENCY varchar(30), "
+                               "PUBKEY varchar(50),"
+                               "UID varchar(255),"
+                               "SIGNATURE varchar(100),"
+                               "BLOCKSTAMP varchar(100),"
+                               "TS int,"
+                               "MEMBER boolean,"
+                               "MS_BUID varchar(100),"
+                               "MS_TIMESTAMP int,"
+                               "PRIMARY KEY (CURRENCY, PUBKEY)"
+                               ")"
+                               )
+
+    def version(self):
+        with self._conn:
+            c = self._conn.execute("SELECT * FROM meta WHERE id=1")
+            data = c.fetchone()
+            if data:
+                return data[1]
+            else:
+                self._conn.execute("INSERT INTO meta VALUES (1, 0)")
+                return 0
+
diff --git a/src/sakia/tests/unit/data/test_identies_repo.py b/src/sakia/tests/unit/data/test_identies_repo.py
index 68bc58e1..c33059fd 100644
--- a/src/sakia/tests/unit/data/test_identies_repo.py
+++ b/src/sakia/tests/unit/data/test_identies_repo.py
@@ -1,4 +1,4 @@
-from sakia.data.repositories import IdentitiesRepo
+from sakia.data.repositories import IdentitiesRepo, MetaDatabase
 from sakia.data.entities import Identity
 from duniterpy.documents import BlockUID
 import unittest
@@ -16,8 +16,10 @@ class TestIdentitiesRepo(unittest.TestCase):
         self.con.close()
 
     def test_add_get_identity(self):
+        meta_repo = MetaDatabase(self.con)
+        meta_repo.prepare()
+        meta_repo.upgrade_database()
         identities_repo = IdentitiesRepo(self.con)
-        identities_repo.prepare()
         identities_repo.insert(Identity("testcurrency", "7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ",
                                         "john",
                                         "H41/8OGV2W4CLKbE35kk5t1HJQsb3jEM0/QGLUf80CwJvGZf3HvVCcNtHPUFoUBKEDQO9mPK3KJkqOoxHpqHCw==",
-- 
GitLab