cognite-neat 0.103.1__py3-none-any.whl → 0.105.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.

Files changed (175) hide show
  1. cognite/neat/_client/_api/data_modeling_loaders.py +83 -23
  2. cognite/neat/_client/_api/schema.py +2 -1
  3. cognite/neat/_client/data_classes/neat_sequence.py +261 -0
  4. cognite/neat/_client/data_classes/schema.py +5 -1
  5. cognite/neat/_client/testing.py +33 -0
  6. cognite/neat/_constants.py +56 -0
  7. cognite/neat/_graph/extractors/_classic_cdf/_base.py +6 -5
  8. cognite/neat/_graph/extractors/_classic_cdf/_sequences.py +225 -11
  9. cognite/neat/_graph/extractors/_mock_graph_generator.py +2 -2
  10. cognite/neat/_graph/loaders/_rdf2dms.py +13 -2
  11. cognite/neat/_graph/transformers/__init__.py +3 -1
  12. cognite/neat/_graph/transformers/_base.py +109 -1
  13. cognite/neat/_graph/transformers/_classic_cdf.py +6 -1
  14. cognite/neat/_graph/transformers/_prune_graph.py +103 -47
  15. cognite/neat/_graph/transformers/_rdfpath.py +41 -17
  16. cognite/neat/_graph/transformers/_value_type.py +188 -151
  17. cognite/neat/_issues/__init__.py +0 -2
  18. cognite/neat/_issues/_base.py +54 -43
  19. cognite/neat/_issues/warnings/__init__.py +4 -1
  20. cognite/neat/_issues/warnings/_general.py +7 -0
  21. cognite/neat/_issues/warnings/_resources.py +12 -1
  22. cognite/neat/_rules/_shared.py +18 -34
  23. cognite/neat/_rules/exporters/_base.py +28 -2
  24. cognite/neat/_rules/exporters/_rules2dms.py +39 -1
  25. cognite/neat/_rules/exporters/_rules2excel.py +13 -2
  26. cognite/neat/_rules/exporters/_rules2instance_template.py +4 -0
  27. cognite/neat/_rules/exporters/_rules2ontology.py +13 -1
  28. cognite/neat/_rules/exporters/_rules2yaml.py +4 -0
  29. cognite/neat/_rules/importers/_base.py +9 -0
  30. cognite/neat/_rules/importers/_dms2rules.py +80 -57
  31. cognite/neat/_rules/importers/_dtdl2rules/dtdl_importer.py +5 -2
  32. cognite/neat/_rules/importers/_rdf/_base.py +10 -8
  33. cognite/neat/_rules/importers/_rdf/_imf2rules.py +4 -0
  34. cognite/neat/_rules/importers/_rdf/_inference2rules.py +7 -0
  35. cognite/neat/_rules/importers/_rdf/_owl2rules.py +4 -0
  36. cognite/neat/_rules/importers/_spreadsheet2rules.py +17 -8
  37. cognite/neat/_rules/importers/_yaml2rules.py +21 -7
  38. cognite/neat/_rules/models/_base_input.py +1 -1
  39. cognite/neat/_rules/models/_base_rules.py +9 -1
  40. cognite/neat/_rules/models/dms/_rules.py +4 -0
  41. cognite/neat/_rules/models/dms/_rules_input.py +9 -0
  42. cognite/neat/_rules/models/entities/_wrapped.py +10 -5
  43. cognite/neat/_rules/models/information/_rules.py +4 -0
  44. cognite/neat/_rules/models/information/_rules_input.py +9 -0
  45. cognite/neat/_rules/models/mapping/_classic2core.py +2 -5
  46. cognite/neat/_rules/models/mapping/_classic2core.yaml +239 -38
  47. cognite/neat/_rules/transformers/__init__.py +13 -6
  48. cognite/neat/_rules/transformers/_base.py +41 -65
  49. cognite/neat/_rules/transformers/_converters.py +404 -234
  50. cognite/neat/_rules/transformers/_mapping.py +93 -72
  51. cognite/neat/_rules/transformers/_verification.py +50 -38
  52. cognite/neat/_session/_base.py +32 -121
  53. cognite/neat/_session/_inspect.py +5 -3
  54. cognite/neat/_session/_mapping.py +17 -105
  55. cognite/neat/_session/_prepare.py +138 -268
  56. cognite/neat/_session/_read.py +39 -195
  57. cognite/neat/_session/_set.py +6 -30
  58. cognite/neat/_session/_show.py +40 -21
  59. cognite/neat/_session/_state.py +49 -107
  60. cognite/neat/_session/_to.py +44 -33
  61. cognite/neat/_shared.py +23 -2
  62. cognite/neat/_store/_provenance.py +3 -82
  63. cognite/neat/_store/_rules_store.py +368 -10
  64. cognite/neat/_store/exceptions.py +23 -0
  65. cognite/neat/_utils/graph_transformations_report.py +36 -0
  66. cognite/neat/_utils/rdf_.py +8 -0
  67. cognite/neat/_utils/reader/_base.py +27 -0
  68. cognite/neat/_utils/spreadsheet.py +5 -4
  69. cognite/neat/_version.py +1 -1
  70. {cognite_neat-0.103.1.dist-info → cognite_neat-0.105.0.dist-info}/METADATA +3 -2
  71. cognite_neat-0.105.0.dist-info/RECORD +179 -0
  72. {cognite_neat-0.103.1.dist-info → cognite_neat-0.105.0.dist-info}/WHEEL +1 -1
  73. cognite/neat/_app/api/__init__.py +0 -0
  74. cognite/neat/_app/api/asgi/metrics.py +0 -4
  75. cognite/neat/_app/api/configuration.py +0 -98
  76. cognite/neat/_app/api/context_manager/__init__.py +0 -3
  77. cognite/neat/_app/api/context_manager/manager.py +0 -16
  78. cognite/neat/_app/api/data_classes/__init__.py +0 -0
  79. cognite/neat/_app/api/data_classes/rest.py +0 -59
  80. cognite/neat/_app/api/explorer.py +0 -66
  81. cognite/neat/_app/api/routers/configuration.py +0 -25
  82. cognite/neat/_app/api/routers/crud.py +0 -102
  83. cognite/neat/_app/api/routers/metrics.py +0 -10
  84. cognite/neat/_app/api/routers/workflows.py +0 -224
  85. cognite/neat/_app/api/utils/__init__.py +0 -0
  86. cognite/neat/_app/api/utils/data_mapping.py +0 -17
  87. cognite/neat/_app/api/utils/logging.py +0 -26
  88. cognite/neat/_app/api/utils/query_templates.py +0 -92
  89. cognite/neat/_app/main.py +0 -17
  90. cognite/neat/_app/monitoring/__init__.py +0 -0
  91. cognite/neat/_app/monitoring/metrics.py +0 -69
  92. cognite/neat/_app/ui/index.html +0 -1
  93. cognite/neat/_app/ui/neat-app/.gitignore +0 -23
  94. cognite/neat/_app/ui/neat-app/README.md +0 -70
  95. cognite/neat/_app/ui/neat-app/build/asset-manifest.json +0 -14
  96. cognite/neat/_app/ui/neat-app/build/favicon.ico +0 -0
  97. cognite/neat/_app/ui/neat-app/build/img/architect-icon.svg +0 -116
  98. cognite/neat/_app/ui/neat-app/build/img/developer-icon.svg +0 -112
  99. cognite/neat/_app/ui/neat-app/build/img/sme-icon.svg +0 -34
  100. cognite/neat/_app/ui/neat-app/build/index.html +0 -1
  101. cognite/neat/_app/ui/neat-app/build/logo192.png +0 -0
  102. cognite/neat/_app/ui/neat-app/build/manifest.json +0 -25
  103. cognite/neat/_app/ui/neat-app/build/robots.txt +0 -3
  104. cognite/neat/_app/ui/neat-app/build/static/css/main.72e3d92e.css +0 -2
  105. cognite/neat/_app/ui/neat-app/build/static/css/main.72e3d92e.css.map +0 -1
  106. cognite/neat/_app/ui/neat-app/build/static/js/main.5a52cf09.js +0 -3
  107. cognite/neat/_app/ui/neat-app/build/static/js/main.5a52cf09.js.LICENSE.txt +0 -88
  108. cognite/neat/_app/ui/neat-app/build/static/js/main.5a52cf09.js.map +0 -1
  109. cognite/neat/_app/ui/neat-app/build/static/media/logo.8093b84df9ed36a174c629d6fe0b730d.svg +0 -1
  110. cognite/neat/_app/ui/neat-app/package-lock.json +0 -18306
  111. cognite/neat/_app/ui/neat-app/package.json +0 -62
  112. cognite/neat/_app/ui/neat-app/public/favicon.ico +0 -0
  113. cognite/neat/_app/ui/neat-app/public/img/architect-icon.svg +0 -116
  114. cognite/neat/_app/ui/neat-app/public/img/developer-icon.svg +0 -112
  115. cognite/neat/_app/ui/neat-app/public/img/sme-icon.svg +0 -34
  116. cognite/neat/_app/ui/neat-app/public/index.html +0 -43
  117. cognite/neat/_app/ui/neat-app/public/logo192.png +0 -0
  118. cognite/neat/_app/ui/neat-app/public/manifest.json +0 -25
  119. cognite/neat/_app/ui/neat-app/public/robots.txt +0 -3
  120. cognite/neat/_app/ui/neat-app/src/App.css +0 -38
  121. cognite/neat/_app/ui/neat-app/src/App.js +0 -17
  122. cognite/neat/_app/ui/neat-app/src/App.test.js +0 -8
  123. cognite/neat/_app/ui/neat-app/src/MainContainer.tsx +0 -70
  124. cognite/neat/_app/ui/neat-app/src/components/JsonViewer.tsx +0 -43
  125. cognite/neat/_app/ui/neat-app/src/components/LocalUploader.tsx +0 -124
  126. cognite/neat/_app/ui/neat-app/src/components/OverviewComponentEditorDialog.tsx +0 -63
  127. cognite/neat/_app/ui/neat-app/src/components/StepEditorDialog.tsx +0 -511
  128. cognite/neat/_app/ui/neat-app/src/components/TabPanel.tsx +0 -36
  129. cognite/neat/_app/ui/neat-app/src/components/Utils.tsx +0 -56
  130. cognite/neat/_app/ui/neat-app/src/components/WorkflowDeleteDialog.tsx +0 -60
  131. cognite/neat/_app/ui/neat-app/src/components/WorkflowExecutionReport.tsx +0 -112
  132. cognite/neat/_app/ui/neat-app/src/components/WorkflowImportExportDialog.tsx +0 -67
  133. cognite/neat/_app/ui/neat-app/src/components/WorkflowMetadataDialog.tsx +0 -79
  134. cognite/neat/_app/ui/neat-app/src/index.css +0 -13
  135. cognite/neat/_app/ui/neat-app/src/index.js +0 -13
  136. cognite/neat/_app/ui/neat-app/src/logo.svg +0 -1
  137. cognite/neat/_app/ui/neat-app/src/reportWebVitals.js +0 -13
  138. cognite/neat/_app/ui/neat-app/src/setupTests.js +0 -5
  139. cognite/neat/_app/ui/neat-app/src/types/WorkflowTypes.ts +0 -388
  140. cognite/neat/_app/ui/neat-app/src/views/AboutView.tsx +0 -61
  141. cognite/neat/_app/ui/neat-app/src/views/ConfigView.tsx +0 -184
  142. cognite/neat/_app/ui/neat-app/src/views/GlobalConfigView.tsx +0 -180
  143. cognite/neat/_app/ui/neat-app/src/views/WorkflowView.tsx +0 -570
  144. cognite/neat/_app/ui/neat-app/tsconfig.json +0 -27
  145. cognite/neat/_rules/transformers/_pipelines.py +0 -70
  146. cognite/neat/_workflows/__init__.py +0 -17
  147. cognite/neat/_workflows/base.py +0 -590
  148. cognite/neat/_workflows/cdf_store.py +0 -393
  149. cognite/neat/_workflows/examples/Export_DMS/workflow.yaml +0 -89
  150. cognite/neat/_workflows/examples/Export_Semantic_Data_Model/workflow.yaml +0 -66
  151. cognite/neat/_workflows/examples/Import_DMS/workflow.yaml +0 -65
  152. cognite/neat/_workflows/examples/Validate_Rules/workflow.yaml +0 -67
  153. cognite/neat/_workflows/examples/Validate_Solution_Model/workflow.yaml +0 -64
  154. cognite/neat/_workflows/manager.py +0 -292
  155. cognite/neat/_workflows/model.py +0 -203
  156. cognite/neat/_workflows/steps/__init__.py +0 -0
  157. cognite/neat/_workflows/steps/data_contracts.py +0 -109
  158. cognite/neat/_workflows/steps/lib/__init__.py +0 -0
  159. cognite/neat/_workflows/steps/lib/current/__init__.py +0 -6
  160. cognite/neat/_workflows/steps/lib/current/graph_extractor.py +0 -100
  161. cognite/neat/_workflows/steps/lib/current/graph_loader.py +0 -51
  162. cognite/neat/_workflows/steps/lib/current/graph_store.py +0 -48
  163. cognite/neat/_workflows/steps/lib/current/rules_exporter.py +0 -537
  164. cognite/neat/_workflows/steps/lib/current/rules_importer.py +0 -398
  165. cognite/neat/_workflows/steps/lib/current/rules_validator.py +0 -106
  166. cognite/neat/_workflows/steps/lib/io/__init__.py +0 -1
  167. cognite/neat/_workflows/steps/lib/io/io_steps.py +0 -393
  168. cognite/neat/_workflows/steps/step_model.py +0 -79
  169. cognite/neat/_workflows/steps_registry.py +0 -218
  170. cognite/neat/_workflows/tasks.py +0 -18
  171. cognite/neat/_workflows/triggers.py +0 -169
  172. cognite/neat/_workflows/utils.py +0 -19
  173. cognite_neat-0.103.1.dist-info/RECORD +0 -275
  174. {cognite_neat-0.103.1.dist-info → cognite_neat-0.105.0.dist-info}/LICENSE +0 -0
  175. {cognite_neat-0.103.1.dist-info → cognite_neat-0.105.0.dist-info}/entry_points.txt +0 -0
@@ -1,15 +1,17 @@
1
1
  from typing import cast
2
2
 
3
3
  from rdflib import Graph, Namespace, URIRef
4
+ from rdflib.query import ResultRow
4
5
 
5
6
  from cognite.neat._constants import DEFAULT_NAMESPACE
6
7
  from cognite.neat._shared import Triple
7
8
  from cognite.neat._utils.rdf_ import as_neat_compliant_uri
8
9
  from cognite.neat._utils.text import sentence_or_string_to_camel
9
10
 
10
- from ._base import BaseTransformer
11
+ from ._base import BaseTransformer, BaseTransformerStandardised, RowTransformationOutput
11
12
 
12
13
 
14
+ # TODO: Standardise after figuring out the bug which appears when running test_iodd_transformers.py
13
15
  class AttachPropertyFromTargetToSource(BaseTransformer):
14
16
  """
15
17
  Transformer that considers a TargetNode and SourceNode relationship, to extract a property that is attached to
@@ -148,6 +150,7 @@ class AttachPropertyFromTargetToSource(BaseTransformer):
148
150
  graph.remove((target_node, None, None))
149
151
 
150
152
 
153
+ # TODO: Remove or adapt IODD
151
154
  class PruneDanglingNodes(BaseTransformer):
152
155
  """
153
156
  Knowledge graph pruner and resolver. Will remove rdf triples from graph that does not have connections
@@ -189,18 +192,12 @@ class PruneDanglingNodes(BaseTransformer):
189
192
  graph.remove((subject, None, None))
190
193
 
191
194
 
192
- class PruneTypes(BaseTransformer):
195
+ class PruneTypes(BaseTransformerStandardised):
193
196
  """
194
197
  Removes all the instances of specific type
195
198
  """
196
199
 
197
200
  description: str = "Prunes nodes of specific rdf types"
198
- _query_template = """
199
- SELECT ?subject
200
- WHERE {{
201
- ?subject a <{rdf_type}> .
202
- }}
203
- """
204
201
 
205
202
  def __init__(
206
203
  self,
@@ -208,50 +205,109 @@ class PruneTypes(BaseTransformer):
208
205
  ):
209
206
  self.node_prune_types = node_prune_types
210
207
 
211
- def transform(self, graph: Graph) -> None:
212
- for type_ in self.node_prune_types:
213
- for (subject,) in list(graph.query(self._query_template.format(rdf_type=type_))): # type: ignore
214
- graph.remove((subject, None, None))
215
-
216
-
217
- class PruneDeadEndEdges(BaseTransformer):
208
+ def _iterate_query(self) -> str:
209
+ filter_string = ""
210
+ for node in self.node_prune_types:
211
+ filter_string += f" <{node}> "
212
+
213
+ query = """
214
+ SELECT ?subject
215
+ WHERE {{
216
+ ?subject a ?type .
217
+ VALUES ?type {{ {rdf_types_string} }}
218
+ }}
219
+ """
220
+ return query.format(rdf_types_string=filter_string)
221
+
222
+ def _count_query(self) -> str:
223
+ filter_string = ""
224
+ for node in self.node_prune_types:
225
+ filter_string += f" <{node}> "
226
+
227
+ query = """
228
+ SELECT ( COUNT( ?subject ) as ?count )
229
+ WHERE {{
230
+ ?subject a ?type .
231
+ VALUES ?type {{ {rdf_types_string} }}
232
+ }}
233
+ """
234
+ return query.format(rdf_types_string=filter_string)
235
+
236
+ def operation(self, query_result_row: ResultRow) -> RowTransformationOutput:
237
+ row_output = RowTransformationOutput()
238
+
239
+ (subject,) = query_result_row
240
+ row_output.remove_triples.append((subject, None, None)) # type: ignore
241
+ row_output.instances_removed_count = 1
242
+
243
+ return row_output
244
+
245
+
246
+ class PruneDeadEndEdges(BaseTransformerStandardised):
218
247
  """
219
248
  Removes all the triples where object is a node that is not found in graph
220
249
  """
