-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathdb_utils.py
More file actions
205 lines (165 loc) · 6.82 KB
/
Copy pathdb_utils.py
File metadata and controls
205 lines (165 loc) · 6.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
import logging
from typing import Final
import pandas as pd
from geoalchemy2 import WKBElement
from geoalchemy2.shape import to_shape
from sqlalchemy import Inspector, delete
import json
from shared.database_gen.sqlacodegen_models import Base
class CustomEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, WKBElement):
# Convert the WKBElement to a shapely shape, then to a geojson format
return to_shape(obj).wkt
# return to_shape(obj).__geo_interface__
elif isinstance(obj, pd.Timestamp):
# Convert Timestamp object to string in ISO 8601 format
return obj.isoformat()
return super().default(obj)
def dump_raw_database(db, file_name="database_raw_dump.json"):
# Create an Inspector and connect it to the engine
inspector = Inspector.from_engine(db.engine)
# Get the list of all tables in the database
all_tables = inspector.get_table_names()
tables_of_interest = [
"feed",
"gtfsrealtimefeed",
"feature",
"feedreference",
"location",
"locationfeed",
"externalid",
"gtfsdataset",
"featurevalidationreport",
"notice",
"redirectingid",
"validationreportgtfsdataset",
"validationreport",
]
tables = [table for table in all_tables if table in tables_of_interest]
# Initialize an empty dictionary to hold data
data = {}
dfs = {}
# Loop through each table
for table in tables:
# Read the table into a DataFrame
df = pd.read_sql_table(table, db.engine)
dfs[table] = df
for table, df in dfs.items():
if df.shape[0] > 0:
# Convert the DataFrame into a JSON object and add it to the data dictionary
records = df.to_dict(orient="records")
data[table] = [{k: v for k, v in record.items() if v is not None} for record in records]
# Write the data dictionary to a JSON file
with open(file_name, "w") as f:
json.dump(data, f, cls=CustomEncoder)
def dump_database(db, file_name):
if file_name is None:
return
# Create an Inspector and connect it to the engine
inspector = Inspector.from_engine(db.engine)
# Get the list of all tables in the database
all_tables = inspector.get_table_names()
tables_of_interest = [
"feed",
"feature",
"feedreference",
"location",
"locationfeed",
"externalid",
"gtfsdataset",
"featurevalidationreport",
"notice",
"redirectingid",
"validationreportgtfsdataset",
"validationreport",
]
tables = [table for table in all_tables if table in tables_of_interest]
# Initialize an empty dictionary to hold data
data = {}
dfs = {}
# Loop through each table
for table in tables:
# Read the table into a DataFrame
df = pd.read_sql_table(table, db.engine)
dfs[table] = df
feeds = dfs["feed"]
# Create a dictionary mapping feed_id to stable_id
feed_id_to_stable_id = feeds.set_index("id")["stable_id"].to_dict()
validationreportgtfsdatasets = dfs["validationreportgtfsdataset"]
# merged_df_1 = pd.merge(dfs['validationreport'], dfs['validationreportgtfsdataset'], left_on='id',
# right_on='validation_report_id')
datasets = dfs["gtfsdataset"]
dataset_id_to_stable_id = datasets.set_index("id")["stable_id"].to_dict()
# Replace feed_id with stable_id in the gtfsdataset DataFrame
datasets["feed_stable_id"] = datasets["feed_id"].replace(feed_id_to_stable_id)
datasets["id"] = datasets["stable_id"]
dfs["datasets"] = datasets.drop(columns=["feed_id", "stable_id"])
validationreports = dfs["validationreport"]
validationreports["name"] = ["vr_" + str(i + 1) for i in range(len(validationreports))]
validationreport_id_to_name = validationreports.set_index("id")["name"].to_dict()
validationreports["id"] = validationreports["id"].replace(validationreport_id_to_name)
validationreports["dataset_id"] = validationreportgtfsdatasets["dataset_id"].replace(dataset_id_to_stable_id)
validationreports["html_report"] = "someurl"
validationreports["json_report"] = "someurl"
dfs["validation_reports"] = validationreports.drop(columns=["name"])
del dfs["validationreport"]
features = dfs["feature"]
# Extract the 'name' values into a list
name_list = features["name"].values
# Convert the list into a DataFrame
dfs["features"] = pd.DataFrame(name_list)
del dfs["feature"]
featurevalidationreports = dfs.get("featurevalidationreport")
featurevalidationreports["validation_report_id"] = featurevalidationreports["validation_id"].replace(
validationreport_id_to_name
)
featurevalidationreports["feature_name"] = featurevalidationreports["feature"]
dfs["validation_report_features"] = featurevalidationreports.drop(columns=["validation_id", "feature"])
del dfs["featurevalidationreport"]
notices = dfs.get("notice")
notices["dataset_id"] = notices["dataset_id"].replace(dataset_id_to_stable_id)
notices["validation_report_id"] = notices["validation_report_id"].replace(validationreport_id_to_name)
dfs["notices"] = notices
del dfs["notice"]
del dfs["feedreference"]
del dfs["location"]
del dfs["locationfeed"]
del dfs["externalid"]
del dfs["gtfsdataset"]
del dfs["redirectingid"]
del dfs["validationreportgtfsdataset"]
del dfs["feed"]
for table, df in dfs.items():
if df.shape[0] > 0:
# Convert the DataFrame into a JSON object and add it to the data dictionary
records = df.to_dict(orient="records")
data[table] = [{k: v for k, v in record.items() if v is not None} for record in records]
# Write the data dictionary to a JSON file
with open(file_name, "w") as f:
json.dump(data, f, cls=CustomEncoder)
def is_test_db(url):
return url is None or "MobilityDatabaseTest" in url
excluded_tables: Final[list[str]] = [
"databasechangelog",
"databasechangeloglock",
"geography_columns",
"geometry_columns",
"spatial_ref_sys",
# Excluding the views
"feedsearch",
"location_with_translations_en",
]
def empty_database(db, url):
if is_test_db(url):
try:
with db.start_db_session() as session:
# Using sorted_tables to respect foreign key constraints
for table in reversed(Base.metadata.sorted_tables):
if table.name not in excluded_tables:
table = Base.metadata.tables[table.name]
delete_stmt = delete(table)
session.execute(delete_stmt)
session.commit()
except Exception as error:
logging.error(f"Error while deleting from test db: {error}")