refactor: create TableService child class from SqliteService
This commit is contained in:
parent
808fb54db5
commit
428f1c435f
7 changed files with 96 additions and 82 deletions
BIN
db/eolas.db
Normal file
BIN
db/eolas.db
Normal file
Binary file not shown.
2
setup.py
2
setup.py
|
@ -8,7 +8,7 @@ setup(
|
||||||
install_requires=["python-frontmatter", "termcolor"],
|
install_requires=["python-frontmatter", "termcolor"],
|
||||||
entry_points={
|
entry_points={
|
||||||
"console_scripts": [
|
"console_scripts": [
|
||||||
"run=app:main",
|
"eolas-db=cli:main",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
10
src/cli.py
10
src/cli.py
|
@ -4,13 +4,13 @@ from constants import EOLAS_DIRECTORY
|
||||||
from controllers.controller import Controller
|
from controllers.controller import Controller
|
||||||
from services.database_service import DatabaseService
|
from services.database_service import DatabaseService
|
||||||
from services.parse_file_service import ParseFileService
|
from services.parse_file_service import ParseFileService
|
||||||
from services.sqlite_service import SqliteService
|
from services.table_service import TableService
|
||||||
|
|
||||||
database_service = DatabaseService("eolas")
|
database_service = DatabaseService("eolas")
|
||||||
database_connection = database_service.connect()
|
database_connection = database_service.connect()
|
||||||
sqlite_service = SqliteService(database_connection)
|
table_service = TableService(database_connection)
|
||||||
parse_file_service = ParseFileService(EOLAS_DIRECTORY)
|
parse_file_service = ParseFileService(EOLAS_DIRECTORY)
|
||||||
controller = Controller(database_service, sqlite_service, parse_file_service)
|
controller = Controller(database_service, table_service, parse_file_service)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
@ -18,11 +18,11 @@ def main():
|
||||||
prog="eolas-db", description="Eolas database manager."
|
prog="eolas-db", description="Eolas database manager."
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"command", choices=["parse", "populate"], help="Command to execute"
|
"command", choices=["populate-database"], help="Command to execute"
|
||||||
)
|
)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.command == "populate":
|
if args.command == "populate-database":
|
||||||
controller.populate_database()
|
controller.populate_database()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
class Controller:
|
class Controller:
|
||||||
def __init__(self, database_service, sqlite_service, parse_file_service):
|
def __init__(self, database_service, table_service, parse_file_service):
|
||||||
self.database_service = database_service
|
self.database_service = database_service
|
||||||
self.sqlite_service = sqlite_service
|
self.table_service = table_service
|
||||||
self.parse_file_service = parse_file_service
|
self.parse_file_service = parse_file_service
|
||||||
|
|
||||||
def populate_database(self):
|
def populate_database(self):
|
||||||
try:
|
try:
|
||||||
entries = self.parse_file_service.parse_source_directory()
|
entries = self.parse_file_service.parse_source_directory()
|
||||||
self.sqlite_service.populate_tables(entries)
|
self.table_service.populate_tables(entries)
|
||||||
finally:
|
finally:
|
||||||
self.database_service.disconnect()
|
self.database_service.disconnect()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import os
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
@ -15,6 +16,9 @@ class DatabaseService:
|
||||||
return self.connection
|
return self.connection
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if not os.path.exists(self.db_path):
|
||||||
|
os.makedirs(self.db_path)
|
||||||
|
print(colored("INFO Created database directory", "light_blue"))
|
||||||
self.connection = sqlite3.connect(f"{self.db_path}/{self.db_name}.db")
|
self.connection = sqlite3.connect(f"{self.db_path}/{self.db_name}.db")
|
||||||
self.connection.execute("PRAGMA foreign_keys = ON")
|
self.connection.execute("PRAGMA foreign_keys = ON")
|
||||||
print(colored("INFO Database connection established", "light_blue"))
|
print(colored("INFO Database connection established", "light_blue"))
|
||||||
|
|
|
@ -8,11 +8,11 @@ from sql.create_tables import tables
|
||||||
|
|
||||||
|
|
||||||
class SqliteService:
|
class SqliteService:
|
||||||
def __init__(self, connection):
|
def __init__(self, db_connection):
|
||||||
self.connection = connection
|
self.connection = db_connection
|
||||||
self.cursor = connection.cursor()
|
self.cursor = db_connection.cursor()
|
||||||
|
|
||||||
def __query(self, sql, params=None, errorMessage: Optional[str] = None):
|
def _query(self, sql, params=None, errorMessage: Optional[str] = None):
|
||||||
try:
|
try:
|
||||||
if params:
|
if params:
|
||||||
self.cursor.execute(sql, params)
|
self.cursor.execute(sql, params)
|
||||||
|
@ -24,72 +24,3 @@ class SqliteService:
|
||||||
if errorMessage:
|
if errorMessage:
|
||||||
raise Exception(f"ERROR {errorMessage}: {e}")
|
raise Exception(f"ERROR {errorMessage}: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def __create_tables(self):
|
|
||||||
for table in tables:
|
|
||||||
self.__query(
|
|
||||||
table["create_statement"],
|
|
||||||
errorMessage=f"Problem creating table {table['name']}",
|
|
||||||
)
|
|
||||||
print(colored("INFO Created tables", "light_blue"))
|
|
||||||
|
|
||||||
def __drop_tables(self):
|
|
||||||
# Reverse the order of `tables` list to avoid foreign key violation when
|
|
||||||
# deleting
|
|
||||||
for table in reversed(tables):
|
|
||||||
self.__query(
|
|
||||||
f"DROP TABLE IF EXISTS {table['name']}",
|
|
||||||
errorMessage=f"Problem truncating table {table['name']}",
|
|
||||||
)
|
|
||||||
print(colored("INFO Cleared tables", "light_blue"))
|
|
||||||
|
|
||||||
def __entry_exists(self, title) -> bool:
|
|
||||||
self.__query("SELECT 1 FROM entries WHERE title = :title", {"title": title})
|
|
||||||
result = self.cursor.fetchone()
|
|
||||||
return result is not None
|
|
||||||
|
|
||||||
def __populate_base_tables(self, entries: list[Entry]):
|
|
||||||
for entry in entries:
|
|
||||||
self.__query(
|
|
||||||
"INSERT INTO entries (title, last_modified, size, body) VALUES (:title, :last_modified, :size, :body)",
|
|
||||||
entry,
|
|
||||||
errorMessage=f"The following entry could not be added to `entries` table: {entry}",
|
|
||||||
)
|
|
||||||
tags = entry.get("tags")
|
|
||||||
if tags:
|
|
||||||
for tag in tags:
|
|
||||||
self.__query(
|
|
||||||
"INSERT OR IGNORE INTO tags (name) VALUES (:tag_name)",
|
|
||||||
{"tag_name": tag},
|
|
||||||
)
|
|
||||||
|
|
||||||
print(colored("INFO Base tables populated", "light_blue"))
|
|
||||||
|
|
||||||
def __populate_junction_tables(self, entries: list[Entry]):
|
|
||||||
for entry in entries:
|
|
||||||
tags = entry.get("tags")
|
|
||||||
links = entry.get("links")
|
|
||||||
if tags:
|
|
||||||
for tag in tags:
|
|
||||||
self.__query(
|
|
||||||
"INSERT INTO entries_tags (entry_title, tag_name) VALUES (:entry_title, :tag_name)",
|
|
||||||
{"entry_title": entry.get("title"), "tag_name": tag},
|
|
||||||
)
|
|
||||||
if links:
|
|
||||||
for link in links:
|
|
||||||
if self.__entry_exists(link):
|
|
||||||
self.__query(
|
|
||||||
"INSERT OR IGNORE INTO backlinks (source_entry_title, target_entry_title) VALUES (:source_entry_title, :target_entry_title)",
|
|
||||||
{
|
|
||||||
"source_entry_title": entry.get("title"),
|
|
||||||
"target_entry_title": link,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
print(colored("INFO Junction tables populated", "light_blue"))
|
|
||||||
|
|
||||||
def populate_tables(self, entries: list[Entry]):
|
|
||||||
self.__drop_tables()
|
|
||||||
self.__create_tables()
|
|
||||||
self.__populate_base_tables(entries)
|
|
||||||
self.__populate_junction_tables(entries)
|
|
||||||
|
|
79
src/services/table_service.py
Normal file
79
src/services/table_service.py
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
from termcolor import colored
|
||||||
|
|
||||||
|
from models.entry import Entry
|
||||||
|
from services.sqlite_service import SqliteService
|
||||||
|
from sql.create_tables import tables
|
||||||
|
|
||||||
|
|
||||||
|
class TableService(SqliteService):
|
||||||
|
def __init__(self, db_connection):
|
||||||
|
super().__init__(db_connection)
|
||||||
|
|
||||||
|
def __create_tables(self):
|
||||||
|
for table in tables:
|
||||||
|
self._query(
|
||||||
|
table["create_statement"],
|
||||||
|
errorMessage=f"Problem creating table {table['name']}",
|
||||||
|
)
|
||||||
|
print(colored("INFO Created tables", "light_blue"))
|
||||||
|
|
||||||
|
def __drop_tables(self):
|
||||||
|
# Reverse the order of `tables` list to avoid foreign key violation when
|
||||||
|
# deleting
|
||||||
|
for table in reversed(tables):
|
||||||
|
self._query(
|
||||||
|
f"DROP TABLE IF EXISTS {table['name']}",
|
||||||
|
errorMessage=f"Problem truncating table {table['name']}",
|
||||||
|
)
|
||||||
|
print(colored("INFO Cleared tables", "light_blue"))
|
||||||
|
|
||||||
|
def __entry_exists(self, title) -> bool:
|
||||||
|
self._query("SELECT 1 FROM entries WHERE title = :title", {"title": title})
|
||||||
|
result = self.cursor.fetchone()
|
||||||
|
return result is not None
|
||||||
|
|
||||||
|
def __populate_base_tables(self, entries: list[Entry]):
|
||||||
|
for entry in entries:
|
||||||
|
self._query(
|
||||||
|
"INSERT INTO entries (title, last_modified, size, body) VALUES (:title, :last_modified, :size, :body)",
|
||||||
|
entry,
|
||||||
|
errorMessage=f"The following entry could not be added to `entries` table: {entry}",
|
||||||
|
)
|
||||||
|
tags = entry.get("tags")
|
||||||
|
if tags:
|
||||||
|
for tag in tags:
|
||||||
|
self._query(
|
||||||
|
"INSERT OR IGNORE INTO tags (name) VALUES (:tag_name)",
|
||||||
|
{"tag_name": tag},
|
||||||
|
)
|
||||||
|
|
||||||
|
print(colored("INFO Base tables populated", "light_blue"))
|
||||||
|
|
||||||
|
def __populate_junction_tables(self, entries: list[Entry]):
|
||||||
|
for entry in entries:
|
||||||
|
tags = entry.get("tags")
|
||||||
|
links = entry.get("links")
|
||||||
|
if tags:
|
||||||
|
for tag in tags:
|
||||||
|
self._query(
|
||||||
|
"INSERT INTO entries_tags (entry_title, tag_name) VALUES (:entry_title, :tag_name)",
|
||||||
|
{"entry_title": entry.get("title"), "tag_name": tag},
|
||||||
|
)
|
||||||
|
if links:
|
||||||
|
for link in links:
|
||||||
|
if self.__entry_exists(link):
|
||||||
|
self._query(
|
||||||
|
"INSERT OR IGNORE INTO backlinks (source_entry_title, target_entry_title) VALUES (:source_entry_title, :target_entry_title)",
|
||||||
|
{
|
||||||
|
"source_entry_title": entry.get("title"),
|
||||||
|
"target_entry_title": link,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
print(colored("INFO Junction tables populated", "light_blue"))
|
||||||
|
|
||||||
|
def populate_tables(self, entries: list[Entry]):
|
||||||
|
self.__drop_tables()
|
||||||
|
self.__create_tables()
|
||||||
|
self.__populate_base_tables(entries)
|
||||||
|
self.__populate_junction_tables(entries)
|
Loading…
Add table
Reference in a new issue