Refactor repositories

This commit is contained in:
pro100ton 2025-01-20 21:42:16 +03:00
parent 73d92645ca
commit 90242d770d
8 changed files with 114 additions and 134 deletions

View file

@ -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

View file

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

59
main.py
View file

@ -7,11 +7,9 @@ from sqlalchemy import Table, create_engine, text, insert
from dotenv import load_dotenv from dotenv import load_dotenv
from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.ext.asyncio import create_async_engine
from dbapi.migrator import FitnessDatabseMigrator from dbapi.migrator import FitnessDatabseMigrator
from dbapi.repositories import ( from dbapi.repositories.approach_repo import ApproachRepository
ApproachRepository, from dbapi.repositories.exercise_repo import ExerciseRepository
ExerciseRepository, from dbapi.repositories.training_repo import TrainingRepository
TrainingRepository,
)
from dbapi.tables import metadata_obj, training, exercise, approach from dbapi.tables import metadata_obj, training, exercise, approach
from obsidian.notes_parser import parse_training_data, remap_unique_exercises from obsidian.notes_parser import parse_training_data, remap_unique_exercises
from apple.notes_parser import parse_training_data as apple_parse_training_data 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 # TODO: Check how migrations are done
# NOTE: Drop all Tables from database # NOTE: Drop all Tables from database
# metadata_obj.drop_all(engine) metadata_obj.drop_all(engine)
# metadata_obj.create_all(engine) metadata_obj.create_all(engine)
# NOTE: Table reflection - generating table object from existing tables (only tables, that are stored in metadata) # 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) # some_table = Table("some_table", metadata_obj, autoload_with=engine)
@ -69,27 +67,26 @@ async_engine = create_async_engine(
# Inserting training values into database # Inserting training values into database
# trainings: List[Training] = parse_training_data() trainings: List[Training] = parse_training_data()
# for train in trainings: for train in trainings:
# if not train: if not train:
# continue continue
# else: else:
# print(train) print(train)
# new_training_pk: int = TrainingRepository(engine).create_training(train.date) new_training_pk: int = TrainingRepository(engine).create_training(train.date)
# for exr in train.exercises: for exr in train.exercises:
# approach_statements = [] approach_statements = []
# new_exercise_pk: int = ExerciseRepository(engine).create_exercise( new_exercise_pk: int = ExerciseRepository(engine).create_exercise(
# training_pk=new_training_pk, exercise_name=exr.name training_pk=new_training_pk, exercise_name=exr.name
# ) )
# for appr in exr.approaches: for appr in exr.approaches:
# new_approach_pk: int = ApproachRepository(engine).create_approach( new_approach_pk: int = ApproachRepository(engine).create_approach(
# exercise_pk=new_exercise_pk, weight=appr.weight, reps=appr.reps exercise_pk=new_exercise_pk, weight=appr.weight, reps=appr.reps
# ) )
#
#
# print("-------------------------\n" * 2) print("-------------------------\n" * 2)
# print("-------------------------\n" * 2) print("-------------------------\n" * 2)
# ExerciseRepository(engine=engine).get_exercises_from_training(1)
# ----- # -----
# Calculating unique exercises for obsidian # Calculating unique exercises for obsidian
@ -185,6 +182,8 @@ async_engine = create_async_engine(
# pprint(unique_exercise_parsed_names) # pprint(unique_exercise_parsed_names)
# print(len(combined_trainings)) # 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())

21
poetry.lock generated
View file

@ -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]] [[package]]
name = "annotated-types" name = "annotated-types"
version = "0.7.0" version = "0.7.0"
description = "Reusable constraint types to use with typing.Annotated" description = "Reusable constraint types to use with typing.Annotated"
category = "main"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -16,7 +15,6 @@ files = [
name = "async-timeout" name = "async-timeout"
version = "5.0.1" version = "5.0.1"
description = "Timeout context manager for asyncio programs" description = "Timeout context manager for asyncio programs"
category = "main"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -28,7 +26,6 @@ files = [
name = "asyncpg" name = "asyncpg"
version = "0.30.0" version = "0.30.0"
description = "An asyncio PostgreSQL driver" description = "An asyncio PostgreSQL driver"
category = "main"
optional = false optional = false
python-versions = ">=3.8.0" python-versions = ">=3.8.0"
files = [ 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" name = "colorama"
version = "0.4.6" version = "0.4.6"
description = "Cross-platform colored terminal text." description = "Cross-platform colored terminal text."
category = "main"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [ files = [
@ -107,7 +103,6 @@ files = [
name = "exceptiongroup" name = "exceptiongroup"
version = "1.2.2" version = "1.2.2"
description = "Backport of PEP 654 (exception groups)" description = "Backport of PEP 654 (exception groups)"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -122,7 +117,6 @@ test = ["pytest (>=6)"]
name = "greenlet" name = "greenlet"
version = "3.1.1" version = "3.1.1"
description = "Lightweight in-process concurrent programming" description = "Lightweight in-process concurrent programming"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -209,7 +203,6 @@ test = ["objgraph", "psutil"]
name = "iniconfig" name = "iniconfig"
version = "2.0.0" version = "2.0.0"
description = "brain-dead simple config-ini parsing" description = "brain-dead simple config-ini parsing"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -221,7 +214,6 @@ files = [
name = "packaging" name = "packaging"
version = "24.2" version = "24.2"
description = "Core utilities for Python packages" description = "Core utilities for Python packages"
category = "main"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -233,7 +225,6 @@ files = [
name = "pluggy" name = "pluggy"
version = "1.5.0" version = "1.5.0"
description = "plugin and hook calling mechanisms for python" description = "plugin and hook calling mechanisms for python"
category = "main"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -249,7 +240,6 @@ testing = ["pytest", "pytest-benchmark"]
name = "psycopg2" name = "psycopg2"
version = "2.9.10" version = "2.9.10"
description = "psycopg2 - Python-PostgreSQL Database Adapter" description = "psycopg2 - Python-PostgreSQL Database Adapter"
category = "main"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -269,7 +259,6 @@ files = [
name = "pydantic" name = "pydantic"
version = "2.10.5" version = "2.10.5"
description = "Data validation using Python type hints" description = "Data validation using Python type hints"
category = "main"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -290,7 +279,6 @@ timezone = ["tzdata"]
name = "pydantic-core" name = "pydantic-core"
version = "2.27.2" version = "2.27.2"
description = "Core functionality for Pydantic validation and serialization" description = "Core functionality for Pydantic validation and serialization"
category = "main"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -403,7 +391,6 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
name = "pytest" name = "pytest"
version = "8.3.4" version = "8.3.4"
description = "pytest: simple powerful testing with Python" description = "pytest: simple powerful testing with Python"
category = "main"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -426,7 +413,6 @@ dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments
name = "python-dotenv" name = "python-dotenv"
version = "1.0.1" version = "1.0.1"
description = "Read key-value pairs from a .env file and set them as environment variables" description = "Read key-value pairs from a .env file and set them as environment variables"
category = "main"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -441,7 +427,6 @@ cli = ["click (>=5.0)"]
name = "sqlalchemy" name = "sqlalchemy"
version = "2.0.37" version = "2.0.37"
description = "Database Abstraction Library" description = "Database Abstraction Library"
category = "main"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
@ -505,7 +490,7 @@ files = [
] ]
[package.dependencies] [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" typing-extensions = ">=4.6.0"
[package.extras] [package.extras]
@ -537,7 +522,6 @@ sqlcipher = ["sqlcipher3_binary"]
name = "tomli" name = "tomli"
version = "2.2.1" version = "2.2.1"
description = "A lil' TOML parser" description = "A lil' TOML parser"
category = "main"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
@ -579,7 +563,6 @@ files = [
name = "typing-extensions" name = "typing-extensions"
version = "4.12.2" version = "4.12.2"
description = "Backported and Experimental Type Hints for Python 3.8+" description = "Backported and Experimental Type Hints for Python 3.8+"
category = "main"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [