orchestrator-core 4.5.0a2__py3-none-any.whl → 4.5.0a3__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.
Files changed (50) hide show
  1. orchestrator/__init__.py +1 -1
  2. orchestrator/api/api_v1/endpoints/search.py +13 -0
  3. orchestrator/devtools/populator.py +16 -0
  4. orchestrator/log_config.py +1 -0
  5. orchestrator/migrations/helpers.py +1 -1
  6. orchestrator/schemas/search.py +13 -0
  7. orchestrator/schemas/workflow.py +1 -0
  8. orchestrator/search/agent/__init__.py +13 -0
  9. orchestrator/search/agent/agent.py +13 -0
  10. orchestrator/search/agent/prompts.py +13 -0
  11. orchestrator/search/agent/state.py +13 -0
  12. orchestrator/search/agent/tools.py +27 -5
  13. orchestrator/search/core/__init__.py +12 -0
  14. orchestrator/search/core/embedding.py +13 -4
  15. orchestrator/search/core/exceptions.py +14 -0
  16. orchestrator/search/core/types.py +15 -0
  17. orchestrator/search/core/validators.py +13 -0
  18. orchestrator/search/filters/__init__.py +13 -0
  19. orchestrator/search/filters/base.py +23 -18
  20. orchestrator/search/filters/date_filters.py +13 -0
  21. orchestrator/search/filters/definitions.py +16 -2
  22. orchestrator/search/filters/ltree_filters.py +16 -3
  23. orchestrator/search/filters/numeric_filter.py +13 -0
  24. orchestrator/search/indexing/__init__.py +13 -0
  25. orchestrator/search/indexing/indexer.py +13 -0
  26. orchestrator/search/indexing/registry.py +13 -0
  27. orchestrator/search/indexing/tasks.py +13 -0
  28. orchestrator/search/indexing/traverse.py +17 -5
  29. orchestrator/search/retrieval/__init__.py +13 -0
  30. orchestrator/search/retrieval/builder.py +17 -7
  31. orchestrator/search/retrieval/engine.py +35 -29
  32. orchestrator/search/retrieval/exceptions.py +90 -0
  33. orchestrator/search/retrieval/pagination.py +13 -0
  34. orchestrator/search/retrieval/retrievers/__init__.py +26 -0
  35. orchestrator/search/retrieval/retrievers/base.py +122 -0
  36. orchestrator/search/retrieval/retrievers/fuzzy.py +94 -0
  37. orchestrator/search/retrieval/retrievers/hybrid.py +188 -0
  38. orchestrator/search/retrieval/retrievers/semantic.py +94 -0
  39. orchestrator/search/retrieval/retrievers/structured.py +39 -0
  40. orchestrator/search/retrieval/utils.py +21 -7
  41. orchestrator/search/retrieval/validation.py +54 -76
  42. orchestrator/search/schemas/__init__.py +12 -0
  43. orchestrator/search/schemas/parameters.py +13 -0
  44. orchestrator/search/schemas/results.py +14 -1
  45. orchestrator/workflows/tasks/validate_products.py +1 -1
  46. {orchestrator_core-4.5.0a2.dist-info → orchestrator_core-4.5.0a3.dist-info}/METADATA +2 -2
  47. {orchestrator_core-4.5.0a2.dist-info → orchestrator_core-4.5.0a3.dist-info}/RECORD +49 -43
  48. orchestrator/search/retrieval/retriever.py +0 -447
  49. {orchestrator_core-4.5.0a2.dist-info → orchestrator_core-4.5.0a3.dist-info}/WHEEL +0 -0
  50. {orchestrator_core-4.5.0a2.dist-info → orchestrator_core-4.5.0a3.dist-info}/licenses/LICENSE +0 -0
orchestrator/__init__.py CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  """This is the orchestrator workflow engine."""
15
15
 
16
- __version__ = "4.5.0a2"
16
+ __version__ = "4.5.0a3"
17
17
 
18
18
 
19
19
  from structlog import get_logger
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from typing import Any, Literal, overload
2
15
 
3
16
  from fastapi import APIRouter, HTTPException, Query, status
@@ -371,6 +371,22 @@ class Populator:
371
371
  self.log.info("Started modify workflow")
372
372
  return self._start_workflow(workflow_name, subscription_id=subscription_id, **kwargs)
373
373
 
