cognite-neat 0.97.2__py3-none-any.whl → 0.98.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.
Potentially problematic release.
This version of cognite-neat might be problematic. Click here for more details.
- cognite/neat/_graph/loaders/__init__.py +1 -2
- cognite/neat/_graph/queries/_base.py +25 -4
- cognite/neat/_issues/warnings/_models.py +9 -0
- cognite/neat/_rules/_shared.py +3 -8
- cognite/neat/_rules/analysis/__init__.py +1 -2
- cognite/neat/_rules/analysis/_base.py +2 -23
- cognite/neat/_rules/analysis/_dms.py +4 -10
- cognite/neat/_rules/analysis/_information.py +2 -10
- cognite/neat/_rules/catalog/info-rules-imf.xlsx +0 -0
- cognite/neat/_rules/exporters/_rules2excel.py +15 -72
- cognite/neat/_rules/exporters/_rules2ontology.py +4 -4
- cognite/neat/_rules/importers/_base.py +3 -4
- cognite/neat/_rules/importers/_dms2rules.py +17 -40
- cognite/neat/_rules/importers/_dtdl2rules/dtdl_converter.py +1 -7
- cognite/neat/_rules/importers/_dtdl2rules/dtdl_importer.py +7 -10
- cognite/neat/_rules/importers/_rdf/_base.py +17 -29
- cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2classes.py +2 -2
- cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2metadata.py +5 -10
- cognite/neat/_rules/importers/_rdf/_imf2rules/_imf2properties.py +1 -2
- cognite/neat/_rules/importers/_rdf/_inference2rules.py +30 -18
- cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2classes.py +2 -2
- cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2metadata.py +5 -8
- cognite/neat/_rules/importers/_rdf/_owl2rules/_owl2properties.py +1 -2
- cognite/neat/_rules/importers/_rdf/_shared.py +25 -140
- cognite/neat/_rules/importers/_spreadsheet2rules.py +10 -41
- cognite/neat/_rules/models/__init__.py +2 -16
- cognite/neat/_rules/models/_base_rules.py +98 -52
- cognite/neat/_rules/models/dms/_exporter.py +7 -160
- cognite/neat/_rules/models/dms/_rules.py +18 -126
- cognite/neat/_rules/models/dms/_rules_input.py +20 -48
- cognite/neat/_rules/models/dms/_schema.py +11 -0
- cognite/neat/_rules/models/dms/_validation.py +9 -122
- cognite/neat/_rules/models/information/_rules.py +19 -114
- cognite/neat/_rules/models/information/_rules_input.py +32 -41
- cognite/neat/_rules/models/information/_validation.py +34 -102
- cognite/neat/_rules/transformers/__init__.py +1 -4
- cognite/neat/_rules/transformers/_converters.py +18 -195
- cognite/neat/_rules/transformers/_mapping.py +1 -5
- cognite/neat/_rules/transformers/_verification.py +0 -14
- cognite/neat/_session/_base.py +37 -13
- cognite/neat/_session/_collector.py +126 -0
- cognite/neat/_session/_inspect.py +5 -5
- cognite/neat/_session/_prepare.py +37 -11
- cognite/neat/_session/_read.py +62 -9
- cognite/neat/_session/_set.py +2 -2
- cognite/neat/_session/_show.py +11 -11
- cognite/neat/_session/_to.py +24 -11
- cognite/neat/_session/exceptions.py +20 -3
- cognite/neat/_store/_provenance.py +2 -2
- cognite/neat/_utils/auxiliary.py +19 -0
- cognite/neat/_version.py +1 -1
- cognite/neat/_workflows/steps/data_contracts.py +2 -10
- cognite/neat/_workflows/steps/lib/current/rules_exporter.py +6 -46
- cognite/neat/_workflows/steps/lib/current/rules_validator.py +2 -7
- {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/METADATA +2 -1
- {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/RECORD +59 -65
- cognite/neat/_graph/loaders/_rdf2asset.py +0 -416
- cognite/neat/_rules/analysis/_asset.py +0 -173
- cognite/neat/_rules/models/asset/__init__.py +0 -13
- cognite/neat/_rules/models/asset/_rules.py +0 -109
- cognite/neat/_rules/models/asset/_rules_input.py +0 -101
- cognite/neat/_rules/models/asset/_validation.py +0 -45
- cognite/neat/_rules/models/domain.py +0 -136
- {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/LICENSE +0 -0
- {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/WHEEL +0 -0
- {cognite_neat-0.97.2.dist-info → cognite_neat-0.98.0.dist-info}/entry_points.txt +0 -0
|
@@ -4,11 +4,23 @@ its sub-models and validators.
|
|
|
4
4
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
|
+
import math
|
|
7
8
|
import sys
|
|
8
9
|
import types
|
|
9
10
|
from abc import ABC, abstractmethod
|
|
10
11
|
from collections.abc import Callable, Hashable, Iterator, MutableSequence, Sequence
|
|
11
|
-
from
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from typing import (
|
|
14
|
+
Annotated,
|
|
15
|
+
Any,
|
|
16
|
+
ClassVar,
|
|
17
|
+
Literal,
|
|
18
|
+
SupportsIndex,
|
|
19
|
+
TypeVar,
|
|
20
|
+
get_args,
|
|
21
|
+
get_origin,
|
|
22
|
+
overload,
|
|
23
|
+
)
|
|
12
24
|
|
|
13
25
|
import pandas as pd
|
|
14
26
|
from pydantic import (
|
|
@@ -23,15 +35,22 @@ from pydantic import (
|
|
|
23
35
|
)
|
|
24
36
|
from pydantic.main import IncEx
|
|
25
37
|
from pydantic_core import core_schema
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
from rdflib import Namespace, URIRef
|
|
39
|
+
|
|
40
|
+
from cognite.neat._constants import DEFAULT_NAMESPACE
|
|
41
|
+
from cognite.neat._rules.models._types import (
|
|
42
|
+
ClassEntityType,
|
|
43
|
+
DataModelExternalIdType,
|
|
44
|
+
InformationPropertyType,
|
|
45
|
+
SpaceType,
|
|
46
|
+
StrListType,
|
|
47
|
+
VersionType,
|
|
48
|
+
)
|
|
28
49
|
|
|
29
50
|
if sys.version_info >= (3, 11):
|
|
30
51
|
from enum import StrEnum
|
|
31
|
-
from typing import Self
|
|
32
52
|
else:
|
|
33
53
|
from backports.strenum import StrEnum
|
|
34
|
-
from typing_extensions import Self
|
|
35
54
|
|
|
36
55
|
|
|
37
56
|
METADATA_VALUE_MAX_LENGTH = 5120
|
|
@@ -82,18 +101,18 @@ class DataModelType(StrEnum):
|
|
|
82
101
|
enterprise = "enterprise"
|
|
83
102
|
|
|
84
103
|
|
|
104
|
+
class DataModelAspect(StrEnum):
|
|
105
|
+
conceptual = "conceptual"
|
|
106
|
+
logical = "logical"
|
|
107
|
+
physical = "physical"
|
|
108
|
+
|
|
109
|
+
|
|
85
110
|
class RoleTypes(StrEnum):
|
|
86
111
|
domain_expert = "domain expert"
|
|
87
112
|
information = "information architect"
|
|
88
|
-
asset = "asset architect"
|
|
89
113
|
dms = "DMS Architect"
|
|
90
114
|
|
|
91
115
|
|
|
92
|
-
class MatchType(StrEnum):
|
|
93
|
-
exact = "exact"
|
|
94
|
-
partial = "partial"
|
|
95
|
-
|
|
96
|
-
|
|
97
116
|
class SchemaModel(BaseModel):
|
|
98
117
|
model_config: ClassVar[ConfigDict] = ConfigDict(
|
|
99
118
|
populate_by_name=True,
|
|
@@ -125,6 +144,46 @@ class BaseMetadata(SchemaModel):
|
|
|
125
144
|
"""
|
|
126
145
|
|
|
127
146
|
role: ClassVar[RoleTypes]
|
|
147
|
+
aspect: ClassVar[DataModelAspect]
|
|
148
|
+
space: SpaceType = Field(alias="prefix")
|
|
149
|
+
external_id: DataModelExternalIdType = Field(alias="externalId")
|
|
150
|
+
version: VersionType
|
|
151
|
+
|
|
152
|
+
name: str | None = Field(
|
|
153
|
+
None,
|
|
154
|
+
description="Human readable name of the data model",
|
|
155
|
+
min_length=1,
|
|
156
|
+
max_length=255,
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
description: str | None = Field(None, min_length=1, max_length=1024)
|
|
160
|
+
|
|
161
|
+
creator: StrListType = Field(
|
|
162
|
+
description=(
|
|
163
|
+
"List of contributors to the data model creation, "
|
|
164
|
+
"typically information architects are considered as contributors."
|
|
165
|
+
),
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
created: datetime = Field(
|
|
169
|
+
description=("Date of the data model creation"),
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
updated: datetime = Field(
|
|
173
|
+
description=("Date of the data model update"),
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
@field_validator("*", mode="before")
|
|
177
|
+
def strip_string(cls, value: Any) -> Any:
|
|
178
|
+
if isinstance(value, str):
|
|
179
|
+
return value.strip()
|
|
180
|
+
return value
|
|
181
|
+
|
|
182
|
+
@field_validator("description", mode="before")
|
|
183
|
+
def nan_as_none(cls, value):
|
|
184
|
+
if isinstance(value, float) and math.isnan(value):
|
|
185
|
+
return None
|
|
186
|
+
return value
|
|
128
187
|
|
|
129
188
|
def to_pandas(self) -> pd.Series:
|
|
130
189
|
"""Converts Metadata to pandas Series."""
|
|
@@ -143,15 +202,30 @@ class BaseMetadata(SchemaModel):
|
|
|
143
202
|
def include_role(self, serializer: Callable) -> dict:
|
|
144
203
|
return {"role": self.role.value, **serializer(self)}
|
|
145
204
|
|
|
146
|
-
@
|
|
205
|
+
@property
|
|
206
|
+
def prefix(self) -> str:
|
|
207
|
+
return self.space
|
|
208
|
+
|
|
147
209
|
def as_identifier(self) -> str:
|
|
148
|
-
"
|
|
149
|
-
raise NotImplementedError()
|
|
210
|
+
return f"{self.prefix}:{self.external_id}"
|
|
150
211
|
|
|
151
|
-
@abstractmethod
|
|
152
212
|
def get_prefix(self) -> str:
|
|
153
|
-
|
|
154
|
-
|
|
213
|
+
return self.prefix
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def identifier(self) -> URIRef:
|
|
217
|
+
"""Globally unique identifier for the data model.
|
|
218
|
+
|
|
219
|
+
!!! note
|
|
220
|
+
Unlike namespace, the identifier does not end with "/" or "#".
|
|
221
|
+
|
|
222
|
+
"""
|
|
223
|
+
return DEFAULT_NAMESPACE[f"data-model/verified/{self.aspect}/{self.space}/{self.external_id}/{self.version}"]
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def namespace(self) -> Namespace:
|
|
227
|
+
"""Namespace for the data model used for the entities in the data model."""
|
|
228
|
+
return Namespace(f"{self.identifier}/")
|
|
155
229
|
|
|
156
230
|
|
|
157
231
|
class BaseRules(SchemaModel, ABC):
|
|
@@ -169,7 +243,6 @@ class BaseRules(SchemaModel, ABC):
|
|
|
169
243
|
"""
|
|
170
244
|
|
|
171
245
|
metadata: BaseMetadata
|
|
172
|
-
reference: Self | None = Field(None, alias="Reference")
|
|
173
246
|
|
|
174
247
|
@classmethod
|
|
175
248
|
def headers_by_sheet(cls, by_alias: bool = False) -> dict[str, list[str]]:
|
|
@@ -207,7 +280,6 @@ class BaseRules(SchemaModel, ABC):
|
|
|
207
280
|
def dump(
|
|
208
281
|
self,
|
|
209
282
|
entities_exclude_defaults: bool = True,
|
|
210
|
-
as_reference: bool = False,
|
|
211
283
|
mode: Literal["python", "json"] = "python",
|
|
212
284
|
by_alias: bool = False,
|
|
213
285
|
exclude: IncEx | None = None,
|
|
@@ -224,9 +296,6 @@ class BaseRules(SchemaModel, ABC):
|
|
|
224
296
|
For example, given a class that is dumped as 'my_prefix:MyClass', if the prefix for the rules
|
|
225
297
|
set in metadata.prefix = 'my_prefix', then this class will be dumped as 'MyClass' when this flag is set.
|
|
226
298
|
Defaults to True.
|
|
227
|
-
as_reference (bool, optional): Whether to dump as reference. For Information and DMS rules, this will
|
|
228
|
-
set the reference column/field to the reference of that entity. This is used in the ExcelExporter
|
|
229
|
-
to dump a reference model.
|
|
230
299
|
mode: The mode in which `to_python` should run.
|
|
231
300
|
If mode is 'json', the output will only contain JSON serializable types.
|
|
232
301
|
If mode is 'python', the output may contain non-JSON-serializable Python objects.
|
|
@@ -242,25 +311,11 @@ class BaseRules(SchemaModel, ABC):
|
|
|
242
311
|
if isinstance(value, SheetList):
|
|
243
312
|
value.sort(key=lambda x: x._identifier())
|
|
244
313
|
|
|
245
|
-
context: dict[str, Any] = {
|
|
314
|
+
context: dict[str, Any] = {}
|
|
246
315
|
if entities_exclude_defaults:
|
|
247
316
|
context["metadata"] = self.metadata
|
|
248
317
|
|
|
249
|
-
exclude_input: IncEx | None
|
|
250
|
-
if self.reference is None:
|
|
251
|
-
exclude_input = exclude
|
|
252
|
-
else:
|
|
253
|
-
# If the rules has a reference, we dump that separately with the as_reference flag set to True.
|
|
254
|
-
# We don't want to include the reference in the main dump, so we exclude it here.
|
|
255
|
-
# This is to include whatever is in the exclude set from the user.
|
|
256
|
-
if isinstance(exclude, dict):
|
|
257
|
-
exclude_input = exclude.copy()
|
|
258
|
-
exclude_input["reference"] = {"__all__"} # type: ignore[index]
|
|
259
|
-
elif isinstance(exclude, set):
|
|
260
|
-
exclude_input = exclude.copy()
|
|
261
|
-
exclude_input.add("reference") # type: ignore[arg-type]
|
|
262
|
-
else:
|
|
263
|
-
exclude_input = {"reference"}
|
|
318
|
+
exclude_input: IncEx | None = exclude
|
|
264
319
|
|
|
265
320
|
output = self.model_dump(
|
|
266
321
|
mode=mode,
|
|
@@ -271,20 +326,7 @@ class BaseRules(SchemaModel, ABC):
|
|
|
271
326
|
exclude_defaults=exclude_defaults,
|
|
272
327
|
context=context,
|
|
273
328
|
)
|
|
274
|
-
|
|
275
|
-
if self.reference is not None and not is_reference_user_excluded:
|
|
276
|
-
# If the rules has a reference, we dump that separately with the as_reference flag set to True.
|
|
277
|
-
# Unless the user has explicitly excluded the reference.
|
|
278
|
-
output["Reference" if by_alias else "reference"] = self.reference.dump(
|
|
279
|
-
mode=mode,
|
|
280
|
-
by_alias=by_alias,
|
|
281
|
-
exclude=exclude,
|
|
282
|
-
exclude_none=exclude_none,
|
|
283
|
-
exclude_unset=exclude_unset,
|
|
284
|
-
exclude_defaults=exclude_defaults,
|
|
285
|
-
entities_exclude_defaults=entities_exclude_defaults,
|
|
286
|
-
as_reference=True,
|
|
287
|
-
)
|
|
329
|
+
|
|
288
330
|
return output
|
|
289
331
|
|
|
290
332
|
|
|
@@ -293,6 +335,10 @@ class SheetRow(SchemaModel):
|
|
|
293
335
|
def _identifier(self) -> tuple[Hashable, ...]:
|
|
294
336
|
raise NotImplementedError()
|
|
295
337
|
|
|
338
|
+
def __repr__(self) -> str:
|
|
339
|
+
# Simplified representation of the object for debugging
|
|
340
|
+
return f"{self.__class__.__name__}({self._identifier()})"
|
|
341
|
+
|
|
296
342
|
|
|
297
343
|
T_SheetRow = TypeVar("T_SheetRow", bound=SheetRow)
|
|
298
344
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import warnings
|
|
2
2
|
from collections import defaultdict
|
|
3
3
|
from collections.abc import Collection, Hashable, Sequence
|
|
4
|
-
from typing import Any
|
|
4
|
+
from typing import Any
|
|
5
5
|
|
|
6
6
|
from cognite.client.data_classes import data_modeling as dm
|
|
7
7
|
from cognite.client.data_classes.data_modeling.containers import BTreeIndex
|
|
@@ -18,10 +18,7 @@ from cognite.neat._issues.warnings import NotSupportedWarning, PropertyNotFoundW
|
|
|
18
18
|
from cognite.neat._issues.warnings.user_modeling import (
|
|
19
19
|
EmptyContainerWarning,
|
|
20
20
|
HasDataFilterOnNoPropertiesViewWarning,
|
|
21
|
-
HasDataFilterOnViewWithReferencesWarning,
|
|
22
|
-
NodeTypeFilterOnParentViewWarning,
|
|
23
21
|
)
|
|
24
|
-
from cognite.neat._rules.models._base_rules import DataModelType, ExtensionCategory, SchemaCompleteness
|
|
25
22
|
from cognite.neat._rules.models.data_types import DataType, Double, Enum, Float
|
|
26
23
|
from cognite.neat._rules.models.entities import (
|
|
27
24
|
ClassEntity,
|
|
@@ -32,7 +29,6 @@ from cognite.neat._rules.models.entities import (
|
|
|
32
29
|
EdgeEntity,
|
|
33
30
|
HasDataFilter,
|
|
34
31
|
NodeTypeFilter,
|
|
35
|
-
ReferenceEntity,
|
|
36
32
|
ReverseConnectionEntity,
|
|
37
33
|
UnitEntity,
|
|
38
34
|
ViewEntity,
|
|
@@ -64,60 +60,19 @@ class _DMSExporter:
|
|
|
64
60
|
self.include_pipeline = include_pipeline
|
|
65
61
|
self.instance_space = instance_space
|
|
66
62
|
self.rules = rules
|
|
67
|
-
self._ref_schema =
|
|
63
|
+
self._ref_schema = None
|
|
68
64
|
if self._ref_schema:
|
|
69
65
|
# We skip version as that will always be missing in the reference
|
|
70
66
|
self._ref_views_by_id = {
|
|
71
67
|
dm.ViewId(view.space, view.external_id): view for view in self._ref_schema.views.values()
|
|
72
68
|
}
|
|
73
69
|
else:
|
|
74
|
-
self._ref_views_by_id = {}
|
|
75
|
-
|
|
76
|
-
self.is_addition = (
|
|
77
|
-
rules.metadata.schema_ is SchemaCompleteness.extended
|
|
78
|
-
and rules.metadata.extension is ExtensionCategory.addition
|
|
79
|
-
)
|
|
80
|
-
self.is_reshape = (
|
|
81
|
-
rules.metadata.schema_ is SchemaCompleteness.extended
|
|
82
|
-
and rules.metadata.extension is ExtensionCategory.reshape
|
|
83
|
-
)
|
|
84
|
-
self.is_rebuild = (
|
|
85
|
-
rules.metadata.schema_ is SchemaCompleteness.extended
|
|
86
|
-
and rules.metadata.extension is ExtensionCategory.rebuild
|
|
87
|
-
)
|
|
70
|
+
self._ref_views_by_id = {} # type: ignore
|
|
88
71
|
|
|
89
72
|
def to_schema(self) -> DMSSchema:
|
|
90
73
|
rules = self.rules
|
|
91
74
|
container_properties_by_id, view_properties_by_id = self._gather_properties(list(self.rules.properties))
|
|
92
75
|
|
|
93
|
-
# If we are reshaping or rebuilding, and there are no properties in the current rules, we will
|
|
94
|
-
# include those properties from the last rules.
|
|
95
|
-
if rules.last and (self.is_reshape or self.is_rebuild):
|
|
96
|
-
selected_views = {view.view for view in rules.views}
|
|
97
|
-
selected_properties = [
|
|
98
|
-
prop
|
|
99
|
-
for prop in rules.last.properties
|
|
100
|
-
if prop.view in selected_views and prop.view.as_id() not in view_properties_by_id
|
|
101
|
-
]
|
|
102
|
-
self._update_with_properties(
|
|
103
|
-
selected_properties, container_properties_by_id, view_properties_by_id, include_new_containers=True
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
# We need to include the properties from the last rules as well to create complete containers and view
|
|
107
|
-
# depending on the type of extension.
|
|
108
|
-
if rules.last and self.is_addition:
|
|
109
|
-
selected_properties = [
|
|
110
|
-
prop for prop in rules.last.properties if (prop.view.as_id() in view_properties_by_id)
|
|
111
|
-
]
|
|
112
|
-
self._update_with_properties(selected_properties, container_properties_by_id, view_properties_by_id)
|
|
113
|
-
elif rules.last and (self.is_reshape or self.is_rebuild):
|
|
114
|
-
selected_properties = [
|
|
115
|
-
prop
|
|
116
|
-
for prop in rules.last.properties
|
|
117
|
-
if prop.container and prop.container.as_id() in container_properties_by_id
|
|
118
|
-
]
|
|
119
|
-
self._update_with_properties(selected_properties, container_properties_by_id, None)
|
|
120
|
-
|
|
121
76
|
containers = self._create_containers(container_properties_by_id, rules.enum) # type: ignore[arg-type]
|
|
122
77
|
|
|
123
78
|
view_properties_with_ancestors_by_id = self._gather_properties_with_ancestors(
|
|
@@ -136,30 +91,11 @@ class _DMSExporter:
|
|
|
136
91
|
node_types = NodeApplyDict([dm.NodeApply(node.space, node.external_id) for node in view_node_type_filters])
|
|
137
92
|
|
|
138
93
|
last_schema: DMSSchema | None = None
|
|
139
|
-
if self.rules.last:
|
|
140
|
-
last_schema = self.rules.last.as_schema()
|
|
141
|
-
# Remove the views that are in the current model, last + current should equal the full model
|
|
142
|
-
# without any duplicates
|
|
143
|
-
last_schema.views = ViewApplyDict(
|
|
144
|
-
{view_id: view for view_id, view in last_schema.views.items() if view_id not in views}
|
|
145
|
-
)
|
|
146
|
-
last_schema.containers = ContainerApplyDict(
|
|
147
|
-
{
|
|
148
|
-
container_id: container
|
|
149
|
-
for container_id, container in last_schema.containers.items()
|
|
150
|
-
if container_id not in containers
|
|
151
|
-
}
|
|
152
|
-
)
|
|
153
94
|
|
|
154
95
|
views_not_in_model = {view.view.as_id() for view in rules.views if not view.in_model}
|
|
155
|
-
if rules.last and self.is_addition:
|
|
156
|
-
views_not_in_model.update({view.view.as_id() for view in rules.last.views if not view.in_model})
|
|
157
|
-
|
|
158
96
|
data_model = rules.metadata.as_data_model()
|
|
159
97
|
|
|
160
98
|
data_model_views = [view_id for view_id in views if view_id not in views_not_in_model]
|
|
161
|
-
if last_schema and self.is_addition:
|
|
162
|
-
data_model_views.extend([view_id for view_id in last_schema.views if view_id not in views_not_in_model])
|
|
163
99
|
|
|
164
100
|
# Sorting to ensure deterministic order
|
|
165
101
|
data_model.views = sorted(data_model_views, key=lambda v: v.as_tuple()) # type: ignore[union-attr]
|
|
@@ -207,17 +143,8 @@ class _DMSExporter:
|
|
|
207
143
|
view_properties_with_ancestors_by_id: dict[dm.ViewId, list[DMSProperty]],
|
|
208
144
|
) -> tuple[ViewApplyDict, set[dm.NodeId]]:
|
|
209
145
|
input_views = list(self.rules.views)
|
|
210
|
-
if self.rules.last:
|
|
211
|
-
existing = {view.view.as_id() for view in input_views}
|
|
212
|
-
modified_views = [
|
|
213
|
-
v
|
|
214
|
-
for v in self.rules.last.views
|
|
215
|
-
if v.view.as_id() in view_properties_by_id and v.view.as_id() not in existing
|
|
216
|
-
]
|
|
217
|
-
input_views.extend(modified_views)
|
|
218
146
|
|
|
219
147
|
views = ViewApplyDict([dms_view.as_view() for dms_view in input_views])
|
|
220
|
-
dms_view_by_id = {dms_view.view.as_id(): dms_view for dms_view in input_views}
|
|
221
148
|
|
|
222
149
|
for view_id, view in views.items():
|
|
223
150
|
view.properties = {}
|
|
@@ -228,43 +155,9 @@ class _DMSExporter:
|
|
|
228
155
|
if view_property is not None:
|
|
229
156
|
view.properties[prop.view_property] = view_property
|
|
230
157
|
|
|
231
|
-
data_model_type = self.rules.metadata.data_model_type
|
|
232
158
|
unique_node_types: set[dm.NodeId] = set()
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
dms_view = dms_view_by_id.get(view_id)
|
|
236
|
-
dms_properties = view_properties_by_id.get(view_id, [])
|
|
237
|
-
view_filter = self._create_view_filter(view, dms_view, data_model_type, dms_properties)
|
|
238
|
-
|
|
239
|
-
view.filter = view_filter.as_dms_filter()
|
|
240
|
-
if isinstance(view_filter, NodeTypeFilter):
|
|
241
|
-
unique_node_types.update(view_filter.nodes)
|
|
242
|
-
if view.as_id() in parent_views:
|
|
243
|
-
warnings.warn(
|
|
244
|
-
NodeTypeFilterOnParentViewWarning(view.as_id()),
|
|
245
|
-
stacklevel=2,
|
|
246
|
-
)
|
|
247
|
-
|
|
248
|
-
elif isinstance(view_filter, HasDataFilter) and data_model_type == DataModelType.solution:
|
|
249
|
-
if dms_view and isinstance(dms_view.reference, ReferenceEntity):
|
|
250
|
-
references = {dms_view.reference.as_view_id()}
|
|
251
|
-
elif any(True for prop in dms_properties if isinstance(prop.reference, ReferenceEntity)):
|
|
252
|
-
references = {
|
|
253
|
-
prop.reference.as_view_id()
|
|
254
|
-
for prop in dms_properties
|
|
255
|
-
if isinstance(prop.reference, ReferenceEntity)
|
|
256
|
-
}
|
|
257
|
-
else:
|
|
258
|
-
continue
|
|
259
|
-
warnings.warn(
|
|
260
|
-
HasDataFilterOnViewWithReferencesWarning(view.as_id(), frozenset(references)),
|
|
261
|
-
stacklevel=2,
|
|
262
|
-
)
|
|
263
|
-
|
|
264
|
-
if data_model_type == DataModelType.enterprise:
|
|
265
|
-
# Enterprise Model needs to create node types for all views,
|
|
266
|
-
# as they are expected for the solution model.
|
|
267
|
-
unique_node_types.add(dm.NodeId(space=view.space, external_id=view.external_id))
|
|
159
|
+
for view in views.values():
|
|
160
|
+
unique_node_types.add(dm.NodeId(space=view.space, external_id=view.external_id))
|
|
268
161
|
|
|
269
162
|
return views, unique_node_types
|
|
270
163
|
|
|
@@ -272,9 +165,6 @@ class _DMSExporter:
|
|
|
272
165
|
def _create_edge_type_from_prop(cls, prop: DMSProperty) -> dm.DirectRelationReference:
|
|
273
166
|
if isinstance(prop.connection, EdgeEntity) and prop.connection.edge_type is not None:
|
|
274
167
|
return prop.connection.edge_type.as_reference()
|
|
275
|
-
elif isinstance(prop.reference, ReferenceEntity):
|
|
276
|
-
ref_view_prop = prop.reference.as_view_property_id()
|
|
277
|
-
return cls._create_edge_type_from_view_id(cast(dm.ViewId, ref_view_prop.source), ref_view_prop.property)
|
|
278
168
|
elif isinstance(prop.value_type, ViewEntity):
|
|
279
169
|
return cls._create_edge_type_from_view_id(prop.view.as_id(), prop.view_property)
|
|
280
170
|
else:
|
|
@@ -298,14 +188,6 @@ class _DMSExporter:
|
|
|
298
188
|
enum_values_by_collection[enum_value.collection].append(enum_value)
|
|
299
189
|
|
|
300
190
|
containers = list(self.rules.containers or [])
|
|
301
|
-
if self.rules.last:
|
|
302
|
-
existing = {container.container.as_id() for container in containers}
|
|
303
|
-
modified_containers = [
|
|
304
|
-
c
|
|
305
|
-
for c in self.rules.last.containers or []
|
|
306
|
-
if c.container.as_id() in container_properties_by_id and c.container.as_id() not in existing
|
|
307
|
-
]
|
|
308
|
-
containers.extend(modified_containers)
|
|
309
191
|
|
|
310
192
|
containers = dm.ContainerApplyList([dms_container.as_container() for dms_container in containers])
|
|
311
193
|
container_to_drop = set()
|
|
@@ -408,17 +290,6 @@ class _DMSExporter:
|
|
|
408
290
|
views: Sequence[DMSView],
|
|
409
291
|
) -> dict[dm.ViewId, list[DMSProperty]]:
|
|
410
292
|
all_view_properties_by_id = view_properties_by_id.copy()
|
|
411
|
-
if self.rules.reference:
|
|
412
|
-
# We need to include t
|
|
413
|
-
ref_view_properties_by_id = self._gather_properties(self.rules.reference.properties)[1]
|
|
414
|
-
for view_id, properties in ref_view_properties_by_id.items():
|
|
415
|
-
if view_id not in all_view_properties_by_id:
|
|
416
|
-
all_view_properties_by_id[view_id] = properties
|
|
417
|
-
else:
|
|
418
|
-
existing_properties = {prop._identifier() for prop in all_view_properties_by_id[view_id]}
|
|
419
|
-
for prop in properties:
|
|
420
|
-
if prop._identifier() not in existing_properties:
|
|
421
|
-
all_view_properties_by_id[view_id].append(prop)
|
|
422
293
|
|
|
423
294
|
view_properties_with_parents_by_id: dict[dm.ViewId, list[DMSProperty]] = defaultdict(list)
|
|
424
295
|
view_by_view_id = {view.view.as_id(): view for view in views}
|
|
@@ -482,37 +353,13 @@ class _DMSExporter:
|
|
|
482
353
|
self,
|
|
483
354
|
view: dm.ViewApply,
|
|
484
355
|
dms_view: DMSView | None,
|
|
485
|
-
|
|
486
|
-
dms_properties: list[DMSProperty],
|
|
487
|
-
) -> DMSFilter:
|
|
356
|
+
) -> DMSFilter | None:
|
|
488
357
|
selected_filter_name = (dms_view and dms_view.filter_ and dms_view.filter_.name) or ""
|
|
489
358
|
|
|
490
359
|
if dms_view and dms_view.filter_ and not dms_view.filter_.is_empty:
|
|
491
360
|
# Has Explicit Filter, use it
|
|
492
361
|
return dms_view.filter_
|
|
493
362
|
|
|
494
|
-
if data_model_type == DataModelType.solution and selected_filter_name in [NodeTypeFilter.name, ""]:
|
|
495
|
-
if (
|
|
496
|
-
dms_view
|
|
497
|
-
and isinstance(dms_view.reference, ReferenceEntity)
|
|
498
|
-
and not dms_properties
|
|
499
|
-
and (ref_view := self._ref_views_by_id.get(dms_view.reference.as_view_id()))
|
|
500
|
-
and ref_view.filter
|
|
501
|
-
):
|
|
502
|
-
# No new properties, only reference, reuse the reference filter
|
|
503
|
-
return DMSFilter.from_dms_filter(ref_view.filter)
|
|
504
|
-
else:
|
|
505
|
-
referenced_node_ids = {
|
|
506
|
-
prop.reference.as_node_entity()
|
|
507
|
-
for prop in dms_properties
|
|
508
|
-
if isinstance(prop.reference, ReferenceEntity)
|
|
509
|
-
}
|
|
510
|
-
if dms_view and isinstance(dms_view.reference, ReferenceEntity):
|
|
511
|
-
referenced_node_ids.add(dms_view.reference.as_node_entity())
|
|
512
|
-
|
|
513
|
-
if referenced_node_ids:
|
|
514
|
-
return NodeTypeFilter(inner=list(referenced_node_ids))
|
|
515
|
-
|
|
516
363
|
# Enterprise Model or (Solution + HasData)
|
|
517
364
|
ref_containers = view.referenced_containers()
|
|
518
365
|
if not ref_containers or selected_filter_name == HasDataFilter.name:
|
|
@@ -597,7 +444,7 @@ class _DMSExporter:
|
|
|
597
444
|
(
|
|
598
445
|
prop
|
|
599
446
|
for prop in view_properties_with_ancestors_by_id.get(source_view_id, [])
|
|
600
|
-
if prop.
|
|
447
|
+
if prop.view_property == reverse_prop_id
|
|
601
448
|
),
|
|
602
449
|
None,
|
|
603
450
|
)
|