Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PYG-53, PYG-55, PYG-47] Query across direct relations #119

Merged
merged 65 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
de7a305
tests: Wrote failing test for quering across direct relation
doctrino Nov 28, 2023
6b97659
refactor: fix query to match
doctrino Nov 28, 2023
a2ba35c
build; SDK to 7.5
doctrino Dec 1, 2023
027cdf9
refactor; implementation for actor for direct relation query
doctrino Dec 2, 2023
4fb44bc
build: changelog
doctrino Dec 2, 2023
fca9739
refactor: move query step into init method of Query class
doctrino Dec 2, 2023
db9c0a9
refactor; update equipment module example
doctrino Dec 2, 2023
c8afc52
refactor: New equipment unit 2 example
doctrino Dec 2, 2023
288e604
refactor: Finish actor example
doctrino Dec 2, 2023
b6694e3
refactor: Update equipment module to multi edges
doctrino Dec 2, 2023
ceb5411
feat; Generate new api core file
doctrino Dec 2, 2023
d4bed55
refactor: Update all versions
doctrino Dec 2, 2023
e1d1a64
refactor: fix data class
doctrino Dec 2, 2023
bc308f3
refactor: new api class generation
doctrino Dec 2, 2023
e4fe21a
refactor; new query class
doctrino Dec 2, 2023
108ba43
tests: Added api class test for equipment unit
doctrino Dec 2, 2023
1f30584
fix: Generator to not generate api for edges
doctrino Dec 2, 2023
7eaafd5
refactor: avoid generation of EdgeDataClasses
doctrino Dec 2, 2023
5f4d935
refactor: working on new generation code
doctrino Dec 2, 2023
a7940cb
refactor: fix tests and avoid bug in node class
doctrino Dec 2, 2023
cbce535
refactor: Regenerate SDK
doctrino Dec 2, 2023
68cd732
refactor: upgrade example
doctrino Dec 2, 2023
a67712a
refactor: Update query example
doctrino Dec 2, 2023
160c25e
refactor: wip for refactoring _core
doctrino Dec 2, 2023
985f06f
refactor; cleanup fields
doctrino Dec 3, 2023
8f348a5
refactor: Cleanup data classes
doctrino Dec 3, 2023
a511b20
refactor: Firt pass of fields
doctrino Dec 3, 2023
b808fb7
refactor: fix lookup timeseries field
doctrino Dec 3, 2023
1b2e253
refactor: Reimplement duplicated view handling
doctrino Dec 3, 2023
e7b91c9
refactor: rename view name to base name
doctrino Dec 3, 2023
6d74b16
tests: Run test to assert
doctrino Dec 3, 2023
5ea92a5
style: fix linting
doctrino Dec 3, 2023
67cf94e
refactor: First generation test passed
doctrino Dec 3, 2023
31bcf6a
tests: update tests
doctrino Dec 3, 2023
23bf258
refactor: First pass data class for nodes
doctrino Dec 3, 2023
2417bc0
refactor: finish gen node data class
doctrino Dec 3, 2023
dc99a9f
fix: naming
doctrino Dec 3, 2023
8694af6
refactor; first pass of API class
doctrino Dec 3, 2023
59459ac
refactor: Generate timeseries
doctrino Dec 4, 2023
0825948
refactor: Generate api node round 2
doctrino Dec 4, 2023
27e6dee
feat: first passs data class edge
doctrino Dec 4, 2023
e1f5d3d
refactor: EdgeAPIclass match use
doctrino Dec 5, 2023
9254a94
refactor: Running edge api
doctrino Dec 5, 2023
f9346ed
refactor: Running edge api
doctrino Dec 5, 2023
dfe08b9
refactor: Running edge api
doctrino Dec 5, 2023
703ce7a
refactor: Generate Edge api with new class
doctrino Dec 5, 2023
59d8400
refactor; Storing progress
doctrino Dec 5, 2023
13c98b7
refactor; Generating query api class
doctrino Dec 5, 2023
05e8b73
refactor: Fix renaming
doctrino Dec 5, 2023
546f1c2
refactor; Generate init file
doctrino Dec 5, 2023
28e16e0
refactor: Finish equipment module gen tests
doctrino Dec 5, 2023
b3b1182
refactor: cleanup'
doctrino Dec 5, 2023
765b9ce
refactor: Minor cleanup
doctrino Dec 5, 2023
26952cc
tests: update tests
doctrino Dec 5, 2023
b6d9e5a
refactor: gen multi api client
doctrino Dec 5, 2023
6a906eb
refactor: Generate multi api
doctrino Dec 5, 2023
10d1947
refactor: fix some minor bugs
doctrino Dec 5, 2023
7c84395
refactor: Regen v2 SDKs
doctrino Dec 5, 2023
8e6b1d1
tests: updated test data
doctrino Dec 5, 2023
2012fa6
refactor; regen v2 SDKs
doctrino Dec 5, 2023
9de121b
refactor; regen v2 SDKs
doctrino Dec 5, 2023
a3b028d
fix; Bug in unpack
doctrino Dec 6, 2023
27dbb62
docs: Updated documentation
doctrino Dec 6, 2023
0e1a211
build: bump
doctrino Dec 6, 2023
8a8fc50
build; added to changelog
doctrino Dec 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1,354 changes: 0 additions & 1,354 deletions cognite/pygen/_core/data_classes.py

