diff --git a/.idea/watcherTasks.xml b/.idea/watcherTasks.xml index 88b542c3d5..6df1a76d86 100644 --- a/.idea/watcherTasks.xml +++ b/.idea/watcherTasks.xml @@ -22,4 +22,4 @@ - \ No newline at end of file + diff --git a/CHANGELOG.md b/CHANGELOG.md index c43dd73898..5fa758b90f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,13 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm +## 0.8.0 (2024-06-11) + + +### Improvements + +- Add search relation support (Allow to to run a search query to find the relation to the entity as part of the mapping) + ## 0.7.1 (2024-06-13) diff --git a/port_ocean/core/handlers/entity_processor/jq_entity_processor.py b/port_ocean/core/handlers/entity_processor/jq_entity_processor.py index 24f46d4369..449ac93e34 100644 --- a/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +++ b/port_ocean/core/handlers/entity_processor/jq_entity_processor.py @@ -1,5 +1,6 @@ import asyncio import functools +from asyncio import Task from dataclasses import dataclass, field from functools import lru_cache from typing import Any, Optional @@ -70,9 +71,13 @@ async def _search_as_bool(self, data: dict[str, Any], pattern: str) -> bool: async def _search_as_object( self, data: dict[str, Any], obj: dict[str, Any] ) -> dict[str, Any | None]: - search_tasks = {} + search_tasks: dict[str,Task[dict[str,Any | None]] | list[Task[dict[str,Any | None]]]] = {} for key, value in obj.items(): - if isinstance(value, dict): + + if isinstance(value,list): + search_tasks[key] = [asyncio.create_task(self._search_as_object(data,obj)) for obj in value] + + elif isinstance(value, dict): search_tasks[key] = asyncio.create_task( self._search_as_object(data, value) ) @@ -82,7 +87,10 @@ async def _search_as_object( result: dict[str, Any | None] = {} for key, task in search_tasks.items(): try: - result[key] = await task + if isinstance(task,list): + result[key] = [await task for task in task] + else: + result[key] = await task except Exception: result[key] = None diff --git a/port_ocean/core/handlers/port_app_config/models.py b/port_ocean/core/handlers/port_app_config/models.py index a608d293a9..7130241181 100644 --- a/port_ocean/core/handlers/port_app_config/models.py +++ b/port_ocean/core/handlers/port_app_config/models.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from typing import Any from pydantic import BaseModel, Field @@ -5,19 +7,31 @@ from port_ocean.clients.port.types import RequestOptions +class Rule(BaseModel): + property: str + operator: str + value: str + + +class SearchRelation(BaseModel): + combinator: str + rules: list[Rule | SearchRelation] + + class EntityMapping(BaseModel): identifier: str title: str | None blueprint: str team: str | None properties: dict[str, str] = Field(default_factory=dict) - relations: dict[str, str] = Field(default_factory=dict) + relations: dict[str, str | SearchRelation] = Field(default_factory=dict) -class PortResourceConfig(BaseModel): - class MappingsConfig(BaseModel): - mappings: EntityMapping +class MappingsConfig(BaseModel): + mappings: EntityMapping + +class PortResourceConfig(BaseModel): entity: MappingsConfig items_to_parse: str | None = Field(alias="itemsToParse") diff --git a/pyproject.toml b/pyproject.toml index 48ed47ffcf..4556263212 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "port-ocean" -version = "0.7.1" +version = "0.8.0" description = "Port Ocean is a CLI tool for managing your Port projects." readme = "README.md" homepage = "https://app.getport.io"