221
250
 
222
- description: str = "Prunes the graph of specified rdf types that do not have connections to other nodes."
223
- _query_template = """
224
- SELECT ?subject ?predicate ?object
225
- WHERE {
226
- ?subject ?predicate ?object .
227
- FILTER (isIRI(?object) && ?predicate != rdf:type)
228
- FILTER NOT EXISTS {?object ?p ?o .}
229
-
230
- }
231
-
232
- """
233
-
234
- def transform(self, graph: Graph) -> None:
235
- for triple in graph.query(self._query_template):
236
- graph.remove(cast(Triple, triple))
237
-
238
-
239
- class PruneInstancesOfUnknownType(BaseTransformer):
251
+ description: str = "Pruning the graph of triples where object is a node that is not found in graph."
252
+
253
+ def _iterate_query(self) -> str:
254
+ return """
255
+ SELECT ?subject ?predicate ?object
256
+ WHERE {
257
+ ?subject ?predicate ?object .
258
+ FILTER (isIRI(?object) && ?predicate != rdf:type)
259
+ FILTER NOT EXISTS {?object ?p ?o .}
260
+ }
261
+ """
262
+
263
+ def _count_query(self) -> str:
264
+ return """
265
+ SELECT (COUNT(?object) AS ?count)
266
+ WHERE {
267
+ ?subject ?predicate ?object .
268
+ FILTER (isIRI(?object) && ?predicate != rdf:type)
269
+ FILTER NOT EXISTS {?object ?p ?o .}
270
+ }
271
+ """
272
+
273
+ def operation(self, row: ResultRow) -> RowTransformationOutput:
274
+ row_output = RowTransformationOutput()
275
+ row_output.remove_triples.append(cast(Triple, row))
276
+ row_output.instances_modified_count = 1
277
+
278
+ return row_output
279
+
280
+
281
+ class PruneInstancesOfUnknownType(BaseTransformerStandardised):
240
282
  """
241
283
  Removes all the triples where object is a node that is not found in graph
242
284
  """