This file was deleted.

493 changes: 318 additions & 175 deletions cognite/pygen/_core/generators.py

Large diffs are not rendered by default.

73 changes: 0 additions & 73 deletions cognite/pygen/_core/logic.py

This file was deleted.

37 changes: 37 additions & 0 deletions cognite/pygen/_core/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from .api_casses import APIClass, MultiAPIClass
from .data_classes import DataClass, EdgeDataClass, NodeDataClass
from .fields import (
CDFExternalField,
EdgeField,
EdgeOneToEndNode,
EdgeOneToMany,
EdgeOneToManyNodes,
EdgeOneToOne,
Field,
PrimitiveField,
PrimitiveFieldCore,
PrimitiveListField,
)
from .filter_method import FilterCondition, FilterConditionOnetoOneEdge, FilterMethod, FilterParameter

__all__ = [
"DataClass",
"APIClass",
"MultiAPIClass",
"NodeDataClass",
"EdgeDataClass",
"Field",
"PrimitiveFieldCore",
"PrimitiveField",
"CDFExternalField",
"EdgeField",
"EdgeOneToManyNodes",
"EdgeOneToOne",
"EdgeOneToEndNode",
"PrimitiveListField",
"FilterMethod",
"FilterParameter",
"FilterCondition",
"FilterConditionOnetoOneEdge",
"EdgeOneToMany",
]
217 changes: 217 additions & 0 deletions cognite/pygen/_core/models/api_casses.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
from __future__ import annotations

from collections.abc import Iterator
from dataclasses import dataclass

from cognite.client.data_classes import data_modeling as dm

from cognite.pygen import config as pygen_config
from cognite.pygen.utils.text import create_name

from .data_classes import DataClass, EdgeDataClass
from .fields import CDFExternalField, EdgeOneToMany, EdgeOneToManyEdges, EdgeOneToManyNodes
from .filter_method import FilterMethod, FilterParameter


@dataclass(frozen=True)
class APIClass:
parent_attribute: str
name: str
file_name: str


@dataclass(frozen=True)
class NodeAPIClass(APIClass):
is_edge_class: bool
view_id: dm.ViewId

@classmethod
def from_view(
cls, view_id: dm.ViewId, base_name: str, is_edge_class: bool, api_class: pygen_config.APIClassNaming
) -> NodeAPIClass:
file_name = create_name(base_name, api_class.file_name)
class_name = create_name(base_name, api_class.name)
return cls(
parent_attribute=create_name(base_name, api_class.client_attribute),
name=f"{class_name}API",
file_name=file_name,
is_edge_class=is_edge_class,
view_id=view_id,
)


@dataclass(frozen=True)
class QueryAPIClass(APIClass):
data_class: DataClass

@classmethod
def create(cls, data_class: DataClass, base_name: str, api_class: pygen_config.APIClassNaming) -> QueryAPIClass:
file_name = create_name(base_name, api_class.file_name)
class_name = create_name(base_name, api_class.name)
parent_attribute = create_name(base_name, api_class.client_attribute)
return cls(
parent_attribute=f"{parent_attribute}_query", # Not used.
name=f"{class_name}QueryAPI",
file_name=f"{file_name}_query",
data_class=data_class,
)


@dataclass(frozen=True)
class EdgeAPIClass(APIClass):
start_class: DataClass
end_class: DataClass
edge_class: DataClass | None
field_name: str
type: dm.DirectRelationReference
filter_method: FilterMethod
doc_name: str
query: QueryAPIClass

@property
def has_edge_class(self) -> bool:
return self.edge_class is not None

