diff --git a/dbapi/repositories.py b/dbapi/repositories.py deleted file mode 100644 index 60b9809..0000000 --- a/dbapi/repositories.py +++ /dev/null @@ -1,85 +0,0 @@ -from sqlalchemy import create_engine, insert, select -from sqlalchemy.engine.base import Engine -from datetime import date -from dbapi.tables import training, exercise, approach - - -class DatabaseInterfasesMixin: - """Mixin for interfaces, that works with database""" - - def __init__(self, engine: Engine) -> None: - self.engine: Engine = engine - - -class TrainingRepository(DatabaseInterfasesMixin): - """Training table repository""" - - def create_training(self, date: date) -> int: - """Method for creating new instance of training - Args: - date: date of a training - - Returns: - Primary key of created training entry - """ - new_instance_statement = insert(training).values(Date=date) - with self.engine.connect() as conn: - result = conn.execute(new_instance_statement) - inerted_entry_pk: int = result.inserted_primary_key[0] - conn.commit() - return inerted_entry_pk - - -class ExerciseRepository(DatabaseInterfasesMixin): - """Exercise table repository""" - - def create_exercise(self, training_pk: int, exercise_name: str) -> int: - """Method for creating new instance of exercise table - Args: - training_pk: Primary key of associated training instance - exercise_name: Name of an exercise - - Returns: - Primary key of created exercise entry - """ - new_instance_statement = insert(exercise).values( - Training=training_pk, Name=exercise_name - ) - with self.engine.connect() as conn: - result = conn.execute(new_instance_statement) - inserted_entry_pk: int = result.inserted_primary_key[0] - conn.commit() - return inserted_entry_pk - - def get_exercises_from_training(self, training_pk: int): - """Method for getting rows of exercises, linked to training by its PK - - Args: - training_pk: Training table primary key - """ - statement = select(exercise).where(exercise.c.Training == training_pk) - print(f"Exercises SQL statement: {statement}") - - -class ApproachRepository(DatabaseInterfasesMixin): - """Approach table repository""" - - def create_approach(self, exercise_pk: int, weight: float, reps: int) -> int: - """Method for creating new instance of approach table - - Args: - exercise_pk: Primary key of an associated exercise - weight: Approach weight - reps: Amount of reps in approach - - Returns: - Primary key of created exercise entry - """ - new_instance_statement = insert(approach).values( - Exercise=exercise_pk, Weight=weight, Reps=reps - ) - with self.engine.connect() as conn: - result = conn.execute(new_instance_statement) - inserted_entry_pk: int = result.inserted_primary_key[0] - conn.commit() - return inserted_entry_pk diff --git a/dbapi/repositories/__init__.py b/dbapi/repositories/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/dbapi/repositories/approach_repo.py b/dbapi/repositories/approach_repo.py new file mode 100644 index 0000000..66a19ea --- /dev/null +++ b/dbapi/repositories/approach_repo.py @@ -0,0 +1,27 @@ +from dbapi.repositories.utils import DatabaseInterfasesMixin +from sqlalchemy import insert +from dbapi.tables import approach + + +class ApproachRepository(DatabaseInterfasesMixin): + """Approach table repository""" + + def create_approach(self, exercise_pk: int, weight: float, reps: int) -> int: + """Method for creating new instance of approach table + + Args: + exercise_pk: Primary key of an associated exercise + weight: Approach weight + reps: Amount of reps in approach + + Returns: + Primary key of created exercise entry + """ + new_instance_statement = insert(approach).values( + Exercise=exercise_pk, Weight=weight, Reps=reps + ) + with self.engine.connect() as conn: + result = conn.execute(new_instance_statement) + inserted_entry_pk: int = result.inserted_primary_key[0] + conn.commit() + return inserted_entry_pk diff --git a/dbapi/repositories/exercise_repo.py b/dbapi/repositories/exercise_repo.py new file mode 100644 index 0000000..45933ed --- /dev/null +++ b/dbapi/repositories/exercise_repo.py @@ -0,0 +1,25 @@ +from sqlalchemy import insert +from dbapi.repositories.utils import DatabaseInterfasesMixin +from dbapi.tables import exercise + + +class ExerciseRepository(DatabaseInterfasesMixin): + """Exercise table repository""" + + def create_exercise(self, training_pk: int, exercise_name: str) -> int: + """Method for creating new instance of exercise table + Args: + training_pk: Primary key of associated training instance + exercise_name: Name of an exercise + + Returns: + Primary key of created exercise entry + """ + new_instance_statement = insert(exercise).values( + Training=training_pk, Name=exercise_name + ) + with self.engine.connect() as conn: + result = conn.execute(new_instance_statement) + inserted_entry_pk: int = result.inserted_primary_key[0] + conn.commit() + return inserted_entry_pk diff --git a/dbapi/repositories/training_repo.py b/dbapi/repositories/training_repo.py new file mode 100644 index 0000000..d84e90c --- /dev/null +++ b/dbapi/repositories/training_repo.py @@ -0,0 +1,23 @@ +from sqlalchemy import insert +from datetime import date +from dbapi.repositories.utils import DatabaseInterfasesMixin +from dbapi.tables import training + + +class TrainingRepository(DatabaseInterfasesMixin): + """Training table repository""" + + def create_training(self, date: date) -> int: + """Method for creating new instance of training + Args: + date: date of a training + + Returns: + Primary key of created training entry + """ + new_instance_statement = insert(training).values(Date=date) + with self.engine.connect() as conn: + result = conn.execute(new_instance_statement) + inerted_entry_pk: int = result.inserted_primary_key[0] + conn.commit() + return inerted_entry_pk diff --git a/dbapi/repositories/utils.py b/dbapi/repositories/utils.py new file mode 100644 index 0000000..544f4a3 --- /dev/null +++ b/dbapi/repositories/utils.py @@ -0,0 +1,8 @@ +from sqlalchemy import Engine + + +class DatabaseInterfasesMixin: + """Mixin for interfaces, that works with database""" + + def __init__(self, engine: Engine) -> None: + self.engine: Engine = engine diff --git a/main.py b/main.py index dfc586e..39b8f31 100644 --- a/main.py +++ b/main.py @@ -7,11 +7,9 @@ from sqlalchemy import Table, create_engine, text, insert from dotenv import load_dotenv from sqlalchemy.ext.asyncio import create_async_engine from dbapi.migrator import FitnessDatabseMigrator -from dbapi.repositories import ( - ApproachRepository, - ExerciseRepository, - TrainingRepository, -) +from dbapi.repositories.approach_repo import ApproachRepository +from dbapi.repositories.exercise_repo import ExerciseRepository +from dbapi.repositories.training_repo import TrainingRepository from dbapi.tables import metadata_obj, training, exercise, approach from obsidian.notes_parser import parse_training_data, remap_unique_exercises from apple.notes_parser import parse_training_data as apple_parse_training_data @@ -58,8 +56,8 @@ async_engine = create_async_engine( # TODO: Check how migrations are done # NOTE: Drop all Tables from database -# metadata_obj.drop_all(engine) -# metadata_obj.create_all(engine) +metadata_obj.drop_all(engine) +metadata_obj.create_all(engine) # NOTE: Table reflection - generating table object from existing tables (only tables, that are stored in metadata) # some_table = Table("some_table", metadata_obj, autoload_with=engine) @@ -69,27 +67,26 @@ async_engine = create_async_engine( # Inserting training values into database -# trainings: List[Training] = parse_training_data() -# for train in trainings: -# if not train: -# continue -# else: -# print(train) -# new_training_pk: int = TrainingRepository(engine).create_training(train.date) -# for exr in train.exercises: -# approach_statements = [] -# new_exercise_pk: int = ExerciseRepository(engine).create_exercise( -# training_pk=new_training_pk, exercise_name=exr.name -# ) -# for appr in exr.approaches: -# new_approach_pk: int = ApproachRepository(engine).create_approach( -# exercise_pk=new_exercise_pk, weight=appr.weight, reps=appr.reps -# ) -# -# -# print("-------------------------\n" * 2) -# print("-------------------------\n" * 2) -# ExerciseRepository(engine=engine).get_exercises_from_training(1) +trainings: List[Training] = parse_training_data() +for train in trainings: + if not train: + continue + else: + print(train) + new_training_pk: int = TrainingRepository(engine).create_training(train.date) + for exr in train.exercises: + approach_statements = [] + new_exercise_pk: int = ExerciseRepository(engine).create_exercise( + training_pk=new_training_pk, exercise_name=exr.name + ) + for appr in exr.approaches: + new_approach_pk: int = ApproachRepository(engine).create_approach( + exercise_pk=new_exercise_pk, weight=appr.weight, reps=appr.reps + ) + + +print("-------------------------\n" * 2) +print("-------------------------\n" * 2) # ----- # Calculating unique exercises for obsidian @@ -185,6 +182,8 @@ async_engine = create_async_engine( # pprint(unique_exercise_parsed_names) # print(len(combined_trainings)) -fbm = FitnessDatabseMigrator(async_engine=async_engine) +# Async engine playground -asyncio.run(fbm.reset_database()) +# fbm = FitnessDatabseMigrator(async_engine=async_engine) +# +# asyncio.run(fbm.reset_database()) diff --git a/poetry.lock b/poetry.lock index 968e47a..8efc810 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "annotated-types" version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -16,7 +15,6 @@ files = [ name = "async-timeout" version = "5.0.1" description = "Timeout context manager for asyncio programs" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -28,7 +26,6 @@ files = [ name = "asyncpg" version = "0.30.0" description = "An asyncio PostgreSQL driver" -category = "main" optional = false python-versions = ">=3.8.0" files = [ @@ -95,7 +92,6 @@ test = ["distro (>=1.9.0,<1.10.0)", "flake8 (>=6.1,<7.0)", "flake8-pyi (>=24.1.0 name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -107,7 +103,6 @@ files = [ name = "exceptiongroup" version = "1.2.2" description = "Backport of PEP 654 (exception groups)" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -122,7 +117,6 @@ test = ["pytest (>=6)"] name = "greenlet" version = "3.1.1" description = "Lightweight in-process concurrent programming" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -209,7 +203,6 @@ test = ["objgraph", "psutil"] name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -221,7 +214,6 @@ files = [ name = "packaging" version = "24.2" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -233,7 +225,6 @@ files = [ name = "pluggy" version = "1.5.0" description = "plugin and hook calling mechanisms for python" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -249,7 +240,6 @@ testing = ["pytest", "pytest-benchmark"] name = "psycopg2" version = "2.9.10" description = "psycopg2 - Python-PostgreSQL Database Adapter" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -269,7 +259,6 @@ files = [ name = "pydantic" version = "2.10.5" description = "Data validation using Python type hints" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -290,7 +279,6 @@ timezone = ["tzdata"] name = "pydantic-core" version = "2.27.2" description = "Core functionality for Pydantic validation and serialization" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -403,7 +391,6 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" name = "pytest" version = "8.3.4" description = "pytest: simple powerful testing with Python" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -426,7 +413,6 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments name = "python-dotenv" version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -441,7 +427,6 @@ cli = ["click (>=5.0)"] name = "sqlalchemy" version = "2.0.37" description = "Database Abstraction Library" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -505,7 +490,7 @@ files = [ ] [package.dependencies] -greenlet = {version = "!=0.4.17", markers = "python_version < \"3.14\" and platform_machine == \"aarch64\" or python_version < \"3.14\" and platform_machine == \"ppc64le\" or python_version < \"3.14\" and platform_machine == \"x86_64\" or python_version < \"3.14\" and platform_machine == \"amd64\" or python_version < \"3.14\" and platform_machine == \"AMD64\" or python_version < \"3.14\" and platform_machine == \"win32\" or python_version < \"3.14\" and platform_machine == \"WIN32\""} +greenlet = {version = "!=0.4.17", markers = "python_version < \"3.14\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"} typing-extensions = ">=4.6.0" [package.extras] @@ -537,7 +522,6 @@ sqlcipher = ["sqlcipher3_binary"] name = "tomli" version = "2.2.1" description = "A lil' TOML parser" -category = "main" optional = false python-versions = ">=3.8" files = [ @@ -579,7 +563,6 @@ files = [ name = "typing-extensions" version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" -category = "main" optional = false python-versions = ">=3.8" files = [