diff --git a/toardb/stationmeta/crud.py b/toardb/stationmeta/crud.py index cecf6a16c4da72822591cbc1a00fe81f170f4321..472ee5246c3ef5d9135bdb99aecece2823bb2221 100644 --- a/toardb/stationmeta/crud.py +++ b/toardb/stationmeta/crud.py @@ -9,6 +9,7 @@ from typing import List from geoalchemy2.types import Geometry from geoalchemy2.elements import WKBElement, WKTElement from sqlalchemy.orm import Session +from sqlalchemy.engine import Engine from sqlalchemy.dialects.postgresql import JSONB, ARRAY from fastapi import File, UploadFile from fastapi.responses import JSONResponse @@ -94,7 +95,7 @@ def get_unique_stationmeta_annotation(db: Session, text: str, contributor_id: in return db_object -def create_stationmeta(db: Session, stationmeta: StationmetaCreate): +def create_stationmeta(db: Session, engine: Engine, stationmeta: StationmetaCreate): stationmeta_dict = stationmeta.dict() roles_data = stationmeta_dict.pop('roles', None) annotations_data = stationmeta_dict.pop('annotations', None) @@ -112,85 +113,100 @@ def create_stationmeta(db: Session, stationmeta: StationmetaCreate): # but return from this method gives: "additional_metadata": {} # ==> there is a mismatch between model(JSONB) and schema(JSON) db_stationmeta.additional_metadata = str(db_stationmeta.additional_metadata).replace("'",'"') - db_stationmeta.type_of_environment = get_value_from_str(ST_enum,db_stationmeta.type_of_environment) - db_stationmeta.type_of_area = get_value_from_str(TA_enum,db_stationmeta.type_of_area) - db.add(db_stationmeta) - result = db.commit() - db.refresh(db_stationmeta) - # get staionmeta_core_id - stationmeta_core_id = db_stationmeta.id - # store roles and update association table - if roles_data: - for r in roles_data: - db_role = models.StationmetaRole(**r) - 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.contact_id, db_role.status) - if db_object: - role_id = db_object.id - else: - db.add(db_role) + fake_conn = engine.raw_connection() + fake_cur = fake_conn.cursor() + radius = 100 + db_cmd = f"select * from stationmeta_core where ST_DistanceSphere(stationmeta_core.coordinates, '{db_stationmeta.coordinates}') < {radius}" + fake_cur.execute(db_cmd) + records = fake_cur.fetchall() + if records: + if len(records) == 1: + print('already in database --> patch record (add station code)') + else: + print('more than one station falls within the given radius!') + print('choose which station record to patch (add station code)') + for record in records: + print(record) + else: + db_stationmeta.type_of_environment = get_value_from_str(ST_enum,db_stationmeta.type_of_environment) + db_stationmeta.type_of_area = get_value_from_str(TA_enum,db_stationmeta.type_of_area) + db.add(db_stationmeta) + result = db.commit() + db.refresh(db_stationmeta) + # get staionmeta_core_id + stationmeta_core_id = db_stationmeta.id + # store roles and update association table + if roles_data: + for r in roles_data: + db_role = models.StationmetaRole(**r) + 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.contact_id, db_role.status) + if db_object: + role_id = db_object.id + else: + db.add(db_role) + db.commit() + db.refresh(db_role) + role_id = db_role.id + db.execute(insert(stationmeta_core_stationmeta_roles_table).values(station_id=stationmeta_core_id, role_id=role_id)) db.commit() - db.refresh(db_role) - role_id = db_role.id - db.execute(insert(stationmeta_core_stationmeta_roles_table).values(station_id=stationmeta_core_id, role_id=role_id)) - db.commit() - # store annotations and update association table - if annotations_data: - for a in annotations_data: - db_annotation = models.StationmetaAnnotation(**a) - # check whether annotation is already present in database - db_object = get_unique_stationmeta_annotation(db, db_annotation.text, db_annotation.contributor_id) - if db_object: - annotation_id = db_object.id - else: - db.add(db_annotation) + # store annotations and update association table + if annotations_data: + for a in annotations_data: + db_annotation = models.StationmetaAnnotation(**a) + # check whether annotation is already present in database + db_object = get_unique_stationmeta_annotation(db, db_annotation.text, db_annotation.contributor_id) + if db_object: + annotation_id = db_object.id + else: + db.add(db_annotation) + db.commit() + db.refresh(db_annotation) + annotation_id = db_annotation.id + db.execute(insert(stationmeta_core_stationmeta_annotations_table).values(station_id=stationmeta_core_id, annotation_id=annotation_id)) db.commit() - db.refresh(db_annotation) - annotation_id = db_annotation.id - db.execute(insert(stationmeta_core_stationmeta_annotations_table).values(station_id=stationmeta_core_id, annotation_id=annotation_id)) - db.commit() - # store aux_images - if aux_images_data: - for i in aux_images_data: - db_aux_image = models.StationmetaAuxImage(**i) - db_aux_image.station_id = stationmeta_core_id - db.add(db_aux_image) - db.commit() - db.refresh(db_aux_image) - # store aux_docs - if aux_docs_data: - for d in aux_docs_data: - db_aux_doc = models.StationmetaAuxDoc(**d) - db_aux_doc.station_id = stationmeta_core_id - db.add(db_aux_doc) + # store aux_images + if aux_images_data: + for i in aux_images_data: + db_aux_image = models.StationmetaAuxImage(**i) + db_aux_image.station_id = stationmeta_core_id + db.add(db_aux_image) + db.commit() + db.refresh(db_aux_image) + # store aux_docs + if aux_docs_data: + for d in aux_docs_data: + db_aux_doc = models.StationmetaAuxDoc(**d) + db_aux_doc.station_id = stationmeta_core_id + db.add(db_aux_doc) + db.commit() + db.refresh(db_aux_doc) + # store aux_urls + if aux_urls_data: + for u in aux_urls_data: + db_aux_url = models.StationmetaAuxUrl(**u) + db_aux_url.station_id = stationmeta_core_id + db.add(db_aux_url) + db.commit() + db.refresh(db_aux_url) + # store globalmeta + if globalmeta_data: + db_global = models.StationmetaGlobal(**globalmeta_data) + if db_global.climatic_zone: + db_global.climatic_zone = get_value_from_str(CZ_enum,db_global.climatic_zone) + db_global.station_id = stationmeta_core_id + db.add(db_global) db.commit() - db.refresh(db_aux_doc) - # store aux_urls - if aux_urls_data: - for u in aux_urls_data: - db_aux_url = models.StationmetaAuxUrl(**u) - db_aux_url.station_id = stationmeta_core_id - db.add(db_aux_url) + db.refresh(db_global) + # store globalservice + if globalservice_data: + db_globalservice = models.StationmetaGlobalService(**globalservice) + db_globalservice.station_id = stationmeta_core_id + db.add(db_globalservice) db.commit() - db.refresh(db_aux_url) - # store globalmeta - if globalmeta_data: - db_global = models.StationmetaGlobal(**globalmeta_data) - if db_global.climatic_zone: - db_global.climatic_zone = get_value_from_str(CZ_enum,db_global.climatic_zone) - db_global.station_id = stationmeta_core_id - db.add(db_global) - db.commit() - db.refresh(db_global) - # store globalservice - if globalservice_data: - db_globalservice = models.StationmetaGlobalService(**globalservice) - db_globalservice.station_id = stationmeta_core_id - db.add(db_globalservice) - db.commit() - db.refresh(db_globalservice) + db.refresh(db_globalservice) # there's a mismatch with coordinates --> how to automatically switch back and forth?! db_stationmeta.coordinates = tmp_coordinates return db_stationmeta @@ -352,13 +368,15 @@ def patch_stationmeta(db: Session, description: str, station_id: int, stationmet def delete_stationmeta_field(db: Session, station_id: int, field: str): + # id can never be deleted (and of course also not changed)!!! + # there are mandatory fields (from stationmeta_core), that cannot be deleted! + # --> set these to their default value field_table = {'roles': stationmeta_core_stationmeta_roles_table, 'annotations': stationmeta_core_stationmeta_annotations_table} # 'aux_images': stationmeta_core_stationmeta_aux_images_table, # 'aux_docs': stationmeta_core_stationmeta_aux_docs_table, # 'aux_urls': stationmeta_core_stationmeta_aux_urls_table, # 'globalmeta': stationmeta_core_stationmeta_globalmeta_table} - # there are mandatory fields (from stationmeta_core), that cannot be deleted! if ((field == 'roles') or (field == 'annotations')): db.execute(delete(field_table[field]).where(field_table[field].c.station_id==station_id)) # problem with automatic conversion of coordinates (although not explicitly fetched from database) diff --git a/toardb/stationmeta/stationmeta.py b/toardb/stationmeta/stationmeta.py index 74b1dd2f44f9820814c668b629b2b7c43be2db6b..8efd0a447c2ab84bdb53e977d03f2aa2bcddb9d7 100644 --- a/toardb/stationmeta/stationmeta.py +++ b/toardb/stationmeta/stationmeta.py @@ -5,8 +5,9 @@ Simple test API for stationmeta management from typing import List from fastapi import APIRouter, Depends, HTTPException, Body from sqlalchemy.orm import Session, sessionmaker +from sqlalchemy.engine import Engine from . import crud, schemas -from toardb.utils.database import get_db +from toardb.utils.database import get_db, get_engine router = APIRouter() @@ -52,17 +53,17 @@ def get_stationmeta_changelog(station_id: int, db: Session = Depends(get_db)): # - get stationmeta_aux # - ... -@router.post('/stationmeta/', response_model=schemas.Stationmeta) +@router.post('/stationmeta/', response_model=schemas.StationmetaCreate) # The following command was not working as long as the upload via Body was defined. # See bug report: https://github.com/tiangolo/fastapi/issues/300 # (Although this seems to be fixed in the meantime, it is not working in my FastAPI version.) #def create_stationmeta_core(stationmeta_core: schemas.StationmetaCoreCreate, db: Session = Depends(get_db)): -def create_stationmeta_core(stationmeta: schemas.StationmetaCreate = Body(..., embed = True), db: Session = Depends(get_db)): +def create_stationmeta_core(stationmeta: schemas.StationmetaCreate = Body(..., embed = True), db: Session = Depends(get_db), engine: Engine = Depends(get_engine)): for station_code in stationmeta.codes: db_stationmeta_core= crud.get_stationmeta_core(db, station_code=station_code) if db_stationmeta_core: raise HTTPException(status_code=400, detail="Station already registered.") - return crud.create_stationmeta(db=db, stationmeta=stationmeta) + return crud.create_stationmeta(db=db, engine=engine, stationmeta=stationmeta) @router.patch('/stationmeta/{station_code}', response_model=schemas.StationmetaPatch) def patch_stationmeta_core(station_code: str, description: str, stationmeta: schemas.StationmetaPatch = Body(..., embed = True), db: Session = Depends(get_db)):