orchestrator-core 4.5.0a2__py3-none-any.whl → 4.5.0a4__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.
- orchestrator/__init__.py +1 -1
- orchestrator/api/api_v1/api.py +7 -5
- orchestrator/api/api_v1/endpoints/search.py +13 -0
- orchestrator/devtools/populator.py +16 -0
- orchestrator/log_config.py +1 -0
- orchestrator/migrations/helpers.py +1 -1
- orchestrator/schemas/search.py +13 -0
- orchestrator/schemas/workflow.py +1 -0
- orchestrator/search/agent/__init__.py +13 -0
- orchestrator/search/agent/agent.py +13 -0
- orchestrator/search/agent/prompts.py +13 -0
- orchestrator/search/agent/state.py +13 -0
- orchestrator/search/agent/tools.py +27 -5
- orchestrator/search/core/__init__.py +12 -0
- orchestrator/search/core/embedding.py +13 -4
- orchestrator/search/core/exceptions.py +14 -0
- orchestrator/search/core/types.py +15 -0
- orchestrator/search/core/validators.py +13 -0
- orchestrator/search/filters/__init__.py +13 -0
- orchestrator/search/filters/base.py +23 -18
- orchestrator/search/filters/date_filters.py +13 -0
- orchestrator/search/filters/definitions.py +16 -2
- orchestrator/search/filters/ltree_filters.py +16 -3
- orchestrator/search/filters/numeric_filter.py +13 -0
- orchestrator/search/indexing/__init__.py +13 -0
- orchestrator/search/indexing/indexer.py +13 -0
- orchestrator/search/indexing/registry.py +13 -0
- orchestrator/search/indexing/tasks.py +13 -0
- orchestrator/search/indexing/traverse.py +17 -5
- orchestrator/search/retrieval/__init__.py +13 -0
- orchestrator/search/retrieval/builder.py +17 -7
- orchestrator/search/retrieval/engine.py +35 -29
- orchestrator/search/retrieval/exceptions.py +90 -0
- orchestrator/search/retrieval/pagination.py +13 -0
- orchestrator/search/retrieval/retrievers/__init__.py +26 -0
- orchestrator/search/retrieval/retrievers/base.py +122 -0
- orchestrator/search/retrieval/retrievers/fuzzy.py +94 -0
- orchestrator/search/retrieval/retrievers/hybrid.py +188 -0
- orchestrator/search/retrieval/retrievers/semantic.py +94 -0
- orchestrator/search/retrieval/retrievers/structured.py +39 -0
- orchestrator/search/retrieval/utils.py +21 -7
- orchestrator/search/retrieval/validation.py +54 -76
- orchestrator/search/schemas/__init__.py +12 -0
- orchestrator/search/schemas/parameters.py +13 -0
- orchestrator/search/schemas/results.py +14 -1
- orchestrator/workflows/steps.py +15 -1
- orchestrator/workflows/tasks/validate_products.py +1 -1
- {orchestrator_core-4.5.0a2.dist-info → orchestrator_core-4.5.0a4.dist-info}/METADATA +6 -6
- {orchestrator_core-4.5.0a2.dist-info → orchestrator_core-4.5.0a4.dist-info}/RECORD +51 -45
- orchestrator/search/retrieval/retriever.py +0 -447
- {orchestrator_core-4.5.0a2.dist-info → orchestrator_core-4.5.0a4.dist-info}/WHEEL +0 -0
- {orchestrator_core-4.5.0a2.dist-info → orchestrator_core-4.5.0a4.dist-info}/licenses/LICENSE +0 -0
orchestrator/__init__.py
CHANGED
orchestrator/api/api_v1/api.py
CHANGED
|
@@ -76,20 +76,22 @@ api_router.include_router(user.router, prefix="/user", tags=["Core", "User"], de
|
|
|
76
76
|
api_router.include_router(
|
|
77
77
|
settings.router, prefix="/settings", tags=["Core", "Settings"], dependencies=[Depends(authorize)]
|
|
78
78
|
)
|
|
79
|
-
api_router.include_router(
|
|
79
|
+
api_router.include_router(
|
|
80
|
+
settings.ws_router, prefix="/settings", tags=["Core", "Settings"]
|
|
81
|
+
) # Auth on the websocket is handled in the Websocket Manager
|
|
80
82
|
api_router.include_router(health.router, prefix="/health", tags=["Core"])
|
|
81
83
|
api_router.include_router(
|
|
82
84
|
translations.router,
|
|
83
85
|
prefix="/translations",
|
|
84
86
|
tags=["Core", "Translations"],
|
|
85
87
|
)
|
|
86
|
-
api_router.include_router(
|
|
88
|
+
api_router.include_router(
|
|
89
|
+
ws.router, prefix="/ws", tags=["Core", "Events"]
|
|
90
|
+
) # Auth on the websocket is handled in the Websocket Manager
|
|
87
91
|
|
|
88
92
|
if llm_settings.LLM_ENABLED:
|
|
89
93
|
from orchestrator.api.api_v1.endpoints import search
|
|
90
94
|
|
|
91
95
|
api_router.include_router(
|
|
92
|
-
search.router,
|
|
93
|
-
prefix="/search",
|
|
94
|
-
tags=["Core", "Search"],
|
|
96
|
+
search.router, prefix="/search", tags=["Core", "Search"], dependencies=[Depends(authorize)]
|
|
95
97
|
)
|
|
@@ -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)
|
orchestrator/log_config.py
CHANGED
|
@@ -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
|
|
orchestrator/schemas/search.py
CHANGED
|
@@ -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
|
orchestrator/schemas/workflow.py
CHANGED
|
@@ -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
|
|
114
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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"
|
|
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"
|
|
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
|
|