diff --git a/changelog/+86c0992a.added.md b/changelog/+86c0992a.added.md new file mode 100644 index 00000000..1e53de4b --- /dev/null +++ b/changelog/+86c0992a.added.md @@ -0,0 +1 @@ +Added ability to order nodes by metadata created_at or updated_at fields diff --git a/infrahub_sdk/enums.py b/infrahub_sdk/enums.py new file mode 100644 index 00000000..75219825 --- /dev/null +++ b/infrahub_sdk/enums.py @@ -0,0 +1,6 @@ +from enum import Enum + + +class OrderDirection(str, Enum): + ASC = "ASC" + DESC = "DESC" diff --git a/infrahub_sdk/graphql/renderers.py b/infrahub_sdk/graphql/renderers.py index 3cd3e557..91b77526 100644 --- a/infrahub_sdk/graphql/renderers.py +++ b/infrahub_sdk/graphql/renderers.py @@ -7,6 +7,8 @@ from pydantic import BaseModel +from infrahub_sdk.types import Order + from .constants import VARIABLE_TYPE_MAPPING @@ -53,6 +55,16 @@ def convert_to_graphql_as_string(value: Any, convert_enum: bool = False) -> str: if isinstance(value, list): values_as_string = [convert_to_graphql_as_string(value=item, convert_enum=convert_enum) for item in value] return "[" + ", ".join(values_as_string) + "]" + if isinstance(value, Order): + data = value.model_dump(exclude_none=True) + return ( + "{ " + + ", ".join( + f"{key}: {convert_to_graphql_as_string(value=val, convert_enum=convert_enum)}" + for key, val in data.items() + ) + + " }" + ) if isinstance(value, BaseModel): data = value.model_dump() return ( @@ -63,6 +75,15 @@ def convert_to_graphql_as_string(value: Any, convert_enum: bool = False) -> str: ) + " }" ) + if isinstance(value, dict): + return ( + "{ " + + ", ".join( + f"{key}: {convert_to_graphql_as_string(value=val, convert_enum=convert_enum)}" + for key, val in value.items() + ) + + " }" + ) return str(value) diff --git a/infrahub_sdk/types.py b/infrahub_sdk/types.py index 666bb71c..59cbedef 100644 --- a/infrahub_sdk/types.py +++ b/infrahub_sdk/types.py @@ -4,7 +4,9 @@ from logging import Logger from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable -from pydantic import BaseModel +from pydantic import BaseModel, Field, model_validator + +from infrahub_sdk.enums import OrderDirection # noqa: TC001 if TYPE_CHECKING: import httpx @@ -68,5 +70,19 @@ def exception(self, event: str | None = None, *args: Any, **kw: Any) -> Any: InfrahubLoggers = InfrahubLogger | Logger +class NodeMetaOrder(BaseModel): + created_at: OrderDirection | None = None + updated_at: OrderDirection | None = None + + @model_validator(mode="after") + def validate_selection(self) -> NodeMetaOrder: + if self.created_at and self.updated_at: + raise ValueError("'created_at' and 'updated_at' are mutually exclusive") + return self + + class Order(BaseModel): - disable: bool | None = None + disable: bool | None = Field( + default=None, description="Disable default ordering, can be used to improve performance" + ) + node_metadata: NodeMetaOrder | None = Field(default=None, description="Order by node meta fields")