pydpm_xl 0.1.39rc32__py3-none-any.whl → 0.2.0__py3-none-any.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.
- py_dpm/__init__.py +1 -1
- py_dpm/api/__init__.py +58 -189
- py_dpm/api/dpm/__init__.py +20 -0
- py_dpm/api/{data_dictionary.py → dpm/data_dictionary.py} +903 -984
- py_dpm/api/dpm/explorer.py +236 -0
- py_dpm/api/dpm/hierarchical_queries.py +142 -0
- py_dpm/api/{migration.py → dpm/migration.py} +16 -19
- py_dpm/api/{operation_scopes.py → dpm/operation_scopes.py} +319 -267
- py_dpm/api/dpm_xl/__init__.py +25 -0
- py_dpm/api/{ast_generator.py → dpm_xl/ast_generator.py} +3 -3
- py_dpm/api/{complete_ast.py → dpm_xl/complete_ast.py} +191 -167
- py_dpm/api/dpm_xl/semantic.py +354 -0
- py_dpm/api/{syntax.py → dpm_xl/syntax.py} +6 -5
- py_dpm/api/explorer.py +4 -0
- py_dpm/api/semantic.py +30 -306
- py_dpm/cli/__init__.py +9 -0
- py_dpm/{client.py → cli/main.py} +8 -8
- py_dpm/dpm/__init__.py +11 -0
- py_dpm/{models.py → dpm/models.py} +112 -88
- py_dpm/dpm/queries/base.py +100 -0
- py_dpm/dpm/queries/basic_objects.py +33 -0
- py_dpm/dpm/queries/explorer_queries.py +352 -0
- py_dpm/dpm/queries/filters.py +139 -0
- py_dpm/dpm/queries/glossary.py +45 -0
- py_dpm/dpm/queries/hierarchical_queries.py +838 -0
- py_dpm/dpm/queries/tables.py +133 -0
- py_dpm/dpm/utils.py +356 -0
- py_dpm/dpm_xl/__init__.py +8 -0
- py_dpm/dpm_xl/ast/__init__.py +14 -0
- py_dpm/{AST/ASTConstructor.py → dpm_xl/ast/constructor.py} +6 -6
- py_dpm/{AST/MLGeneration.py → dpm_xl/ast/ml_generation.py} +137 -87
- py_dpm/{AST/ModuleAnalyzer.py → dpm_xl/ast/module_analyzer.py} +7 -7
- py_dpm/{AST/ModuleDependencies.py → dpm_xl/ast/module_dependencies.py} +56 -41
- py_dpm/{AST/ASTObjects.py → dpm_xl/ast/nodes.py} +1 -1
- py_dpm/{AST/check_operands.py → dpm_xl/ast/operands.py} +16 -13
- py_dpm/{AST/ASTTemplate.py → dpm_xl/ast/template.py} +2 -2
- py_dpm/{AST/WhereClauseChecker.py → dpm_xl/ast/where_clause.py} +2 -2
- py_dpm/dpm_xl/grammar/__init__.py +18 -0
- py_dpm/dpm_xl/operators/__init__.py +19 -0
- py_dpm/{Operators/AggregateOperators.py → dpm_xl/operators/aggregate.py} +7 -7
- py_dpm/{Operators/NumericOperators.py → dpm_xl/operators/arithmetic.py} +6 -6
- py_dpm/{Operators/Operator.py → dpm_xl/operators/base.py} +5 -5
- py_dpm/{Operators/BooleanOperators.py → dpm_xl/operators/boolean.py} +5 -5
- py_dpm/{Operators/ClauseOperators.py → dpm_xl/operators/clause.py} +8 -8
- py_dpm/{Operators/ComparisonOperators.py → dpm_xl/operators/comparison.py} +5 -5
- py_dpm/{Operators/ConditionalOperators.py → dpm_xl/operators/conditional.py} +7 -7
- py_dpm/{Operators/StringOperators.py → dpm_xl/operators/string.py} +5 -5
- py_dpm/{Operators/TimeOperators.py → dpm_xl/operators/time.py} +6 -6
- py_dpm/{semantics/SemanticAnalyzer.py → dpm_xl/semantic_analyzer.py} +168 -68
- py_dpm/{semantics/Symbols.py → dpm_xl/symbols.py} +3 -3
- py_dpm/dpm_xl/types/__init__.py +13 -0
- py_dpm/{DataTypes/TypePromotion.py → dpm_xl/types/promotion.py} +2 -2
- py_dpm/{DataTypes/ScalarTypes.py → dpm_xl/types/scalar.py} +2 -2
- py_dpm/dpm_xl/utils/__init__.py +14 -0
- py_dpm/{data_handlers.py → dpm_xl/utils/data_handlers.py} +2 -2
- py_dpm/{Utils → dpm_xl/utils}/operands_mapping.py +1 -1
- py_dpm/{Utils → dpm_xl/utils}/operator_mapping.py +8 -8
- py_dpm/{OperationScopes/OperationScopeService.py → dpm_xl/utils/scopes_calculator.py} +148 -58
- py_dpm/{Utils/ast_serialization.py → dpm_xl/utils/serialization.py} +2 -2
- py_dpm/dpm_xl/validation/__init__.py +12 -0
- py_dpm/{Utils/ValidationsGenerationUtils.py → dpm_xl/validation/generation_utils.py} +2 -3
- py_dpm/{ValidationsGeneration/PropertiesConstraintsProcessor.py → dpm_xl/validation/property_constraints.py} +56 -21
- py_dpm/{ValidationsGeneration/auxiliary_functions.py → dpm_xl/validation/utils.py} +2 -2
- py_dpm/{ValidationsGeneration/VariantsProcessor.py → dpm_xl/validation/variants.py} +149 -55
- py_dpm/exceptions/__init__.py +23 -0
- py_dpm/{Exceptions → exceptions}/exceptions.py +7 -2
- pydpm_xl-0.2.0.dist-info/METADATA +278 -0
- pydpm_xl-0.2.0.dist-info/RECORD +88 -0
- pydpm_xl-0.2.0.dist-info/entry_points.txt +2 -0
- py_dpm/Exceptions/__init__.py +0 -0
- py_dpm/OperationScopes/__init__.py +0 -0
- py_dpm/Operators/__init__.py +0 -0
- py_dpm/Utils/__init__.py +0 -0
- py_dpm/Utils/utils.py +0 -2
- py_dpm/ValidationsGeneration/Utils.py +0 -364
- py_dpm/ValidationsGeneration/__init__.py +0 -0
- py_dpm/api/data_dictionary_validation.py +0 -614
- py_dpm/db_utils.py +0 -221
- py_dpm/grammar/__init__.py +0 -0
- py_dpm/grammar/dist/__init__.py +0 -0
- py_dpm/grammar/dpm_xlLexer.g4 +0 -437
- py_dpm/grammar/dpm_xlParser.g4 +0 -263
- py_dpm/semantics/DAG/DAGAnalyzer.py +0 -158
- py_dpm/semantics/DAG/__init__.py +0 -0
- py_dpm/semantics/__init__.py +0 -0
- py_dpm/views/data_types.sql +0 -12
- py_dpm/views/datapoints.sql +0 -65
- py_dpm/views/hierarchy_operand_reference.sql +0 -11
- py_dpm/views/hierarchy_preconditions.sql +0 -13
- py_dpm/views/hierarchy_variables.sql +0 -26
- py_dpm/views/hierarchy_variables_context.sql +0 -14
- py_dpm/views/key_components.sql +0 -18
- py_dpm/views/module_from_table.sql +0 -11
- py_dpm/views/open_keys.sql +0 -13
- py_dpm/views/operation_info.sql +0 -27
- py_dpm/views/operation_list.sql +0 -18
- py_dpm/views/operations_versions_from_module_version.sql +0 -30
- py_dpm/views/precondition_info.sql +0 -17
- py_dpm/views/report_type_operand_reference_info.sql +0 -18
- py_dpm/views/subcategory_info.sql +0 -17
- py_dpm/views/table_info.sql +0 -19
- pydpm_xl-0.1.39rc32.dist-info/METADATA +0 -53
- pydpm_xl-0.1.39rc32.dist-info/RECORD +0 -96
- pydpm_xl-0.1.39rc32.dist-info/entry_points.txt +0 -2
- /py_dpm/{AST → cli/commands}/__init__.py +0 -0
- /py_dpm/{migration.py → dpm/migration.py} +0 -0
- /py_dpm/{AST/ASTVisitor.py → dpm_xl/ast/visitor.py} +0 -0
- /py_dpm/{DataTypes → dpm_xl/grammar/generated}/__init__.py +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlLexer.interp +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlLexer.py +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlLexer.tokens +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlParser.interp +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlParser.py +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlParser.tokens +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlParserListener.py +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/dpm_xlParserVisitor.py +0 -0
- /py_dpm/{grammar/dist → dpm_xl/grammar/generated}/listeners.py +0 -0
- /py_dpm/{DataTypes/TimeClasses.py → dpm_xl/types/time.py} +0 -0
- /py_dpm/{Utils → dpm_xl/utils}/tokens.py +0 -0
- /py_dpm/{Exceptions → exceptions}/messages.py +0 -0
- {pydpm_xl-0.1.39rc32.dist-info → pydpm_xl-0.2.0.dist-info}/WHEEL +0 -0
- {pydpm_xl-0.1.39rc32.dist-info → pydpm_xl-0.2.0.dist-info}/licenses/LICENSE +0 -0
- {pydpm_xl-0.1.39rc32.dist-info → pydpm_xl-0.2.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,838 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from sqlalchemy import func, literal, and_, or_, join
|
|
4
|
+
from sqlalchemy.orm import aliased
|
|
5
|
+
|
|
6
|
+
from py_dpm.dpm.models import (
|
|
7
|
+
Framework,
|
|
8
|
+
Module,
|
|
9
|
+
ModuleVersionComposition,
|
|
10
|
+
Table,
|
|
11
|
+
ModuleVersion,
|
|
12
|
+
TableVersion,
|
|
13
|
+
Header,
|
|
14
|
+
HeaderVersion,
|
|
15
|
+
TableVersionHeader,
|
|
16
|
+
Cell,
|
|
17
|
+
TableVersionCell,
|
|
18
|
+
VariableVersion,
|
|
19
|
+
Property,
|
|
20
|
+
DataType,
|
|
21
|
+
Item,
|
|
22
|
+
ItemCategory,
|
|
23
|
+
ContextComposition,
|
|
24
|
+
SubCategoryVersion,
|
|
25
|
+
SubCategoryItem,
|
|
26
|
+
)
|
|
27
|
+
from py_dpm.dpm.queries.filters import (
|
|
28
|
+
filter_by_release,
|
|
29
|
+
filter_by_date,
|
|
30
|
+
filter_active_only,
|
|
31
|
+
filter_item_version,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class HierarchicalQuery:
|
|
36
|
+
"""
|
|
37
|
+
Queries that return hierarchical dictionaries for collections
|
|
38
|
+
and similar objects
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
@staticmethod
|
|
42
|
+
def get_module_version(
|
|
43
|
+
session,
|
|
44
|
+
module_code: str,
|
|
45
|
+
release_id: Optional[int] = None,
|
|
46
|
+
date: Optional[str] = None,
|
|
47
|
+
release_code: Optional[str] = None,
|
|
48
|
+
) -> dict:
|
|
49
|
+
|
|
50
|
+
if sum(bool(x) for x in [release_id, date, release_code]) > 1:
|
|
51
|
+
raise ValueError(
|
|
52
|
+
"Specify a maximum of one of release_id, release_code or date."
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
q = session.query(ModuleVersion).filter(ModuleVersion.code == module_code)
|
|
56
|
+
|
|
57
|
+
if date:
|
|
58
|
+
q = filter_by_date(
|
|
59
|
+
q,
|
|
60
|
+
date,
|
|
61
|
+
ModuleVersion.fromreferencedate,
|
|
62
|
+
ModuleVersion.toreferencedate,
|
|
63
|
+
)
|
|
64
|
+
elif release_id:
|
|
65
|
+
q = filter_by_release(
|
|
66
|
+
q,
|
|
67
|
+
start_col=ModuleVersion.startreleaseid,
|
|
68
|
+
end_col=ModuleVersion.endreleaseid,
|
|
69
|
+
release_id=release_id,
|
|
70
|
+
)
|
|
71
|
+
elif release_code:
|
|
72
|
+
q = filter_by_release(
|
|
73
|
+
q,
|
|
74
|
+
start_col=ModuleVersion.startreleaseid,
|
|
75
|
+
end_col=ModuleVersion.endreleaseid,
|
|
76
|
+
release_code=release_code,
|
|
77
|
+
)
|
|
78
|
+
else:
|
|
79
|
+
q = filter_active_only(q, end_col=ModuleVersion.endreleaseid)
|
|
80
|
+
|
|
81
|
+
query_result = q.all()
|
|
82
|
+
|
|
83
|
+
if len(query_result) != 1:
|
|
84
|
+
raise ValueError(
|
|
85
|
+
f"Should return 1 record, but returned {len(query_result)}"
|
|
86
|
+
)
|
|
87
|
+
result = query_result[0].to_dict()
|
|
88
|
+
|
|
89
|
+
table_versions = query_result[0].table_versions
|
|
90
|
+
result["table_versions"] = [tv.to_dict() for tv in table_versions]
|
|
91
|
+
|
|
92
|
+
return result
|
|
93
|
+
|
|
94
|
+
@staticmethod
|
|
95
|
+
def get_all_frameworks(
|
|
96
|
+
session,
|
|
97
|
+
release_id: Optional[int] = None,
|
|
98
|
+
date: Optional[str] = None,
|
|
99
|
+
release_code: Optional[str] = None,
|
|
100
|
+
) -> list[dict]:
|
|
101
|
+
|
|
102
|
+
if sum(bool(x) for x in [release_id, date, release_code]) > 1:
|
|
103
|
+
raise ValueError(
|
|
104
|
+
"Specify a maximum of one of release_id, release_code or date."
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
q = (
|
|
108
|
+
session.query(
|
|
109
|
+
# Framework
|
|
110
|
+
Framework.frameworkid,
|
|
111
|
+
Framework.code.label("framework_code"),
|
|
112
|
+
Framework.name.label("framework_name"),
|
|
113
|
+
Framework.description.label("framework_description"),
|
|
114
|
+
# ModuleVersion
|
|
115
|
+
ModuleVersion.modulevid,
|
|
116
|
+
ModuleVersion.moduleid,
|
|
117
|
+
ModuleVersion.startreleaseid.label("module_version_startreleaseid"),
|
|
118
|
+
ModuleVersion.endreleaseid.label("module_version_endreleaseid"),
|
|
119
|
+
ModuleVersion.code.label("module_version_code"),
|
|
120
|
+
ModuleVersion.name.label("module_version_name"),
|
|
121
|
+
ModuleVersion.description.label("module_version_description"),
|
|
122
|
+
ModuleVersion.versionnumber,
|
|
123
|
+
ModuleVersion.fromreferencedate,
|
|
124
|
+
ModuleVersion.toreferencedate,
|
|
125
|
+
# TableVersion
|
|
126
|
+
TableVersion.tablevid,
|
|
127
|
+
TableVersion.code.label("table_version_code"),
|
|
128
|
+
TableVersion.name.label("table_version_name"),
|
|
129
|
+
TableVersion.description.label("table_version_description"),
|
|
130
|
+
TableVersion.tableid.label("table_version_tableid"),
|
|
131
|
+
TableVersion.abstracttableid,
|
|
132
|
+
TableVersion.startreleaseid.label("table_version_startreleaseid"),
|
|
133
|
+
TableVersion.endreleaseid.label("table_version_endreleaseid"),
|
|
134
|
+
# Table
|
|
135
|
+
Table.tableid.label("table_tableid"),
|
|
136
|
+
Table.isabstract,
|
|
137
|
+
Table.hasopencolumns,
|
|
138
|
+
Table.hasopenrows,
|
|
139
|
+
Table.hasopensheets,
|
|
140
|
+
Table.isnormalised,
|
|
141
|
+
Table.isflat,
|
|
142
|
+
)
|
|
143
|
+
.join(Module, Framework.modules)
|
|
144
|
+
.join(ModuleVersion, Module.module_versions)
|
|
145
|
+
.join(
|
|
146
|
+
ModuleVersionComposition,
|
|
147
|
+
ModuleVersion.module_version_compositions,
|
|
148
|
+
)
|
|
149
|
+
.join(TableVersion, ModuleVersionComposition.table_version)
|
|
150
|
+
.join(Table, TableVersion.table)
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
if date:
|
|
154
|
+
q = filter_by_date(
|
|
155
|
+
q,
|
|
156
|
+
date,
|
|
157
|
+
ModuleVersion.fromreferencedate,
|
|
158
|
+
ModuleVersion.toreferencedate,
|
|
159
|
+
)
|
|
160
|
+
elif release_id:
|
|
161
|
+
q = filter_by_release(
|
|
162
|
+
q,
|
|
163
|
+
start_col=ModuleVersion.startreleaseid,
|
|
164
|
+
end_col=ModuleVersion.endreleaseid,
|
|
165
|
+
release_id=release_id,
|
|
166
|
+
)
|
|
167
|
+
elif release_code:
|
|
168
|
+
q = filter_by_release(
|
|
169
|
+
q,
|
|
170
|
+
start_col=ModuleVersion.startreleaseid,
|
|
171
|
+
end_col=ModuleVersion.endreleaseid,
|
|
172
|
+
release_code=release_code,
|
|
173
|
+
)
|
|
174
|
+
else:
|
|
175
|
+
q = filter_active_only(q, end_col=ModuleVersion.endreleaseid)
|
|
176
|
+
|
|
177
|
+
# Execute query and return list of dictionaries
|
|
178
|
+
query_result = [dict(row._mapping) for row in q.all()]
|
|
179
|
+
|
|
180
|
+
frameworks = {}
|
|
181
|
+
|
|
182
|
+
for row in query_result:
|
|
183
|
+
fw_id = row["frameworkid"]
|
|
184
|
+
if fw_id not in frameworks:
|
|
185
|
+
frameworks[fw_id] = {
|
|
186
|
+
"frameworkid": row["frameworkid"],
|
|
187
|
+
"code": row["framework_code"],
|
|
188
|
+
"name": row["framework_name"],
|
|
189
|
+
"description": row["framework_description"],
|
|
190
|
+
"module_versions": {},
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
fw = frameworks[fw_id]
|
|
194
|
+
|
|
195
|
+
mod_vid = row["modulevid"]
|
|
196
|
+
if mod_vid not in fw["module_versions"]:
|
|
197
|
+
fw["module_versions"][mod_vid] = {
|
|
198
|
+
"modulevid": row["modulevid"],
|
|
199
|
+
"moduleid": row["moduleid"],
|
|
200
|
+
"startreleaseid": row["module_version_startreleaseid"],
|
|
201
|
+
"endreleaseid": row["module_version_endreleaseid"],
|
|
202
|
+
"code": row["module_version_code"],
|
|
203
|
+
"name": row["module_version_name"],
|
|
204
|
+
"description": row["module_version_description"],
|
|
205
|
+
"versionnumber": row["versionnumber"],
|
|
206
|
+
"fromreferencedate": row["fromreferencedate"],
|
|
207
|
+
"toreferencedate": row["toreferencedate"],
|
|
208
|
+
"table_versions": [],
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
mod = fw["module_versions"][mod_vid]
|
|
212
|
+
|
|
213
|
+
# Flatten TableVersion and Table info
|
|
214
|
+
table_ver = {
|
|
215
|
+
"tablevid": row["tablevid"],
|
|
216
|
+
"code": row["table_version_code"],
|
|
217
|
+
"name": row["table_version_name"],
|
|
218
|
+
"description": row["table_version_description"],
|
|
219
|
+
"tableid": row["table_version_tableid"],
|
|
220
|
+
"abstracttableid": row["abstracttableid"],
|
|
221
|
+
"startreleaseid": row["table_version_startreleaseid"],
|
|
222
|
+
"endreleaseid": row["table_version_endreleaseid"],
|
|
223
|
+
"isabstract": row["isabstract"],
|
|
224
|
+
"hasopencolumns": row["hasopencolumns"],
|
|
225
|
+
"hasopenrows": row["hasopenrows"],
|
|
226
|
+
"hasopensheets": row["hasopensheets"],
|
|
227
|
+
"isnormalised": row["isnormalised"],
|
|
228
|
+
"isflat": row["isflat"],
|
|
229
|
+
}
|
|
230
|
+
mod["table_versions"].append(table_ver)
|
|
231
|
+
|
|
232
|
+
# Convert dicts back to lists
|
|
233
|
+
final_result = []
|
|
234
|
+
for fw in frameworks.values():
|
|
235
|
+
fw["module_versions"] = list(fw["module_versions"].values())
|
|
236
|
+
final_result.append(fw)
|
|
237
|
+
|
|
238
|
+
return final_result
|
|
239
|
+
|
|
240
|
+
@staticmethod
|
|
241
|
+
def get_table_details(
|
|
242
|
+
session,
|
|
243
|
+
table_code: str,
|
|
244
|
+
release_id: Optional[int] = None,
|
|
245
|
+
date: Optional[str] = None,
|
|
246
|
+
release_code: Optional[str] = None,
|
|
247
|
+
) -> dict:
|
|
248
|
+
# Input Validation: Mutually exclusive release params
|
|
249
|
+
if sum(bool(x) for x in [release_id, release_code, date]) > 1:
|
|
250
|
+
raise ValueError(
|
|
251
|
+
"Specify a maximum of one of release_id, release_code or date."
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
# Determine the relevant table version using the same filter helpers
|
|
255
|
+
# as other hierarchical queries.
|
|
256
|
+
q_tv = (
|
|
257
|
+
session.query(TableVersion)
|
|
258
|
+
.join(
|
|
259
|
+
ModuleVersionComposition,
|
|
260
|
+
ModuleVersionComposition.tablevid == TableVersion.tablevid,
|
|
261
|
+
)
|
|
262
|
+
.join(
|
|
263
|
+
ModuleVersion,
|
|
264
|
+
ModuleVersion.modulevid == ModuleVersionComposition.modulevid,
|
|
265
|
+
)
|
|
266
|
+
.filter(TableVersion.code == table_code)
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
if date:
|
|
270
|
+
q_tv = filter_by_date(
|
|
271
|
+
q_tv,
|
|
272
|
+
date,
|
|
273
|
+
ModuleVersion.fromreferencedate,
|
|
274
|
+
ModuleVersion.toreferencedate,
|
|
275
|
+
)
|
|
276
|
+
elif release_id or release_code:
|
|
277
|
+
q_tv = filter_by_release(
|
|
278
|
+
q_tv,
|
|
279
|
+
start_col=ModuleVersion.startreleaseid,
|
|
280
|
+
end_col=ModuleVersion.endreleaseid,
|
|
281
|
+
release_id=release_id,
|
|
282
|
+
release_code=release_code,
|
|
283
|
+
)
|
|
284
|
+
else:
|
|
285
|
+
q_tv = filter_active_only(q_tv, end_col=ModuleVersion.endreleaseid)
|
|
286
|
+
|
|
287
|
+
table_version = q_tv.order_by(
|
|
288
|
+
ModuleVersion.startreleaseid.desc()
|
|
289
|
+
).first()
|
|
290
|
+
|
|
291
|
+
# If no table version matches the filters, the table does not exist
|
|
292
|
+
# (for the requested context).
|
|
293
|
+
if not table_version:
|
|
294
|
+
raise ValueError(f"Table {table_code} was not found.")
|
|
295
|
+
|
|
296
|
+
# If the underlying table is not abstract, return details for this
|
|
297
|
+
# single table version as before.
|
|
298
|
+
table_obj = table_version.table
|
|
299
|
+
if not table_obj or not table_obj.isabstract:
|
|
300
|
+
header_results, cell_results = HierarchicalQuery._fetch_header_and_cells(
|
|
301
|
+
session, table_version.tablevid
|
|
302
|
+
)
|
|
303
|
+
if not header_results:
|
|
304
|
+
return {}
|
|
305
|
+
return HierarchicalQuery._transform_to_dpm_format(
|
|
306
|
+
header_results, cell_results
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
# If the table is abstract, consolidate details for all table versions
|
|
310
|
+
# that reference this table as their abstract table, applying the same
|
|
311
|
+
# release/date filters.
|
|
312
|
+
q_child = (
|
|
313
|
+
session.query(TableVersion)
|
|
314
|
+
.join(
|
|
315
|
+
ModuleVersionComposition,
|
|
316
|
+
ModuleVersionComposition.tablevid == TableVersion.tablevid,
|
|
317
|
+
)
|
|
318
|
+
.join(
|
|
319
|
+
ModuleVersion,
|
|
320
|
+
ModuleVersion.modulevid == ModuleVersionComposition.modulevid,
|
|
321
|
+
)
|
|
322
|
+
.filter(TableVersion.abstracttableid == table_obj.tableid)
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
if date:
|
|
326
|
+
q_child = filter_by_date(
|
|
327
|
+
q_child,
|
|
328
|
+
date,
|
|
329
|
+
ModuleVersion.fromreferencedate,
|
|
330
|
+
ModuleVersion.toreferencedate,
|
|
331
|
+
)
|
|
332
|
+
elif release_id or release_code:
|
|
333
|
+
q_child = filter_by_release(
|
|
334
|
+
q_child,
|
|
335
|
+
start_col=ModuleVersion.startreleaseid,
|
|
336
|
+
end_col=ModuleVersion.endreleaseid,
|
|
337
|
+
release_id=release_id,
|
|
338
|
+
release_code=release_code,
|
|
339
|
+
)
|
|
340
|
+
else:
|
|
341
|
+
q_child = filter_active_only(q_child, end_col=ModuleVersion.endreleaseid)
|
|
342
|
+
|
|
343
|
+
child_versions = q_child.all()
|
|
344
|
+
|
|
345
|
+
# If there are no child versions, fall back to the abstract table
|
|
346
|
+
# version itself.
|
|
347
|
+
if not child_versions:
|
|
348
|
+
header_results, cell_results = HierarchicalQuery._fetch_header_and_cells(
|
|
349
|
+
session, table_version.tablevid
|
|
350
|
+
)
|
|
351
|
+
if not header_results:
|
|
352
|
+
return {}
|
|
353
|
+
result = HierarchicalQuery._transform_to_dpm_format(
|
|
354
|
+
header_results, cell_results
|
|
355
|
+
)
|
|
356
|
+
result["tableCode"] = table_version.code
|
|
357
|
+
result["tableTitle"] = table_version.name
|
|
358
|
+
result["tableVid"] = table_version.tablevid
|
|
359
|
+
return result
|
|
360
|
+
|
|
361
|
+
# Collect headers and cells from all matching child table versions.
|
|
362
|
+
all_headers = []
|
|
363
|
+
all_cells = []
|
|
364
|
+
for child_tv in child_versions:
|
|
365
|
+
child_headers, child_cells = HierarchicalQuery._fetch_header_and_cells(
|
|
366
|
+
session, child_tv.tablevid
|
|
367
|
+
)
|
|
368
|
+
all_headers.extend(child_headers)
|
|
369
|
+
all_cells.extend(child_cells)
|
|
370
|
+
|
|
371
|
+
if not all_headers:
|
|
372
|
+
return {}
|
|
373
|
+
|
|
374
|
+
result = HierarchicalQuery._transform_to_dpm_format(all_headers, all_cells)
|
|
375
|
+
|
|
376
|
+
# Represent the consolidated view as belonging to the originally
|
|
377
|
+
# requested (abstract) table version.
|
|
378
|
+
result["tableCode"] = table_version.code
|
|
379
|
+
result["tableTitle"] = table_version.name
|
|
380
|
+
result["tableVid"] = table_version.tablevid
|
|
381
|
+
return result
|
|
382
|
+
|
|
383
|
+
@staticmethod
|
|
384
|
+
def get_table_modelling(
|
|
385
|
+
session,
|
|
386
|
+
table_code: str,
|
|
387
|
+
release_id: Optional[int] = None,
|
|
388
|
+
date: Optional[str] = None,
|
|
389
|
+
release_code: Optional[str] = None,
|
|
390
|
+
) -> dict:
|
|
391
|
+
"""
|
|
392
|
+
Return modelling metadata for a table, based on the context
|
|
393
|
+
composition associated with each header.
|
|
394
|
+
|
|
395
|
+
The selection logic for the relevant table version mirrors
|
|
396
|
+
``get_table_details``: table code plus optional release/date filters.
|
|
397
|
+
"""
|
|
398
|
+
# Input Validation: Mutually exclusive release params
|
|
399
|
+
if sum(bool(x) for x in [release_id, release_code, date]) > 1:
|
|
400
|
+
raise ValueError(
|
|
401
|
+
"Specify a maximum of one of release_id, release_code or date."
|
|
402
|
+
)
|
|
403
|
+
|
|
404
|
+
# Resolve the relevant table version using the same pattern as
|
|
405
|
+
# get_table_details.
|
|
406
|
+
q_tv = (
|
|
407
|
+
session.query(TableVersion)
|
|
408
|
+
.join(
|
|
409
|
+
ModuleVersionComposition,
|
|
410
|
+
ModuleVersionComposition.tablevid == TableVersion.tablevid,
|
|
411
|
+
)
|
|
412
|
+
.join(
|
|
413
|
+
ModuleVersion,
|
|
414
|
+
ModuleVersion.modulevid == ModuleVersionComposition.modulevid,
|
|
415
|
+
)
|
|
416
|
+
.filter(TableVersion.code == table_code)
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
if date:
|
|
420
|
+
q_tv = filter_by_date(
|
|
421
|
+
q_tv,
|
|
422
|
+
date,
|
|
423
|
+
ModuleVersion.fromreferencedate,
|
|
424
|
+
ModuleVersion.toreferencedate,
|
|
425
|
+
)
|
|
426
|
+
elif release_id or release_code:
|
|
427
|
+
q_tv = filter_by_release(
|
|
428
|
+
q_tv,
|
|
429
|
+
start_col=ModuleVersion.startreleaseid,
|
|
430
|
+
end_col=ModuleVersion.endreleaseid,
|
|
431
|
+
release_id=release_id,
|
|
432
|
+
release_code=release_code,
|
|
433
|
+
)
|
|
434
|
+
else:
|
|
435
|
+
q_tv = filter_active_only(q_tv, end_col=ModuleVersion.endreleaseid)
|
|
436
|
+
|
|
437
|
+
table_version = q_tv.order_by(
|
|
438
|
+
ModuleVersion.startreleaseid.desc()
|
|
439
|
+
).first()
|
|
440
|
+
|
|
441
|
+
if not table_version:
|
|
442
|
+
raise ValueError(f"Table {table_code} was not found.")
|
|
443
|
+
|
|
444
|
+
# Aliases for Item and ItemCategory used multiple times in the query
|
|
445
|
+
iccp = aliased(ItemCategory) # context property category
|
|
446
|
+
icci = aliased(ItemCategory) # context item category
|
|
447
|
+
icmp = aliased(ItemCategory) # main property category
|
|
448
|
+
icp = aliased(Item) # context property item
|
|
449
|
+
ici = aliased(Item) # context item
|
|
450
|
+
mpi = aliased(Item) # main property item
|
|
451
|
+
|
|
452
|
+
# Pre-build joined table expressions so that the SQL more closely
|
|
453
|
+
# matches:
|
|
454
|
+
# LEFT JOIN (ItemCategory_X JOIN Item_Y ON ...) ON ...
|
|
455
|
+
context_property_join = join(iccp, icp, iccp.itemid == icp.itemid)
|
|
456
|
+
context_item_join = join(icci, ici, icci.itemid == ici.itemid)
|
|
457
|
+
main_property_join = join(icmp, mpi, icmp.itemid == mpi.itemid)
|
|
458
|
+
|
|
459
|
+
# ORM translation of the desired SQL query with left joins so that
|
|
460
|
+
# headers without a context (or without a main property) are still
|
|
461
|
+
# returned.
|
|
462
|
+
q = (
|
|
463
|
+
session.query(
|
|
464
|
+
HeaderVersion.headerid.label("header_id"),
|
|
465
|
+
icmp.signature.label("main_property_code"),
|
|
466
|
+
mpi.name.label("main_property_name"),
|
|
467
|
+
iccp.signature.label("context_property_code"),
|
|
468
|
+
icp.name.label("context_property_name"),
|
|
469
|
+
icci.signature.label("context_item_code"),
|
|
470
|
+
ici.name.label("context_item_name"),
|
|
471
|
+
)
|
|
472
|
+
.select_from(TableVersion)
|
|
473
|
+
.join(
|
|
474
|
+
TableVersionHeader,
|
|
475
|
+
TableVersionHeader.tablevid == TableVersion.tablevid,
|
|
476
|
+
)
|
|
477
|
+
.join(
|
|
478
|
+
HeaderVersion,
|
|
479
|
+
TableVersionHeader.headervid == HeaderVersion.headervid,
|
|
480
|
+
)
|
|
481
|
+
# Context is optional, so use LEFT JOIN
|
|
482
|
+
.outerjoin(
|
|
483
|
+
ContextComposition,
|
|
484
|
+
HeaderVersion.contextid == ContextComposition.contextid,
|
|
485
|
+
)
|
|
486
|
+
# Context property (optional, versioned)
|
|
487
|
+
.outerjoin(
|
|
488
|
+
context_property_join,
|
|
489
|
+
and_(
|
|
490
|
+
ContextComposition.propertyid == iccp.itemid,
|
|
491
|
+
filter_item_version(
|
|
492
|
+
TableVersion.startreleaseid,
|
|
493
|
+
iccp.startreleaseid,
|
|
494
|
+
iccp.endreleaseid,
|
|
495
|
+
),
|
|
496
|
+
),
|
|
497
|
+
)
|
|
498
|
+
# Context item (optional, versioned)
|
|
499
|
+
.outerjoin(
|
|
500
|
+
context_item_join,
|
|
501
|
+
and_(
|
|
502
|
+
ContextComposition.itemid == icci.itemid,
|
|
503
|
+
filter_item_version(
|
|
504
|
+
TableVersion.startreleaseid,
|
|
505
|
+
icci.startreleaseid,
|
|
506
|
+
icci.endreleaseid,
|
|
507
|
+
),
|
|
508
|
+
),
|
|
509
|
+
)
|
|
510
|
+
# Main property (optional, versioned)
|
|
511
|
+
.outerjoin(
|
|
512
|
+
main_property_join,
|
|
513
|
+
and_(
|
|
514
|
+
HeaderVersion.propertyid == icmp.itemid,
|
|
515
|
+
filter_item_version(
|
|
516
|
+
TableVersion.startreleaseid,
|
|
517
|
+
icmp.startreleaseid,
|
|
518
|
+
icmp.endreleaseid,
|
|
519
|
+
),
|
|
520
|
+
),
|
|
521
|
+
)
|
|
522
|
+
.filter(TableVersion.tablevid == table_version.tablevid)
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
modelling: dict[int, list[dict]] = {}
|
|
526
|
+
for row in q.all():
|
|
527
|
+
header_id = row.header_id
|
|
528
|
+
if header_id not in modelling:
|
|
529
|
+
modelling[header_id] = []
|
|
530
|
+
|
|
531
|
+
# Main property pair (if present)
|
|
532
|
+
if row.main_property_code is not None or row.main_property_name is not None:
|
|
533
|
+
modelling[header_id].append(
|
|
534
|
+
{
|
|
535
|
+
"main_property_code": row.main_property_code,
|
|
536
|
+
"main_property_name": row.main_property_name,
|
|
537
|
+
}
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
# Context pair: property and item metadata in a single object
|
|
541
|
+
if (
|
|
542
|
+
row.context_property_code is not None
|
|
543
|
+
or row.context_property_name is not None
|
|
544
|
+
or row.context_item_code is not None
|
|
545
|
+
or row.context_item_name is not None
|
|
546
|
+
):
|
|
547
|
+
modelling[header_id].append(
|
|
548
|
+
{
|
|
549
|
+
"context_property_code": row.context_property_code,
|
|
550
|
+
"context_property_name": row.context_property_name,
|
|
551
|
+
"context_item_code": row.context_item_code,
|
|
552
|
+
"context_item_name": row.context_item_name,
|
|
553
|
+
}
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
return modelling
|
|
557
|
+
|
|
558
|
+
@staticmethod
|
|
559
|
+
def _fetch_header_and_cells(session, table_vid):
|
|
560
|
+
# Get the table version and module version info for release filtering
|
|
561
|
+
tv_info = (
|
|
562
|
+
session.query(
|
|
563
|
+
TableVersion.tablevid,
|
|
564
|
+
TableVersion.startreleaseid,
|
|
565
|
+
ModuleVersion.startreleaseid.label("mv_startreleaseid"),
|
|
566
|
+
)
|
|
567
|
+
.join(
|
|
568
|
+
ModuleVersionComposition,
|
|
569
|
+
ModuleVersionComposition.tablevid == TableVersion.tablevid,
|
|
570
|
+
)
|
|
571
|
+
.join(
|
|
572
|
+
ModuleVersion,
|
|
573
|
+
ModuleVersion.modulevid == ModuleVersionComposition.modulevid,
|
|
574
|
+
)
|
|
575
|
+
.filter(TableVersion.tablevid == table_vid)
|
|
576
|
+
.first()
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
if not tv_info:
|
|
580
|
+
return [], []
|
|
581
|
+
|
|
582
|
+
release_id = tv_info.mv_startreleaseid
|
|
583
|
+
|
|
584
|
+
# Aliases for the multiple ItemCategory and Item joins
|
|
585
|
+
ic_prop = aliased(ItemCategory) # For property code
|
|
586
|
+
ic_enum = aliased(ItemCategory) # For enumeration items
|
|
587
|
+
item_prop = aliased(Item) # For property name
|
|
588
|
+
item_enum = aliased(Item) # For enumeration item names
|
|
589
|
+
|
|
590
|
+
# Headers query with property codes and enumeration items
|
|
591
|
+
header_query = (
|
|
592
|
+
session.query(
|
|
593
|
+
TableVersion.tablevid.label("table_vid"),
|
|
594
|
+
TableVersion.code.label("table_code"),
|
|
595
|
+
TableVersion.name.label("table_name"),
|
|
596
|
+
TableVersionHeader.headerid.label("header_id"),
|
|
597
|
+
TableVersionHeader.parentheaderid.label("parent_header_id"),
|
|
598
|
+
TableVersionHeader.parentfirst.label("parent_first"),
|
|
599
|
+
TableVersionHeader.order.label("order"),
|
|
600
|
+
TableVersionHeader.isabstract.label("is_abstract"),
|
|
601
|
+
HeaderVersion.code.label("header_code"),
|
|
602
|
+
HeaderVersion.label.label("label"),
|
|
603
|
+
Header.direction.label("direction"),
|
|
604
|
+
Header.iskey.label("is_key"),
|
|
605
|
+
ic_prop.code.label("property_code"),
|
|
606
|
+
item_prop.name.label("property_name"),
|
|
607
|
+
DataType.name.label("data_type_name"),
|
|
608
|
+
ic_enum.signature.label("item_signature"),
|
|
609
|
+
item_enum.name.label("item_label"),
|
|
610
|
+
)
|
|
611
|
+
.join(
|
|
612
|
+
TableVersionHeader,
|
|
613
|
+
TableVersionHeader.tablevid == TableVersion.tablevid,
|
|
614
|
+
)
|
|
615
|
+
.join(
|
|
616
|
+
HeaderVersion,
|
|
617
|
+
TableVersionHeader.headervid == HeaderVersion.headervid,
|
|
618
|
+
)
|
|
619
|
+
.join(Header, HeaderVersion.headerid == Header.headerid)
|
|
620
|
+
.outerjoin(
|
|
621
|
+
ic_prop,
|
|
622
|
+
and_(
|
|
623
|
+
HeaderVersion.propertyid == ic_prop.itemid,
|
|
624
|
+
filter_item_version(
|
|
625
|
+
release_id,
|
|
626
|
+
ic_prop.startreleaseid,
|
|
627
|
+
ic_prop.endreleaseid,
|
|
628
|
+
),
|
|
629
|
+
),
|
|
630
|
+
)
|
|
631
|
+
# Property and its Item (for name) do not require an ItemCategory row
|
|
632
|
+
.outerjoin(Property, HeaderVersion.propertyid == Property.propertyid)
|
|
633
|
+
.outerjoin(item_prop, Property.propertyid == item_prop.itemid)
|
|
634
|
+
.outerjoin(DataType, Property.datatypeid == DataType.datatypeid)
|
|
635
|
+
.outerjoin(
|
|
636
|
+
SubCategoryVersion,
|
|
637
|
+
HeaderVersion.subcategoryvid == SubCategoryVersion.subcategoryvid,
|
|
638
|
+
)
|
|
639
|
+
.outerjoin(
|
|
640
|
+
SubCategoryItem,
|
|
641
|
+
SubCategoryVersion.subcategoryvid
|
|
642
|
+
== SubCategoryItem.subcategoryvid,
|
|
643
|
+
)
|
|
644
|
+
.outerjoin(
|
|
645
|
+
ic_enum,
|
|
646
|
+
and_(
|
|
647
|
+
SubCategoryItem.itemid == ic_enum.itemid,
|
|
648
|
+
filter_item_version(
|
|
649
|
+
release_id,
|
|
650
|
+
ic_enum.startreleaseid,
|
|
651
|
+
ic_enum.endreleaseid,
|
|
652
|
+
),
|
|
653
|
+
),
|
|
654
|
+
)
|
|
655
|
+
.outerjoin(item_enum, ic_enum.itemid == item_enum.itemid)
|
|
656
|
+
.filter(TableVersion.tablevid == table_vid)
|
|
657
|
+
.order_by(TableVersionHeader.order)
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
header_results = header_query.all()
|
|
661
|
+
|
|
662
|
+
if not header_results:
|
|
663
|
+
return [], []
|
|
664
|
+
|
|
665
|
+
# Cells query: ORM-based, returning cell-level metadata for the
|
|
666
|
+
# selected table version.
|
|
667
|
+
hv_col = aliased(HeaderVersion)
|
|
668
|
+
hv_row = aliased(HeaderVersion)
|
|
669
|
+
hv_sheet = aliased(HeaderVersion)
|
|
670
|
+
|
|
671
|
+
# Aliases for ItemCategory and Property/DataType for each axis
|
|
672
|
+
ic_col = aliased(ItemCategory)
|
|
673
|
+
ic_row = aliased(ItemCategory)
|
|
674
|
+
ic_sheet = aliased(ItemCategory)
|
|
675
|
+
prop_col = aliased(Property)
|
|
676
|
+
prop_row = aliased(Property)
|
|
677
|
+
prop_sheet = aliased(Property)
|
|
678
|
+
dt_col = aliased(DataType)
|
|
679
|
+
dt_row = aliased(DataType)
|
|
680
|
+
dt_sheet = aliased(DataType)
|
|
681
|
+
|
|
682
|
+
cell_query = (
|
|
683
|
+
session.query(
|
|
684
|
+
hv_col.code.label("column_code"),
|
|
685
|
+
hv_row.code.label("row_code"),
|
|
686
|
+
hv_sheet.code.label("sheet_code"),
|
|
687
|
+
VariableVersion.variableid.label("variable_id"),
|
|
688
|
+
VariableVersion.variablevid.label("variable_vid"),
|
|
689
|
+
TableVersionCell.isnullable.label("cell_is_nullable"),
|
|
690
|
+
TableVersionCell.isexcluded.label("cell_is_excluded"),
|
|
691
|
+
TableVersionCell.isvoid.label("cell_is_void"),
|
|
692
|
+
TableVersionCell.sign.label("cell_sign"),
|
|
693
|
+
func.coalesce(
|
|
694
|
+
ic_col.code, ic_row.code, ic_sheet.code
|
|
695
|
+
).label("property_code"),
|
|
696
|
+
func.coalesce(
|
|
697
|
+
dt_col.name, dt_row.name, dt_sheet.name
|
|
698
|
+
).label("data_type_name"),
|
|
699
|
+
)
|
|
700
|
+
.select_from(TableVersionCell)
|
|
701
|
+
.join(
|
|
702
|
+
TableVersion,
|
|
703
|
+
TableVersion.tablevid == TableVersionCell.tablevid,
|
|
704
|
+
)
|
|
705
|
+
.join(Cell, TableVersionCell.cellid == Cell.cellid)
|
|
706
|
+
.outerjoin(hv_col, Cell.columnid == hv_col.headerid)
|
|
707
|
+
.outerjoin(hv_row, Cell.rowid == hv_row.headerid)
|
|
708
|
+
.outerjoin(hv_sheet, Cell.sheetid == hv_sheet.headerid)
|
|
709
|
+
.join(
|
|
710
|
+
VariableVersion,
|
|
711
|
+
VariableVersion.variablevid == TableVersionCell.variablevid,
|
|
712
|
+
)
|
|
713
|
+
# Column axis ItemCategory, Property, DataType
|
|
714
|
+
.outerjoin(
|
|
715
|
+
ic_col,
|
|
716
|
+
and_(
|
|
717
|
+
hv_col.propertyid == ic_col.itemid,
|
|
718
|
+
filter_item_version(
|
|
719
|
+
release_id,
|
|
720
|
+
ic_col.startreleaseid,
|
|
721
|
+
ic_col.endreleaseid,
|
|
722
|
+
),
|
|
723
|
+
ic_col.isdefaultitem != 0,
|
|
724
|
+
),
|
|
725
|
+
)
|
|
726
|
+
.outerjoin(prop_col, hv_col.propertyid == prop_col.propertyid)
|
|
727
|
+
.outerjoin(dt_col, prop_col.datatypeid == dt_col.datatypeid)
|
|
728
|
+
# Row axis ItemCategory, Property, DataType
|
|
729
|
+
.outerjoin(
|
|
730
|
+
ic_row,
|
|
731
|
+
and_(
|
|
732
|
+
hv_row.propertyid == ic_row.itemid,
|
|
733
|
+
filter_item_version(
|
|
734
|
+
release_id,
|
|
735
|
+
ic_row.startreleaseid,
|
|
736
|
+
ic_row.endreleaseid,
|
|
737
|
+
),
|
|
738
|
+
ic_row.isdefaultitem != 0,
|
|
739
|
+
),
|
|
740
|
+
)
|
|
741
|
+
.outerjoin(prop_row, hv_row.propertyid == prop_row.propertyid)
|
|
742
|
+
.outerjoin(dt_row, prop_row.datatypeid == dt_row.datatypeid)
|
|
743
|
+
# Sheet axis ItemCategory, Property, DataType
|
|
744
|
+
.outerjoin(
|
|
745
|
+
ic_sheet,
|
|
746
|
+
and_(
|
|
747
|
+
hv_sheet.propertyid == ic_sheet.itemid,
|
|
748
|
+
filter_item_version(
|
|
749
|
+
release_id,
|
|
750
|
+
ic_sheet.startreleaseid,
|
|
751
|
+
ic_sheet.endreleaseid,
|
|
752
|
+
),
|
|
753
|
+
ic_sheet.isdefaultitem != 0,
|
|
754
|
+
),
|
|
755
|
+
)
|
|
756
|
+
.outerjoin(prop_sheet, hv_sheet.propertyid == prop_sheet.propertyid)
|
|
757
|
+
.outerjoin(dt_sheet, prop_sheet.datatypeid == dt_sheet.datatypeid)
|
|
758
|
+
.filter(TableVersionCell.tablevid == table_vid)
|
|
759
|
+
.distinct()
|
|
760
|
+
)
|
|
761
|
+
|
|
762
|
+
cell_results = cell_query.all()
|
|
763
|
+
|
|
764
|
+
return header_results, cell_results
|
|
765
|
+
|
|
766
|
+
@staticmethod
|
|
767
|
+
def _transform_to_dpm_format(header_rows, cell_rows) -> dict:
|
|
768
|
+
if not header_rows:
|
|
769
|
+
return {}
|
|
770
|
+
|
|
771
|
+
first_row = header_rows[0]
|
|
772
|
+
|
|
773
|
+
# Group header rows by header_id and aggregate enumeration items
|
|
774
|
+
headers_dict = {}
|
|
775
|
+
for row in header_rows:
|
|
776
|
+
header_id = row.header_id
|
|
777
|
+
|
|
778
|
+
if header_id not in headers_dict:
|
|
779
|
+
headers_dict[header_id] = {
|
|
780
|
+
"id": row.header_id,
|
|
781
|
+
"parentId": row.parent_header_id,
|
|
782
|
+
"code": row.header_code,
|
|
783
|
+
"label": row.label,
|
|
784
|
+
"direction": row.direction,
|
|
785
|
+
"order": row.order,
|
|
786
|
+
"isAbstract": row.is_abstract,
|
|
787
|
+
"isKey": row.is_key,
|
|
788
|
+
"propertyCode": getattr(row, "property_code", None),
|
|
789
|
+
"propertyName": row.property_name,
|
|
790
|
+
"dataTypeName": row.data_type_name,
|
|
791
|
+
"items": [],
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
# Aggregate enumeration items
|
|
795
|
+
if (
|
|
796
|
+
hasattr(row, "item_signature")
|
|
797
|
+
and row.item_signature
|
|
798
|
+
and hasattr(row, "item_label")
|
|
799
|
+
and row.item_label
|
|
800
|
+
):
|
|
801
|
+
item_str = f"{row.item_signature} - {row.item_label}"
|
|
802
|
+
if item_str not in headers_dict[header_id]["items"]:
|
|
803
|
+
headers_dict[header_id]["items"].append(item_str)
|
|
804
|
+
|
|
805
|
+
# Convert to list and sort by order
|
|
806
|
+
headers = sorted(headers_dict.values(), key=lambda x: x["order"])
|
|
807
|
+
|
|
808
|
+
cells = []
|
|
809
|
+
for row in cell_rows:
|
|
810
|
+
cells.append(
|
|
811
|
+
{
|
|
812
|
+
"column_code": row.column_code,
|
|
813
|
+
"row_code": row.row_code,
|
|
814
|
+
"sheet_code": row.sheet_code,
|
|
815
|
+
"variable_id": row.variable_id,
|
|
816
|
+
"variable_vid": row.variable_vid,
|
|
817
|
+
"cell_is_nullable": row.cell_is_nullable,
|
|
818
|
+
"cell_is_excluded": row.cell_is_excluded,
|
|
819
|
+
"cell_is_void": row.cell_is_void,
|
|
820
|
+
"cell_sign": row.cell_sign,
|
|
821
|
+
"property_code": getattr(row, "property_code", None),
|
|
822
|
+
"data_type_name": row.data_type_name,
|
|
823
|
+
}
|
|
824
|
+
)
|
|
825
|
+
|
|
826
|
+
return {
|
|
827
|
+
"tableCode": first_row.table_code,
|
|
828
|
+
"tableTitle": first_row.table_name, # Assuming Name -> Title mapping
|
|
829
|
+
"tableVid": first_row.table_vid,
|
|
830
|
+
"headers": headers,
|
|
831
|
+
"data": {},
|
|
832
|
+
"metadata": {
|
|
833
|
+
"version": "1.0",
|
|
834
|
+
"source": "database",
|
|
835
|
+
"recordCount": len(headers),
|
|
836
|
+
},
|
|
837
|
+
"cells": cells,
|
|
838
|
+
}
|