243
285
 
244
- description: str = "Prunes the graph of specified rdf types that do not have connections to other nodes."
245
- _query_template = """
246
- SELECT DISTINCT ?subject
247
- WHERE {
248
- ?subject ?p ?o .
249
- FILTER NOT EXISTS {?subject a ?object .}
250
-
251
- }
252
-
253
- """
254
-
255
- def transform(self, graph: Graph) -> None:
256
- for (subject,) in graph.query(self._query_template): # type: ignore
257
- graph.remove((subject, None, None))
286
+ description: str = "Prunes the graph of triples where the object is a node that is not found in the graph."
287
+
288
+ def _iterate_query(self) -> str:
289
+ return """
290
+ SELECT DISTINCT ?subject
291
+ WHERE {
292
+ ?subject ?p ?o .
293
+ FILTER NOT EXISTS {?subject a ?object .}
294
+
295
+ }
296
+ """
297
+
298
+ def _count_query(self) -> str:
299
+ return """
300
+ SELECT (COUNT(DISTINCT ?subject) as ?count)
301
+ WHERE {
302
+ ?subject ?p ?o .
303
+ FILTER NOT EXISTS {?subject a ?object .}
304
+ }
305
+ """
306
+
307
+ def operation(self, query_result_row: ResultRow) -> RowTransformationOutput:
308
+ row_output = RowTransformationOutput()
309
+ (subject,) = query_result_row
310
+ row_output.remove_triples.append(cast(Triple, (subject, None, None)))
311
+ row_output.instances_removed_count = 1
312
+
313
+ return row_output
@@ -2,15 +2,16 @@ from typing import cast
2
2
  from urllib.parse import quote
3
3
 
4
4
  from rdflib import Graph, URIRef
5
+ from rdflib.query import ResultRow
5
6
 
