# -*- coding: utf-8 -*- """ Pydantic schemas for TOAR database """ from typing import List, Any from pydantic import BaseModel, Json, validator, Field import datetime as dt from toardb.generic.models import RS_enum, RC_enum from toardb.contacts.schemas import Contact from .models import DA_enum, SF_enum, AT_enum, DS_enum, MM_enum from toardb.variables.schemas import Variable #from toardb.stationmeta.schemas import StationmetaCoreCreate from toardb.stationmeta.schemas import StationmetaCoreBase #from toardb.stationmeta.schemas import StationmetaCore #from toardb.stationmeta.schemas import StationmetaCreate #from toardb.stationmeta.schemas import StationmetaBase #from toardb.stationmeta.schemas import Stationmeta # ======== Timeseries ========= class TimeseriesCoreBaseStub(BaseModel): id: int = None label: str = Field(..., description="a short string to distinguish this timeseries from others with the same combination of station and variable") order: int = Field(..., description="indicates position of this timeseries in a list when several timeseries share the same station and variable combination") access_rights: str = Field(..., description="Access rights of timeseries data") sampling_frequency: str = Field(..., description="Sampling frequency of data in this timeseries") aggregation: str = Field(..., description="Aggregation type in this timeseries") source: str data_start_date: dt.datetime = Field(..., description="Start date of the variable data available for this station") data_end_date: dt.datetime = Field(..., description="End date of the variable data available for this station") measurement_method: str = Field(..., description="instrument principle of measurement") sampling_height: float = Field(..., description="Height above the ground of the inlet/instrument/sampler (in m)") date_added: dt.datetime = Field(..., description="Date of timeseries metadata entry into TOAR database") date_modified: dt.datetime = Field(..., description="Date of last timeseries metadata modification") additional_metadata: Json = Field(..., description="Additional information about the timeseries as JSON structure.") # still missing: "Score values from automated data QA (5-star evaluation)" # still missing: "detailed report of timeseries QA/QC evaluation" # still missing: "arbitrary additional information about this timeseries" @validator('access_rights') def check_access_rights(cls, v): return tuple(filter(lambda x: x.value == int(v), DA_enum))[0].string @validator('sampling_frequency') def check_sampling_frequency(cls, v): return tuple(filter(lambda x: x.value == int(v), SF_enum))[0].string @validator('aggregation') def check_aggregation(cls, v): return tuple(filter(lambda x: x.value == int(v), AT_enum))[0].string @validator('source') def check_source(cls, v): return tuple(filter(lambda x: x.value == int(v), DS_enum))[0].string @validator('measurement_method') def check_measurement_method(cls, v): return tuple(filter(lambda x: x.value == int(v), MM_enum))[0].string class TimeseriesCoreBase(TimeseriesCoreBaseStub): station_id: int variable_id: int programme_id: int = None class TimeseriesCoreCreate(TimeseriesCoreBase): pass @validator('access_rights') def check_access_rights(cls, v): if tuple(filter(lambda x: x.string == v, DA_enum)): return v else: raise ValueError(f"data access rights not known: {v}") @validator('sampling_frequency') def check_sampling_frequency(cls, v): if tuple(filter(lambda x: x.string == v, SF_enum)): return v else: raise ValueError(f"sampling frequency not known: {v}") @validator('aggregation') def check_aggregation(cls, v): if tuple(filter(lambda x: x.string == v, AT_enum)): return v else: raise ValueError(f"aggregation type not known: {v}") @validator('source') def check_source(cls, v): if tuple(filter(lambda x: x.string == v, DS_enum)): return v else: raise ValueError(f"data source not known: {v}") @validator('measurement_method') def check_measurement_method(cls, v): if tuple(filter(lambda x: x.string == v, MM_enum)): return v else: raise ValueError(f"measurement method not known: {v}") class TimeseriesCore(TimeseriesCoreBase): id: int class Config: orm_mode = True # ======== TimeseriesRole ========= class TimeseriesRoleBase(BaseModel): id: int = None role: str status: str contact: Contact @validator('role') def check_role(cls, v): return tuple(filter(lambda x: x.value == int(v), RC_enum))[0].string @validator('status') def check_status(cls, v): return tuple(filter(lambda x: x.value == int(v), RS_enum))[0].string class TimeseriesRoleCreate(TimeseriesRoleBase): pass @validator('role') def check_role(cls, v): if tuple(filter(lambda x: x.string == v, RC_enum)): return v else: raise ValueError(f"role code not known: {v}") @validator('status') def check_status(cls, v): if tuple(filter(lambda x: x.string == v, RS_enum)): return v else: raise ValueError(f"role status not known: {v}") class TimeseriesRole(TimeseriesRoleBase): id: int contact: Contact class Config: orm_mode = True # ======== TimeseriesAnnotation ========= class TimeseriesAnnotationBase(BaseModel): id: int = None kind: int text: str date_added: dt.datetime approved: bool contributor_id: int timeseries_id: int class TimeseriesAnnotationCreate(TimeseriesAnnotationBase): pass class TimeseriesAnnotation(TimeseriesAnnotationBase): id: int class Config: orm_mode = True # ======== TimeseriesProgramme ========= class TimeseriesProgrammeBase(BaseModel): id: int = None name: str longname: str homepage: str description: str class TimeseriesProgrammeCreate(TimeseriesProgrammeBase): pass class TimeseriesProgramme(TimeseriesProgrammeBase): id: int class Config: orm_mode = True # ======== TimeseriesChangelog ========= class TimeseriesChangelogBase(BaseModel): id: int datetime: dt.datetime description: str old_value: str new_value: str timeseries_id: int author_id: int type_of_change: int period_start: dt.datetime = None period_end: dt.datetime = None version: str = None class TimeseriesChangelog(TimeseriesChangelogBase): id: int class Config: orm_mode = True # ======== for nested view/upload ========= class TimeseriesBase(TimeseriesCoreBaseStub): roles: List[TimeseriesRole] = None annotations: List[TimeseriesAnnotation] = None variable: Variable # station: StationmetaCoreCreate # station: StationmetaCore # station: StationmetaCreate # station: StationmetaBase # station: Stationmeta # Try, which one of the above is wanted for station # The next one works: station: StationmetaCoreBase programme: TimeseriesProgramme changelog: List[TimeseriesChangelog] = None class Config: orm_mode = True class TimeseriesPatch(BaseModel): label: str = None order: int = None access_rights: str = None sampling_frequency: str = None aggregation: str = None source: str = None data_start_date: dt.datetime = None data_end_date: dt.datetime = None measurement_method: str = None sampling_height: float = None date_added: dt.datetime = None date_modified: dt.datetime = None additional_metadata: Json = None roles: List[TimeseriesRole] = None annotations: List[TimeseriesAnnotation] = None variable: Variable = None station: StationmetaCoreBase = None programme: TimeseriesProgramme = None class Config: orm_mode = True class TimeseriesCreate(TimeseriesCoreCreate): roles: List[TimeseriesRoleCreate] = None annotations: List[TimeseriesAnnotation] = None class Config: orm_mode = True class Timeseries(TimeseriesBase): id: int class Config: orm_mode = True