julee 0.1.0__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.
- julee/__init__.py +3 -0
- julee/api/__init__.py +20 -0
- julee/api/app.py +180 -0
- julee/api/dependencies.py +257 -0
- julee/api/requests.py +175 -0
- julee/api/responses.py +43 -0
- julee/api/routers/__init__.py +43 -0
- julee/api/routers/assembly_specifications.py +212 -0
- julee/api/routers/documents.py +182 -0
- julee/api/routers/knowledge_service_configs.py +79 -0
- julee/api/routers/knowledge_service_queries.py +293 -0
- julee/api/routers/system.py +137 -0
- julee/api/routers/workflows.py +234 -0
- julee/api/services/__init__.py +20 -0
- julee/api/services/system_initialization.py +214 -0
- julee/api/tests/__init__.py +14 -0
- julee/api/tests/routers/__init__.py +17 -0
- julee/api/tests/routers/test_assembly_specifications.py +749 -0
- julee/api/tests/routers/test_documents.py +301 -0
- julee/api/tests/routers/test_knowledge_service_configs.py +234 -0
- julee/api/tests/routers/test_knowledge_service_queries.py +738 -0
- julee/api/tests/routers/test_system.py +179 -0
- julee/api/tests/routers/test_workflows.py +393 -0
- julee/api/tests/test_app.py +285 -0
- julee/api/tests/test_dependencies.py +245 -0
- julee/api/tests/test_requests.py +250 -0
- julee/domain/__init__.py +22 -0
- julee/domain/models/__init__.py +49 -0
- julee/domain/models/assembly/__init__.py +17 -0
- julee/domain/models/assembly/assembly.py +103 -0
- julee/domain/models/assembly/tests/__init__.py +0 -0
- julee/domain/models/assembly/tests/factories.py +37 -0
- julee/domain/models/assembly/tests/test_assembly.py +430 -0
- julee/domain/models/assembly_specification/__init__.py +24 -0
- julee/domain/models/assembly_specification/assembly_specification.py +172 -0
- julee/domain/models/assembly_specification/knowledge_service_query.py +123 -0
- julee/domain/models/assembly_specification/tests/__init__.py +0 -0
- julee/domain/models/assembly_specification/tests/factories.py +78 -0
- julee/domain/models/assembly_specification/tests/test_assembly_specification.py +490 -0
- julee/domain/models/assembly_specification/tests/test_knowledge_service_query.py +310 -0
- julee/domain/models/custom_fields/__init__.py +0 -0
- julee/domain/models/custom_fields/content_stream.py +68 -0
- julee/domain/models/custom_fields/tests/__init__.py +0 -0
- julee/domain/models/custom_fields/tests/test_custom_fields.py +53 -0
- julee/domain/models/document/__init__.py +17 -0
- julee/domain/models/document/document.py +150 -0
- julee/domain/models/document/tests/__init__.py +0 -0
- julee/domain/models/document/tests/factories.py +76 -0
- julee/domain/models/document/tests/test_document.py +297 -0
- julee/domain/models/knowledge_service_config/__init__.py +17 -0
- julee/domain/models/knowledge_service_config/knowledge_service_config.py +86 -0
- julee/domain/models/policy/__init__.py +15 -0
- julee/domain/models/policy/document_policy_validation.py +220 -0
- julee/domain/models/policy/policy.py +203 -0
- julee/domain/models/policy/tests/__init__.py +0 -0
- julee/domain/models/policy/tests/factories.py +47 -0
- julee/domain/models/policy/tests/test_document_policy_validation.py +420 -0
- julee/domain/models/policy/tests/test_policy.py +546 -0
- julee/domain/repositories/__init__.py +27 -0
- julee/domain/repositories/assembly.py +45 -0
- julee/domain/repositories/assembly_specification.py +52 -0
- julee/domain/repositories/base.py +146 -0
- julee/domain/repositories/document.py +49 -0
- julee/domain/repositories/document_policy_validation.py +52 -0
- julee/domain/repositories/knowledge_service_config.py +54 -0
- julee/domain/repositories/knowledge_service_query.py +44 -0
- julee/domain/repositories/policy.py +49 -0
- julee/domain/use_cases/__init__.py +17 -0
- julee/domain/use_cases/decorators.py +107 -0
- julee/domain/use_cases/extract_assemble_data.py +649 -0
- julee/domain/use_cases/initialize_system_data.py +842 -0
- julee/domain/use_cases/tests/__init__.py +7 -0
- julee/domain/use_cases/tests/test_extract_assemble_data.py +548 -0
- julee/domain/use_cases/tests/test_initialize_system_data.py +455 -0
- julee/domain/use_cases/tests/test_validate_document.py +1228 -0
- julee/domain/use_cases/validate_document.py +736 -0
- julee/fixtures/assembly_specifications.yaml +70 -0
- julee/fixtures/documents.yaml +178 -0
- julee/fixtures/knowledge_service_configs.yaml +37 -0
- julee/fixtures/knowledge_service_queries.yaml +27 -0
- julee/repositories/__init__.py +17 -0
- julee/repositories/memory/__init__.py +31 -0
- julee/repositories/memory/assembly.py +84 -0
- julee/repositories/memory/assembly_specification.py +125 -0
- julee/repositories/memory/base.py +227 -0
- julee/repositories/memory/document.py +149 -0
- julee/repositories/memory/document_policy_validation.py +104 -0
- julee/repositories/memory/knowledge_service_config.py +123 -0
- julee/repositories/memory/knowledge_service_query.py +120 -0
- julee/repositories/memory/policy.py +87 -0
- julee/repositories/memory/tests/__init__.py +0 -0
- julee/repositories/memory/tests/test_document.py +212 -0
- julee/repositories/memory/tests/test_document_policy_validation.py +161 -0
- julee/repositories/memory/tests/test_policy.py +443 -0
- julee/repositories/minio/__init__.py +31 -0
- julee/repositories/minio/assembly.py +103 -0
- julee/repositories/minio/assembly_specification.py +170 -0
- julee/repositories/minio/client.py +570 -0
- julee/repositories/minio/document.py +530 -0
- julee/repositories/minio/document_policy_validation.py +120 -0
- julee/repositories/minio/knowledge_service_config.py +187 -0
- julee/repositories/minio/knowledge_service_query.py +211 -0
- julee/repositories/minio/policy.py +106 -0
- julee/repositories/minio/tests/__init__.py +0 -0
- julee/repositories/minio/tests/fake_client.py +213 -0
- julee/repositories/minio/tests/test_assembly.py +374 -0
- julee/repositories/minio/tests/test_assembly_specification.py +391 -0
- julee/repositories/minio/tests/test_client_protocol.py +57 -0
- julee/repositories/minio/tests/test_document.py +591 -0
- julee/repositories/minio/tests/test_document_policy_validation.py +192 -0
- julee/repositories/minio/tests/test_knowledge_service_config.py +374 -0
- julee/repositories/minio/tests/test_knowledge_service_query.py +438 -0
- julee/repositories/minio/tests/test_policy.py +559 -0
- julee/repositories/temporal/__init__.py +38 -0
- julee/repositories/temporal/activities.py +114 -0
- julee/repositories/temporal/activity_names.py +34 -0
- julee/repositories/temporal/proxies.py +159 -0
- julee/services/__init__.py +18 -0
- julee/services/knowledge_service/__init__.py +48 -0
- julee/services/knowledge_service/anthropic/__init__.py +12 -0
- julee/services/knowledge_service/anthropic/knowledge_service.py +331 -0
- julee/services/knowledge_service/anthropic/tests/test_knowledge_service.py +318 -0
- julee/services/knowledge_service/factory.py +138 -0
- julee/services/knowledge_service/knowledge_service.py +160 -0
- julee/services/knowledge_service/memory/__init__.py +13 -0
- julee/services/knowledge_service/memory/knowledge_service.py +278 -0
- julee/services/knowledge_service/memory/test_knowledge_service.py +345 -0
- julee/services/knowledge_service/test_factory.py +112 -0
- julee/services/temporal/__init__.py +38 -0
- julee/services/temporal/activities.py +86 -0
- julee/services/temporal/activity_names.py +22 -0
- julee/services/temporal/proxies.py +41 -0
- julee/util/__init__.py +0 -0
- julee/util/domain.py +119 -0
- julee/util/repos/__init__.py +0 -0
- julee/util/repos/minio/__init__.py +0 -0
- julee/util/repos/minio/file_storage.py +213 -0
- julee/util/repos/temporal/__init__.py +11 -0
- julee/util/repos/temporal/client_proxies/file_storage.py +68 -0
- julee/util/repos/temporal/data_converter.py +123 -0
- julee/util/repos/temporal/minio_file_storage.py +12 -0
- julee/util/repos/temporal/proxies/__init__.py +0 -0
- julee/util/repos/temporal/proxies/file_storage.py +58 -0
- julee/util/repositories.py +55 -0
- julee/util/temporal/__init__.py +22 -0
- julee/util/temporal/activities.py +123 -0
- julee/util/temporal/decorators.py +473 -0
- julee/util/tests/__init__.py +1 -0
- julee/util/tests/test_decorators.py +770 -0
- julee/util/validation/__init__.py +29 -0
- julee/util/validation/repository.py +100 -0
- julee/util/validation/type_guards.py +369 -0
- julee/worker.py +211 -0
- julee/workflows/__init__.py +26 -0
- julee/workflows/extract_assemble.py +215 -0
- julee/workflows/validate_document.py +228 -0
- julee-0.1.0.dist-info/METADATA +195 -0
- julee-0.1.0.dist-info/RECORD +161 -0
- julee-0.1.0.dist-info/WHEEL +5 -0
- julee-0.1.0.dist-info/licenses/LICENSE +674 -0
- julee-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Minio implementation of KnowledgeServiceConfigRepository.
|
|
3
|
+
|
|
4
|
+
This module provides a Minio-based implementation of the
|
|
5
|
+
KnowledgeServiceConfigRepository
|
|
6
|
+
protocol that follows the Clean Architecture patterns defined in the
|
|
7
|
+
Fun-Police Framework. It handles knowledge service configuration storage
|
|
8
|
+
as JSON objects in Minio, ensuring idempotency and proper error handling.
|
|
9
|
+
|
|
10
|
+
The implementation stores knowledge service configurations as JSON objects
|
|
11
|
+
in Minio, following the large payload handling pattern from the architectural
|
|
12
|
+
guidelines. Each configuration is stored with its knowledge_service_id as the
|
|
13
|
+
key.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
from typing import Optional, List, Dict
|
|
18
|
+
|
|
19
|
+
from julee.domain.models.knowledge_service_config import (
|
|
20
|
+
KnowledgeServiceConfig,
|
|
21
|
+
)
|
|
22
|
+
from julee.domain.repositories.knowledge_service_config import (
|
|
23
|
+
KnowledgeServiceConfigRepository,
|
|
24
|
+
)
|
|
25
|
+
from .client import MinioClient, MinioRepositoryMixin
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class MinioKnowledgeServiceConfigRepository(
|
|
29
|
+
KnowledgeServiceConfigRepository, MinioRepositoryMixin
|
|
30
|
+
):
|
|
31
|
+
"""
|
|
32
|
+
Minio implementation of KnowledgeServiceConfigRepository using Minio for
|
|
33
|
+
persistence.
|
|
34
|
+
|
|
35
|
+
This implementation stores knowledge service configurations as JSON
|
|
36
|
+
objects:
|
|
37
|
+
- Knowledge Service Configs: JSON objects in the
|
|
38
|
+
"knowledge-service-configs" bucket
|
|
39
|
+
|
|
40
|
+
Each configuration is stored with its knowledge_service_id as the object
|
|
41
|
+
name
|
|
42
|
+
for efficient retrieval and updates.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, client: MinioClient) -> None:
|
|
46
|
+
"""Initialize repository with Minio client.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
client: MinioClient protocol implementation (real or fake)
|
|
50
|
+
"""
|
|
51
|
+
self.client = client
|
|
52
|
+
self.logger = logging.getLogger("MinioKnowledgeServiceConfigRepository")
|
|
53
|
+
self.bucket_name = "knowledge-service-configs"
|
|
54
|
+
self.ensure_buckets_exist(self.bucket_name)
|
|
55
|
+
|
|
56
|
+
async def get(self, knowledge_service_id: str) -> Optional[KnowledgeServiceConfig]:
|
|
57
|
+
"""Retrieve a knowledge service configuration by ID.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
knowledge_service_id: Unique knowledge service identifier
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
KnowledgeServiceConfig object if found, None otherwise
|
|
64
|
+
"""
|
|
65
|
+
object_name = f"config/{knowledge_service_id}"
|
|
66
|
+
|
|
67
|
+
return self.get_json_object(
|
|
68
|
+
bucket_name=self.bucket_name,
|
|
69
|
+
object_name=object_name,
|
|
70
|
+
model_class=KnowledgeServiceConfig,
|
|
71
|
+
not_found_log_message="Knowledge service config not found",
|
|
72
|
+
error_log_message="Error retrieving knowledge service config",
|
|
73
|
+
extra_log_data={"knowledge_service_id": knowledge_service_id},
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
async def save(self, knowledge_service: KnowledgeServiceConfig) -> None:
|
|
77
|
+
"""Save a knowledge service configuration.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
knowledge_service: Complete KnowledgeServiceConfig to save
|
|
81
|
+
"""
|
|
82
|
+
# Update timestamps
|
|
83
|
+
self.update_timestamps(knowledge_service)
|
|
84
|
+
|
|
85
|
+
object_name = f"config/{knowledge_service.knowledge_service_id}"
|
|
86
|
+
|
|
87
|
+
self.put_json_object(
|
|
88
|
+
bucket_name=self.bucket_name,
|
|
89
|
+
object_name=object_name,
|
|
90
|
+
model=knowledge_service,
|
|
91
|
+
success_log_message="Knowledge service config saved successfully",
|
|
92
|
+
error_log_message="Error saving knowledge service config",
|
|
93
|
+
extra_log_data={
|
|
94
|
+
"knowledge_service_id": (knowledge_service.knowledge_service_id),
|
|
95
|
+
"service_name": knowledge_service.name,
|
|
96
|
+
"service_api": knowledge_service.service_api.value,
|
|
97
|
+
},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
async def get_many(
|
|
101
|
+
self, knowledge_service_ids: List[str]
|
|
102
|
+
) -> Dict[str, Optional[KnowledgeServiceConfig]]:
|
|
103
|
+
"""Retrieve multiple knowledge service configs by ID.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
knowledge_service_ids: List of unique knowledge service
|
|
107
|
+
identifiers
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Dict mapping knowledge_service_id to KnowledgeServiceConfig (or
|
|
111
|
+
None if not found)
|
|
112
|
+
"""
|
|
113
|
+
# Convert knowledge service IDs to object names
|
|
114
|
+
object_names = [f"config/{service_id}" for service_id in knowledge_service_ids]
|
|
115
|
+
|
|
116
|
+
# Get objects from Minio using batch method
|
|
117
|
+
object_results = self.get_many_json_objects(
|
|
118
|
+
bucket_name=self.bucket_name,
|
|
119
|
+
object_names=object_names,
|
|
120
|
+
model_class=KnowledgeServiceConfig,
|
|
121
|
+
not_found_log_message="Knowledge service config not found",
|
|
122
|
+
error_log_message="Error retrieving knowledge service config",
|
|
123
|
+
extra_log_data={"knowledge_service_ids": knowledge_service_ids},
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# Convert object names back to knowledge service IDs for the result
|
|
127
|
+
result: Dict[str, Optional[KnowledgeServiceConfig]] = {}
|
|
128
|
+
for i, service_id in enumerate(knowledge_service_ids):
|
|
129
|
+
object_name = object_names[i]
|
|
130
|
+
result[service_id] = object_results[object_name]
|
|
131
|
+
|
|
132
|
+
return result
|
|
133
|
+
|
|
134
|
+
async def generate_id(self) -> str:
|
|
135
|
+
"""Generate a unique knowledge service identifier.
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
Unique knowledge service ID string
|
|
139
|
+
"""
|
|
140
|
+
return self.generate_id_with_prefix("ks")
|
|
141
|
+
|
|
142
|
+
async def list_all(self) -> List[KnowledgeServiceConfig]:
|
|
143
|
+
"""List all knowledge service configurations.
|
|
144
|
+
|
|
145
|
+
Returns:
|
|
146
|
+
List of all knowledge service configurations, sorted by
|
|
147
|
+
knowledge_service_id
|
|
148
|
+
"""
|
|
149
|
+
try:
|
|
150
|
+
# Extract knowledge service IDs from objects with config/ prefix
|
|
151
|
+
service_ids = self.list_objects_with_prefix_extract_ids(
|
|
152
|
+
bucket_name=self.bucket_name,
|
|
153
|
+
prefix="config/",
|
|
154
|
+
entity_type_name="configs",
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
if not service_ids:
|
|
158
|
+
return []
|
|
159
|
+
|
|
160
|
+
# Get all configurations using the existing get_many method
|
|
161
|
+
config_results = await self.get_many(service_ids)
|
|
162
|
+
|
|
163
|
+
# Filter out None results and sort by knowledge_service_id
|
|
164
|
+
configs = [
|
|
165
|
+
config for config in config_results.values() if config is not None
|
|
166
|
+
]
|
|
167
|
+
configs.sort(key=lambda x: x.knowledge_service_id)
|
|
168
|
+
|
|
169
|
+
self.logger.debug(
|
|
170
|
+
"Retrieved configs",
|
|
171
|
+
extra={"count": len(configs)},
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
return configs
|
|
175
|
+
|
|
176
|
+
except Exception as e:
|
|
177
|
+
self.logger.error(
|
|
178
|
+
"Error listing configs",
|
|
179
|
+
exc_info=True,
|
|
180
|
+
extra={
|
|
181
|
+
"error_type": type(e).__name__,
|
|
182
|
+
"error_message": str(e),
|
|
183
|
+
"bucket": self.bucket_name,
|
|
184
|
+
},
|
|
185
|
+
)
|
|
186
|
+
# Return empty list on error to avoid breaking the API
|
|
187
|
+
return []
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Minio implementation of KnowledgeServiceQueryRepository.
|
|
3
|
+
|
|
4
|
+
This module provides a Minio-based implementation of the
|
|
5
|
+
KnowledgeServiceQueryRepository protocol that follows the Clean Architecture
|
|
6
|
+
patterns defined in the Fun-Police Framework. It handles knowledge service
|
|
7
|
+
query storage as JSON objects in Minio, ensuring idempotency and proper
|
|
8
|
+
error handling.
|
|
9
|
+
|
|
10
|
+
The implementation stores knowledge service queries as JSON objects in Minio,
|
|
11
|
+
following the large payload handling pattern from the architectural
|
|
12
|
+
guidelines.
|
|
13
|
+
Each query is stored as a separate object with the query ID as the key.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
import uuid
|
|
18
|
+
|
|
19
|
+
from typing import Optional, List, Dict
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
from julee.domain.models.assembly_specification import (
|
|
23
|
+
KnowledgeServiceQuery,
|
|
24
|
+
)
|
|
25
|
+
from .client import MinioClient, MinioRepositoryMixin
|
|
26
|
+
from julee.domain.repositories.knowledge_service_query import (
|
|
27
|
+
KnowledgeServiceQueryRepository,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class MinioKnowledgeServiceQueryRepository(
|
|
35
|
+
KnowledgeServiceQueryRepository, MinioRepositoryMixin
|
|
36
|
+
):
|
|
37
|
+
"""
|
|
38
|
+
Minio implementation of KnowledgeServiceQueryRepository.
|
|
39
|
+
|
|
40
|
+
This implementation stores knowledge service queries as JSON objects in
|
|
41
|
+
Minio buckets, following the established patterns for Minio repositories
|
|
42
|
+
in this system. Each query is stored as a separate object with
|
|
43
|
+
deterministic naming.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
def __init__(self, client: MinioClient) -> None:
|
|
47
|
+
"""Initialize repository with Minio client.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
client: MinioClient protocol implementation (real or fake)
|
|
51
|
+
"""
|
|
52
|
+
self.client = client
|
|
53
|
+
self.logger = logging.getLogger("MinioKnowledgeServiceQueryRepository")
|
|
54
|
+
self.bucket_name = "knowledge-service-queries"
|
|
55
|
+
self.ensure_buckets_exist(self.bucket_name)
|
|
56
|
+
|
|
57
|
+
async def get(self, query_id: str) -> Optional[KnowledgeServiceQuery]:
|
|
58
|
+
"""Retrieve a knowledge service query by ID.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
query_id: Unique query identifier
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
KnowledgeServiceQuery object if found, None otherwise
|
|
65
|
+
"""
|
|
66
|
+
logger.debug(
|
|
67
|
+
"MinioKnowledgeServiceQueryRepository: Attempting to retrieve " "query",
|
|
68
|
+
extra={"query_id": query_id, "bucket": self.bucket_name},
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
object_name = f"query/{query_id}"
|
|
72
|
+
|
|
73
|
+
# Get object from Minio
|
|
74
|
+
query_data = self.get_json_object(
|
|
75
|
+
bucket_name=self.bucket_name,
|
|
76
|
+
object_name=object_name,
|
|
77
|
+
model_class=KnowledgeServiceQuery,
|
|
78
|
+
not_found_log_message="Knowledge service query not found",
|
|
79
|
+
error_log_message="Error retrieving knowledge service query",
|
|
80
|
+
extra_log_data={"query_id": query_id},
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
return query_data
|
|
84
|
+
|
|
85
|
+
async def save(self, query: KnowledgeServiceQuery) -> None:
|
|
86
|
+
"""Store or update a knowledge service query.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
query: KnowledgeServiceQuery object to store
|
|
90
|
+
"""
|
|
91
|
+
logger.debug(
|
|
92
|
+
"MinioKnowledgeServiceQueryRepository: Saving query",
|
|
93
|
+
extra={"query_id": query.query_id, "bucket": self.bucket_name},
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Update the updated_at timestamp
|
|
97
|
+
self.update_timestamps(query)
|
|
98
|
+
|
|
99
|
+
object_name = f"query/{query.query_id}"
|
|
100
|
+
|
|
101
|
+
# Store in Minio
|
|
102
|
+
self.put_json_object(
|
|
103
|
+
bucket_name=self.bucket_name,
|
|
104
|
+
object_name=object_name,
|
|
105
|
+
model=query,
|
|
106
|
+
success_log_message="Knowledge service query saved successfully",
|
|
107
|
+
error_log_message="Failed to save knowledge service query",
|
|
108
|
+
extra_log_data={"query_id": query.query_id},
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
async def generate_id(self) -> str:
|
|
112
|
+
"""Generate a unique query identifier.
|
|
113
|
+
|
|
114
|
+
Returns:
|
|
115
|
+
Unique string identifier for a new query
|
|
116
|
+
"""
|
|
117
|
+
query_id = f"query-{uuid.uuid4().hex[:12]}"
|
|
118
|
+
|
|
119
|
+
logger.debug(
|
|
120
|
+
"MinioKnowledgeServiceQueryRepository: Generated query ID",
|
|
121
|
+
extra={"query_id": query_id},
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
return query_id
|
|
125
|
+
|
|
126
|
+
async def get_many(
|
|
127
|
+
self, query_ids: List[str]
|
|
128
|
+
) -> Dict[str, Optional[KnowledgeServiceQuery]]:
|
|
129
|
+
"""Retrieve multiple knowledge service queries by ID.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
query_ids: List of unique query identifiers
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Dict mapping query_id to KnowledgeServiceQuery (or None if not
|
|
136
|
+
found)
|
|
137
|
+
"""
|
|
138
|
+
logger.debug(
|
|
139
|
+
"MinioKnowledgeServiceQueryRepository: Attempting to retrieve "
|
|
140
|
+
"multiple queries",
|
|
141
|
+
extra={
|
|
142
|
+
"query_ids": query_ids,
|
|
143
|
+
"count": len(query_ids),
|
|
144
|
+
"bucket": self.bucket_name,
|
|
145
|
+
},
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Convert query IDs to object names
|
|
149
|
+
object_names = [f"query/{query_id}" for query_id in query_ids]
|
|
150
|
+
|
|
151
|
+
# Get objects from Minio using batch method
|
|
152
|
+
object_results = self.get_many_json_objects(
|
|
153
|
+
bucket_name=self.bucket_name,
|
|
154
|
+
object_names=object_names,
|
|
155
|
+
model_class=KnowledgeServiceQuery,
|
|
156
|
+
not_found_log_message="Knowledge service query not found",
|
|
157
|
+
error_log_message="Error retrieving knowledge service query",
|
|
158
|
+
extra_log_data={"query_ids": query_ids},
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# Convert object names back to query IDs for the result
|
|
162
|
+
result: Dict[str, Optional[KnowledgeServiceQuery]] = {}
|
|
163
|
+
for i, query_id in enumerate(query_ids):
|
|
164
|
+
object_name = object_names[i]
|
|
165
|
+
result[query_id] = object_results[object_name]
|
|
166
|
+
|
|
167
|
+
return result
|
|
168
|
+
|
|
169
|
+
async def list_all(self) -> List[KnowledgeServiceQuery]:
|
|
170
|
+
"""List all knowledge service queries.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
List of all knowledge service queries, sorted by query_id
|
|
174
|
+
"""
|
|
175
|
+
try:
|
|
176
|
+
# Extract query IDs from objects with the query/ prefix
|
|
177
|
+
query_ids = self.list_objects_with_prefix_extract_ids(
|
|
178
|
+
bucket_name=self.bucket_name,
|
|
179
|
+
prefix="query/",
|
|
180
|
+
entity_type_name="queries",
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
if not query_ids:
|
|
184
|
+
return []
|
|
185
|
+
|
|
186
|
+
# Get all queries using the existing get_many method
|
|
187
|
+
query_results = await self.get_many(query_ids)
|
|
188
|
+
|
|
189
|
+
# Filter out None results and sort by query_id
|
|
190
|
+
queries = [query for query in query_results.values() if query is not None]
|
|
191
|
+
queries.sort(key=lambda x: x.query_id)
|
|
192
|
+
|
|
193
|
+
logger.debug(
|
|
194
|
+
"Retrieved queries",
|
|
195
|
+
extra={"count": len(queries)},
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
return queries
|
|
199
|
+
|
|
200
|
+
except Exception as e:
|
|
201
|
+
logger.error(
|
|
202
|
+
"Error listing queries",
|
|
203
|
+
exc_info=True,
|
|
204
|
+
extra={
|
|
205
|
+
"error_type": type(e).__name__,
|
|
206
|
+
"error_message": str(e),
|
|
207
|
+
"bucket": self.bucket_name,
|
|
208
|
+
},
|
|
209
|
+
)
|
|
210
|
+
# Return empty list on error to avoid breaking the API
|
|
211
|
+
return []
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Minio implementation of PolicyRepository.
|
|
3
|
+
|
|
4
|
+
This module provides a Minio-based implementation of the PolicyRepository
|
|
5
|
+
protocol that follows the Clean Architecture patterns defined in the
|
|
6
|
+
Fun-Police Framework. It handles policy storage as JSON objects in Minio,
|
|
7
|
+
ensuring idempotency and proper error handling.
|
|
8
|
+
|
|
9
|
+
The implementation stores policies as JSON objects in Minio, following the
|
|
10
|
+
large payload handling pattern from the architectural guidelines. Each
|
|
11
|
+
policy is stored as a complete JSON document with its validation scores
|
|
12
|
+
and transformation queries.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import logging
|
|
16
|
+
from typing import Optional, List, Dict
|
|
17
|
+
|
|
18
|
+
from julee.domain.models.policy import Policy
|
|
19
|
+
from julee.domain.repositories.policy import PolicyRepository
|
|
20
|
+
from .client import MinioClient, MinioRepositoryMixin
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MinioPolicyRepository(PolicyRepository, MinioRepositoryMixin):
|
|
24
|
+
"""
|
|
25
|
+
Minio implementation of PolicyRepository using Minio for persistence.
|
|
26
|
+
|
|
27
|
+
This implementation stores policies as JSON objects in the "policies"
|
|
28
|
+
bucket. Each policy includes its complete validation scores and optional
|
|
29
|
+
transformation queries.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, client: MinioClient) -> None:
|
|
33
|
+
"""Initialize repository with Minio client.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
client: MinioClient protocol implementation (real or fake)
|
|
37
|
+
"""
|
|
38
|
+
self.client = client
|
|
39
|
+
self.logger = logging.getLogger("MinioPolicyRepository")
|
|
40
|
+
self.policies_bucket = "policies"
|
|
41
|
+
self.ensure_buckets_exist(self.policies_bucket)
|
|
42
|
+
|
|
43
|
+
async def get(self, policy_id: str) -> Optional[Policy]:
|
|
44
|
+
"""Retrieve a policy by ID."""
|
|
45
|
+
return self.get_json_object(
|
|
46
|
+
bucket_name=self.policies_bucket,
|
|
47
|
+
object_name=policy_id,
|
|
48
|
+
model_class=Policy,
|
|
49
|
+
not_found_log_message="Policy not found",
|
|
50
|
+
error_log_message="Error retrieving policy",
|
|
51
|
+
extra_log_data={"policy_id": policy_id},
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
async def save(self, policy: Policy) -> None:
|
|
55
|
+
"""Save a policy to Minio."""
|
|
56
|
+
# Update timestamps
|
|
57
|
+
self.update_timestamps(policy)
|
|
58
|
+
|
|
59
|
+
self.put_json_object(
|
|
60
|
+
bucket_name=self.policies_bucket,
|
|
61
|
+
object_name=policy.policy_id,
|
|
62
|
+
model=policy,
|
|
63
|
+
success_log_message="Policy saved successfully",
|
|
64
|
+
error_log_message="Error saving policy",
|
|
65
|
+
extra_log_data={
|
|
66
|
+
"policy_id": policy.policy_id,
|
|
67
|
+
"title": policy.title,
|
|
68
|
+
"status": policy.status.value,
|
|
69
|
+
"validation_scores_count": len(policy.validation_scores),
|
|
70
|
+
"has_transformations": policy.has_transformations,
|
|
71
|
+
"version": policy.version,
|
|
72
|
+
},
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
async def get_many(self, policy_ids: List[str]) -> Dict[str, Optional[Policy]]:
|
|
76
|
+
"""Retrieve multiple policies by ID.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
policy_ids: List of unique policy identifiers
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
Dict mapping policy_id to Policy (or None if not found)
|
|
83
|
+
"""
|
|
84
|
+
# Convert policy IDs to object names (direct mapping in this case)
|
|
85
|
+
object_names = policy_ids
|
|
86
|
+
|
|
87
|
+
# Get objects from Minio using batch method
|
|
88
|
+
object_results = self.get_many_json_objects(
|
|
89
|
+
bucket_name=self.policies_bucket,
|
|
90
|
+
object_names=object_names,
|
|
91
|
+
model_class=Policy,
|
|
92
|
+
not_found_log_message="Policy not found",
|
|
93
|
+
error_log_message="Error retrieving policy",
|
|
94
|
+
extra_log_data={"policy_ids": policy_ids},
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Convert object names back to policy IDs for the result
|
|
98
|
+
result: Dict[str, Optional[Policy]] = {}
|
|
99
|
+
for policy_id in policy_ids:
|
|
100
|
+
result[policy_id] = object_results[policy_id]
|
|
101
|
+
|
|
102
|
+
return result
|
|
103
|
+
|
|
104
|
+
async def generate_id(self) -> str:
|
|
105
|
+
"""Generate a unique policy identifier."""
|
|
106
|
+
return self.generate_id_with_prefix("policy")
|
|
File without changes
|