From 74e18bef7c7eb6619f9f8bb0a887a7e00e3498d4 Mon Sep 17 00:00:00 2001 From: Verox Date: Wed, 10 Jan 2024 19:16:28 +0100 Subject: [PATCH] Finished DB management and DB migration scripts --- .gitignore | 2 + .idea/dataSources.xml | 15 ++++++++ .idea/sqldialects.xml | 7 ++++ app.py | 1 + db/create_migration.py | 30 +++++++++++++++ db/migrate.py | 63 +++++++++++++++++++++++++++++++ db/migrations/1704909465_test.sql | 3 ++ 7 files changed, 121 insertions(+) create mode 100644 .idea/dataSources.xml create mode 100644 .idea/sqldialects.xml create mode 100644 db/create_migration.py create mode 100644 db/migrate.py create mode 100644 db/migrations/1704909465_test.sql diff --git a/.gitignore b/.gitignore index 5d381cc..7743451 100644 --- a/.gitignore +++ b/.gitignore @@ -160,3 +160,5 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ +db/db.sqlite + diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..82a2a09 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,15 @@ + + + + + sqlite.xerial + true + org.sqlite.JDBC + jdbc:sqlite:$PROJECT_DIR$/db/db.sqlite + + + + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml new file mode 100644 index 0000000..87a5a6e --- /dev/null +++ b/.idea/sqldialects.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/app.py b/app.py index 0cf7364..3ea5139 100644 --- a/app.py +++ b/app.py @@ -1,4 +1,5 @@ from flask import Flask, render_template +from db.migrate import _CREATE_MIGRATIONS_TABLE # Create a new Flask instance app = Flask(__name__) diff --git a/db/create_migration.py b/db/create_migration.py new file mode 100644 index 0000000..8b00067 --- /dev/null +++ b/db/create_migration.py @@ -0,0 +1,30 @@ +import datetime +import os + + +def is_snake_case(s): + if not s: + return False + + return s.islower() and all(char.isalpha() or char == '_' for char in s) + +if __name__ == "__main__": + migration_name = "" + while not is_snake_case(migration_name): + if migration_name: + print(f"{migration_name} ist nicht im Camcel-Case") + migration_name = input('Gebe einen Namen für die Migration im snake_case an: ') + + timestamp = datetime.datetime.now().timestamp() + migrations_path = os.path.join(os.path.dirname(__file__), 'migrations') + print(migrations_path) + + try: + if not os.path.isdir(migrations_path): + raise FileNotFoundError + + file = open(os.path.join(os.path.dirname(__file__), 'migrations', str(int(timestamp)) + '_' + migration_name + '.sql'), 'w') + file.close() + + except FileNotFoundError: + print("migrations/ Directive could not be found within the db directory, contained in the project main directory.") \ No newline at end of file diff --git a/db/migrate.py b/db/migrate.py new file mode 100644 index 0000000..16dbe07 --- /dev/null +++ b/db/migrate.py @@ -0,0 +1,63 @@ +import datetime +import os +import sqlite3 +from pathlib import Path +from sqlite3 import Connection + +CREATE_MIGRATIONS_TABLE = """ +CREATE TABLE IF NOT EXISTS migrations ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + file TEXT, + created_at TEXT +); +""" + +def init_db(): + conn = sqlite3.connect("db.sqlite") + + # Create migration table, if not exists yet + conn.execute(CREATE_MIGRATIONS_TABLE) + conn.commit() + +def create_migration(conn: Connection, migration: str): + conn.execute(f""" + INSERT INTO migrations (file, created_at) VALUES ("{migration}", "{datetime.datetime.now()}"); + """) + +""" +Returns True, if the migration has already been migrates once. +""" +def check_migration(conn: Connection, migration: str): + res = conn.cursor().execute(f""" + SELECT EXISTS(SELECT file FROM migrations WHERE file = "{migration}"); + """) + return res.fetchone()[0] == 1 + +if __name__ == "__main__": + # Init DB with migrations table + init_db() + + migrations_path = os.path.join(os.path.dirname(__file__), 'migrations') + + try: + if not os.path.isdir(migrations_path): + raise FileNotFoundError + + conn = sqlite3.connect("db.sqlite") + for file in os.listdir(migrations_path): + if not file.endswith('.sql'): + continue + with open(os.path.join(os.path.dirname(__file__), 'migrations', file)) as migration: + migration_name = Path(file).stem + + if check_migration(conn, migration_name): + continue + + print(f"Migrating {migration_name}...") + create_migration(conn, migration_name) + conn.execute(migration.read()) + print(f"Migrated {migration_name}\n") + + conn.commit() + except FileNotFoundError: + print("migrations/ Directive could not be found within the db directory, contained in the project main directory.") \ No newline at end of file diff --git a/db/migrations/1704909465_test.sql b/db/migrations/1704909465_test.sql new file mode 100644 index 0000000..cad9344 --- /dev/null +++ b/db/migrations/1704909465_test.sql @@ -0,0 +1,3 @@ +CREATE TABLE test ( + id INTEGER PRIMARY KEY AUTOINCREMENT +); \ No newline at end of file