diff --git a/soitool/database.py b/soitool/database.py index cc0c69d8655e819c504d083de14bca65daf7a5b1..45d04f94db6e9c8e09ac015b4fe809aa7d398991 100644 --- a/soitool/database.py +++ b/soitool/database.py @@ -5,6 +5,8 @@ import json from datetime import datetime import soitool.coder from soitool.enumerates import CodebookSort +from soitool.serialize_export_import_soi import serialize_soi +from soitool.compressor import compress # Set name and path to default (future) database DBNAME = "database" @@ -15,6 +17,7 @@ DBPATH = os.path.join(CURDIR, DBNAME) SECONDS_IN_24H = 24 * 60 * 60 # DDL-statements for creating tables +SOI = "CREATE TABLE SOI(Title VARCHAR PRIMARY KEY, SOI TEXT, Date DATETIME)" CODEBOOK = ( "CREATE TABLE CodeBook(" "Word VARCHAR PRIMARY KEY NOT NULL CHECK(length(Word) > 0), " @@ -66,7 +69,7 @@ class Database: def create_tables(self): """Create tables CodeBook, CategoryWords and ByHeart.""" - stmts = [CODEBOOK, CATEGORYWORDS, BYHEART, LASTUPDATED] + stmts = [SOI, CODEBOOK, CATEGORYWORDS, BYHEART, LASTUPDATED] for stmt in stmts: self.conn.execute(stmt) @@ -337,3 +340,31 @@ class Database: stmt = "UPDATE CodeBook SET Code = ? WHERE Word = ?" self.conn.execute(stmt, (code, word)) self.conn.commit() + + def insert_soi(self, soi): + """Serialize, compress and insert SOI into database-table SOI. + + If one or more SOI's with the same title exists in db, (1), (2), ... + is added to the Title-column of the SOI to insert. + + Parameters + ---------- + soi : soitool.soi.SOI + The SOI-instance to insert into database. + """ + title = soi.title + date = datetime.now().strftime("%Y-%m-%d") + serialized_soi = serialize_soi(soi) + compressed_soi = compress(serialized_soi) + + # Count SOI's with equal title + length = len(title) + stmt = "SELECT COUNT(*) FROM SOI WHERE substr(Title,0,?)=?" + count = self.conn.execute(stmt, (length + 1, title)).fetchone()[0] + # Add '(x)' to title if SOI with equal title exists + if count > 0: + title += "(" + str(count + 1) + ")" + + stmt = "INSERT INTO SOI (Title, SOI, Date) VALUES(?,?,?)" + self.conn.execute(stmt, (title, compressed_soi, date)) + self.conn.commit() diff --git a/soitool/main_window.py b/soitool/main_window.py index 4cd761f9badc0f5a0e76a6449a85dbfc044cc163..555948fbd0de22374224d799eb81c6a347d34641 100644 --- a/soitool/main_window.py +++ b/soitool/main_window.py @@ -6,6 +6,7 @@ import sys import os from enum import Enum from functools import partial +from sqlite3 import IntegrityError from PySide2.QtWidgets import ( QTabWidget, QMainWindow, @@ -26,6 +27,7 @@ from soitool.serialize_export_import_soi import ( export_soi, import_soi, ) +from soitool.compressor import compress class ModuleType(Enum): @@ -118,6 +120,7 @@ class MainWindow(QMainWindow): save_soi = QAction("Lagre i DB", self) save_soi.setShortcut("Ctrl+s") save_soi.setStatusTip("Lagre SOI i databasen") + save_soi.triggered.connect(self.save_soi_db) file_menu.addAction(save_soi) # Export SOI @@ -276,6 +279,20 @@ class MainWindow(QMainWindow): else: regenerate() + def save_soi_db(self): + """Save the SOI of the current tab in the database.""" + tab_widget = self.tabs.currentWidget() + + # If tab contains an SOI + if isinstance(tab_widget, SOIWorkspaceWidget): + self.database.insert_soi(tab_widget.soi) + else: + exec_info_dialog( + "Valgt tab er ingen SOI-tab", + "Den valgte taben inneholder ingen SOI.\n" + "Riktig tab må velges for å lagre en SOI i DB.", + ) + def open_shortcut_help(self): """Open shortcut dialog.""" self.popup_shortcut_help.setWindowTitle("Hurtigtaster") diff --git a/test/test_database.py b/test/test_database.py index b34691a32c49a5def6548e6925cd1b4f71e3cf12..848cdd620c1029b9b85c1e11e4df8493a1dbdbbd 100644 --- a/test/test_database.py +++ b/test/test_database.py @@ -6,6 +6,7 @@ import json from time import sleep from datetime import datetime from soitool.database import Database +from soitool.soi import SOI from soitool.coder import get_code_length_needed TESTDBNAME = "testDatabase" @@ -293,6 +294,31 @@ class DatabaseTest(unittest.TestCase): ] self.assertRegex(code, "[A-Z0-9]") + def test_insert_soi(self): + """Test inserting an SOI to SOI-table.""" + test_title = "TestTitle" + test_date = datetime.now().strftime("%Y-%m-%d") + # Create and insert SOI + soi = SOI(title=test_title, date=test_date) + self.database.insert_soi(soi) + + # Assert only one SOI is in table + stmt = "SELECT * FROM SOI" + queried = self.database.conn.execute(stmt).fetchall() + self.assertEqual(len(queried), 1) + + # Assert SOI was written correctly + self.assertEqual(queried[0]["Title"], test_title) + self.assertEqual(queried[0]["Date"], test_date) + + # Insert same SOI again and assert '(2)' is added to title + self.database.insert_soi(soi) + stmt = "SELECT COUNT(*) FROM SOI WHERE Title=?" + count = self.database.conn.execute( + stmt, (test_title + "(2)",) + ).fetchone()[0] + self.assertEqual(count, 1) + def delete_db(self): """Delete generated database-file.""" if os.path.exists(TESTDBPATH):