-
Notifications
You must be signed in to change notification settings - Fork 37
/
characteristic.py
112 lines (89 loc) · 5.04 KB
/
characteristic.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
from sqlalchemy import Column, Integer, ForeignKey, Float, String
from sqlalchemy.orm import relationship, Session
from isatools.model import Characteristic as CharacteristicModel, OntologyAnnotation as OntologyAnnotationModel
from isatools.database.models.relationships import (
source_characteristics,
sample_characteristics,
materials_characteristics
)
from isatools.database.models.constraints import build_characteristic_constraints
from isatools.database.utils import Base
from isatools.database.models.utils import make_get_table_method
class Characteristic(Base):
""" The SQLAlchemy model for the Characteristic table """
__tablename__: str = 'characteristic'
__table_args__: tuple = (*build_characteristic_constraints(), {"comment": "Characteristic table"})
# Base fields
characteristic_id: int = Column(Integer, primary_key=True)
value_int: float = Column(Float, comment='Characteristic value as a float')
unit_str: str = Column(String, comment='Characteristic unit as a string')
category_str: str = Column(String, comment='Characteristic category as a string')
# Relationships: back-ref
sources: relationship = relationship('Source', secondary=source_characteristics, back_populates='characteristics')
samples: relationship = relationship('Sample', secondary=sample_characteristics, back_populates='characteristics')
materials: relationship = relationship(
'Material', secondary=materials_characteristics, back_populates='characteristics')
# Relationships many-to-one
value_id: str = Column(String, ForeignKey(
'ontology_annotation.ontology_annotation_id'), comment='Value of the characteristic as an OntologyAnnotation')
value_oa: relationship = relationship(
'OntologyAnnotation', backref='characteristics_value', foreign_keys=[value_id])
unit_id: str = Column(
String, ForeignKey('ontology_annotation.ontology_annotation_id'),
comment='Characteristic unit as an ontology annotation')
unit_oa: relationship = relationship('OntologyAnnotation', backref='characteristics_unit', foreign_keys=[unit_id])
category_id: str = Column(
String, ForeignKey('ontology_annotation.ontology_annotation_id'),
comment='Characteristic category as an ontology annotation')
category_oa: relationship = relationship(
'OntologyAnnotation', backref='characteristics_category', foreign_keys=[category_id])
# Relationships one-to-many
comments: relationship = relationship('Comment', back_populates='characteristic')
def to_json(self) -> dict:
""" Convert the SQLAlchemy object to a dictionary
:return: The dictionary representation of the object taken from the database
"""
comments = [c.to_json() for c in self.comments]
unit = self.unit_str
if self.unit_oa:
unit = self.unit_oa.to_json()
value = self.value_int
if self.value_oa:
value = self.value_oa.to_json()
category = self.category_str
if self.category_oa:
category = self.category_oa.to_json()
return {"value": value, "comments": comments, "unit": unit, "category": category}
def make_characteristic_methods():
""" This function will dynamically add the methods to the Characteristic class that are required to interact with
the database. This is done to avoid circular imports and to extra dependencies in the models package. It's called
in the init of the database models package.
"""
def to_sql(self, session: Session) -> Characteristic:
""" Convert the Characteristic object to a SQLAlchemy object so that it can be added to the database.
:param self: the Characteristic object. Will be injected automatically.
:param session: The SQLAlchemy session to use.
:return: The SQLAlchemy object ready to be committed to the database session.
"""
characteristic = {"comments": [c.to_sql() for c in self.comments]}
if isinstance(self.value, int) or isinstance(self.value, float):
value = self.value
if isinstance(self.value, int):
value = float(self.value)
characteristic["value_int"] = value
elif not isinstance(self.value, str):
characteristic["value_oa"] = self.value.to_sql(session)
else:
value = OntologyAnnotationModel(term=self.value)
characteristic["value_oa"] = value.to_sql(session)
if isinstance(self.unit, str):
characteristic["unit_str"] = self.unit
elif self.unit:
characteristic["unit_id"] = self.unit.id
if isinstance(self.category, str):
characteristic["category_str"] = self.category
else:
characteristic["category_id"] = self.category.id
return Characteristic(**characteristic)
setattr(CharacteristicModel, 'to_sql', to_sql)
setattr(CharacteristicModel, 'get_table', make_get_table_method(Characteristic))