From 094fb7f0159db28fd3ccaef8a0c51fc6863b794c Mon Sep 17 00:00:00 2001
From: Pierre-Antoine Rouby <pierre-antoine.rouby@inrae.fr>
Date: Mon, 26 Jun 2023 17:33:50 +0200
Subject: [PATCH] Config: Switch save from pickle to sqlite.

---
 src/config.py | 202 ++++++++++++++++++++++++++++++++++++++++++++++----
 src/tools.py  |  33 +++++++++
 2 files changed, 220 insertions(+), 15 deletions(-)

diff --git a/src/config.py b/src/config.py
index f1db3b8c..f665a6ae 100644
--- a/src/config.py
+++ b/src/config.py
@@ -3,18 +3,199 @@
 import os
 import pickle
 
+from tools import SQL
+
+from Model.Stricklers.Stricklers import Stricklers
 from Model.Stricklers.StricklersList import StricklersList
 
+from Solver.Solvers import solver_type_list
+
 config_dir = "/.cache/pamhyr/"
-config_file = "config.pkl"
+config_file = "config.sqlite3"
 
-class Config(object):
+class Config(SQL):
     def __init__(self):
-        super(Config, self).__init__()
-
+        self._version = '0.0.1'
         self.filename = Config.filename()
         self.set_default_value()
 
+        super(Config, self).__init__(db = self.filename)
+
+    def _create(self):
+        cur = self._db.cursor()
+
+        # Info (meta data)
+        cur.execute("CREATE TABLE info(key TEXT NOT NULL UNIQUE, value TEXT NOT NULL)")
+        cur.execute(f"INSERT INTO info VALUES ('version', '{self._version}')")
+
+        # Key / Value (data)
+        cur.execute("CREATE TABLE data(key TEXT NOT NULL UNIQUE, value TEXT NOT NULL)")
+
+        # Solver
+        cur.execute("""
+           CREATE TABLE solver(
+             type TEXT NOT NULL,
+             name TEXT NOT NULL UNIQUE,
+             description TEXT NOT NULL,
+
+             path_input TEXT NOT NULL,
+             path_solver TEXT NOT NULL,
+             path_output TEXT NOT NULL,
+
+             cmd_input TEXT NOT NULL,
+             cmd_solver TEXT NOT NULL,
+             cmd_output TEXT NOT NULL
+           )
+           """)
+
+        # Stricklers
+        cur.execute("""
+           CREATE TABLE stricklers(
+             name TEXT NOT NULL UNIQUE,
+             comment TEXT NOT NULL,
+             minor REAL NOT NULL,
+             medium REAL NOT NULL
+           )
+           """)
+
+        self._db.commit()
+
+    def _update(self):
+        cur = self._db.cursor()
+        version = cur.execute(f"SELECT value FROM info WHERE key='version'")
+
+        if version.fetchone()[0] != self._version:
+            print("update")
+
+    def _load_solver(self):
+        cur = self._db.cursor()
+        self._solvers = []
+
+        solvers = cur.execute("SELECT * FROM solver")
+        for solver in solvers.fetchall():
+            solver_type = solver[0]
+            ctor = solver_type_list[solver_type]
+
+            new = ctor(solver[1])
+            new._description = solver[2]
+            new._path_input = solver[3]
+            new._path_solver = solver[4]
+            new._path_output = solver[5]
+            new._cmd_input = solver[6]
+            new._cmd_solver = solver[7]
+            new._cmd_output = solver[8]
+
+            self._solvers.append(new)
+
+    def _load_stricklers(self):
+        cur = self._db.cursor()
+        self.stricklers = StricklersList()
+
+        id = 0
+        stricklers = cur.execute("SELECT * FROM stricklers")
+        for strickler in stricklers.fetchall():
+            new = Stricklers()
+            new._name = strickler[0]
+            new._comment = strickler[1]
+            new._minor = float(strickler[2])
+            new._medium = float(strickler[3])
+
+            self.stricklers.insert(id, new)
+            id += 1
+
+    def _load(self):
+        cur = self._db.cursor()
+
+        # Meshing tool
+        v = cur.execute("SELECT value FROM data WHERE key='meshing_tool'")
+        self.meshing_tool = v.fetchone()[0]
+
+        # Const
+        v = cur.execute("SELECT value FROM data WHERE key='segment'")
+        self.segment = int(v.fetchone()[0])
+        v = cur.execute("SELECT value FROM data WHERE key='max_listing'")
+        self.max_listing = int(v.fetchone()[0])
+
+        # Backup
+        v = cur.execute("SELECT value FROM data WHERE key='backup_enable'")
+        self.backup_enable = v.fetchone()[0] == "True"
+        v = cur.execute("SELECT value FROM data WHERE key='backup_path'")
+        self.backup_path = v.fetchone()[0]
+        v = cur.execute("SELECT value FROM data WHERE key='backup_frequence'")
+        self.backup_frequence = v.fetchone()[0]
+        v = cur.execute("SELECT value FROM data WHERE key='backup_max'")
+        self.backup_max = int(v.fetchone()[0])
+
+        # Editor
+        v = cur.execute("SELECT value FROM data WHERE key='editor'")
+        self.editor = v.fetchone()[0]
+
+        # Languages
+        v = cur.execute("SELECT value FROM data WHERE key='lang'")
+        self.lang = v.fetchone()[0]
+
+        self._load_solver()
+        self._load_stricklers()
+
+    def _save_solver(self):
+        cur = self._db.cursor()
+        cur.execute(f"DELETE FROM solver")
+
+        for solver in self.solvers:
+            cur.execute(f"""
+              INSERT INTO solver VALUES (
+                '{solver._type}',
+                '{solver._name}',
+                '{solver._description}',
+                '{solver._path_input}',
+                '{solver._path_solver}',
+                '{solver._path_output}',
+                '{solver._cmd_input}',
+                '{solver._cmd_solver}',
+                '{solver._cmd_output}'
+              )
+            """)
+
+        self._db.commit()
+
+    def _save_stricklers(self):
+        cur = self._db.cursor()
+        cur.execute(f"DELETE FROM stricklers")
+
+        for stricklers in self.stricklers.stricklers:
+            cur.execute(f"""
+              INSERT INTO stricklers VALUES (
+                '{stricklers._name}',
+                '{stricklers._comment}',
+                '{stricklers._minor}',
+                '{stricklers._medium}'
+              )
+            """)
+
+        self._db.commit()
+
+    def _save(self):
+        cur = self._db.cursor()
+        data = {
+            "segment": self.segment,
+            "meshing_tool": self.meshing_tool,
+            "max_listing": self.max_listing,
+            "backup_enable": self.backup_enable,
+            "backup_path": self.backup_path,
+            "backup_frequence": self.backup_frequence,
+            "backup_max": self.backup_max,
+            "editor": self.editor,
+            "lang": self.lang,
+        }
+
+        for key in data:
+            cur.execute(f"INSERT OR IGNORE INTO data VALUES ('{key}', '{data[key]}')")
+            cur.execute(f"UPDATE data SET value='{data[key]}' WHERE key='{key}'")
+
+        self._db.commit()
+        self._save_solver()
+        self._save_stricklers()
+
     def set_default_value(self):
         # Solvers
         self._solvers = []