6
7
  from cognite.neat._constants import DEFAULT_NAMESPACE
7
8
  from cognite.neat._rules.analysis import InformationAnalysis
8
9
  from cognite.neat._rules.models._rdfpath import RDFPath, SingleProperty
9
10
  from cognite.neat._rules.models.information import InformationRules
10
11
  from cognite.neat._shared import Triple
11
- from cognite.neat._utils.rdf_ import add_triples_in_batch, remove_namespace_from_uri
12
+ from cognite.neat._utils.rdf_ import remove_namespace_from_uri
12
13
 
13
- from ._base import BaseTransformer
14
+ from ._base import BaseTransformer, BaseTransformerStandardised, RowTransformationOutput
14
15
 
15
16
 
16
17
  class ReduceHopTraversal(BaseTransformer):
@@ -19,6 +20,7 @@ class ReduceHopTraversal(BaseTransformer):
19
20
  ...
20
21
 
21
22
 
23
+ # TODO: Standardise
22
24
  class AddSelfReferenceProperty(BaseTransformer):
23
25
  description: str = "Adds property that contains id of reference to all references of given class in Rules"
24
26
  _use_only_once: bool = True
@@ -56,17 +58,10 @@ class AddSelfReferenceProperty(BaseTransformer):
56
58
  property_.transformation = RDFPath(traversal=traversal)
57
59
 
58
60
 
59
- class MakeConnectionOnExactMatch(BaseTransformer):
61
+ class MakeConnectionOnExactMatch(BaseTransformerStandardised):
60
62
  description: str = "Adds property that contains id of reference to all references of given class in Rules"
61
63
  _use_only_once: bool = True
62
64
  _need_changes = frozenset({})
63
- _ref_template: str = """SELECT DISTINCT ?subject ?object
64
- WHERE {{
65
- ?subject a <{subject_type}> .
66
- ?subject <{subject_predicate}> ?value .
67
- ?object <{object_predicate}> ?value .
68
- ?object a <{object_type}> .
69
- }}"""
70
65
 
71
66
  def __init__(
72
67
  self,
@@ -90,20 +85,49 @@ class MakeConnectionOnExactMatch(BaseTransformer):
90
85
 
91
86
  self.limit = limit
92
87
 
93
- def transform(self, graph: Graph) -> None:
94
- query = self._ref_template.format(
88
+ def _iterate_query(self) -> str:
89
+ query = """SELECT DISTINCT ?subject ?object
90
+ WHERE {{
91
+ ?subject a <{subject_type}> .
92
+ ?subject <{subject_predicate}> ?value .
93
+ ?object <{object_predicate}> ?value .
94
+ ?object a <{object_type}> .
95
+ }}"""
96
+
97
+ if self.limit and isinstance(self.limit, int) and self.limit > 0:
98
+ query += f" LIMIT {self.limit}"
99
+
100
+ return query.format(
95
101
  subject_type=self.subject_type,
96
102
  subject_predicate=self.subject_predicate,
97
103
  object_type=self.object_type,
98
104
  object_predicate=self.object_predicate,
99
105
  )
100
106
 
107
+ def _count_query(self) -> str:
108
+ query = """SELECT (COUNT(DISTINCT (?subject ?object)) as ?count)
109
+ WHERE {{
110
+ ?subject a <{subject_type}> .
111
+ ?subject <{subject_predicate}> ?value .
112
+ ?object <{object_predicate}> ?value .
113
+ ?object a <{object_type}> .
114
+ }}"""
115
+
101
116
  if self.limit and isinstance(self.limit, int) and self.limit > 0:
102
117
  query += f" LIMIT {self.limit}"
103
118
 
104
- triples: list[Triple] = []
105
- for subject, object in graph.query(query): # type: ignore [misc]
106
- triples.append(cast(Triple, (subject, self.connection, object)))
119
+ return query.format(
120
+ subject_type=self.subject_type,
121
+ subject_predicate=self.subject_predicate,
122
+ object_type=self.object_type,
123
+ object_predicate=self.object_predicate,
124
+ )
125
+
126
+ def operation(self, query_result_row: ResultRow) -> RowTransformationOutput:
127
+ row_output = RowTransformationOutput()
128
+
129
+ subject, object = query_result_row
107
130
 
108
- print(f"Found {len(triples)} connections. Adding them to the graph...")
109
- add_triples_in_batch(graph, triples)
131
+ row_output.add_triples.append(cast(Triple, (subject, self.connection, object)))
132
+ row_output.instances_modified_count += 1
133
+ return row_output