diff --git a/src/submissions/backend/db/__init__.py b/src/submissions/backend/db/__init__.py index f4ba6c6..7f3ae7c 100644 --- a/src/submissions/backend/db/__init__.py +++ b/src/submissions/backend/db/__init__.py @@ -69,6 +69,6 @@ def update_log(mapper, connection, target): else: logger.info(f"No changes detected, not updating logs.") - -# event.listen(LogMixin, 'after_update', update_log, propagate=True) -# event.listen(LogMixin, 'after_insert', update_log, propagate=True) +if ctx.database_schema == "sqlite": + event.listen(LogMixin, 'after_update', update_log, propagate=True) + event.listen(LogMixin, 'after_insert', update_log, propagate=True) diff --git a/src/submissions/backend/db/models/__init__.py b/src/submissions/backend/db/models/__init__.py index 7931bfc..8e4d07f 100644 --- a/src/submissions/backend/db/models/__init__.py +++ b/src/submissions/backend/db/models/__init__.py @@ -4,8 +4,8 @@ Contains all models for sqlalchemy from __future__ import annotations import sys, logging -import pandas as pd -from sqlalchemy import Column, INTEGER, String, JSON, inspect +from pandas import DataFrame +from sqlalchemy import Column, INTEGER, String, JSON from sqlalchemy.orm import DeclarativeMeta, declarative_base, Query, Session from sqlalchemy.ext.declarative import declared_attr from sqlalchemy.exc import ArgumentError @@ -100,11 +100,21 @@ class BaseClass(Base): Returns: dict | list | str: Output of key:value dict or single (list, str) desired variable """ + # NOTE: singles is a list of fields that need to be limited to 1 result. singles = list(set(cls.singles + BaseClass.singles)) return dict(singles=singles) @classmethod - def find_regular_subclass(cls, name: str | None = None): + def find_regular_subclass(cls, name: str | None = None) -> Any: + """ + + Args: + name (str): name of subclass of interest. + + Returns: + Any: Subclass of this object + + """ if not name: return cls if " " in name: @@ -140,7 +150,7 @@ class BaseClass(Base): return query.limit(50).all() @classmethod - def results_to_df(cls, objects: list, **kwargs) -> pd.DataFrame: + def results_to_df(cls, objects: list, **kwargs) -> DataFrame: """ Args: @@ -148,15 +158,15 @@ class BaseClass(Base): **kwargs (): Arguments necessary for the to_sub_dict method. eg extraction_kit=X Returns: - pd.Dataframe + Dataframe """ records = [obj.to_sub_dict(**kwargs) for obj in objects] - return pd.DataFrame.from_records(records) + return DataFrame.from_records(records) @classmethod def query(cls, **kwargs) -> Any | List[Any]: """ - Default query function for models. Overridden in most models. + Default query function for models. Overridden in most models with additional filters. Returns: Any | List[Any]: Result of query execution. @@ -209,11 +219,9 @@ class BaseClass(Base): """ # logger.debug(f"Saving object: {pformat(self.__dict__)}") report = Report() - state = inspect(self) try: self.__database_session__.add(self) self.__database_session__.commit() - return state except Exception as e: logger.critical(f"Problem saving object: {e}") logger.error(f"Error message: {type(e)}") diff --git a/src/submissions/backend/db/models/audit.py b/src/submissions/backend/db/models/audit.py index 9f695bd..477af90 100644 --- a/src/submissions/backend/db/models/audit.py +++ b/src/submissions/backend/db/models/audit.py @@ -1,3 +1,8 @@ +""" +Contains the audit log class and functions. +""" +from typing import List + from dateutil.parser import parse from sqlalchemy.orm import declarative_base, DeclarativeMeta, Query from . import BaseClass @@ -13,7 +18,7 @@ class AuditLog(Base): __tablename__ = "_auditlog" - id = Column(INTEGER, primary_key=True) #: primary key + id = Column(INTEGER, primary_key=True, autoincrement=True) #: primary key user = Column(String(64)) time = Column(TIMESTAMP) object = Column(String(64)) @@ -23,7 +28,17 @@ class AuditLog(Base): return f"<{self.user} @ {self.time}>" @classmethod - def query(cls, start_date: date | str | int | None = None, end_date: date | str | int | None = None, ): + def query(cls, start_date: date | str | int | None = None, end_date: date | str | int | None = None) -> List["AuditLog"]: + """ + Searches for database transactions by date. + + Args: + start_date (date | str | int | None, Optional): Earliest date sought. Defaults to None + end_date (date | str | int | None, Optional): Latest date sought. Defaults to None + + Returns: + List[AuditLog]: List of transactions made to the database. + """ session = BaseClass.__database_session__ query: Query = session.query(cls) if start_date is not None and end_date is None: diff --git a/src/submissions/backend/db/models/kits.py b/src/submissions/backend/db/models/kits.py index 0a2d8b9..e081903 100644 --- a/src/submissions/backend/db/models/kits.py +++ b/src/submissions/backend/db/models/kits.py @@ -401,7 +401,7 @@ class ReagentRole(BaseClass): super().save() -class Reagent(BaseClass): +class Reagent(BaseClass, LogMixin): """ Concrete reagent instance """ diff --git a/src/submissions/tools/__init__.py b/src/submissions/tools/__init__.py index 12974b0..4e52d0d 100644 --- a/src/submissions/tools/__init__.py +++ b/src/submissions/tools/__init__.py @@ -955,10 +955,6 @@ def report_result(func): match output: case Report(): report = output - # case InstanceState(): - # for attr in output.attrs: - # print(f"{attr}: {attr.load_history()}") - # return case tuple(): try: report = [item for item in output if isinstance(item, Report)][0]