374
+ def start_reconcile_workflow(self, workflow_name: str, subscription_id: UUIDstr | UUID, **kwargs: Any) -> UUIDstr:
375
+ """Start a reconcile workflow for the provided name and subscription_id.
376
+
377
+ Args:
378
+ workflow_name: workflow name
379
+ subscription_id: uuid of the subscription you want to modify
380
+ kwargs: values to be used as form input
381
+
382
+ Returns: the process_id of the workflow process
383
+
384
+ """
385
+ subscription_id = str(subscription_id)
386
+ self.log = self.log.bind(subscription_id=subscription_id)
387
+ self.log.info("Started reconcile workflow")
388
+ return self._start_workflow(workflow_name, subscription_id=subscription_id, **kwargs)
389
+
374
390
  def start_verify_workflow(self, workflow_name: str, subscription_id: UUIDstr | UUID) -> UUIDstr:
375
391
  subscription_id = str(subscription_id)
376
392
  self.log = self.log.bind(subscription_id=subscription_id)
@@ -44,5 +44,6 @@ LOGGER_OVERRIDES = dict(
44
44
  logger_config("orchestrator.graphql.autoregistration"),
45
45
  logger_config("sqlalchemy.engine", default_level="WARNING"),
46
46
  logger_config("uvicorn"),
47
+ logger_config("LiteLLM", default_level="WARNING"),
47
48
  ]
48
49
  )
@@ -155,7 +155,7 @@ def create_workflow(conn: sa.engine.Connection, workflow: dict) -> None:
155
155
  conn: DB connection as available in migration main file.
156
156
  workflow: Dict with data for a new workflow.
157
157
  name: Name of the workflow.
158
- target: Target of the workflow ("CREATE", "MODIFY", "TERMINATE", "SYSTEM")
158
+ target: Target of the workflow ("CREATE", "MODIFY", "RECONCILE", "TERMINATE", "SYSTEM")
159
159
  description: Description of the workflow.
160
160
  product_type: Product type to add the workflow to.
161
161
 
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from datetime import datetime
2
15
  from typing import Any, Generic, TypeVar
3
16
  from uuid import UUID
@@ -60,6 +60,7 @@ class SubscriptionWorkflowListsSchema(OrchestratorBaseModel):
60
60
  modify: list[WorkflowListItemSchema]
61
61
  terminate: list[WorkflowListItemSchema]
62
62
  system: list[WorkflowListItemSchema]
63
+ reconcile: list[WorkflowListItemSchema]
63
64
  validate_: list[WorkflowListItemSchema] = Field(default_factory=list, alias="validate")
64
65
 
65
66
 
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  # This module requires: pydantic-ai==0.7.0, ag-ui-protocol>=0.1.8
2
15
 
3
16
 
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from typing import Any
2
15
 
3
16
  import structlog
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  import json
2
15
  from textwrap import dedent
3
16
 
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from typing import Any
2
15
 
3
16
  from pydantic import BaseModel, Field
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from collections.abc import Awaitable, Callable
2
15
  from typing import Any, TypeVar
3
16
 