@@ -62,17 +243,8 @@ class Config(object):
         self._solvers = solvers
 
     def save(self):
-        os.makedirs(os.path.dirname(self.filename), exist_ok=True)
-        with open(self.filename, 'wb') as out_file:
-            pickle.dump(self, out_file)
+        self._save()
 
     @classmethod
     def load(cls):
-        filename = cls.filename()
-        if os.path.isfile(filename):
-            with open(filename, 'rb') as in_file:
-                me = pickle.load(in_file)
-                return me
-        else:
-            print("config: New config")
-            return cls()
+        return cls()
diff --git a/src/tools.py b/src/tools.py
index be41a5b3..858779fb 100644
--- a/src/tools.py
+++ b/src/tools.py
@@ -1,8 +1,11 @@
 # -*- coding: utf-8 -*-
 
 import time
+import sqlite3
 import traceback
 
+from pathlib import Path
+
 from colorama import Fore
 from colorama import Back
 from colorama import Style
@@ -153,3 +156,33 @@ def old_pamhyr_date_to_timestamp(date:str):
     )
 
     return ts
+
+#######
+# SQL #
+#######
+
+# This class is an abstract class to make class with save and load
+# from sqlite3.
+
+class SQL(object):
+    def __init__(self, db = "db.sqlite3"):
+        exists = Path(db).exists()
+        self._db = sqlite3.connect(db)
+        if not exists:
+            self._create()      # Create db
+            self._save()        # Save
+        else:
+            self._update()      # Update db scheme if necessary
+            self._load()        # Load data
+
+    def _create(self):
+        print("Create")
+
+    def _update(self):
+        print("Update")
+
+    def _save(self):
+        print("Save")
+
+    def _load(self):
+        print("Load")
-- 
GitLab