From 8fbb8ffc31430b45308dbeb6b9766c06f2c1ba28 Mon Sep 17 00:00:00 2001 From: schroeder5 <s.schroeder@fz-juelich.de> Date: Sat, 4 Jul 2020 22:52:20 +0200 Subject: [PATCH] #5: model organisation is integrated into contact; TBD: nested download not yet working as desired --- toardb/contacts/contacts.py | 21 +++++++-------- toardb/contacts/crud.py | 12 +++++++++ toardb/contacts/models.py | 43 ++++++++++++++++++++++++++++++- toardb/contacts/schemas.py | 10 ++++++- toardb/stationmeta/crud.py | 6 ++--- toardb/stationmeta/models_role.py | 12 ++++----- toardb/stationmeta/schemas.py | 7 ++++- toardb/timeseries/crud.py | 6 ++--- toardb/timeseries/models_role.py | 16 ++++++------ toardb/timeseries/schemas.py | 5 +++- 10 files changed, 101 insertions(+), 37 deletions(-) diff --git a/toardb/contacts/contacts.py b/toardb/contacts/contacts.py index 171a549..210c090 100644 --- a/toardb/contacts/contacts.py +++ b/toardb/contacts/contacts.py @@ -12,6 +12,8 @@ router = APIRouter() # plain views to post and get contacts +# 1. persons + #get all entries of table persons @router.get('/contacts/persons/', response_model=List[schemas.Person]) def get_all_persons(skip: int = 0, limit: int = None, db: Session = Depends(get_db)): @@ -33,11 +35,6 @@ def get_person(name: str, db: Session = Depends(get_db)): raise HTTPException(status_code=404, detail="Person not found.") return db_person -#some more gets to be inserted: -# -# -# - @router.post('/contacts/persons/', response_model=schemas.Person) def create_person(person: schemas.PersonCreate = Body(..., embed = True), db: Session = Depends(get_db)): db_person = crud.get_person_by_name(db, name=person.name) @@ -46,7 +43,7 @@ def create_person(person: schemas.PersonCreate = Body(..., embed = True), db: Se return crud.create_person(db=db, person=person) -# plain views to post and get organisations +# 2. organisations #get all entries of table organisations @router.get('/contacts/organisations/', response_model=List[schemas.Organisation]) @@ -69,12 +66,6 @@ def get_organisation(name: str, db: Session = Depends(get_db)): raise HTTPException(status_code=404, detail="Organisation not found.") return db_organisation - -#some more gets to be inserted: -# -# -# - @router.post('/contacts/organisations/', response_model=schemas.Organisation) def create_organisation(organisation: schemas.OrganisationCreate = Body(..., embed = True), db: Session = Depends(get_db)): db_organisation = crud.get_organisation_by_name(db, name=organisation.name) @@ -82,3 +73,9 @@ def create_organisation(organisation: schemas.OrganisationCreate = Body(..., emb raise HTTPException(status_code=400, detail="Organisation already registered.") return crud.create_organisation(db=db, organisation=organisation) +# 3. combined (person + organisation) +#get all entries of table contacts +@router.get('/contacts/', response_model=List[schemas.Contact]) +def get_all_contacts(skip: int = 0, limit: int = None, db: Session = Depends(get_db)): + contacts = crud.get_all_contacts(db, skip=skip, limit=limit) + return contacts diff --git a/toardb/contacts/crud.py b/toardb/contacts/crud.py index 5a3460d..9ad7c03 100644 --- a/toardb/contacts/crud.py +++ b/toardb/contacts/crud.py @@ -30,6 +30,10 @@ def create_organisation(db: Session, organisation: OrganisationCreate): db.add(db_organisation) result = db.commit() db.refresh(db_organisation) + db_contact = models.Contact(person_id=0,organisation_id=db_organisation) + db.add(db_contact) + result = db.commit() + db.refresh(db_contact) return db_organisation @@ -49,4 +53,12 @@ def create_person(db: Session, person: PersonCreate): db.add(db_person) result = db.commit() db.refresh(db_person) + db_contact = models.Contact(person_id=db_person.id,organisation_id=0) + db.add(db_contact) + result = db.commit() + db.refresh(db_contact) return db_person + + +def get_all_contacts(db: Session, skip : int = 0, limit: int = None): + return db.query(models.Contact).offset(skip).limit(limit).all() diff --git a/toardb/contacts/models.py b/toardb/contacts/models.py index c4cbe6e..0c33a6e 100644 --- a/toardb/contacts/models.py +++ b/toardb/contacts/models.py @@ -1,11 +1,18 @@ # coding: utf-8 +""" +class Contact(Base) +=================== +""" + from toardb.base import Base from .models_person import Person from .models_organisation import Organisation -from sqlalchemy import Table, Column, Integer, String +from sqlalchemy import Table, Column, Integer, String, \ + ForeignKey, text, CheckConstraint, Sequence from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import relationship # controlled vocabulary @@ -29,3 +36,37 @@ OK_enum = ( Enumdict(7, 'Other', 'other') ) +CONTACTS_ID_SEQ = Sequence('contacts_id_seq') # define sequence explicitly +class Contact(Base): + """ Table "public.contacts" + + +-----------------+---------+-----------+----------+----------------------------------------+ + | Column | Type | Collation | Nullable | Default | + +=================+=========+===========+==========+========================================+ + | id | integer | | not null | nextval('contacts_id_seq'::regclass) | + +-----------------+---------+-----------+----------+----------------------------------------+ + | person_id | integer | | | | + +-----------------+---------+-----------+----------+----------------------------------------+ + | organisation_id | integer | | | | + +-----------------+---------+-----------+----------+----------------------------------------+ + Indexes: + "contacts_pkey" PRIMARY KEY, btree (id) + Check constraints: + "ck_contact" CHECK (person_id > 0 AND organisation_id = 0 OR person_id = 0 AND organisation_id > 0) + Foreign-key constraints: + "contacts_organisation_id_fkey" FOREIGN KEY (organisation_id) REFERENCES organisations(id) + "contacts_person_id_fkey" FOREIGN KEY (person_id) REFERENCES persons(id) + """ + + __tablename__ = 'contacts' + __table_args__ = ( + CheckConstraint('((person_id > 0) AND (organisation_id = 0)) OR ((person_id = 0) AND (organisation_id > 0))'), + ) + + id = Column(Integer, primary_key=True, server_default=text("nextval('contacts_id_seq'::regclass)")) + person_id = Column(ForeignKey('persons.id')) + organisation_id = Column(ForeignKey('organisations.id')) + + organisation = relationship('Organisation') + person = relationship('Person') + diff --git a/toardb/contacts/schemas.py b/toardb/contacts/schemas.py index 25cd340..296b88a 100644 --- a/toardb/contacts/schemas.py +++ b/toardb/contacts/schemas.py @@ -3,7 +3,7 @@ Pydantic schemas for TOAR database """ -from typing import List +from typing import List, Dict, Any from pydantic import BaseModel, validator from .models import OK_enum @@ -61,4 +61,12 @@ class Person(PersonBase): class Config: orm_mode = True +# ======== for nested view ========= + +class Contact(BaseModel): + person: Person + organisation: Organisation + + class Config: + orm_mode = True diff --git a/toardb/stationmeta/crud.py b/toardb/stationmeta/crud.py index 47cce8b..24a21c4 100644 --- a/toardb/stationmeta/crud.py +++ b/toardb/stationmeta/crud.py @@ -58,9 +58,9 @@ def get_all_stationmeta(db: Session, skip : int = 0, limit: int = None): # is this internal, or should this also go to public REST api? -def get_unique_stationmeta_role(db: Session, role: int, person_id: int, status: int): +def get_unique_stationmeta_role(db: Session, role: int, contact_id: int, status: int): db_object = db.query(models.StationmetaRole).filter(models.StationmetaRole.role == role) \ - .filter(models.StationmetaRole.person_id == person_id) \ + .filter(models.StationmetaRole.contact_id == contact_id) \ .filter(models.StationmetaRole.status == status) \ .first() return db_object @@ -107,7 +107,7 @@ def create_stationmeta(db: Session, stationmeta: StationmetaCreate): db_role.role = get_value_from_str(RC_enum,db_role.role) db_role.status = get_value_from_str(RS_enum,db_role.status) # check whether role is already present in database - db_object = get_unique_stationmeta_role(db, db_role.role, db_role.person_id, db_role.status) + db_object = get_unique_stationmeta_role(db, db_role.role, db_role.contact_id, db_role.status) if db_object: role_id = db_object.id else: diff --git a/toardb/stationmeta/models_role.py b/toardb/stationmeta/models_role.py index e052591..ced78b8 100644 --- a/toardb/stationmeta/models_role.py +++ b/toardb/stationmeta/models_role.py @@ -6,7 +6,7 @@ class StationmetaRole (Base) from sqlalchemy import Column, ForeignKey, Integer, \ CheckConstraint, UniqueConstraint, Table, Sequence from sqlalchemy.orm import relationship -from toardb.contacts.models import Person +from toardb.contacts.models import Contact from toardb.base import Base @@ -30,16 +30,16 @@ class StationmetaRole(Base): +------------+---------+-----------+----------+-----------------------------------------------+ | status | integer | | not null | | +------------+---------+-----------+----------+-----------------------------------------------+ - | person_id | integer | | not null | | + | contact_id | integer | | not null | | +------------+---------+-----------+----------+-----------------------------------------------+ Indexes: "stationmeta_roles_pkey" PRIMARY KEY, btree (id) - "stationmeta_roles_person_id_3bd9c160" btree (person_id) + "stationmeta_roles_contact_id_3bd9c160" btree (contact_id) Check constraints: "stationmeta_roles_role_check" CHECK (role >= 0) "stationmeta_roles_status_check" CHECK (status >= 0) Foreign-key constraints: - "stationmeta_roles_person_id_3bd9c160_fk_persons_id" FOREIGN KEY (person_id) REFERENCES persons(id) DEFERRABLE INITIALLY DEFERRED + "stationmeta_roles_contact_id_3bd9c160_fk_contacts_id" FOREIGN KEY (contact_id) REFERENCES contacts(id) DEFERRABLE INITIALLY DEFERRED "stationmeta_roles_role_fk_rc_vocabulary_enum_val" FOREIGN KEY (role) REFERENCES rc_vocabulary(enum_val) "stationmeta_roles_status_fk_rs_vocabulary_enum_val" FOREIGN KEY (status) REFERENCES rs_vocabulary(enum_val) """ @@ -56,9 +56,7 @@ class StationmetaRole(Base): # do not use string declaration here (not working for pytest) # use the explicit class name here, # see: https://groups.google.com/forum/#!topic/sqlalchemy/YjGhE4d6K4U - person_id = Column(ForeignKey(Person.id, deferrable=True, initially='DEFERRED'), nullable=False, index=True) -# how to reactivate the following two lines?! -# person = relationship('Person') + contact_id = Column(ForeignKey(Contact.id, deferrable=True, initially='DEFERRED'), nullable=False, index=True) station = relationship("StationmetaCore", secondary=stationmeta_core_stationmeta_roles_table, diff --git a/toardb/stationmeta/schemas.py b/toardb/stationmeta/schemas.py index db22981..85e9e54 100644 --- a/toardb/stationmeta/schemas.py +++ b/toardb/stationmeta/schemas.py @@ -12,6 +12,7 @@ import datetime as dt from .models import CZ_enum, CV_enum, ST_enum, TA_enum, TC_enum, \ TR_enum, DL_enum from toardb.generic.models import RC_enum, RS_enum +from toardb.contacts.models import Contact # the following class was taken from: @@ -320,7 +321,8 @@ class StationmetaRoleBase(BaseModel): id: int = None role: str status: str - person_id: int +# contact: Contact + contact_id: int @validator('role') def check_role(cls, v): @@ -330,6 +332,9 @@ class StationmetaRoleBase(BaseModel): def check_status(cls, v): return tuple(filter(lambda x: x.value == int(v), RS_enum))[0].string + class Config: + orm_mode = True + class StationmetaRoleCreate(StationmetaRoleBase): pass diff --git a/toardb/timeseries/crud.py b/toardb/timeseries/crud.py index 4fec5d0..03480e8 100644 --- a/toardb/timeseries/crud.py +++ b/toardb/timeseries/crud.py @@ -53,9 +53,9 @@ def get_role_ids_of_timeseries(db: Session, timeseries_id: int): # is this internal, or should this also go to public REST api? -def get_unique_timeseries_role(db: Session, role: int, person_id: int, status: int): +def get_unique_timeseries_role(db: Session, role: int, contact_id: int, status: int): db_object = db.query(models.TimeseriesRole).filter(models.TimeseriesRole.role == role) \ - .filter(models.TimeseriesRole.person_id == person_id) \ + .filter(models.TimeseriesRole.contact_id == contact_id) \ .filter(models.TimeseriesRole.status == status) \ .first() return db_object @@ -97,7 +97,7 @@ def create_timeseries(db: Session, timeseries: TimeseriesCreate): db_role.role = get_value_from_str(RC_enum,db_role.role) db_role.status = get_value_from_str(RS_enum,db_role.status) # check whether role is already present in database - db_object = get_unique_timeseries_role(db, db_role.role, db_role.person_id, db_role.status) + db_object = get_unique_timeseries_role(db, db_role.role, db_role.contact_id, db_role.status) if db_object: role_id = db_object.id else: diff --git a/toardb/timeseries/models_role.py b/toardb/timeseries/models_role.py index bf88739..2db40ea 100644 --- a/toardb/timeseries/models_role.py +++ b/toardb/timeseries/models_role.py @@ -7,7 +7,7 @@ from sqlalchemy import Column, ForeignKey, Integer, text, \ CheckConstraint, UniqueConstraint, \ Table, Sequence from sqlalchemy.orm import relationship -from toardb.contacts.models import Person +from toardb.contacts.models import Contact from toardb.base import Base @@ -30,24 +30,24 @@ class TimeseriesRole(Base): +---------------+---------+-----------+----------+----------------------------------------------+ | status | integer | | not null | | +---------------+---------+-----------+----------+----------------------------------------------+ - | person_id | integer | | not null | | + | contact_id | integer | | not null | | +---------------+---------+-----------+----------+----------------------------------------------+ Indexes: "timeseries_roles_pkey" PRIMARY KEY, btree (id) - "timeseries_roles_role_person_id_uniq" UNIQUE CONSTRAINT, btree (role, person_id) - "timeseries_roles_person_id" btree (person_id) + "timeseries_roles_role_contact_id_uniq" UNIQUE CONSTRAINT, btree (role, contact_id) + "timeseries_roles_contact_id" btree (contact_id) Check constraints: "timeseries_roles_role_check" CHECK (role >= 0) "timeseries_roles_status_check" CHECK (status >= 0) Foreign-key constraints: - "timeseries_roles_person_id_3e26200e_fk_persons_id" FOREIGN KEY (person_id) REFERENCES persons(id) DEFERRABLE INITIALLY DEFERRED + "timeseries_roles_contact_id_fk_contacts_id" FOREIGN KEY (contact_id) REFERENCES contacts(id) DEFERRABLE INITIALLY DEFERRED """ __tablename__ = 'timeseries_roles' __table_args__ = ( CheckConstraint('role >= 0'), CheckConstraint('status >= 0'), - UniqueConstraint('role', 'person_id') + UniqueConstraint('role', 'contact_id') ) id = Column(Integer, TIMESERIES_ROLES_ID_SEQ, primary_key=True, server_default=TIMESERIES_ROLES_ID_SEQ.next_value()) @@ -56,8 +56,8 @@ class TimeseriesRole(Base): # do not use string declaration here (not working for pytest) # use the explicit class name here, # see: https://groups.google.com/forum/#!topic/sqlalchemy/YjGhE4d6K4U - person_id = Column(ForeignKey(Person.id, deferrable=True, initially='DEFERRED'), nullable=False, index=True) -# person = relationship(Person) + contact_id = Column(ForeignKey(Contact.id, deferrable=True, initially='DEFERRED'), nullable=False, index=True) + contact = relationship(Contact) # rc_vocabulary = relationship('RcVocabulary') # rs_vocabulary = relationship('RsVocabulary') diff --git a/toardb/timeseries/schemas.py b/toardb/timeseries/schemas.py index 46d2498..75d0637 100644 --- a/toardb/timeseries/schemas.py +++ b/toardb/timeseries/schemas.py @@ -9,6 +9,7 @@ from typing import List, Any from pydantic import BaseModel, Json, validator import datetime as dt from toardb.generic.models import RS_enum, RC_enum +from toardb.contacts.models 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 @@ -115,7 +116,9 @@ class TimeseriesRoleBase(BaseModel): id: int = None role: str status: str - person_id: int +# contact_id: int # works +# contact: Contact # does not work! + contact: Any @validator('role') def check_role(cls, v): -- GitLab