def filter_parameters(self, include_nodes: bool = True) -> Iterator[FilterParameter]:
if include_nodes:
yield FilterParameter(
name=f"from_{self.start_class.variable}",
type_="str | list[str] | dm.NodeId | list[dm.NodeId]",
description=f"ID of the source { self.start_class.doc_name}.",
default=None,
)
yield FilterParameter(
name=f"from_{self.start_class.variable}_space",
type_="str",
description=f"Location of the {self.start_class.doc_list_name}.",
default="DEFAULT_INSTANCE_SPACE",
is_nullable=False,
)
yield FilterParameter(
name=f"to_{self.end_class.variable}",
type_="str | list[str] | dm.NodeId | list[dm.NodeId]",
description=f"ID of the target { self.end_class.doc_name}.",
default=None,
)
yield FilterParameter(
name=f"to_{self.end_class.variable}_space",
type_="str",
description=f"Location of the {self.end_class.doc_list_name}.",
default="DEFAULT_INSTANCE_SPACE",
is_nullable=False,
)
yield from self.filter_method.parameters

@classmethod
def from_fields(
cls,
field: EdgeOneToMany,
data_class: DataClass,
base_name: str,
query_class_by_view_id: dict[dm.ViewId, QueryAPIClass],
pygen_config: pygen_config.PygenConfig,
) -> EdgeAPIClass:
api_class = pygen_config.naming.api_class
base_name = f"{base_name}_{field.name}"
file_name = create_name(base_name, api_class.file_name)
class_name = create_name(base_name, api_class.name)
parent_attribute = create_name(field.name, api_class.client_attribute)

edge_class: DataClass | None
end_class: DataClass
if isinstance(field, EdgeOneToManyEdges):
edge_class = field.data_class
if not isinstance(edge_class, EdgeDataClass):
raise ValueError("Expected EdgeOneToManyEdges")
try:
end_class = next(
c.end_class for c in edge_class.end_node_field.edge_classes if c.edge_type == field.edge_type
)
except StopIteration:
raise ValueError("Could not find end class") from None
filter_method = FilterMethod.from_fields(edge_class.fields, pygen_config.filtering, is_edge_class=True)
elif isinstance(field, EdgeOneToManyNodes):
edge_class = None
end_class = field.data_class
filter_method = FilterMethod.from_fields([], pygen_config.filtering)
else:
raise ValueError(f"Expected EdgeOneToMany: {type(field)}")

return cls(
parent_attribute=f"{parent_attribute}_edge",
name=f"{class_name}API",
file_name=file_name,
edge_class=edge_class,
field_name=field.name,
type=field.edge_type,
start_class=data_class,
end_class=end_class,
filter_method=filter_method,
doc_name=create_name(field.name, api_class.doc_name),
query=query_class_by_view_id[end_class.view_id],
)


@dataclass(frozen=True)
class TimeSeriesAPIClass(APIClass):
query_class: str
prop_name: str
variable: str

@classmethod
def from_field(
cls, field: CDFExternalField, base_name: str, api_class: pygen_config.APIClassNaming
) -> TimeSeriesAPIClass:
base_name = f"{base_name}_{field.name}"
file_name = create_name(base_name, api_class.file_name)
class_name = create_name(base_name, api_class.name)
parent_attribute = create_name(field.name, api_class.client_attribute)
variable = create_name(field.name, api_class.variable)

return cls(
parent_attribute=f"{parent_attribute}",
name=f"{class_name}API",
file_name=f"{file_name}",
query_class=f"{class_name}Query",
prop_name=field.prop_name,
variable=variable,
)


@dataclass(frozen=True)
class MultiAPIClass:
"""
This represents a set of APIs which are generated from a single data model.

The motivation for having this class is the case when you want to create one SDK for multiple data models.
"""

sub_apis_by_view_id: dict[dm.ViewId, APIClass]
parent_attribute: str
name: str
model: dm.DataModel[dm.View]

@property
def model_id(self) -> dm.DataModelId:
return self.model.as_id()

@classmethod
def from_data_model(
cls,
data_model: dm.DataModel[dm.View],
api_class_by_view_id: dict[dm.ViewId, APIClass],
multi_api_class: pygen_config.MultiAPIClassNaming,
) -> MultiAPIClass:
sub_apis: dict[dm.ViewId, APIClass] = {}
for view in sorted(data_model.views, key=lambda v: (v.name or v.external_id, v.space, v.version)):
if view.as_id() in api_class_by_view_id:
sub_apis[view.as_id()] = api_class_by_view_id[view.as_id()]

data_model_name = data_model.name or data_model.external_id

return cls(
sub_apis_by_view_id=sub_apis,
parent_attribute=create_name(data_model_name, multi_api_class.client_attribute),
name=f"{create_name(data_model_name, multi_api_class.name)}APIs",
model=data_model,
)
Loading