cerc-persistence 0.1.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cerc-persistence-0.1.0.4/PKG-INFO +13 -0
- cerc-persistence-0.1.0.4/README.md +63 -0
- cerc-persistence-0.1.0.4/cerc_persistence/__init__.py +3 -0
- cerc-persistence-0.1.0.4/cerc_persistence/configuration.py +67 -0
- cerc-persistence-0.1.0.4/cerc_persistence/db_control.py +241 -0
- cerc-persistence-0.1.0.4/cerc_persistence/db_setup.py +70 -0
- cerc-persistence-0.1.0.4/cerc_persistence/models/__init__.py +8 -0
- cerc-persistence-0.1.0.4/cerc_persistence/models/application.py +32 -0
- cerc-persistence-0.1.0.4/cerc_persistence/models/city.py +36 -0
- cerc-persistence-0.1.0.4/cerc_persistence/models/city_object.py +82 -0
- cerc-persistence-0.1.0.4/cerc_persistence/models/simulation_results.py +33 -0
- cerc-persistence-0.1.0.4/cerc_persistence/models/user.py +42 -0
- cerc-persistence-0.1.0.4/cerc_persistence/repositories/__init__.py +3 -0
- cerc-persistence-0.1.0.4/cerc_persistence/repositories/application.py +111 -0
- cerc-persistence-0.1.0.4/cerc_persistence/repositories/city.py +138 -0
- cerc-persistence-0.1.0.4/cerc_persistence/repositories/city_object.py +200 -0
- cerc-persistence-0.1.0.4/cerc_persistence/repositories/simulation_results.py +193 -0
- cerc-persistence-0.1.0.4/cerc_persistence/repositories/user.py +159 -0
- cerc-persistence-0.1.0.4/cerc_persistence/repository.py +22 -0
- cerc-persistence-0.1.0.4/cerc_persistence/version.py +4 -0
- cerc-persistence-0.1.0.4/cerc_persistence.egg-info/PKG-INFO +13 -0
- cerc-persistence-0.1.0.4/cerc_persistence.egg-info/SOURCES.txt +27 -0
- cerc-persistence-0.1.0.4/cerc_persistence.egg-info/dependency_links.txt +1 -0
- cerc-persistence-0.1.0.4/cerc_persistence.egg-info/requires.txt +7 -0
- cerc-persistence-0.1.0.4/cerc_persistence.egg-info/top_level.txt +1 -0
- cerc-persistence-0.1.0.4/pyproject.toml +8 -0
- cerc-persistence-0.1.0.4/requirements.txt +6 -0
- cerc-persistence-0.1.0.4/setup.cfg +4 -0
- cerc-persistence-0.1.0.4/setup.py +41 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: cerc-persistence
|
|
3
|
+
Version: 0.1.0.4
|
|
4
|
+
Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
|
|
5
|
+
Classifier: Programming Language :: Python
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Requires-Dist: pathlib
|
|
8
|
+
Requires-Dist: python-dotenv
|
|
9
|
+
Requires-Dist: SQLAlchemy
|
|
10
|
+
Requires-Dist: cerc-hub
|
|
11
|
+
Requires-Dist: psycopg2-binary
|
|
12
|
+
Requires-Dist: sqlalchemy_utils
|
|
13
|
+
Requires-Dist: setuptools
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# CERC Persistence
|
|
2
|
+
|
|
3
|
+
The persistence package includes classes to store different class objects in a Postgres database.
|
|
4
|
+
|
|
5
|
+
## Models
|
|
6
|
+
|
|
7
|
+
This defines models for all class objects that we want to persist. It is used for Object Relation Mapping (ORM)
|
|
8
|
+
of the class objects to database table columns
|
|
9
|
+
|
|
10
|
+
## Repositories
|
|
11
|
+
|
|
12
|
+
This defines repository classes that contain CRUD methods for database operations. The constructor of all repositories
|
|
13
|
+
requires the database name to connect to and the application environment (PROD or TEST). Tests use a different database
|
|
14
|
+
from the production environment, which is why this is necessary. An example is shown below:
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from cerc_persistence.db_setup import DBSetup
|
|
18
|
+
|
|
19
|
+
# instantiate city repo for hub production database
|
|
20
|
+
db = DBSetup(db_name='hub', app_env='PROD', dotenv_path='/path/to/.env', admin_password='application_password', application_uuid='UUID')
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
All database operations are conducted with the production database (*PROD*) named *hub* in the example above.
|
|
24
|
+
|
|
25
|
+
## config_db
|
|
26
|
+
|
|
27
|
+
This Python file is a configuration class that contains variables that map to configuration parameters in a .env file.
|
|
28
|
+
It also contains a method ``def conn_string()`` which returns the connection string to a Postgres database.
|
|
29
|
+
|
|
30
|
+
## Base
|
|
31
|
+
|
|
32
|
+
This class has a constructor that establishes a database connection and returns a reference for database-related CRUD
|
|
33
|
+
operations.
|
|
34
|
+
|
|
35
|
+
## Database Configuration Parameter
|
|
36
|
+
|
|
37
|
+
A .env file (or environment variables) with configuration parameters described below are needed to establish a database
|
|
38
|
+
connection:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
# production database credentials
|
|
42
|
+
PROD_DB_USER=postgres-database-user
|
|
43
|
+
PROD_DB_PASSWORD=postgres-database-password
|
|
44
|
+
PROD_DB_HOST=database-host
|
|
45
|
+
PROD_DB_PORT=database-port
|
|
46
|
+
|
|
47
|
+
# test database credentials
|
|
48
|
+
TEST_DB_USER=postgres-database-user
|
|
49
|
+
TEST_DB_PASSWORD=postgres-database-password
|
|
50
|
+
TEST_DB_HOST=database-host
|
|
51
|
+
TEST_DB_PORT=database-port
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Database Related Unit Test
|
|
55
|
+
|
|
56
|
+
Unit tests that involve database operations require a Postgres database to be set up.
|
|
57
|
+
The tests connect to the database server using the default postgres user (*postgres*).
|
|
58
|
+
NB: You can provide any credentials for the test to connect to postgres, just make sure
|
|
59
|
+
the credentials are set in your .env file as explained above in *Database Configuration Parameters* section.
|
|
60
|
+
|
|
61
|
+
When the tests are run, a **test_db** database is created and then the required tables for
|
|
62
|
+
the test. Before the tests run, the *test_db* is deleted to ensure that each test starts
|
|
63
|
+
on a clean slate.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Persistence (Postgresql) configuration
|
|
3
|
+
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
4
|
+
Copyright © 2022 Concordia CERC group
|
|
5
|
+
Project Coder Peter Yefi peteryefi@gmail.com
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
import os
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from dotenv import load_dotenv
|
|
12
|
+
from sqlalchemy.ext.declarative import declarative_base
|
|
13
|
+
|
|
14
|
+
Models = declarative_base()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Configuration:
|
|
18
|
+
"""
|
|
19
|
+
Configuration class to hold common persistence configuration
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, db_name: str, dotenv_path: str, app_env='TEST'):
|
|
23
|
+
"""
|
|
24
|
+
:param db_name: database name
|
|
25
|
+
:param app_env: application environment, test or production
|
|
26
|
+
:param dotenv_path: the absolute path to dotenv file
|
|
27
|
+
"""
|
|
28
|
+
try:
|
|
29
|
+
# load environmental variables
|
|
30
|
+
if not Path(dotenv_path).exists():
|
|
31
|
+
error_message = f'dotenv file doesn\'t exists at {dotenv_path}'
|
|
32
|
+
logging.error(error_message)
|
|
33
|
+
raise FileNotFoundError(error_message)
|
|
34
|
+
load_dotenv(dotenv_path=dotenv_path)
|
|
35
|
+
|
|
36
|
+
self._db_name = db_name
|
|
37
|
+
self._db_host = os.getenv(f'{app_env}_DB_HOST')
|
|
38
|
+
self._db_user = os.getenv(f'{app_env}_DB_USER')
|
|
39
|
+
self._db_pass = os.getenv(f'{app_env}_DB_PASSWORD')
|
|
40
|
+
self._db_port = os.getenv(f'{app_env}_DB_PORT')
|
|
41
|
+
self.hub_token = os.getenv('HUB_TOKEN')
|
|
42
|
+
except KeyError as err:
|
|
43
|
+
logging.error('Error with credentials: %s', err)
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def connection_string(self):
|
|
47
|
+
"""
|
|
48
|
+
Returns a connection string postgresql
|
|
49
|
+
:return: connection string
|
|
50
|
+
"""
|
|
51
|
+
if self._db_pass:
|
|
52
|
+
return f'postgresql://{self._db_user}:{self._db_pass}@{self._db_host}:{self._db_port}/{self._db_name}'
|
|
53
|
+
return f'postgresql://{self._db_user}@{self._db_host}:{self._db_port}/{self._db_name}'
|
|
54
|
+
|
|
55
|
+
@property
|
|
56
|
+
def db_user(self):
|
|
57
|
+
"""
|
|
58
|
+
retrieve the configured username
|
|
59
|
+
"""
|
|
60
|
+
return self._db_user
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def db_name(self):
|
|
64
|
+
"""
|
|
65
|
+
retrieve the configured database name
|
|
66
|
+
"""
|
|
67
|
+
return self._db_name
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DBFactory performs read related operations
|
|
3
|
+
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
4
|
+
Copyright © 2022 Concordia CERC group
|
|
5
|
+
Project CoderPeter Yefi peteryefi@gmail.com
|
|
6
|
+
"""
|
|
7
|
+
from typing import Dict
|
|
8
|
+
|
|
9
|
+
from cerc_persistence.repositories.application import Application
|
|
10
|
+
from cerc_persistence.repositories.city import City
|
|
11
|
+
from cerc_persistence.repositories.city_object import CityObject
|
|
12
|
+
from cerc_persistence.repositories.simulation_results import SimulationResults
|
|
13
|
+
from cerc_persistence.repositories.user import User
|
|
14
|
+
from cerc_persistence.repositories.user import UserRoles
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DBControl:
|
|
18
|
+
"""
|
|
19
|
+
DBFactory class
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, db_name, app_env, dotenv_path):
|
|
23
|
+
self._city = City(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env)
|
|
24
|
+
self._application = Application(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
|
|
25
|
+
self._user = User(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
|
|
26
|
+
self._city_object = CityObject(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
|
|
27
|
+
self._simulation_results = SimulationResults(db_name=db_name, dotenv_path=dotenv_path, app_env=app_env)
|
|
28
|
+
|
|
29
|
+
def application_info(self, application_uuid) -> Application:
|
|
30
|
+
"""
|
|
31
|
+
Retrieve the application info for the given uuid from the database
|
|
32
|
+
:param application_uuid: the uuid for the application
|
|
33
|
+
:return: Application
|
|
34
|
+
"""
|
|
35
|
+
return self._application.get_by_uuid(application_uuid)
|
|
36
|
+
|
|
37
|
+
def user_info(self, name, password, application_id) -> User:
|
|
38
|
+
"""
|
|
39
|
+
Retrieve the user info for the given name and password and application_id from the database
|
|
40
|
+
:param name: the username
|
|
41
|
+
:param password: the user password
|
|
42
|
+
:param application_id: the application id
|
|
43
|
+
:return: User
|
|
44
|
+
"""
|
|
45
|
+
return self._user.get_by_name_application_id_and_password(name, password, application_id)
|
|
46
|
+
|
|
47
|
+
def user_login(self, name, password, application_uuid) -> User:
|
|
48
|
+
"""
|
|
49
|
+
Retrieve the user info from the database
|
|
50
|
+
:param name: the username
|
|
51
|
+
:param password: the user password
|
|
52
|
+
:param application_uuid: the application uuid
|
|
53
|
+
:return: User
|
|
54
|
+
"""
|
|
55
|
+
return self._user.get_by_name_application_uuid_and_password(name, password, application_uuid)
|
|
56
|
+
|
|
57
|
+
def cities_by_user_and_application(self, user_id, application_id) -> [City]:
|
|
58
|
+
"""
|
|
59
|
+
Retrieve the cities belonging to the user and the application from the database
|
|
60
|
+
:param user_id: User id
|
|
61
|
+
:param application_id: Application id
|
|
62
|
+
:return: [City]
|
|
63
|
+
"""
|
|
64
|
+
return self._city.get_by_user_id_and_application_id(user_id, application_id)
|
|
65
|
+
|
|
66
|
+
def building(self, name, user_id, application_id, scenario) -> CityObject:
|
|
67
|
+
"""
|
|
68
|
+
Retrieve the building from the database
|
|
69
|
+
:param name: Building name
|
|
70
|
+
:param user_id: User id
|
|
71
|
+
:param application_id: Application id
|
|
72
|
+
:param scenario: Scenario
|
|
73
|
+
:
|
|
74
|
+
"""
|
|
75
|
+
cities = self._city.get_by_user_id_application_id_and_scenario(user_id, application_id, scenario)
|
|
76
|
+
city = [city[0].id for city in cities]
|
|
77
|
+
result = self._city_object.building_in_cities_info(name, city)
|
|
78
|
+
if result is not None:
|
|
79
|
+
return result
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
def building_info(self, name, city_id) -> CityObject:
|
|
83
|
+
"""
|
|
84
|
+
Retrieve the building info from the database
|
|
85
|
+
:param name: Building name
|
|
86
|
+
:param city_id: City ID
|
|
87
|
+
:return: CityObject
|
|
88
|
+
"""
|
|
89
|
+
return self._city_object.get_by_name_or_alias_and_city(name, city_id)
|
|
90
|
+
|
|
91
|
+
def building_info_in_cities(self, name, cities) -> CityObject:
|
|
92
|
+
"""
|
|
93
|
+
Retrieve the building info from the database
|
|
94
|
+
:param name: Building name
|
|
95
|
+
:param cities: [City ID]
|
|
96
|
+
:return: CityObject
|
|
97
|
+
"""
|
|
98
|
+
return self._city_object.get_by_name_or_alias_in_cities(name, cities)
|
|
99
|
+
|
|
100
|
+
def results(self, user_id, application_id, request_values, result_names=None) -> Dict:
|
|
101
|
+
"""
|
|
102
|
+
Retrieve the simulation results for the given cities from the database
|
|
103
|
+
:param user_id: the user id owning the results
|
|
104
|
+
:param application_id: the application id owning the results
|
|
105
|
+
:param request_values: dictionary containing the scenario and building names to grab the results
|
|
106
|
+
:param result_names: if given, filter the results to the selected names
|
|
107
|
+
"""
|
|
108
|
+
if result_names is None:
|
|
109
|
+
result_names = []
|
|
110
|
+
results = {}
|
|
111
|
+
for scenario in request_values['scenarios']:
|
|
112
|
+
for scenario_name in scenario.keys():
|
|
113
|
+
result_sets = self._city.get_by_user_id_application_id_and_scenario(
|
|
114
|
+
user_id,
|
|
115
|
+
application_id,
|
|
116
|
+
scenario_name
|
|
117
|
+
)
|
|
118
|
+
if result_sets is None:
|
|
119
|
+
continue
|
|
120
|
+
results[scenario_name] = []
|
|
121
|
+
city_ids = [r[0].id for r in result_sets]
|
|
122
|
+
for building_name in scenario[scenario_name]:
|
|
123
|
+
_building = self._city_object.get_by_name_or_alias_in_cities(building_name, city_ids)
|
|
124
|
+
if _building is None:
|
|
125
|
+
continue
|
|
126
|
+
city_object_id = _building.id
|
|
127
|
+
_ = self._simulation_results.get_simulation_results_by_city_object_id_and_names(
|
|
128
|
+
city_object_id,
|
|
129
|
+
result_names)
|
|
130
|
+
|
|
131
|
+
for value in _:
|
|
132
|
+
values = value.values
|
|
133
|
+
values["building"] = building_name
|
|
134
|
+
results[scenario_name].append(values)
|
|
135
|
+
return results
|
|
136
|
+
|
|
137
|
+
def persist_city(self, city: City, pickle_path, scenario, application_id: int, user_id: int):
|
|
138
|
+
"""
|
|
139
|
+
Creates a city into the database
|
|
140
|
+
:param city: City to be stored
|
|
141
|
+
:param pickle_path: Path to save the pickle file
|
|
142
|
+
:param scenario: Simulation scenario name
|
|
143
|
+
:param application_id: Application id owning this city
|
|
144
|
+
:param user_id: User who create the city
|
|
145
|
+
return identity_id
|
|
146
|
+
"""
|
|
147
|
+
return self._city.insert(city, pickle_path, scenario, application_id, user_id)
|
|
148
|
+
|
|
149
|
+
def update_city(self, city_id, city):
|
|
150
|
+
"""
|
|
151
|
+
Update an existing city in the database
|
|
152
|
+
:param city_id: the id of the city to update
|
|
153
|
+
:param city: the updated city object
|
|
154
|
+
"""
|
|
155
|
+
return self._city.update(city_id, city)
|
|
156
|
+
|
|
157
|
+
def persist_application(self, name: str, description: str, application_uuid: str):
|
|
158
|
+
"""
|
|
159
|
+
Creates information for an application in the database
|
|
160
|
+
:param name: name of application
|
|
161
|
+
:param description: the description of the application
|
|
162
|
+
:param application_uuid: the uuid of the application to be created
|
|
163
|
+
"""
|
|
164
|
+
return self._application.insert(name, description, application_uuid)
|
|
165
|
+
|
|
166
|
+
def update_application(self, name: str, description: str, application_uuid: str):
|
|
167
|
+
"""
|
|
168
|
+
Update the application information stored in the database
|
|
169
|
+
:param name: name of application
|
|
170
|
+
:param description: the description of the application
|
|
171
|
+
:param application_uuid: the uuid of the application to be created
|
|
172
|
+
"""
|
|
173
|
+
return self._application.update(application_uuid, name, description)
|
|
174
|
+
|
|
175
|
+
def add_simulation_results(self, name, values, city_id=None, city_object_id=None):
|
|
176
|
+
"""
|
|
177
|
+
Add simulation results to the city or to the city_object to the database
|
|
178
|
+
:param name: simulation and simulation engine name
|
|
179
|
+
:param values: simulation values in json format
|
|
180
|
+
:param city_id: city id or None
|
|
181
|
+
:param city_object_id: city object id or None
|
|
182
|
+
"""
|
|
183
|
+
return self._simulation_results.insert(name, values, city_id, city_object_id)
|
|
184
|
+
|
|
185
|
+
def create_user(self, name: str, application_id: int, password: str, role: UserRoles):
|
|
186
|
+
"""
|
|
187
|
+
Creates a new user in the database
|
|
188
|
+
:param name: the name of the user
|
|
189
|
+
:param application_id: the application id of the user
|
|
190
|
+
:param password: the password of the user
|
|
191
|
+
:param role: the role of the user
|
|
192
|
+
"""
|
|
193
|
+
return self._user.insert(name, password, role, application_id)
|
|
194
|
+
|
|
195
|
+
def update_user(self, user_id: int, name: str, password: str, role: UserRoles):
|
|
196
|
+
"""
|
|
197
|
+
Updates a user in the database
|
|
198
|
+
:param user_id: the id of the user
|
|
199
|
+
:param name: the name of the user
|
|
200
|
+
:param password: the password of the user
|
|
201
|
+
:param role: the role of the user
|
|
202
|
+
"""
|
|
203
|
+
return self._user.update(user_id, name, password, role)
|
|
204
|
+
|
|
205
|
+
def get_by_name_and_application(self, name: str, application: int):
|
|
206
|
+
"""
|
|
207
|
+
Retrieve a single user from the database
|
|
208
|
+
:param name: username
|
|
209
|
+
:param application: application accessing hub
|
|
210
|
+
"""
|
|
211
|
+
return self._user.get_by_name_and_application(name, application)
|
|
212
|
+
|
|
213
|
+
def delete_user(self, user_id):
|
|
214
|
+
"""
|
|
215
|
+
Delete a single user from the database
|
|
216
|
+
:param user_id: the id of the user to delete
|
|
217
|
+
"""
|
|
218
|
+
self._user.delete(user_id)
|
|
219
|
+
|
|
220
|
+
def delete_city(self, city_id):
|
|
221
|
+
"""
|
|
222
|
+
Deletes a single city from the database
|
|
223
|
+
:param city_id: the id of the city to get
|
|
224
|
+
"""
|
|
225
|
+
self._city.delete(city_id)
|
|
226
|
+
|
|
227
|
+
def delete_results_by_name(self, name, city_id=None, city_object_id=None):
|
|
228
|
+
"""
|
|
229
|
+
Deletes city object simulation results from the database
|
|
230
|
+
:param name: simulation name
|
|
231
|
+
:param city_id: if given, delete delete the results for the city with id city_id
|
|
232
|
+
:param city_object_id: if given, delete delete the results for the city object with id city_object_id
|
|
233
|
+
"""
|
|
234
|
+
self._simulation_results.delete(name, city_id=city_id, city_object_id=city_object_id)
|
|
235
|
+
|
|
236
|
+
def delete_application(self, application_uuid):
|
|
237
|
+
"""
|
|
238
|
+
Deletes a single application from the database
|
|
239
|
+
:param application_uuid: the id of the application to get
|
|
240
|
+
"""
|
|
241
|
+
self._application.delete(application_uuid)
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Database setup
|
|
3
|
+
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
4
|
+
Copyright © 2022 Concordia CERC group
|
|
5
|
+
Project Coder Peter Yefi peteryefi@gmail.com
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from cerc_persistence.repository import Repository
|
|
10
|
+
from cerc_persistence.models import Application
|
|
11
|
+
from cerc_persistence.models import City
|
|
12
|
+
from cerc_persistence.models import CityObject
|
|
13
|
+
from cerc_persistence.models import User
|
|
14
|
+
from cerc_persistence.models import UserRoles
|
|
15
|
+
from cerc_persistence.models import SimulationResults
|
|
16
|
+
from cerc_persistence.repositories.user import User as UserRepository
|
|
17
|
+
from cerc_persistence.repositories.application import Application as ApplicationRepository
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class DBSetup:
|
|
21
|
+
"""
|
|
22
|
+
Creates a Persistence database structure
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, db_name, app_env, dotenv_path, admin_password, application_uuid):
|
|
26
|
+
"""
|
|
27
|
+
Creates database tables a default admin user and a default admin app with the given password and uuid
|
|
28
|
+
:param db_name: database name
|
|
29
|
+
:param app_env: application environment type [TEST|PROD]
|
|
30
|
+
:param dotenv_path: .env file path
|
|
31
|
+
:param admin_password: administrator password for the application uuid
|
|
32
|
+
:application_uuid: application uuid
|
|
33
|
+
"""
|
|
34
|
+
repository = Repository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
|
|
35
|
+
|
|
36
|
+
# Create the tables using the models
|
|
37
|
+
Application.__table__.create(bind=repository.engine, checkfirst=True)
|
|
38
|
+
User.__table__.create(bind=repository.engine, checkfirst=True)
|
|
39
|
+
City.__table__.create(bind=repository.engine, checkfirst=True)
|
|
40
|
+
CityObject.__table__.create(bind=repository.engine, checkfirst=True)
|
|
41
|
+
SimulationResults.__table__.create(bind=repository.engine, checkfirst=True)
|
|
42
|
+
|
|
43
|
+
self._user_repo = UserRepository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
|
|
44
|
+
self._application_repo = ApplicationRepository(db_name=db_name, app_env=app_env, dotenv_path=dotenv_path)
|
|
45
|
+
application_id = self._create_admin_app(self._application_repo, application_uuid)
|
|
46
|
+
self._create_admin_user(self._user_repo, admin_password, application_id)
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def _create_admin_app(application_repo, application_uuid):
|
|
50
|
+
name = 'AdminTool'
|
|
51
|
+
description = 'Admin tool to control city persistence and to test the API v1.4'
|
|
52
|
+
logging.info('Creating default admin tool application...')
|
|
53
|
+
application = application_repo.insert(name, description, application_uuid)
|
|
54
|
+
|
|
55
|
+
if isinstance(application, dict):
|
|
56
|
+
logging.info(application)
|
|
57
|
+
else:
|
|
58
|
+
msg = f'Created Admin tool with application_uuid: {application_uuid}'
|
|
59
|
+
logging.info(msg)
|
|
60
|
+
return application.id
|
|
61
|
+
|
|
62
|
+
@staticmethod
|
|
63
|
+
def _create_admin_user(user_repo, admin_password, application_id):
|
|
64
|
+
password = admin_password
|
|
65
|
+
logging.info('Creating default admin user...')
|
|
66
|
+
user = user_repo.insert('Administrator', password, UserRoles.Admin, application_id)
|
|
67
|
+
if isinstance(user, dict):
|
|
68
|
+
logging.info(user)
|
|
69
|
+
else:
|
|
70
|
+
logging.info('Created Admin user')
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Model representation of an application
|
|
3
|
+
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
4
|
+
Copyright © 2022 Concordia CERC group
|
|
5
|
+
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import datetime
|
|
9
|
+
|
|
10
|
+
from sqlalchemy import Column, Integer, String, Sequence
|
|
11
|
+
from sqlalchemy import DateTime
|
|
12
|
+
from sqlalchemy.dialects.postgresql import UUID
|
|
13
|
+
|
|
14
|
+
from cerc_persistence.configuration import Models
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Application(Models):
|
|
18
|
+
"""
|
|
19
|
+
A model representation of an application
|
|
20
|
+
"""
|
|
21
|
+
__tablename__ = 'application'
|
|
22
|
+
id = Column(Integer, Sequence('application_id_seq'), primary_key=True)
|
|
23
|
+
name = Column(String, nullable=False)
|
|
24
|
+
description = Column(String, nullable=False)
|
|
25
|
+
application_uuid = Column(UUID(as_uuid=True), nullable=False)
|
|
26
|
+
created = Column(DateTime, default=datetime.datetime.utcnow)
|
|
27
|
+
updated = Column(DateTime, default=datetime.datetime.utcnow)
|
|
28
|
+
|
|
29
|
+
def __init__(self, name, description, application_uuid):
|
|
30
|
+
self.name = name
|
|
31
|
+
self.description = description
|
|
32
|
+
self.application_uuid = application_uuid
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Model representation of a City
|
|
3
|
+
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
4
|
+
Copyright © 2022 Concordia CERC group
|
|
5
|
+
Project Coder Peter Yefi peteryefi@gmail.com
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import datetime
|
|
9
|
+
|
|
10
|
+
from sqlalchemy import Column, Integer, String, Sequence, ForeignKey
|
|
11
|
+
from sqlalchemy import DateTime
|
|
12
|
+
|
|
13
|
+
from cerc_persistence.configuration import Models
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class City(Models):
|
|
17
|
+
"""A model representation of a city
|
|
18
|
+
"""
|
|
19
|
+
__tablename__ = 'city'
|
|
20
|
+
id = Column(Integer, Sequence('city_id_seq'), primary_key=True)
|
|
21
|
+
pickle_path = Column(String, nullable=False)
|
|
22
|
+
name = Column(String, nullable=False)
|
|
23
|
+
scenario = Column(String, nullable=False)
|
|
24
|
+
application_id = Column(Integer, ForeignKey('application.id', ondelete='CASCADE'), nullable=False)
|
|
25
|
+
user_id = Column(Integer, ForeignKey('user.id', ondelete='CASCADE'), nullable=True)
|
|
26
|
+
hub_release = Column(String, nullable=False)
|
|
27
|
+
created = Column(DateTime, default=datetime.datetime.utcnow)
|
|
28
|
+
updated = Column(DateTime, default=datetime.datetime.utcnow)
|
|
29
|
+
|
|
30
|
+
def __init__(self, pickle_path, name, scenario, application_id, user_id, hub_release):
|
|
31
|
+
self.pickle_path = str(pickle_path)
|
|
32
|
+
self.name = name
|
|
33
|
+
self.scenario = scenario
|
|
34
|
+
self.application_id = application_id
|
|
35
|
+
self.user_id = user_id
|
|
36
|
+
self.hub_release = hub_release
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Model representation of a city object
|
|
3
|
+
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
4
|
+
Copyright © 2022 Concordia CERC group
|
|
5
|
+
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import datetime
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
from sqlalchemy import Column, Integer, String, Sequence, ForeignKey, Float
|
|
12
|
+
from sqlalchemy import DateTime
|
|
13
|
+
|
|
14
|
+
from hub.city_model_structure.building import Building
|
|
15
|
+
from cerc_persistence.configuration import Models
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CityObject(Models):
|
|
19
|
+
"""
|
|
20
|
+
A model representation of an application
|
|
21
|
+
"""
|
|
22
|
+
__tablename__ = 'city_object'
|
|
23
|
+
id = Column(Integer, Sequence('city_object_id_seq'), primary_key=True)
|
|
24
|
+
city_id = Column(Integer, ForeignKey('city.id', ondelete='CASCADE'), nullable=False)
|
|
25
|
+
name = Column(String, nullable=False)
|
|
26
|
+
aliases = Column(String, nullable=True)
|
|
27
|
+
type = Column(String, nullable=False)
|
|
28
|
+
year_of_construction = Column(Integer, nullable=True)
|
|
29
|
+
function = Column(String, nullable=True)
|
|
30
|
+
usage = Column(String, nullable=True)
|
|
31
|
+
volume = Column(Float, nullable=False)
|
|
32
|
+
area = Column(Float, nullable=False)
|
|
33
|
+
total_heating_area = Column(Float, nullable=False)
|
|
34
|
+
wall_area = Column(Float, nullable=False)
|
|
35
|
+
windows_area = Column(Float, nullable=False)
|
|
36
|
+
roof_area = Column(Float, nullable=False)
|
|
37
|
+
total_pv_area = Column(Float, nullable=False)
|
|
38
|
+
system_name = Column(String, nullable=False)
|
|
39
|
+
created = Column(DateTime, default=datetime.datetime.utcnow)
|
|
40
|
+
updated = Column(DateTime, default=datetime.datetime.utcnow)
|
|
41
|
+
|
|
42
|
+
def __init__(self, city_id, building: Building):
|
|
43
|
+
self.city_id = city_id
|
|
44
|
+
self.name = building.name
|
|
45
|
+
self.aliases = building.aliases
|
|
46
|
+
self.type = building.type
|
|
47
|
+
self.year_of_construction = building.year_of_construction
|
|
48
|
+
self.function = building.function
|
|
49
|
+
self.usage = building.usages_percentage
|
|
50
|
+
self.volume = building.volume
|
|
51
|
+
self.area = building.floor_area
|
|
52
|
+
self.roof_area = sum(roof.solid_polygon.area for roof in building.roofs)
|
|
53
|
+
self.total_pv_area = sum(
|
|
54
|
+
roof.solid_polygon.area * roof.solar_collectors_area_reduction_factor for roof in building.roofs
|
|
55
|
+
)
|
|
56
|
+
storeys = building.storeys_above_ground
|
|
57
|
+
wall_area = 0
|
|
58
|
+
window_ratio = 0
|
|
59
|
+
try:
|
|
60
|
+
if storeys is None:
|
|
61
|
+
storeys = building.max_height / building.average_storey_height
|
|
62
|
+
for internal_zone in building.internal_zones:
|
|
63
|
+
for thermal_zone in internal_zone.thermal_zones_from_internal_zones:
|
|
64
|
+
for thermal_boundary in thermal_zone.thermal_boundaries:
|
|
65
|
+
window_ratio = thermal_boundary.window_ratio
|
|
66
|
+
break
|
|
67
|
+
except TypeError:
|
|
68
|
+
storeys = 0
|
|
69
|
+
logging.warning(
|
|
70
|
+
'building %s has no storey height so heating area, storeys and window ratio cannot be calculated',
|
|
71
|
+
self.name
|
|
72
|
+
)
|
|
73
|
+
self.total_heating_area = building.floor_area * storeys
|
|
74
|
+
|
|
75
|
+
for wall in building.walls:
|
|
76
|
+
wall_area += wall.solid_polygon.area
|
|
77
|
+
self.wall_area = wall_area
|
|
78
|
+
self.windows_area = wall_area * window_ratio
|
|
79
|
+
system_name = building.energy_systems_archetype_name
|
|
80
|
+
if system_name is None:
|
|
81
|
+
system_name = ''
|
|
82
|
+
self.system_name = system_name
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Model representation of simulation results
|
|
3
|
+
SPDX - License - Identifier: LGPL - 3.0 - or -later
|
|
4
|
+
Copyright © 2022 Concordia CERC group
|
|
5
|
+
Project Coder Guille Gutierrez Guillermo.GutierrezMorote@concordia.ca
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import datetime
|
|
9
|
+
|
|
10
|
+
from sqlalchemy import Column, Integer, String, Sequence, ForeignKey
|
|
11
|
+
from sqlalchemy import DateTime
|
|
12
|
+
from sqlalchemy.dialects.postgresql import JSONB
|
|
13
|
+
from cerc_persistence.configuration import Models
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class SimulationResults(Models):
|
|
17
|
+
"""
|
|
18
|
+
A model representation of an application
|
|
19
|
+
"""
|
|
20
|
+
__tablename__ = 'simulation_results'
|
|
21
|
+
id = Column(Integer, Sequence('simulation_results_id_seq'), primary_key=True)
|
|
22
|
+
city_id = Column(Integer, ForeignKey('city.id', ondelete='CASCADE'), nullable=True)
|
|
23
|
+
city_object_id = Column(Integer, ForeignKey('city_object.id', ondelete='CASCADE'), nullable=True)
|
|
24
|
+
name = Column(String, nullable=False)
|
|
25
|
+
values = Column(JSONB, nullable=False)
|
|
26
|
+
created = Column(DateTime, default=datetime.datetime.utcnow)
|
|
27
|
+
updated = Column(DateTime, default=datetime.datetime.utcnow)
|
|
28
|
+
|
|
29
|
+
def __init__(self, name, values, city_id=None, city_object_id=None):
|
|
30
|
+
self.name = name
|
|
31
|
+
self.values = values
|
|
32
|
+
self.city_id = city_id
|
|
33
|
+
self.city_object_id = city_object_id
|