From 635cb1db4731be1a002d7b9f53bd1115d16f03c7 Mon Sep 17 00:00:00 2001
From: Christian Heller <c.heller@plomlompom.de>
Date: Sun, 24 Nov 2024 18:46:58 +0100
Subject: [PATCH] Create initial migration.

---
 install.py            | 20 +++++++++---------
 migrations/init_0.sql | 32 ++++++++++++++++++++++++++++
 ytplom/misc.py        | 49 ++++++++-----------------------------------
 3 files changed, 51 insertions(+), 50 deletions(-)
 create mode 100644 migrations/init_0.sql

diff --git a/install.py b/install.py
index db188e8..991ef5f 100755
--- a/install.py
+++ b/install.py
@@ -3,14 +3,14 @@
 from shutil import copyfile
 from os import makedirs, scandir
 from os.path import basename, join as path_join
-from ytplom.misc import NAME_TEMPLATES_DIR, PATH_APP_DATA, PATH_TEMPLATES
+from ytplom.misc import PATH_APP_DATA, PATH_MIGRATIONS, PATH_TEMPLATES
 
-print(f'ensuring {PATH_APP_DATA}')
-makedirs(PATH_APP_DATA)
-print(f'ensuring {PATH_TEMPLATES}')
-makedirs(PATH_TEMPLATES)
-for e in scandir(NAME_TEMPLATES_DIR):
-    target_path = path_join(PATH_TEMPLATES, basename(e.path))
-    print(f'copying {e.path} to {target_path}')
-    copyfile(e.path, target_path)
-print(f'installation finished')
+for path in (PATH_APP_DATA, PATH_TEMPLATES, PATH_MIGRATIONS):
+    print(f'ensuring {path}')
+    makedirs(path)
+for path_dir in (PATH_MIGRATIONS, PATH_TEMPLATES):
+    for entry in scandir(basename(path_dir)):
+        target_path = path_join(path_dir, basename(entry.path))
+        print(f'copying {entry.path} to {target_path}')
+        copyfile(entry.path, target_path)
+print('installation finished')
diff --git a/migrations/init_0.sql b/migrations/init_0.sql
new file mode 100644
index 0000000..5b45769
--- /dev/null
+++ b/migrations/init_0.sql
@@ -0,0 +1,32 @@
+CREATE TABLE yt_queries (
+  id TEXT PRIMARY KEY,
+  text TEXT NOT NULL,
+  retrieved_at TEXT NOT NULL
+);
+CREATE TABLE yt_videos (
+  id TEXT PRIMARY KEY,
+  title TEXT NOT NULL,
+  description TEXT NOT NULL,
+  published_at TEXT NOT NULL,
+  duration TEXT NOT NULL,
+  definition TEXT NOT NULL
+);
+CREATE TABLE yt_query_results (
+  query_id TEXT NOT NULL,
+  video_id TEXT NOT NULL,
+  PRIMARY KEY (query_id, video_id),
+  FOREIGN KEY (query_id) REFERENCES yt_queries(id),
+  FOREIGN KEY (video_id) REFERENCES yt_videos(id)
+);
+CREATE TABLE quota_costs (
+  id TEXT PRIMARY KEY,
+  timestamp TEXT NOT NULL,
+  cost INT NOT NULL
+);
+CREATE TABLE files (
+  rel_path TEXT PRIMARY KEY,
+  yt_id TEXT NOT NULL DEFAULT "",
+  flags INTEGER NOT NULL DEFAULT 0,
+  FOREIGN KEY (yt_id) REFERENCES yt_videos(id)
+);
+
diff --git a/ytplom/misc.py b/ytplom/misc.py
index 9c893bd..9e46c82 100644
--- a/ytplom/misc.py
+++ b/ytplom/misc.py
@@ -57,8 +57,7 @@ PATH_TEMP = PathStr(path_join(PATH_CACHE, 'temp'))
 PATH_THUMBNAILS = PathStr(path_join(PATH_CACHE, 'thumbnails'))
 
 # template paths
-NAME_TEMPLATES_DIR = 'templates'
-PATH_TEMPLATES = PathStr(path_join(PATH_APP_DATA, NAME_TEMPLATES_DIR))
+PATH_TEMPLATES = PathStr(path_join(PATH_APP_DATA, 'templates'))
 NAME_TEMPLATE_QUERIES = PathStr('queries.tmpl')
 NAME_TEMPLATE_RESULTS = PathStr('results.tmpl')
 NAME_TEMPLATE_VIDEOS = PathStr('videos.tmpl')
@@ -83,47 +82,16 @@ QUOTA_COST_YOUTUBE_DETAILS = QuotaCost(1)
 # local expectations
 TIMESTAMP_FMT = '%Y-%m-%d %H:%M:%S.%f'
 LEGAL_EXTENSIONS = {'webm', 'mp4', 'mkv'}
+VIDEO_FLAGS: dict[FlagName, FlagsInt] = {
+  FlagName('delete'): FlagsInt(1 << 62)
+}
 
 # tables to create database with
 EXPECTED_DB_VERSION = 0
 SQL_DB_VERSION = SqlText('PRAGMA user_version')
-SCRIPT_INIT_DB = '''
-CREATE TABLE yt_queries (
-  id TEXT PRIMARY KEY,
-  text TEXT NOT NULL,
-  retrieved_at TEXT NOT NULL
-);
-CREATE TABLE yt_videos (
-  id TEXT PRIMARY KEY,
-  title TEXT NOT NULL,
-  description TEXT NOT NULL,
-  published_at TEXT NOT NULL,
-  duration TEXT NOT NULL,
-  definition TEXT NOT NULL
-);
-CREATE TABLE yt_query_results (
-  query_id TEXT NOT NULL,
-  video_id TEXT NOT NULL,
-  PRIMARY KEY (query_id, video_id),
-  FOREIGN KEY (query_id) REFERENCES yt_queries(id),
-  FOREIGN KEY (video_id) REFERENCES yt_videos(id)
-);
-CREATE TABLE quota_costs (
-  id TEXT PRIMARY KEY,
-  timestamp TEXT NOT NULL,
-  cost INT NOT NULL
-);
-CREATE TABLE files (
-  rel_path TEXT PRIMARY KEY,
-  yt_id TEXT NOT NULL DEFAULT "",
-  flags INTEGER NOT NULL DEFAULT 0,
-  FOREIGN KEY (yt_id) REFERENCES yt_videos(id)
-);
-'''
-
-VIDEO_FLAGS: dict[FlagName, FlagsInt] = {
-  FlagName('delete'): FlagsInt(1 << 62)
-}
+PATH_MIGRATIONS = PathStr(path_join(PATH_APP_DATA, 'migrations'))
+PATH_DB_SCHEMA = PathStr(path_join(PATH_MIGRATIONS,
+                                   f'init_{EXPECTED_DB_VERSION}.sql'))
 
 
 class NotFoundException(Exception):
@@ -160,7 +128,8 @@ class DatabaseConnection:
                         f'cannot find {path_db_dir} as directory to put DB '
                         'into, did you run install.py?')
             with sql_connect(self._path) as conn:
-                conn.executescript(SCRIPT_INIT_DB)
+                with open(PATH_DB_SCHEMA, 'r', encoding='utf8') as f:
+                    conn.executescript(f.read())
                 conn.execute(f'{SQL_DB_VERSION} = {EXPECTED_DB_VERSION}')
         with sql_connect(self._path) as conn:
             db_version = list(conn.execute(SQL_DB_VERSION))[0][0]
-- 
2.30.2