Added Hub GitLab commit to manager versions of the same city
This commit is contained in:
parent
3ed115f5f3
commit
1881c1db78
|
@ -11,8 +11,7 @@ from persistence.models import Building
|
|||
from persistence.models import City
|
||||
|
||||
if __name__ == '__main__':
|
||||
config = BaseConfiguration()
|
||||
config = BaseConfiguration(db_name='peteryefi')
|
||||
engine = create_engine(config.conn_string())
|
||||
City.__table__.create(bind=engine, checkfirst=True)
|
||||
Building.__table__.create(bind=engine, checkfirst=True)
|
||||
|
||||
|
|
|
@ -4,10 +4,21 @@ from typing import Dict, List, Union
|
|||
import numpy as np
|
||||
|
||||
|
||||
class CityUtil:
|
||||
class CityUtil(object):
|
||||
# holds a single instance of this class
|
||||
_instance = None
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __new__(cls):
|
||||
"""
|
||||
Implemented for a singleton pattern
|
||||
"""
|
||||
if cls._instance is None:
|
||||
cls._instance = super(CityUtil, cls).__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
def _class_object_to_dict(self, class_obj) -> Union[Dict, None]:
|
||||
"""
|
||||
converts a class object to a dictionary
|
||||
|
@ -34,6 +45,16 @@ class CityUtil:
|
|||
return building_dict[key]
|
||||
return None
|
||||
|
||||
def object_list_to_dict_list(self, object_list):
|
||||
"""
|
||||
converts a list of objects to a list of dictionaries
|
||||
:param object_list: a list of objects
|
||||
:return:
|
||||
"""
|
||||
if object_list is None:
|
||||
return []
|
||||
return [self._class_object_to_dict(obj) for obj in object_list]
|
||||
|
||||
def _serialize_points(self, points) -> List:
|
||||
"""
|
||||
Deserializes arry of Point objects to array of dictionarier
|
||||
|
|
|
@ -21,7 +21,6 @@ This Python file is in the root of Hub and should be run to create all the requi
|
|||
### Database Configuration Parameter ###
|
||||
A .env file (or environment variables) with configuration parameters described below are needed to establish a database connection:
|
||||
```
|
||||
DB_NAME=postgres-database-name
|
||||
DB_USER=postgres-database-user
|
||||
DB_PASSWORD=postgres-database-password
|
||||
DB_HOST=database-host
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from .Base import BaseRepo
|
||||
from .repositories.CityRepo import CityRepo
|
||||
from .repositories.BuildingRepo import BuildingRepo
|
||||
from .base import BaseRepo
|
||||
from .repositories.city_repo import CityRepo
|
||||
from .repositories.building_repo import BuildingRepo
|
||||
from .repositories.city_repo import CityRepo
|
|
@ -11,7 +11,8 @@ from sqlalchemy.orm import Session
|
|||
|
||||
|
||||
class BaseRepo:
|
||||
def __init__(self):
|
||||
config = BaseConfiguration()
|
||||
def __init__(self, db_name):
|
||||
config = BaseConfiguration(db_name)
|
||||
engine = create_engine(config.conn_string())
|
||||
self.config = config
|
||||
self.session = Session(engine)
|
|
@ -20,12 +20,13 @@ class BaseConfiguration(object):
|
|||
"""
|
||||
Base configuration class to hold common persistence configuration
|
||||
"""
|
||||
def __init__(self):
|
||||
self._db_name = os.getenv('DB_NAME')
|
||||
def __init__(self, db_name: str):
|
||||
self._db_name = db_name
|
||||
self._db_host = os.getenv('DB_HOST')
|
||||
self._db_user = os.getenv('DB_USER')
|
||||
self._db_pass = os.getenv('DB_PASSWORD')
|
||||
self._db_port = os.getenv('DB_PORT')
|
||||
self.hub_token = os.getenv('HUB_TOKEN')
|
||||
|
||||
def conn_string(self):
|
||||
"""
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
"""
|
||||
Model representation of a City
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
|
||||
from sqlalchemy import Column, Integer, String, Sequence, Float
|
||||
from persistence.db_config import Base
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
|
||||
class City(Base):
|
||||
"""A model representation of a city
|
||||
|
||||
Attributes:
|
||||
name The name of the city.
|
||||
uid A unique identifier for each city object
|
||||
location The location of the building.
|
||||
country_code The country where the city is located.
|
||||
latitude The GPS latitude location of the city.
|
||||
longitude The GPS longitude location of the city.
|
||||
building A relationship for fetching all buildings in the city
|
||||
"""
|
||||
__tablename__ = "city"
|
||||
id = Column(Integer, Sequence('city_id_seq'), primary_key=True)
|
||||
name = Column(String, nullable=False)
|
||||
time_zone = Column(String, nullable=True)
|
||||
country_code = Column(String, nullable=False)
|
||||
latitude = Column(Float)
|
||||
longitude = Column(Float)
|
||||
buildings = relationship('Building', backref='city', lazy=True, cascade="all, delete-orphan")
|
|
@ -1,2 +1,3 @@
|
|||
from .Building import Building
|
||||
from .City import City
|
||||
from .building import Building
|
||||
from .city import City
|
||||
from .city import City
|
||||
|
|
30
persistence/models/city.py
Normal file
30
persistence/models/city.py
Normal file
|
@ -0,0 +1,30 @@
|
|||
"""
|
||||
Model representation of a City
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
|
||||
from sqlalchemy import Column, Integer, String, Sequence, PickleType, Float
|
||||
from persistence.db_config import Base
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
|
||||
|
||||
class City(Base):
|
||||
"""A model representation of a city
|
||||
"""
|
||||
__tablename__ = "city"
|
||||
id = Column(Integer, Sequence('city_id_seq'), primary_key=True)
|
||||
city = Column(PickleType, nullable=False)
|
||||
name = Column(String, nullable=False)
|
||||
srs_name = Column(String, nullable=False)
|
||||
climate_reference_city = Column(String, nullable=True)
|
||||
time_zone = Column(String, nullable=True)
|
||||
country_code = Column(String, nullable=False)
|
||||
latitude = Column(Float)
|
||||
longitude = Column(Float)
|
||||
lower_corner = Column(JSONB, nullable=False)
|
||||
upper_corner = Column(JSONB, nullable=False)
|
||||
hub_release = Column(String, nullable=False)
|
||||
city_version = Column(Integer, nullable=False)
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
"""
|
||||
City repository with database CRUD operations
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
|
||||
from city_model_structure.city import City
|
||||
from persistence.models import City as ModelCity
|
||||
from persistence import BaseRepo
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy import select
|
||||
|
||||
|
||||
class CityRepo(BaseRepo):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def insert(self, city: City):
|
||||
model_city = ModelCity()
|
||||
model_city.name = city.name
|
||||
model_city.longitude = city.longitude
|
||||
model_city.latitude = city.latitude
|
||||
model_city.country_code = city.country_code
|
||||
model_city.time_zone = city.time_zone
|
||||
try:
|
||||
self.session.add(model_city)
|
||||
self.session.flush()
|
||||
self.session.commit()
|
||||
return model_city
|
||||
except SQLAlchemyError as err:
|
||||
print(f'Error while adding city: {err}')
|
||||
|
||||
def get_by_id(self, city_id: int) -> ModelCity:
|
||||
"""
|
||||
Fetch a City based on the id
|
||||
:param city_id: the city id
|
||||
:return: a city
|
||||
"""
|
||||
try:
|
||||
return self.session.execute(select(ModelCity).where(ModelCity.id == city_id)).first()[0]
|
||||
except SQLAlchemyError as err:
|
||||
print(f'Error while fetching city: {err}')
|
||||
|
||||
def get_by_name(self, city_name: str) -> [ModelCity]:
|
||||
"""
|
||||
Fetch city based on the name
|
||||
:param city_name: the name of the building
|
||||
:return: [ModelCity] with the provided name
|
||||
"""
|
||||
try:
|
||||
result_set = self.session.execute(select(ModelCity).where(ModelCity.name == city_name))
|
||||
return [building[0] for building in result_set]
|
||||
except SQLAlchemyError as err:
|
||||
print(f'Error while fetching city by name: {err}')
|
|
@ -15,8 +15,8 @@ from sqlalchemy import select
|
|||
|
||||
class BuildingRepo(BaseRepo):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
def __init__(self, db_name):
|
||||
super().__init__(db_name)
|
||||
self._city_util = CityUtil()
|
||||
|
||||
def insert(self, building: CityBuilding, city_id: int) -> Building:
|
120
persistence/repositories/city_repo.py
Normal file
120
persistence/repositories/city_repo.py
Normal file
|
@ -0,0 +1,120 @@
|
|||
"""
|
||||
City repository with database CRUD operations
|
||||
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
||||
Copyright © 2022 Concordia CERC group
|
||||
Project Coder Peter Yefi peteryefi@gmail.com
|
||||
"""
|
||||
|
||||
from city_model_structure.city import City
|
||||
from persistence import BaseRepo
|
||||
from sqlalchemy.exc import SQLAlchemyError
|
||||
from sqlalchemy import select
|
||||
from helpers.city_util import CityUtil
|
||||
from persistence.models import City
|
||||
import pickle
|
||||
import requests
|
||||
from urllib3.exceptions import HTTPError
|
||||
from typing import Union, Dict
|
||||
|
||||
|
||||
class CityRepo(BaseRepo):
|
||||
def __init__(self, db_name):
|
||||
super().__init__(db_name)
|
||||
self._city_util = CityUtil()
|
||||
|
||||
def insert(self, city: City) -> Union[City, Dict]:
|
||||
model_city = City()
|
||||
model_city.name = city.name
|
||||
model_city.climate_reference_city = city.climate_reference_city
|
||||
model_city.srs_name = city.srs_name
|
||||
model_city.longitude = city.longitude
|
||||
model_city.latitude = city.latitude
|
||||
model_city.country_code = city.country_code
|
||||
model_city.time_zone = city.time_zone
|
||||
model_city.lower_corner = city.lower_corner.tolist()
|
||||
model_city.upper_corner = city.upper_corner.tolist()
|
||||
model_city.city = pickle.dumps(city)
|
||||
|
||||
try:
|
||||
# Retrieve hub project latest release
|
||||
response = requests.get("https://rs-loy-gitlab.concordia.ca/api/v4/projects/2/repository/branches/master",
|
||||
headers={"PRIVATE-TOKEN": self.config.hub_token})
|
||||
recent_commit = response.json()["commit"]["id"]
|
||||
exiting_city = self._get_by_hub_version(recent_commit, city.name)
|
||||
|
||||
# Do not persist the same city for the same version of Hub
|
||||
if exiting_city is None:
|
||||
model_city.hub_release = recent_commit
|
||||
cities = self.get_by_name(city.name)
|
||||
# update version for the same city but different hub versions
|
||||
if len(cities) == 0:
|
||||
model_city.city_version = 0
|
||||
else:
|
||||
model_city.city_version = cities[-1].city_version + 1
|
||||
|
||||
# Persist city
|
||||
self.session.add(model_city)
|
||||
self.session.flush()
|
||||
self.session.commit()
|
||||
return model_city
|
||||
else:
|
||||
return {'message': f'Same version of {city.name} exist'}
|
||||
except SQLAlchemyError as err:
|
||||
print(f'Error while adding city: {err}')
|
||||
except HTTPError as err:
|
||||
print(f'Error retrieving Hub latest release: {err}')
|
||||
|
||||
def get_by_id(self, city_id: int) -> City:
|
||||
"""
|
||||
Fetch a City based on the id
|
||||
:param city_id: the city id
|
||||
:return: a city
|
||||
"""
|
||||
try:
|
||||
return self.session.execute(select(City).where(City.id == city_id)).first()[0]
|
||||
except SQLAlchemyError as err:
|
||||
print(f'Error while fetching city: {err}')
|
||||
|
||||
def _get_by_hub_version(self, hub_commit: str, city_name: str) -> City:
|
||||
"""
|
||||
Fetch a City based on the name and hub project recent commit
|
||||
:param hub_commit: the latest hub commit
|
||||
:param city_name: the name of the city
|
||||
:return: a city
|
||||
"""
|
||||
try:
|
||||
return self.session.execute(select(City)
|
||||
.where(City.hub_release == hub_commit, City.name == city_name)).first()
|
||||
except SQLAlchemyError as err:
|
||||
print(f'Error while fetching city: {err}')
|
||||
|
||||
def update(self, city_id: int, city: City):
|
||||
"""
|
||||
Updates a city
|
||||
:param city_id: the id of the city to be updated
|
||||
:param city: the city object
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
self.session.query(City).filter(City.id == city_id) \
|
||||
.update({
|
||||
'name': city.name, 'srs_name': city.srs_name, 'country_code': city.country_code, 'longitude': city.longitude,
|
||||
'latitude': city.latitude, 'time_zone': city.time_zone, 'lower_corner': city.lower_corner.tolist(),
|
||||
'upper_corner': city.upper_corner.tolist(), 'climate_reference_city': city.climate_reference_city,
|
||||
})
|
||||
|
||||
self.session.commit()
|
||||
except SQLAlchemyError as err:
|
||||
print(f'Error while updating city: {err}')
|
||||
|
||||
def get_by_name(self, city_name: str) -> [City]:
|
||||
"""
|
||||
Fetch city based on the name
|
||||
:param city_name: the name of the building
|
||||
:return: [ModelCity] with the provided name
|
||||
"""
|
||||
try:
|
||||
result_set = self.session.execute(select(City).where(City.name == city_name))
|
||||
return [building[0] for building in result_set]
|
||||
except SQLAlchemyError as err:
|
||||
print(f'Error while fetching city by name: {err}')
|
Loading…
Reference in New Issue
Block a user