dsgrid-toolkit 0.3.3__cp313-cp313-win_amd64.whl
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.
- build_backend.py +93 -0
- dsgrid/__init__.py +22 -0
- dsgrid/api/__init__.py +0 -0
- dsgrid/api/api_manager.py +179 -0
- dsgrid/api/app.py +419 -0
- dsgrid/api/models.py +60 -0
- dsgrid/api/response_models.py +116 -0
- dsgrid/apps/__init__.py +0 -0
- dsgrid/apps/project_viewer/app.py +216 -0
- dsgrid/apps/registration_gui.py +444 -0
- dsgrid/chronify.py +32 -0
- dsgrid/cli/__init__.py +0 -0
- dsgrid/cli/common.py +120 -0
- dsgrid/cli/config.py +176 -0
- dsgrid/cli/download.py +13 -0
- dsgrid/cli/dsgrid.py +157 -0
- dsgrid/cli/dsgrid_admin.py +92 -0
- dsgrid/cli/install_notebooks.py +62 -0
- dsgrid/cli/query.py +729 -0
- dsgrid/cli/registry.py +1862 -0
- dsgrid/cloud/__init__.py +0 -0
- dsgrid/cloud/cloud_storage_interface.py +140 -0
- dsgrid/cloud/factory.py +31 -0
- dsgrid/cloud/fake_storage_interface.py +37 -0
- dsgrid/cloud/s3_storage_interface.py +156 -0
- dsgrid/common.py +36 -0
- dsgrid/config/__init__.py +0 -0
- dsgrid/config/annual_time_dimension_config.py +194 -0
- dsgrid/config/common.py +142 -0
- dsgrid/config/config_base.py +148 -0
- dsgrid/config/dataset_config.py +907 -0
- dsgrid/config/dataset_schema_handler_factory.py +46 -0
- dsgrid/config/date_time_dimension_config.py +136 -0
- dsgrid/config/dimension_config.py +54 -0
- dsgrid/config/dimension_config_factory.py +65 -0
- dsgrid/config/dimension_mapping_base.py +350 -0
- dsgrid/config/dimension_mappings_config.py +48 -0
- dsgrid/config/dimensions.py +1025 -0
- dsgrid/config/dimensions_config.py +71 -0
- dsgrid/config/file_schema.py +190 -0
- dsgrid/config/index_time_dimension_config.py +80 -0
- dsgrid/config/input_dataset_requirements.py +31 -0
- dsgrid/config/mapping_tables.py +209 -0
- dsgrid/config/noop_time_dimension_config.py +42 -0
- dsgrid/config/project_config.py +1462 -0
- dsgrid/config/registration_models.py +188 -0
- dsgrid/config/representative_period_time_dimension_config.py +194 -0
- dsgrid/config/simple_models.py +49 -0
- dsgrid/config/supplemental_dimension.py +29 -0
- dsgrid/config/time_dimension_base_config.py +192 -0
- dsgrid/data_models.py +155 -0
- dsgrid/dataset/__init__.py +0 -0
- dsgrid/dataset/dataset.py +123 -0
- dsgrid/dataset/dataset_expression_handler.py +86 -0
- dsgrid/dataset/dataset_mapping_manager.py +121 -0
- dsgrid/dataset/dataset_schema_handler_base.py +945 -0
- dsgrid/dataset/dataset_schema_handler_one_table.py +209 -0
- dsgrid/dataset/dataset_schema_handler_two_table.py +322 -0
- dsgrid/dataset/growth_rates.py +162 -0
- dsgrid/dataset/models.py +51 -0
- dsgrid/dataset/table_format_handler_base.py +257 -0
- dsgrid/dataset/table_format_handler_factory.py +17 -0
- dsgrid/dataset/unpivoted_table.py +121 -0
- dsgrid/dimension/__init__.py +0 -0
- dsgrid/dimension/base_models.py +230 -0
- dsgrid/dimension/dimension_filters.py +308 -0
- dsgrid/dimension/standard.py +252 -0
- dsgrid/dimension/time.py +352 -0
- dsgrid/dimension/time_utils.py +103 -0
- dsgrid/dsgrid_rc.py +88 -0
- dsgrid/exceptions.py +105 -0
- dsgrid/filesystem/__init__.py +0 -0
- dsgrid/filesystem/cloud_filesystem.py +32 -0
- dsgrid/filesystem/factory.py +32 -0
- dsgrid/filesystem/filesystem_interface.py +136 -0
- dsgrid/filesystem/local_filesystem.py +74 -0
- dsgrid/filesystem/s3_filesystem.py +118 -0
- dsgrid/loggers.py +132 -0
- dsgrid/minimal_patterns.cp313-win_amd64.pyd +0 -0
- dsgrid/notebooks/connect_to_dsgrid_registry.ipynb +949 -0
- dsgrid/notebooks/registration.ipynb +48 -0
- dsgrid/notebooks/start_notebook.sh +11 -0
- dsgrid/project.py +451 -0
- dsgrid/query/__init__.py +0 -0
- dsgrid/query/dataset_mapping_plan.py +142 -0
- dsgrid/query/derived_dataset.py +388 -0
- dsgrid/query/models.py +728 -0
- dsgrid/query/query_context.py +287 -0
- dsgrid/query/query_submitter.py +994 -0
- dsgrid/query/report_factory.py +19 -0
- dsgrid/query/report_peak_load.py +70 -0
- dsgrid/query/reports_base.py +20 -0
- dsgrid/registry/__init__.py +0 -0
- dsgrid/registry/bulk_register.py +165 -0
- dsgrid/registry/common.py +287 -0
- dsgrid/registry/config_update_checker_base.py +63 -0
- dsgrid/registry/data_store_factory.py +34 -0
- dsgrid/registry/data_store_interface.py +74 -0
- dsgrid/registry/dataset_config_generator.py +158 -0
- dsgrid/registry/dataset_registry_manager.py +950 -0
- dsgrid/registry/dataset_update_checker.py +16 -0
- dsgrid/registry/dimension_mapping_registry_manager.py +575 -0
- dsgrid/registry/dimension_mapping_update_checker.py +16 -0
- dsgrid/registry/dimension_registry_manager.py +413 -0
- dsgrid/registry/dimension_update_checker.py +16 -0
- dsgrid/registry/duckdb_data_store.py +207 -0
- dsgrid/registry/filesystem_data_store.py +150 -0
- dsgrid/registry/filter_registry_manager.py +123 -0
- dsgrid/registry/project_config_generator.py +57 -0
- dsgrid/registry/project_registry_manager.py +1623 -0
- dsgrid/registry/project_update_checker.py +48 -0
- dsgrid/registry/registration_context.py +223 -0
- dsgrid/registry/registry_auto_updater.py +316 -0
- dsgrid/registry/registry_database.py +667 -0
- dsgrid/registry/registry_interface.py +446 -0
- dsgrid/registry/registry_manager.py +558 -0
- dsgrid/registry/registry_manager_base.py +367 -0
- dsgrid/registry/versioning.py +92 -0
- dsgrid/rust_ext/__init__.py +14 -0
- dsgrid/rust_ext/find_minimal_patterns.py +129 -0
- dsgrid/spark/__init__.py +0 -0
- dsgrid/spark/functions.py +589 -0
- dsgrid/spark/types.py +110 -0
- dsgrid/tests/__init__.py +0 -0
- dsgrid/tests/common.py +140 -0
- dsgrid/tests/make_us_data_registry.py +265 -0
- dsgrid/tests/register_derived_datasets.py +103 -0
- dsgrid/tests/utils.py +25 -0
- dsgrid/time/__init__.py +0 -0
- dsgrid/time/time_conversions.py +80 -0
- dsgrid/time/types.py +67 -0
- dsgrid/units/__init__.py +0 -0
- dsgrid/units/constants.py +113 -0
- dsgrid/units/convert.py +71 -0
- dsgrid/units/energy.py +145 -0
- dsgrid/units/power.py +87 -0
- dsgrid/utils/__init__.py +0 -0
- dsgrid/utils/dataset.py +830 -0
- dsgrid/utils/files.py +179 -0
- dsgrid/utils/filters.py +125 -0
- dsgrid/utils/id_remappings.py +100 -0
- dsgrid/utils/py_expression_eval/LICENSE +19 -0
- dsgrid/utils/py_expression_eval/README.md +8 -0
- dsgrid/utils/py_expression_eval/__init__.py +847 -0
- dsgrid/utils/py_expression_eval/tests.py +283 -0
- dsgrid/utils/run_command.py +70 -0
- dsgrid/utils/scratch_dir_context.py +65 -0
- dsgrid/utils/spark.py +918 -0
- dsgrid/utils/spark_partition.py +98 -0
- dsgrid/utils/timing.py +239 -0
- dsgrid/utils/utilities.py +221 -0
- dsgrid/utils/versioning.py +36 -0
- dsgrid_toolkit-0.3.3.dist-info/METADATA +193 -0
- dsgrid_toolkit-0.3.3.dist-info/RECORD +157 -0
- dsgrid_toolkit-0.3.3.dist-info/WHEEL +4 -0
- dsgrid_toolkit-0.3.3.dist-info/entry_points.txt +4 -0
- dsgrid_toolkit-0.3.3.dist-info/licenses/LICENSE +29 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import itertools
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Any, Generator
|
|
5
|
+
|
|
6
|
+
import pandas as pd
|
|
7
|
+
from sqlalchemy import Connection, Engine
|
|
8
|
+
|
|
9
|
+
from dsgrid.config.dataset_config import DatasetConfigModel
|
|
10
|
+
from dsgrid.config.dimension_mapping_base import DimensionMappingBaseModel
|
|
11
|
+
from dsgrid.config.dimensions import DimensionBaseModel, handle_dimension_union
|
|
12
|
+
from dsgrid.config.mapping_tables import MappingTableModel
|
|
13
|
+
from dsgrid.config.project_config import ProjectConfigModel
|
|
14
|
+
from dsgrid.data_models import DSGBaseDatabaseModel, DSGBaseModel
|
|
15
|
+
from dsgrid.registry.common import (
|
|
16
|
+
DatasetRegistryStatus,
|
|
17
|
+
MODEL_TYPE_TO_ID_FIELD_MAPPING,
|
|
18
|
+
RegistrationModel,
|
|
19
|
+
RegistryType,
|
|
20
|
+
)
|
|
21
|
+
from dsgrid.registry.registry_database import RegistryDatabase
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class RegistryInterfaceBase(abc.ABC):
|
|
28
|
+
"""Interface base class"""
|
|
29
|
+
|
|
30
|
+
def __init__(self, db: RegistryDatabase):
|
|
31
|
+
self._db = db
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def engine(self) -> Engine:
|
|
35
|
+
"""Return the sqlalchemy engine."""
|
|
36
|
+
return self._db.engine
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
@abc.abstractmethod
|
|
40
|
+
def _model_type() -> RegistryType:
|
|
41
|
+
"""Return the model type."""
|
|
42
|
+
|
|
43
|
+
@abc.abstractmethod
|
|
44
|
+
def _get_model_id(self, model) -> str:
|
|
45
|
+
"""Return the dsgrid ID for the model."""
|
|
46
|
+
|
|
47
|
+
@abc.abstractmethod
|
|
48
|
+
def _get_model_id_field(self):
|
|
49
|
+
"""Return the field representing the model ID for the model."""
|
|
50
|
+
|
|
51
|
+
def _insert_contains_edges(self, conn: Connection, model) -> None:
|
|
52
|
+
"""Add contains edges to any dependent documents."""
|
|
53
|
+
|
|
54
|
+
@staticmethod
|
|
55
|
+
@abc.abstractmethod
|
|
56
|
+
def _make_dsgrid_model(db_data: dict) -> Any:
|
|
57
|
+
"""Convert the database object into a dsgrid model."""
|
|
58
|
+
|
|
59
|
+
def delete_all(self, conn: Connection | None, model_id: str) -> None:
|
|
60
|
+
"""Delete all database instances with model_id."""
|
|
61
|
+
if conn is None:
|
|
62
|
+
with self._db.engine.begin() as conn:
|
|
63
|
+
return self._db.delete_models(conn, self._model_type(), model_id)
|
|
64
|
+
return self._db.delete_models(conn, self._model_type(), model_id)
|
|
65
|
+
|
|
66
|
+
def get_by_version(self, conn: Connection | None, model_id, version) -> DSGBaseDatabaseModel:
|
|
67
|
+
"""Return the model by version"""
|
|
68
|
+
return self._make_dsgrid_model(self._get_by_version(conn, model_id, version))
|
|
69
|
+
|
|
70
|
+
def get_latest(self, conn: Connection | None, model_id) -> DSGBaseModel:
|
|
71
|
+
"""Return the model with the latest version."""
|
|
72
|
+
return self._make_dsgrid_model(self._get_latest(conn, model_id))
|
|
73
|
+
|
|
74
|
+
def get_latest_version(self, conn: Connection | None, model_id: str) -> str:
|
|
75
|
+
"""Return the latest version of the model_id.
|
|
76
|
+
|
|
77
|
+
Parameters
|
|
78
|
+
----------
|
|
79
|
+
model_id : str
|
|
80
|
+
dsgrid identifier for a model item
|
|
81
|
+
|
|
82
|
+
Returns
|
|
83
|
+
-------
|
|
84
|
+
str
|
|
85
|
+
"""
|
|
86
|
+
if conn is None:
|
|
87
|
+
with self._db.engine.connect() as conn:
|
|
88
|
+
return self._db.get_latest_version(conn, self._model_type(), model_id)
|
|
89
|
+
return self._db.get_latest_version(conn, self._model_type(), model_id)
|
|
90
|
+
|
|
91
|
+
def get_registration(
|
|
92
|
+
self, conn: Connection | None, model: DSGBaseDatabaseModel
|
|
93
|
+
) -> RegistrationModel:
|
|
94
|
+
"""Return the registration information for the model."""
|
|
95
|
+
if conn is None:
|
|
96
|
+
with self._db.engine.connect() as conn:
|
|
97
|
+
return self._db.get_registration(conn, model.id)
|
|
98
|
+
return self._db.get_registration(conn, model.id)
|
|
99
|
+
|
|
100
|
+
def get_initial_registration(
|
|
101
|
+
self, conn: Connection | None, model_id: str
|
|
102
|
+
) -> RegistrationModel:
|
|
103
|
+
"""Return the initial registration information for the model."""
|
|
104
|
+
if conn is None:
|
|
105
|
+
with self._db.engine.connect() as conn:
|
|
106
|
+
return self._db.get_initial_registration(conn, self._model_type(), model_id)
|
|
107
|
+
return self._db.get_initial_registration(conn, self._model_type(), model_id)
|
|
108
|
+
|
|
109
|
+
def has(self, conn: Connection | None, model_id: str, version: str | None = None) -> bool:
|
|
110
|
+
"""Return True if the model_id is stored in the database."""
|
|
111
|
+
if conn is None:
|
|
112
|
+
with self._db.engine.connect() as conn:
|
|
113
|
+
return self._db.has(conn, self._model_type(), model_id, version=version)
|
|
114
|
+
return self._db.has(conn, self._model_type(), model_id, version=version)
|
|
115
|
+
|
|
116
|
+
def insert(
|
|
117
|
+
self,
|
|
118
|
+
conn: Connection | None,
|
|
119
|
+
model: DSGBaseDatabaseModel,
|
|
120
|
+
registration: RegistrationModel,
|
|
121
|
+
) -> DSGBaseModel:
|
|
122
|
+
"""Add a new model in the database."""
|
|
123
|
+
if conn is None:
|
|
124
|
+
with self._db.engine.begin() as conn:
|
|
125
|
+
return self._insert(conn, model, registration)
|
|
126
|
+
return self._insert(conn, model, registration)
|
|
127
|
+
|
|
128
|
+
def _insert(
|
|
129
|
+
self, conn: Connection, model: DSGBaseDatabaseModel, registration: RegistrationModel
|
|
130
|
+
) -> DSGBaseModel:
|
|
131
|
+
new_model = self._make_dsgrid_model(
|
|
132
|
+
self._db.insert_model(
|
|
133
|
+
conn, self._model_type(), model.model_dump(mode="json"), registration
|
|
134
|
+
)
|
|
135
|
+
)
|
|
136
|
+
self._insert_contains_edges(conn, new_model)
|
|
137
|
+
return new_model
|
|
138
|
+
|
|
139
|
+
def insert_registration(
|
|
140
|
+
self, conn: Connection | None, registration: RegistrationModel
|
|
141
|
+
) -> RegistrationModel:
|
|
142
|
+
"""Add the registration to the database.
|
|
143
|
+
|
|
144
|
+
Returns
|
|
145
|
+
-------
|
|
146
|
+
database ID of registration entry
|
|
147
|
+
"""
|
|
148
|
+
if conn is None:
|
|
149
|
+
with self._db.engine.begin() as conn:
|
|
150
|
+
return self._db.insert_registration(conn, registration)
|
|
151
|
+
return self._db.insert_registration(conn, registration)
|
|
152
|
+
|
|
153
|
+
def list_model_ids(self, conn: Connection | None = None) -> list[str]:
|
|
154
|
+
"""Return a list of all distinct dsgrid model IDs."""
|
|
155
|
+
if conn is None:
|
|
156
|
+
with self._db.engine.connect() as conn:
|
|
157
|
+
return self._db.list_model_ids(conn, self._model_type())
|
|
158
|
+
return self._db.list_model_ids(conn, self._model_type())
|
|
159
|
+
|
|
160
|
+
def iter_models(
|
|
161
|
+
self,
|
|
162
|
+
conn: Connection | None = None,
|
|
163
|
+
all_versions: bool = False,
|
|
164
|
+
filter_config: dict[str, Any] | None = None,
|
|
165
|
+
) -> Generator[DSGBaseDatabaseModel, None, None]:
|
|
166
|
+
"""Return a generator of dsgrid models converted from database objects.
|
|
167
|
+
|
|
168
|
+
Parameters
|
|
169
|
+
----------
|
|
170
|
+
all_versions : bool
|
|
171
|
+
If False, return only the latest version of each model in the registry of this type.
|
|
172
|
+
If True, return all versions of each model (such as all versions of every project).
|
|
173
|
+
filter_config : None | dict
|
|
174
|
+
If set, it must be a dict of model field names to values. Only return models that
|
|
175
|
+
match the filter
|
|
176
|
+
"""
|
|
177
|
+
if conn is None:
|
|
178
|
+
with self._db.engine.connect() as conn:
|
|
179
|
+
yield from self._iter_models(
|
|
180
|
+
conn, all_versions=all_versions, filter_config=filter_config
|
|
181
|
+
)
|
|
182
|
+
else:
|
|
183
|
+
yield from self._iter_models(
|
|
184
|
+
conn, all_versions=all_versions, filter_config=filter_config
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
def _iter_models(
|
|
188
|
+
self,
|
|
189
|
+
conn: Connection,
|
|
190
|
+
all_versions: bool = False,
|
|
191
|
+
filter_config: dict[str, Any] | None = None,
|
|
192
|
+
) -> Generator[DSGBaseDatabaseModel, None, None]:
|
|
193
|
+
for data in self._db.iter_models(conn, self._model_type(), all_versions=all_versions):
|
|
194
|
+
model = self._make_dsgrid_model(data)
|
|
195
|
+
if filter_config is None or self._does_filter_match(model, filter_config):
|
|
196
|
+
yield self._make_dsgrid_model(data)
|
|
197
|
+
|
|
198
|
+
def get_containing_models(
|
|
199
|
+
self,
|
|
200
|
+
conn: Connection | None,
|
|
201
|
+
model: DSGBaseDatabaseModel,
|
|
202
|
+
version: str | None = None,
|
|
203
|
+
parent_model_type: RegistryType | None = None,
|
|
204
|
+
) -> dict[RegistryType, list[DSGBaseDatabaseModel]]:
|
|
205
|
+
"""Return all models that contain the given model. If version is not set, use the current
|
|
206
|
+
version of model. Only looks at the latest version of each parent model.
|
|
207
|
+
"""
|
|
208
|
+
version_ = version or model.version
|
|
209
|
+
if isinstance(model, ProjectConfigModel):
|
|
210
|
+
model_type = RegistryType.PROJECT
|
|
211
|
+
elif isinstance(model, DatasetConfigModel):
|
|
212
|
+
model_type = RegistryType.DATASET
|
|
213
|
+
elif isinstance(model, DimensionBaseModel):
|
|
214
|
+
model_type = RegistryType.DIMENSION
|
|
215
|
+
elif isinstance(model, DimensionMappingBaseModel):
|
|
216
|
+
model_type = RegistryType.DIMENSION_MAPPING
|
|
217
|
+
else:
|
|
218
|
+
msg = str(type(model))
|
|
219
|
+
raise NotImplementedError(msg)
|
|
220
|
+
model_id = getattr(model, MODEL_TYPE_TO_ID_FIELD_MAPPING[model_type])
|
|
221
|
+
if conn is None:
|
|
222
|
+
with self._db.engine.connect() as conn:
|
|
223
|
+
return self._get_containing_models(
|
|
224
|
+
conn, model_type, model_id, version_, parent_model_type=parent_model_type
|
|
225
|
+
)
|
|
226
|
+
return self._get_containing_models(
|
|
227
|
+
conn, model_type, model_id, version_, parent_model_type=parent_model_type
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
def _get_containing_models(
|
|
231
|
+
self,
|
|
232
|
+
conn: Connection,
|
|
233
|
+
child_model_type: RegistryType,
|
|
234
|
+
model_id: str,
|
|
235
|
+
version: str,
|
|
236
|
+
parent_model_type: RegistryType | None = None,
|
|
237
|
+
) -> dict[RegistryType, list[DSGBaseDatabaseModel]]:
|
|
238
|
+
results = {x: [] for x in RegistryType}
|
|
239
|
+
for model_type, data in self._db.get_containing_models(
|
|
240
|
+
conn, child_model_type, model_id, version, parent_model_type=parent_model_type
|
|
241
|
+
):
|
|
242
|
+
model = _INTERFACE_BY_TYPE[model_type]._make_dsgrid_model(data)
|
|
243
|
+
results[model_type].append(model)
|
|
244
|
+
return results
|
|
245
|
+
|
|
246
|
+
@staticmethod
|
|
247
|
+
def _does_filter_match(model: DSGBaseDatabaseModel, filter_config):
|
|
248
|
+
for key, val in filter_config.items():
|
|
249
|
+
if getattr(model, key) != val:
|
|
250
|
+
return False
|
|
251
|
+
return True
|
|
252
|
+
|
|
253
|
+
def replace(self, conn: Connection | None, model: DSGBaseDatabaseModel):
|
|
254
|
+
"""Replace an existing model in the database."""
|
|
255
|
+
if conn is None:
|
|
256
|
+
with self._db.engine.begin() as conn:
|
|
257
|
+
return self._replace(conn, model)
|
|
258
|
+
return self._replace(conn, model)
|
|
259
|
+
|
|
260
|
+
def _replace(self, conn: Connection, model: DSGBaseDatabaseModel):
|
|
261
|
+
return self._db.replace_model(conn, model.model_dump(mode="json"))
|
|
262
|
+
|
|
263
|
+
def update(
|
|
264
|
+
self,
|
|
265
|
+
conn: Connection | None,
|
|
266
|
+
model: DSGBaseDatabaseModel,
|
|
267
|
+
registration: RegistrationModel,
|
|
268
|
+
) -> DSGBaseDatabaseModel:
|
|
269
|
+
"""Update an existing model in the database."""
|
|
270
|
+
if conn is None:
|
|
271
|
+
with self._db.engine.begin() as conn:
|
|
272
|
+
return self._update(conn, model, registration)
|
|
273
|
+
return self._update(conn, model, registration)
|
|
274
|
+
|
|
275
|
+
def _update(
|
|
276
|
+
self, conn: Connection, model: DSGBaseDatabaseModel, registration: RegistrationModel
|
|
277
|
+
) -> DSGBaseDatabaseModel:
|
|
278
|
+
new_model = self._make_dsgrid_model(
|
|
279
|
+
self._db.update_model(
|
|
280
|
+
conn, self._model_type(), model.model_dump(mode="json"), registration
|
|
281
|
+
)
|
|
282
|
+
)
|
|
283
|
+
self._insert_contains_edges(conn, new_model)
|
|
284
|
+
return new_model
|
|
285
|
+
|
|
286
|
+
def _get_by_version(self, conn: Connection | None, model_id, version) -> dict[str, Any]:
|
|
287
|
+
if conn is None:
|
|
288
|
+
with self._db.engine.connect() as conn:
|
|
289
|
+
return self._db._get_by_version(conn, self._model_type(), model_id, version)
|
|
290
|
+
return self._db._get_by_version(conn, self._model_type(), model_id, version)
|
|
291
|
+
|
|
292
|
+
def _get_latest(self, conn: Connection | None, model_id: str) -> dict[str, Any]:
|
|
293
|
+
if conn is None:
|
|
294
|
+
with self._db.engine.connect() as conn:
|
|
295
|
+
return self._db.get_latest(conn, self._model_type(), model_id)
|
|
296
|
+
return self._db.get_latest(conn, self._model_type(), model_id)
|
|
297
|
+
|
|
298
|
+
@property
|
|
299
|
+
def datasets(self) -> Generator[dict[str, Any], None, None]:
|
|
300
|
+
with self.engine.connect() as conn:
|
|
301
|
+
yield from self._db.iter_models(conn, RegistryType.DATASET)
|
|
302
|
+
|
|
303
|
+
@property
|
|
304
|
+
def dimensions(self) -> Generator[dict[str, Any], None, None]:
|
|
305
|
+
with self.engine.connect() as conn:
|
|
306
|
+
yield from self._db.iter_models(conn, RegistryType.DIMENSION)
|
|
307
|
+
|
|
308
|
+
@property
|
|
309
|
+
def dimension_mappings(self) -> Generator[dict[str, Any], None, None]:
|
|
310
|
+
with self.engine.connect() as conn:
|
|
311
|
+
yield from self._db.iter_models(conn, RegistryType.DIMENSION_MAPPING)
|
|
312
|
+
|
|
313
|
+
@property
|
|
314
|
+
def projects(self) -> Generator[dict[str, Any], None, None]:
|
|
315
|
+
with self.engine.connect() as conn:
|
|
316
|
+
yield from self._db.iter_models(conn, RegistryType.PROJECT)
|
|
317
|
+
|
|
318
|
+
def sql(
|
|
319
|
+
self, query: str, params: Any | None = None, conn: Connection | None = None
|
|
320
|
+
) -> pd.DataFrame:
|
|
321
|
+
"""Return the results of a query as a Pandas DataFrame."""
|
|
322
|
+
if conn is None:
|
|
323
|
+
with self.engine.connect() as conn:
|
|
324
|
+
return pd.read_sql(query, con=conn, params=params)
|
|
325
|
+
return pd.read_sql(query, con=conn, params=params)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
class DatasetRegistryInterface(RegistryInterfaceBase):
|
|
329
|
+
"""Interface to database for datasets"""
|
|
330
|
+
|
|
331
|
+
@staticmethod
|
|
332
|
+
def _model_type() -> RegistryType:
|
|
333
|
+
return RegistryType.DATASET
|
|
334
|
+
|
|
335
|
+
def _get_model_id(self, model):
|
|
336
|
+
return model.dataset_id
|
|
337
|
+
|
|
338
|
+
def _get_model_id_field(self):
|
|
339
|
+
return "dataset_id"
|
|
340
|
+
|
|
341
|
+
@staticmethod
|
|
342
|
+
def _make_dsgrid_model(db_data: dict):
|
|
343
|
+
return DatasetConfigModel(**db_data)
|
|
344
|
+
|
|
345
|
+
def _insert_contains_edges(self, conn: Connection, model):
|
|
346
|
+
dim_intf = DimensionRegistryInterface(self._db)
|
|
347
|
+
for ref in model.dimension_references:
|
|
348
|
+
dim = dim_intf.get_by_version(conn, ref.dimension_id, ref.version)
|
|
349
|
+
self._db.insert_contains_edge(conn, model.id, dim.id)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
class DimensionRegistryInterface(RegistryInterfaceBase):
|
|
353
|
+
"""Interface to database for dimensions"""
|
|
354
|
+
|
|
355
|
+
@staticmethod
|
|
356
|
+
def _model_type() -> RegistryType:
|
|
357
|
+
return RegistryType.DIMENSION
|
|
358
|
+
|
|
359
|
+
def _get_model_id(self, model):
|
|
360
|
+
return model.dimension_id
|
|
361
|
+
|
|
362
|
+
def _get_model_id_field(self):
|
|
363
|
+
return "dimension_id"
|
|
364
|
+
|
|
365
|
+
@staticmethod
|
|
366
|
+
def _make_dsgrid_model(db_data: dict):
|
|
367
|
+
return handle_dimension_union([db_data])[0]
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
class DimensionMappingRegistryInterface(RegistryInterfaceBase):
|
|
371
|
+
"""Interface to database for dimension mappings"""
|
|
372
|
+
|
|
373
|
+
@staticmethod
|
|
374
|
+
def _model_type() -> RegistryType:
|
|
375
|
+
return RegistryType.DIMENSION_MAPPING
|
|
376
|
+
|
|
377
|
+
def _get_model_id(self, model):
|
|
378
|
+
return model.mapping_id
|
|
379
|
+
|
|
380
|
+
def _get_model_id_field(self):
|
|
381
|
+
return "mapping_id"
|
|
382
|
+
|
|
383
|
+
@staticmethod
|
|
384
|
+
def _make_dsgrid_model(db_data: dict[str, Any]):
|
|
385
|
+
return MappingTableModel(**db_data)
|
|
386
|
+
|
|
387
|
+
def _insert_contains_edges(self, conn, model):
|
|
388
|
+
dim_intf = DimensionRegistryInterface(self._db)
|
|
389
|
+
for ref in (model.from_dimension, model.to_dimension):
|
|
390
|
+
dim = dim_intf.get_by_version(conn, ref.dimension_id, ref.version)
|
|
391
|
+
self._db.insert_contains_edge(conn, model.id, dim.id)
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
class ProjectRegistryInterface(RegistryInterfaceBase):
|
|
395
|
+
"""Interface to database for projects"""
|
|
396
|
+
|
|
397
|
+
@staticmethod
|
|
398
|
+
def _model_type() -> RegistryType:
|
|
399
|
+
return RegistryType.PROJECT
|
|
400
|
+
|
|
401
|
+
def _get_model_id(self, model):
|
|
402
|
+
return model.project_id
|
|
403
|
+
|
|
404
|
+
def _get_model_id_field(self):
|
|
405
|
+
return "project_id"
|
|
406
|
+
|
|
407
|
+
@staticmethod
|
|
408
|
+
def _make_dsgrid_model(db_data: dict):
|
|
409
|
+
return ProjectConfigModel(**db_data)
|
|
410
|
+
|
|
411
|
+
def _insert_contains_edges(self, conn: Connection, model):
|
|
412
|
+
dim_intf = DimensionRegistryInterface(self._db)
|
|
413
|
+
dim_mapping_intf = DimensionMappingRegistryInterface(self._db)
|
|
414
|
+
dataset_intf = DatasetRegistryInterface(self._db)
|
|
415
|
+
|
|
416
|
+
for ref in itertools.chain(
|
|
417
|
+
model.dimensions.base_dimension_references,
|
|
418
|
+
model.dimensions.supplemental_dimension_references,
|
|
419
|
+
):
|
|
420
|
+
dim = dim_intf.get_by_version(conn, ref.dimension_id, ref.version)
|
|
421
|
+
self._db.insert_contains_edge(conn, model.id, dim.id)
|
|
422
|
+
|
|
423
|
+
for ref in model.dimension_mappings.base_to_supplemental_references:
|
|
424
|
+
mapping = dim_mapping_intf.get_by_version(conn, ref.mapping_id, ref.version)
|
|
425
|
+
self._db.insert_contains_edge(conn, model.id, mapping.id)
|
|
426
|
+
|
|
427
|
+
for dataset in model.datasets:
|
|
428
|
+
if dataset.status == DatasetRegistryStatus.REGISTERED.value:
|
|
429
|
+
dset = dataset_intf.get_by_version(conn, dataset.dataset_id, dataset.version)
|
|
430
|
+
self._db.insert_contains_edge(conn, model.id, dset.id)
|
|
431
|
+
|
|
432
|
+
def add_contains_dataset(
|
|
433
|
+
self, conn: Connection, project: ProjectConfigModel, dataset: DatasetConfigModel
|
|
434
|
+
) -> None:
|
|
435
|
+
assert project.id is not None
|
|
436
|
+
assert dataset.id is not None
|
|
437
|
+
self._db.insert_contains_edge(conn, project.id, dataset.id)
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
_INTERFACE_BY_TYPE = {
|
|
441
|
+
RegistryType.PROJECT: ProjectRegistryInterface,
|
|
442
|
+
RegistryType.DATASET: DatasetRegistryInterface,
|
|
443
|
+
RegistryType.DIMENSION: DimensionRegistryInterface,
|
|
444
|
+
RegistryType.DIMENSION_MAPPING: DimensionMappingRegistryInterface,
|
|
445
|
+
}
|
|
446
|
+
assert len(_INTERFACE_BY_TYPE) == len(RegistryType)
|