@@ -20,6 +33,7 @@ from orchestrator.api.api_v1.endpoints.search import (
20
33
  from orchestrator.schemas.search import SearchResultsSchema
21
34
  from orchestrator.search.core.types import ActionType, EntityType, FilterOp
22
35
  from orchestrator.search.filters import FilterTree
36
+ from orchestrator.search.retrieval.exceptions import FilterValidationError, PathNotFoundError
23
37
  from orchestrator.search.retrieval.validation import validate_filter_tree
24
38
  from orchestrator.search.schemas.parameters import PARAMETER_REGISTRY, BaseSearchParameters
25
39
 
@@ -110,9 +124,16 @@ async def set_filter_tree(
110
124
 
111
125
  try:
112
126
  await validate_filter_tree(filters, entity_type)
113
- except Exception as e:
114
- # TODO: Define specific filter validation exceptions and catch them instructing what should change.
127
+ except PathNotFoundError as e:
128
+ logger.debug(f"{PathNotFoundError.__name__}: {str(e)}")
129
+ raise ModelRetry(f"{str(e)} Use discover_filter_paths tool to find valid paths.")
130
+ except FilterValidationError as e:
131
+ # ModelRetry will trigger an agent retry, containing the specific validation error.
132
+ logger.debug(f"Filter validation failed: {str(e)}")
115
133
  raise ModelRetry(str(e))
134
+ except Exception as e:
135
+ logger.error("Unexpected Filter validation exception", error=str(e))
136
+ raise ModelRetry(f"Filter validation failed: {str(e)}. Please check your filter structure and try again.")
116
137
 
117
138
  filter_data = None if filters is None else filters.model_dump(mode="json", by_alias=True)
118
139
  ctx.deps.state.parameters["filters"] = filter_data
@@ -122,7 +143,7 @@ async def set_filter_tree(
122
143
  @search_toolset.tool
123
144
  async def execute_search(
124
145
  ctx: RunContext[StateDeps[SearchState]],
125
- limit: int = 5,
146
+ limit: int = 10,
126
147
  ) -> StateSnapshotEvent:
127
148
  """Execute the search with the current parameters."""
128
149
  if not ctx.deps.state.parameters:
@@ -146,16 +167,17 @@ async def execute_search(
146
167
  if params.filters:
147
168
  logger.debug("Search filters", filters=params.filters)
148
169
 
170
+ params.limit = limit
171
+
149
172
  fn = SEARCH_FN_MAP[entity_type]
150
173
  search_results = await fn(params)
151
174
 
152
175
  logger.debug(
153
176
  "Search completed",
154
177
  total_results=len(search_results.data) if search_results.data else 0,
155
- limited_to=limit,
156
178
  )
157
179
 
158
- ctx.deps.state.results = search_results.data[:limit]
180
+ ctx.deps.state.results = search_results.data
159
181
 
160
182
  return StateSnapshotEvent(type=EventType.STATE_SNAPSHOT, snapshot=ctx.deps.state.model_dump())
161
183
 
@@ -0,0 +1,12 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
@@ -1,4 +1,16 @@
1
- import logging
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
2
14
 
3
15
  import structlog
4
16
  from litellm import aembedding as llm_aembedding
@@ -9,9 +21,6 @@ from orchestrator.llm_settings import llm_settings
9
21
 
10
22
  logger = structlog.get_logger(__name__)
11
23
 
12
- # Its logging alot of noise such as embedding vectors.
13
- logging.getLogger("LiteLLM").setLevel(logging.WARNING)
14
-
15
24
 
16
25
  class EmbeddingIndexer:
17
26
 
@@ -1,3 +1,17 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
14
+
1
15
  class SearchUtilsError(Exception):
2
16
  """Base exception for this module."""
3
17
 
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from dataclasses import dataclass
2
15
  from datetime import date, datetime
3
16
  from enum import Enum, IntEnum
@@ -14,6 +27,8 @@ from .validators import is_bool_string, is_iso_date, is_uuid
14
27
 
15
28
  SQLAColumn: TypeAlias = ColumnElement[Any] | InstrumentedAttribute[Any]
16
29
 
30
+ LTREE_SEPARATOR = "."
31
+
17
32
 
18
33
  @dataclass
19
34
  class SearchMetadata:
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  import uuid
2
15
 
3
16
  from dateutil.parser import isoparse
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from .base import (
2
15
  EqualityFilter,
3
16
  FilterCondition,
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from __future__ import annotations
2
15
 
3
16
  from itertools import count
@@ -123,18 +136,14 @@ class PathFilter(BaseModel):
123
136
  This method creates a type guard to ensure we only match compatible field types,
124
137
  then delegates to the specific filter condition.
125
138
 
126
- Parameters
127
- ----------
128
- value_column : ColumnElement
129
- The SQLAlchemy column element representing the value to be filtered.
130
- value_type_column : ColumnElement
131
- The SQLAlchemy column element representing the field type.
139
+ Args:
140
+ value_column (ColumnElement): The SQLAlchemy column element representing the value to be filtered.
141
+ value_type_column (ColumnElement): The SQLAlchemy column element representing the field type.
132
142
 
133
143
  Returns:
134
- -------
135
- ColumnElement[bool]
136
- A SQLAlchemy boolean expression that can be used in a ``WHERE`` clause.
144
+ ColumnElement[bool]: A SQLAlchemy boolean expression that can be used in a ``WHERE`` clause.
137
145
  """
146
+
138
147
  # Type guard - only match compatible field types
139
148
  allowed_field_types = [ft.value for ft in FieldType if UIType.from_field_type(ft) == self.value_kind]
140
149
  type_guard = value_type_column.in_(allowed_field_types) if allowed_field_types else literal(True)
@@ -225,18 +234,14 @@ class FilterTree(BaseModel):
225
234
  ) -> ColumnElement[bool]:
226
235
  """Compile this tree into a SQLAlchemy boolean expression.
227
236
 
228
- Parameters
229
- ----------
230
- entity_id_col : SQLAColumn
231
- Column in the outer query representing the entity ID.
232
- entity_type_value : str, optional
233
- If provided, each subquery is additionally constrained to this entity type.
237
+ Args:
238
+ entity_id_col (SQLAColumn): Column in the outer query representing the entity ID.
239
+ entity_type_value (str, optional): If provided, each subquery is additionally constrained to this entity type.
234
240
 
235
241
  Returns:
236
- -------
237
- ColumnElement[bool]
238
- A SQLAlchemy expression suitable for use in a WHERE clause.
242
+ ColumnElement[bool]: A SQLAlchemy expression suitable for use in a WHERE clause.
239
243
  """
244
+
240
245
  alias_idx = count(1)
241
246
 
242
247
  def leaf_exists(pf: PathFilter) -> ColumnElement[bool]:
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from datetime import date, datetime
2
15
  from typing import Annotated, Any, Literal
3
16
 
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from orchestrator.search.core.types import FieldType, FilterOp, UIType
2
15
  from orchestrator.search.schemas.results import TypeDefinition, ValueSchema
3
16
 
@@ -60,6 +73,7 @@ def value_schema_for(ft: FieldType) -> dict[FilterOp, ValueSchema]:
60
73
  return {
61
74
  FilterOp.EQ: ValueSchema(kind=UIType.STRING),
62
75
  FilterOp.NEQ: ValueSchema(kind=UIType.STRING),
76
+ FilterOp.LIKE: ValueSchema(kind=UIType.STRING),
63
77
  }
64
78
 
65
79
 
@@ -73,7 +87,7 @@ def generate_definitions() -> dict[UIType, TypeDefinition]:
73
87
  comp_ops = component_operators()
74
88
  definitions[ui_type] = TypeDefinition(
75
89
  operators=list(comp_ops.keys()),
76
- valueSchema=comp_ops,
90
+ value_schema=comp_ops,
77
91
  )
78
92
  else:
79
93
  # Regular field types
@@ -88,6 +102,6 @@ def generate_definitions() -> dict[UIType, TypeDefinition]:
88
102
 
89
103
  definitions[ui_type] = TypeDefinition(
90
104
  operators=operators_for(rep_ft),
91
- valueSchema=value_schema_for(rep_ft),
105
+ value_schema=value_schema_for(rep_ft),
92
106
  )
93
107
  return definitions
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from typing import Literal
2
15
 
3
16
  from pydantic import BaseModel, Field
@@ -5,7 +18,7 @@ from sqlalchemy import TEXT, bindparam
5
18
  from sqlalchemy.sql.elements import ColumnElement
6
19
  from sqlalchemy_utils.types.ltree import Ltree
7
20
 
8
- from orchestrator.search.core.types import FilterOp, SQLAColumn
21
+ from orchestrator.search.core.types import LTREE_SEPARATOR, FilterOp, SQLAColumn
9
22
 
10
23
 
11
24
  class LtreeFilter(BaseModel):
@@ -38,6 +51,6 @@ class LtreeFilter(BaseModel):
38
51
  ltree_value = Ltree(path)
39
52
  return column == ltree_value
40
53
  case FilterOp.HAS_COMPONENT | FilterOp.NOT_HAS_COMPONENT:
41
- return column.op("~")(bindparam(None, f"*.{self.value}.*", type_=TEXT))
54
+ return column.op("~")(bindparam(None, f"*{LTREE_SEPARATOR}{self.value}{LTREE_SEPARATOR}*", type_=TEXT))
42
55
  case FilterOp.ENDS_WITH:
43
- return column.op("~")(bindparam(None, f"*.{self.value}", type_=TEXT))
56
+ return column.op("~")(bindparam(None, f"*{LTREE_SEPARATOR}{self.value}", type_=TEXT))
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from typing import Annotated, Any, Literal
2
15
 
3
16
  from pydantic import BaseModel, Field, model_validator
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from .tasks import run_indexing_for_entity
2
15
 
3
16
  __all__ = ["run_indexing_for_entity"]
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  import hashlib
2
15
  from collections.abc import Generator, Iterable, Iterator
3
16
  from contextlib import contextmanager, nullcontext
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  from dataclasses import dataclass
2
15
  from typing import Generic, TypeVar
3
16
  from uuid import UUID
@@ -1,3 +1,16 @@
1
+ # Copyright 2019-2025 SURF, GÉANT.
2
+ # Licensed under the Apache License, Version 2.0 (the "License");
3
+ # you may not use this file except in compliance with the License.
4
+ # You may obtain a copy of the License at
5
+ #
6
+ # http://www.apache.org/licenses/LICENSE-2.0
7
+ #
8
+ # Unless required by applicable law or agreed to in writing, software
9
+ # distributed under the License is distributed on an "AS IS" BASIS,
10
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ # See the License for the specific language governing permissions and
12
+ # limitations under the License.
13
+
1
14
  import structlog
2
15
  from sqlalchemy.orm import Query
3
16