"""
All databases schemes for instrumentation and instrumentation journal entries (including templates) go here.
"""
from dataclasses import dataclass
from datetime import datetime
# from typing import List, Set, Any # Needs to be here for compatibility with python 3.8
# from ResearchNotes.search import add_to_index, remove_from_index, query_index, delete_index
from ResearchNotes.database import db
from ResearchNotes.database.mixins import SearchableMixin
# =============================================================================
# Many-to-many table for instruments
# =============================================================================
SharedInstrumentsToGuestUsers = db.Table(
"shared_instruments_to_guest_users",
db.Column("intrument_id", db.Integer, db.ForeignKey("instrument.id")),
db.Column("user_id", db.Integer, db.ForeignKey("users.id")),
)
# =============================================================================
# Instrument database scheme
# =============================================================================
[docs]@dataclass(init=False, eq=False)
class Instrument(SearchableMixin, db.Model): # type: ignore
"""
Define the Instrument database scheme.
An instrument has an id, an identifier, a description, and a creator.
It also stores creation and update date.
One-to-many relations:
- user_id
- group_id
- location_id
Backref:
- InstrumentationJournalEntry
Many-to-many relation:
- InstrumentSharedWithGroups
"""
__tablename__ = "instrument"
__searchable__ = ["identifier", "description"]
id: int = db.Column(db.Integer, primary_key=True)
identifier: str = db.Column(db.String(80), nullable=False)
description: str = db.Column(db.Text, nullable=False)
active: bool = db.Column(db.Boolean, nullable=False, default=True)
created: datetime = db.Column(db.DateTime, nullable=False, index=True, default=datetime.utcnow)
updated: datetime = db.Column(
db.DateTime,
nullable=False,
index=True,
default=datetime.utcnow,
onupdate=datetime.utcnow,
)
# One to many
# Creator of record
creator_id: int = db.Column(db.Integer, db.ForeignKey("users.id"))
# Group which owns instrument
group_id: int = db.Column(db.Integer, db.ForeignKey("groups.id"))
# Storage location
location_id: int = db.Column(db.Integer, db.ForeignKey("locations.id"), default=1)
# Default template for E/S/S
default_ess_template_id: int = db.Column(db.Integer, db.ForeignKey("templatesamples.id"))
# Default template for P/P/M
default_ppm_template_id: int = db.Column(db.Integer, db.ForeignKey("templatemeasurements.id"))
# Default template for instrumentation journal entries
default_entry_template_id: int = db.Column(db.Integer, db.ForeignKey("templateentry.id"))
# Backref
#
# Instrumentation Journal entries related to Instrument
# Creates InstrumentationJournalEntry.instrument
#
journal_entries = db.relationship(
"InstrumentationJournalEntry",
backref="instrument",
lazy="dynamic",
order_by="desc(InstrumentationJournalEntry.created)",
)
# PPM that were made using this instrument
#
measurements = db.relationship(
"Measurements",
backref="instrument",
lazy="dynamic",
order_by="desc(Measurements.updated)",
)
# Instrumentation journal entry types associated with this instrument
etypes = db.relationship(
"EntryType",
backref="instrument",
lazy="dynamic",
)
# Many-to-many relationship for shared Instrument
#
guest_users = db.relationship(
"User",
secondary="shared_instruments_to_guest_users",
back_populates="shared_instruments",
)
def __repr__(self) -> str:
"""
Return a representation string of the Instrument database scheme.
Returns
-------
str
Representation string.
"""
return f"Instrument ID:{self.id}-Instrument identifier: {self.identifier}"
@property
def guest_users_list(self) -> list[int]:
"""
Return a list with the IDs of all guest users
Returns
-------
List[int]
The IDs of the users this instrument is shared with
"""
return [user.id for user in self.guest_users]
@property
def is_shared(self) -> bool:
"""
Return true, if the instrument is shared with some group.
Returns
-------
Bool
True if there is an entry in the shared_with_groups_list.
"""
return len(self.guest_users_list) > 0
# =============================================================================
# Instrument template database scheme
# =============================================================================
[docs]@dataclass(init=False, eq=False)
class TemplateInstrument(db.Model): # type: ignore
"""
Instrument template database scheme.
Class for instrument templates, that can be created from exiting
instruments or made from scratch.
"""
__tablename__ = "templateinstrument"
id: int = db.Column(db.Integer, primary_key=True)
creator_id: int = db.Column(db.Integer, db.ForeignKey("users.id"))
group_id: int = db.Column(db.Integer, db.ForeignKey("groups.id"))
tname: str = db.Column(db.String(80), nullable=False)
location_id: int = db.Column(db.Integer, default=1)
identifier: str = db.Column(db.String(80), nullable=False)
description: str = db.Column(db.Text, nullable=False)
created: datetime = db.Column(db.DateTime, nullable=False, index=True, default=datetime.utcnow)
updated: datetime = db.Column(
db.DateTime,
nullable=False,
index=True,
default=datetime.utcnow,
onupdate=datetime.utcnow,
)
# =============================================================================
# Instrumentation journal entry type database scheme
# =============================================================================
#
[docs]@dataclass(init=False, eq=False)
class EntryType(db.Model): # type: ignore
"""
Defines the EntryType database scheme.
Type has an ID and a name. It relates to its instrument.
"""
# id: int = field(init=False)
# name: str
# group_id: int
__tablename__ = "entrytype"
id: int = db.Column(db.Integer, primary_key=True)
name: str = db.Column(db.String(50), nullable=False)
# One to many
# Instrument that the instrumentation journal entry type is associated with
instrument_id: int = db.Column(db.Integer, db.ForeignKey("instrument.id"))
# Backref
# Instrumentation journal entries of this type
# Creates InstrumentationJournalEntry.etype
entries = db.relationship("InstrumentationJournalEntry", backref="etype", lazy="dynamic")
def __repr__(self) -> str:
"""
Representation string of the EntryType database scheme.
Returns
-------
str
Representation of the class.
"""
return f"EntryType ID:{self.id}, EntryType name: {self.name}"
# =============================================================================
# Instrument Journal Entry database scheme
# =============================================================================
[docs]@dataclass(init=False, eq=False)
class InstrumentationJournalEntry(SearchableMixin, db.Model): # type: ignore
"""
Define the Instrumentation Journal Entry database scheme.
An entry has an id, an identifier, a description, and a creator.
It also stores creation and update date.
One-to-many relations:
- user_id
- group_id
- location_id
"""
__tablename__ = "instrumentation_journal_entry"
__searchable__ = ["identifier", "description"]
id: int = db.Column(db.Integer, primary_key=True)
identifier: str = db.Column(db.String(80), nullable=False)
description: str = db.Column(db.Text, nullable=False)
created: datetime = db.Column(db.DateTime, nullable=False, index=True, default=datetime.utcnow)
updated: datetime = db.Column(
db.DateTime,
nullable=False,
index=True,
default=datetime.utcnow,
onupdate=datetime.utcnow,
)
# One to many
# Entry type
etype_id: int = db.Column(db.Integer, db.ForeignKey("entrytype.id"))
# Creator of record
creator_id: int = db.Column(db.Integer, db.ForeignKey("users.id"))
# ID of instrument being journaled about
instrument_id: int = db.Column(db.Integer, db.ForeignKey("instrument.id"))
# ID of owner group
group_id: int = db.Column(db.Integer, db.ForeignKey("groups.id"))
def __repr__(self) -> str:
"""
Return a representation string of the InstrumentationJournalEntry
database scheme.
Returns
-------
str
Representation string.
"""
return f"InstrumentationJournalEntry ID:{self.id}, Identifier: {self.identifier}, "
# =============================================================================
# InstrumentationJournalEntry template database scheme
# =============================================================================
[docs]@dataclass(init=False, eq=False)
class TemplateInstrumentationJournalEntry(db.Model): # type: ignore
"""
Instrumentation journal entry template database scheme.
Class for instrumentation journal entry templates, that can be created from
exiting entries or made from scratch.
"""
__tablename__ = "templateentry"
id: int = db.Column(db.Integer, primary_key=True)
creator_id: int = db.Column(db.Integer, db.ForeignKey("users.id"))
group_id: int = db.Column(db.Integer, db.ForeignKey("groups.id"))
tname: str = db.Column(db.String(80), nullable=False)
identifier: str = db.Column(db.String(80), nullable=False)
description: str = db.Column(db.Text, nullable=False)
created: datetime = db.Column(db.DateTime, nullable=False, index=True, default=datetime.utcnow)
updated: datetime = db.Column(
db.DateTime,
nullable=False,
index=True,
default=datetime.utcnow,
onupdate=datetime.utcnow,
)
etype_id: int = db.Column(db.Integer, default=0)
instruments_default = db.relationship(
"Instrument",
backref="default_entry_template",
lazy="dynamic",
order_by="desc(Instrument.updated)",
)