"""Models
This file provides all database models stored in the database.
This file can be imported as a module and contains the following classes:
* Base: Base class which defines a database model.
* Global: Model for representing a global user in the database.
* Version: Model for representing a version in the database.
* Project: Model for representing a project in the database.
"""
from __future__ import annotations
from datetime import datetime, timezone
from typing import NewType
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import WriteOnlyMapped, WriteOnlyCollection
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
from sqlalchemy import ForeignKey
from sqlalchemy import String
from sqlalchemy import PickleType
from tzlocal import get_localzone
from uppaal2jetracer.uppaalmodel.system import System
from uppaal2jetracer.versioncontrol.config import Config
Pickle = NewType("pickle", str)
db_config = Config()
[docs]
class Base(DeclarativeBase):
"""
A class for representing a standard database model.
"""
type_annotation_map = {
Pickle: PickleType()
}
[docs]
class Global(Base):
"""
A db model for representing the global user.
:ivar _g_id: The id of the global model.
:vartype _g_id: int
:ivar _version_max: The version limit of all projects.
:vartype _version_max: int
:ivar _c_id: The id of the current project.
:vartype _c_id: int
:ivar _current_project: The current project.
:vartype _current_project: Project
"""
__tablename__ = "global"
_g_id: Mapped[int] = mapped_column(primary_key = True)
_version_max: Mapped[int]
_c_id: Mapped[int] = mapped_column(ForeignKey("project._p_id"), index = True, nullable = True)
_current_project: Mapped[Project] = relationship(back_populates = "_current_user")
@property
def g_id(self) -> int:
"""
Get the id of the global model.
:return: The id of the global model.
:rtype: int
"""
return self._g_id
@property
def version_max(self) -> int:
"""
Get the current version limit.
:return: The version limit.
:rtype: int
"""
return self._version_max
@property
def c_id(self) -> int:
"""
Get the current project id.
:return: The current project id.
:rtype: int
"""
return self._c_id
@property
def current_project(self) -> Project:
"""
Get the current project.
:return: The project currently being used.
:rtype: Project
"""
return self._current_project
@current_project.setter
def current_project(self, project: Project):
"""
Select a project to be the new current project.
:param project: The project you wish to select.
:type project: Project
"""
if project is None:
self.c_id = None
self._current_project = None
return
self.c_id = project.p_id
self._current_project = project
@c_id.setter
def c_id(self, p_id: int):
"""
Set the current project id.
:param p_id: The project id you wish to set.
:type p_id: int
"""
self._c_id = p_id
@version_max.setter
def version_max(self, num: int):
"""
Set a new version limit.
:param num: The number the limit should be set to.
:type num: int
"""
self._version_max = num
[docs]
def get_model_protected(self) -> dict:
"""
Get the main attributes of the model.
:return: A dictionary with the attributes.
:rtype: dict
"""
return {
"g_id": self._g_id,
"version_max": self._version_max,
"c_id": self._c_id,
}
[docs]
class Version(Base):
"""
A db model for representing a version.
:ivar _v_id: The id of the version.
:vartype _v_id: int
:ivar _name: The name of the version.
:vartype _name: str
:ivar _date: The creation timestamp of the version.
:vartype _date: datetime
:ivar _favorite: Whether the version is favorited or not.
:vartype _favorite: bool
:ivar _file: The file data as a pickled object.
:vartype _file: Pickle
:ivar _p_id: The id of the version's project.
:vartype _p_id: int
:ivar _project: The version's project.
:vartype _project: Project
"""
__tablename__ = "version"
_v_id: Mapped[int] = mapped_column(primary_key = True)
_name: Mapped[str] = mapped_column(String(db_config.DB_VERSION_NAME_MAX))
_date: Mapped[datetime] = mapped_column(
index = True,
default = lambda: datetime.now(timezone.utc).astimezone(get_localzone())
)
_favorite: Mapped[bool] = mapped_column(default = False)
_file: Mapped[Pickle]
_p_id: Mapped[int] = mapped_column(ForeignKey("project._p_id"), index = True)
_project: Mapped[Project] = relationship(back_populates = "_versions")
[docs]
def toggle_favorite(self):
"""
Toggle whether the version is favorited or not.
"""
self._favorite = not self._favorite
@property
def v_id(self) -> int:
"""
Get the id of the version.
:return: The id of the version.
:rtype: int
"""
return self._v_id
@property
def name(self) -> str:
"""
Get the name of the version.
:return: The name of the version.
:rtype: str
"""
return self._name
@property
def date(self) -> datetime:
"""
Get the date of the version.
:return: The date of the version.
:rtype: datetime
"""
return self._date
@property
def favorite(self) -> bool:
"""
Get whether the version is favorited or not.
:return: If the version is favorited.
:rtype: bool
"""
return self._favorite
@property
def file(self) -> System:
"""
Get the file data of the version.
:return: The System object of the pickled file.
:rtype: System
"""
return self._file
@property
def p_id(self) -> int:
"""
Get the project id of the version.
:return: The project id of the version.
:rtype: int
"""
return self._p_id
@property
def project(self) -> Project:
"""
Get the project of the version.
:return: The project this version is inside of.
:rtype: Project
"""
return self._project
[docs]
def get_model_protected(self) -> dict:
"""
Get the main attributes of the model.
:return: A dictionary with the attributes.
:rtype: dict
"""
return {
"v_id": self._v_id,
"name": self._name,
"date": self._date.strftime("%Y-%m-%d-%H:%M:%S"),
"favorite": self._favorite,
"p_id": self._p_id
}
[docs]
class Project(Base):
"""
A db model for representing a project.
:ivar _p_id: The id of the project.
:vartype _p_id: int
:ivar _name: The name of the project.
:vartype _name: str
:ivar _date: The creation timestamp of the project.
:vartype _date: datetime
:ivar _versions: The versions of the project.
:vartype _versions: WriteOnlyMapped[Version]
:ivar _current_user: The user model of the project.
:vartype _current_user: Global
"""
__tablename__ = "project"
_p_id: Mapped[int] = mapped_column(primary_key = True)
_name: Mapped[str] = mapped_column(String(db_config.DB_PROJECT_NAME_MAX))
_date: Mapped[datetime] = mapped_column(
index = True,
default = lambda: datetime.now(timezone.utc).astimezone(get_localzone())
)
_versions: WriteOnlyMapped[Version] = relationship(
back_populates = "_project",
passive_deletes = True
)
_current_user: Mapped[Global] = relationship(back_populates = "_current_project")
[docs]
def add_version(self, version: Version):
"""
Add a version to the project.
:param version: The version to add.
:type version: Version
"""
self._versions.add(version)
[docs]
def remove_version(self, version: Version):
"""
Remove a version from the project.
:param version: The version to remove.
:type version: Version
"""
self._versions.remove(version)
@property
def p_id(self) -> int:
"""
Get the id of the project
:return: The id of the project.
:rtype: int
"""
return self._p_id
@property
def name(self) -> str:
"""
Get the name of the project
:return: The name of the project
:rtype: str
"""
return self._name
@property
def date(self) -> datetime:
"""
Get the date of the project.
:return: The date of the project.
:rtype: datetime
"""
return self._date
@property
def versions(self) -> WriteOnlyCollection[Version]:
"""
Get the versions inside the project.
:return: Collection of versions in the project.
:rtype: WriteOnlyCollection[Version]
"""
return self._versions
@property
def current_user(self) -> Global:
"""
Get the current user of the project.
:return: The current user of the project.
:rtype: Global
"""
return self._current_user
[docs]
def get_model_protected(self) -> dict:
"""
Get the main attributes of the model.
:return: A dictionary with the attributes.
:rtype: dict
"""
return {
"p_id": self._p_id,
"name": self._name,
"date": self._date.strftime("%Y-%m-%d-%H:%M:%S")
}