graph-dependency-analyzer 0.2.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.
- graph_dependency_analyzer-0.2.0.dist-info/METADATA +158 -0
- graph_dependency_analyzer-0.2.0.dist-info/RECORD +86 -0
- graph_dependency_analyzer-0.2.0.dist-info/WHEEL +5 -0
- graph_dependency_analyzer-0.2.0.dist-info/entry_points.txt +2 -0
- graph_dependency_analyzer-0.2.0.dist-info/top_level.txt +1 -0
- src/__init__.py +0 -0
- src/application/__init__.py +0 -0
- src/application/dtos/__init__.py +0 -0
- src/application/dtos/affected_component.py +59 -0
- src/application/dtos/batch_processing_result.py +17 -0
- src/application/dtos/impact_analysis_response.py +56 -0
- src/application/dtos/impact_query_request.py +38 -0
- src/application/dtos/index_batch_request.py +53 -0
- src/application/dtos/index_batch_response.py +72 -0
- src/application/dtos/index_result.py +20 -0
- src/application/dtos/repository_index_result.py +79 -0
- src/application/exceptions.py +41 -0
- src/application/services/__init__.py +0 -0
- src/application/services/file_scanner_service.py +258 -0
- src/application/services/progress_tracker.py +132 -0
- src/application/use_cases/__init__.py +0 -0
- src/application/use_cases/clear_all_data_use_case.py +180 -0
- src/application/use_cases/index_batch_use_case.py +153 -0
- src/application/use_cases/index_repository_use_case.py +683 -0
- src/application/use_cases/indexing_orchestrator.py +181 -0
- src/application/use_cases/list_repositories_use_case.py +84 -0
- src/cli.py +512 -0
- src/config/__init__.py +5 -0
- src/config/container.py +211 -0
- src/config/logging_config.py +123 -0
- src/config/settings.py +165 -0
- src/domain/__init__.py +0 -0
- src/domain/entities/__init__.py +20 -0
- src/domain/entities/ast_node.py +32 -0
- src/domain/entities/code_chunk.py +45 -0
- src/domain/entities/code_file.py +44 -0
- src/domain/entities/dependency_graph.py +110 -0
- src/domain/entities/repository.py +46 -0
- src/domain/exceptions.py +36 -0
- src/domain/repositories/__init__.py +22 -0
- src/domain/repositories/i_code_parser.py +50 -0
- src/domain/repositories/i_dependency_extractor.py +35 -0
- src/domain/repositories/i_embedding_provider.py +31 -0
- src/domain/repositories/i_graph_repository.py +78 -0
- src/domain/repositories/i_vector_repository.py +55 -0
- src/domain/services/__init__.py +8 -0
- src/domain/services/dependency_extractor.py +962 -0
- src/domain/services/semantic_chunk_builder.py +719 -0
- src/domain/value_objects/__init__.py +12 -0
- src/domain/value_objects/chunk_type.py +24 -0
- src/domain/value_objects/dependency_type.py +22 -0
- src/domain/value_objects/node_type.py +22 -0
- src/domain/value_objects/qualified_name.py +78 -0
- src/infrastructure/__init__.py +0 -0
- src/infrastructure/exceptions.py +41 -0
- src/infrastructure/external_apis/__init__.py +0 -0
- src/infrastructure/external_apis/ollama_embedding_provider.py +134 -0
- src/infrastructure/external_apis/openai_embedding_provider.py +231 -0
- src/infrastructure/parsing/__init__.py +20 -0
- src/infrastructure/parsing/config_file_parser.py +347 -0
- src/infrastructure/parsing/gradle_dependency_parser.py +159 -0
- src/infrastructure/parsing/groovy_parser.py +198 -0
- src/infrastructure/parsing/maven_dependency_parser.py +147 -0
- src/infrastructure/parsing/microfrontend_config_parser.py +242 -0
- src/infrastructure/parsing/npm_package_dependency_parser.py +255 -0
- src/infrastructure/parsing/python_parser.py +211 -0
- src/infrastructure/parsing/sql_schema_parser.py +658 -0
- src/infrastructure/parsing/tree_sitter_java_parser.py +434 -0
- src/infrastructure/parsing/tree_sitter_typescript_parser.py +600 -0
- src/infrastructure/persistence/__init__.py +0 -0
- src/infrastructure/persistence/graph_export_repository.py +443 -0
- src/infrastructure/persistence/neo4j_dependency_repository.py +657 -0
- src/infrastructure/persistence/qdrant_vector_repository.py +357 -0
- src/infrastructure/persistence/repository_relationship_repository.py +1312 -0
- src/presentation/__init__.py +0 -0
- src/presentation/api/__init__.py +0 -0
- src/presentation/api/rest/__init__.py +0 -0
- src/presentation/api/rest/exception_handlers.py +174 -0
- src/presentation/api/rest/main.py +80 -0
- src/presentation/api/rest/routers/__init__.py +5 -0
- src/presentation/api/rest/routers/admin.py +103 -0
- src/presentation/api/rest/routers/analysis.py +980 -0
- src/presentation/api/rest/routers/export.py +442 -0
- src/presentation/api/rest/routers/health.py +117 -0
- src/presentation/api/rest/routers/indexing.py +148 -0
- src/presentation/api/rest/routers/relationships.py +1089 -0
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""DependencyGraph entities - represent dependency graph structures."""
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@dataclass
|
|
6
|
+
class DependencyNode:
|
|
7
|
+
"""
|
|
8
|
+
DependencyNode representing a node in the dependency graph.
|
|
9
|
+
|
|
10
|
+
Can represent: Repository, Class, Method, Library, API, Database.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
id: Unique identifier for the node
|
|
14
|
+
node_type: Type of node (REPOSITORY, CLASS, METHOD, LIBRARY, API, DATABASE)
|
|
15
|
+
properties: Node properties (name, path, version, etc.)
|
|
16
|
+
"""
|
|
17
|
+
id: str
|
|
18
|
+
node_type: str
|
|
19
|
+
properties: dict
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class DependencyEdge:
|
|
24
|
+
"""
|
|
25
|
+
DependencyEdge representing an edge in the dependency graph.
|
|
26
|
+
|
|
27
|
+
Can represent: CONTAINS, HAS_METHOD, CALLS, IMPORTS, USES_LIBRARY,
|
|
28
|
+
CALLS_API, CONNECTS_TO, DEPENDS_ON.
|
|
29
|
+
|
|
30
|
+
Attributes:
|
|
31
|
+
source: Source node ID
|
|
32
|
+
target: Target node ID
|
|
33
|
+
edge_type: Type of relationship
|
|
34
|
+
properties: Edge properties (line number, reason, etc.)
|
|
35
|
+
"""
|
|
36
|
+
source: str
|
|
37
|
+
target: str
|
|
38
|
+
edge_type: str
|
|
39
|
+
properties: dict = field(default_factory=dict)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class DependencyGraph:
|
|
44
|
+
"""
|
|
45
|
+
DependencyGraph containing nodes and edges.
|
|
46
|
+
|
|
47
|
+
Represents the complete dependency structure of a repository,
|
|
48
|
+
including internal dependencies (code-to-code) and external
|
|
49
|
+
dependencies (APIs, databases, libraries).
|
|
50
|
+
|
|
51
|
+
Attributes:
|
|
52
|
+
nodes: List of DependencyNode entities
|
|
53
|
+
edges: List of DependencyEdge entities
|
|
54
|
+
|
|
55
|
+
Business Rules:
|
|
56
|
+
- Edges always reference nodes that exist in the graph
|
|
57
|
+
- No duplicate nodes (unique by ID)
|
|
58
|
+
"""
|
|
59
|
+
nodes: list[DependencyNode] = field(default_factory=list)
|
|
60
|
+
edges: list[DependencyEdge] = field(default_factory=list)
|
|
61
|
+
|
|
62
|
+
def add_node(self, node: DependencyNode) -> None:
|
|
63
|
+
"""
|
|
64
|
+
Add a node to the graph.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
node: DependencyNode to add
|
|
68
|
+
"""
|
|
69
|
+
self.nodes.append(node)
|
|
70
|
+
|
|
71
|
+
def add_edge(self, edge: DependencyEdge) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Add an edge to the graph.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
edge: DependencyEdge to add
|
|
77
|
+
"""
|
|
78
|
+
self.edges.append(edge)
|
|
79
|
+
|
|
80
|
+
def get_dependents(self, target: str) -> list[DependencyNode]:
|
|
81
|
+
"""
|
|
82
|
+
Get all nodes that depend on the target node.
|
|
83
|
+
|
|
84
|
+
Returns nodes where there's an edge pointing TO the target.
|
|
85
|
+
(Who depends on this target?)
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
target: Node ID to find dependents for
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
List of DependencyNode that have edges pointing to target
|
|
92
|
+
"""
|
|
93
|
+
dependent_ids = {edge.source for edge in self.edges if edge.target == target}
|
|
94
|
+
return [node for node in self.nodes if node.id in dependent_ids]
|
|
95
|
+
|
|
96
|
+
def get_dependencies(self, source: str) -> list[DependencyNode]:
|
|
97
|
+
"""
|
|
98
|
+
Get all dependencies of the source node.
|
|
99
|
+
|
|
100
|
+
Returns nodes where there's an edge FROM source pointing to them.
|
|
101
|
+
(What does this source depend on?)
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
source: Node ID to find dependencies for
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
List of DependencyNode that source depends on
|
|
108
|
+
"""
|
|
109
|
+
dependency_ids = {edge.target for edge in self.edges if edge.source == source}
|
|
110
|
+
return [node for node in self.nodes if node.id in dependency_ids]
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Repository entity - represents a Git repository being indexed."""
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class Repository:
|
|
9
|
+
"""
|
|
10
|
+
Repository entity representing a codebase being indexed.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
name: Repository name (e.g., "order-service")
|
|
14
|
+
path: Absolute path to repository directory
|
|
15
|
+
language: Primary language (e.g., "java")
|
|
16
|
+
indexed_at: Timestamp when indexing occurred
|
|
17
|
+
files: List of CodeFile entities in this repository
|
|
18
|
+
|
|
19
|
+
Business Rules:
|
|
20
|
+
- Repository name must be unique
|
|
21
|
+
- Path must exist and be accessible
|
|
22
|
+
"""
|
|
23
|
+
name: str
|
|
24
|
+
path: Path
|
|
25
|
+
language: str
|
|
26
|
+
indexed_at: datetime = field(default_factory=datetime.now)
|
|
27
|
+
files: list = field(default_factory=list)
|
|
28
|
+
|
|
29
|
+
def add_file(self, code_file) -> None:
|
|
30
|
+
"""
|
|
31
|
+
Add a CodeFile to this repository.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
code_file: CodeFile entity to add
|
|
35
|
+
"""
|
|
36
|
+
self.files.append(code_file)
|
|
37
|
+
|
|
38
|
+
def get_dependency_graph(self):
|
|
39
|
+
"""
|
|
40
|
+
Get dependency graph for this repository.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
DependencyGraph with nodes and edges extracted from files
|
|
44
|
+
"""
|
|
45
|
+
from src.domain.entities.dependency_graph import DependencyGraph
|
|
46
|
+
return DependencyGraph()
|
src/domain/exceptions.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Domain Layer Exceptions (Task 9.3)
|
|
3
|
+
|
|
4
|
+
Exception hierarchy for domain layer errors.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class DomainException(Exception):
|
|
9
|
+
"""Base exception for domain layer errors."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, message: str, details: dict | None = None):
|
|
12
|
+
"""
|
|
13
|
+
Initialize domain exception.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
message: Human-readable error message
|
|
17
|
+
details: Optional dict with additional context
|
|
18
|
+
"""
|
|
19
|
+
super().__init__(message)
|
|
20
|
+
self.message = message
|
|
21
|
+
self.details = details or {}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class InvalidDependencyError(DomainException):
|
|
25
|
+
"""Invalid dependency detected."""
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class InvalidQualifiedNameError(DomainException):
|
|
30
|
+
"""Invalid qualified name format."""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ChunkingError(DomainException):
|
|
35
|
+
"""Error during semantic chunking."""
|
|
36
|
+
pass
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Domain repository interfaces module."""
|
|
2
|
+
from src.domain.repositories.i_code_parser import ICodeParser, ParseResult
|
|
3
|
+
from src.domain.repositories.i_vector_repository import IVectorRepository, VectorStorageResult
|
|
4
|
+
from src.domain.repositories.i_graph_repository import (
|
|
5
|
+
IGraphRepository,
|
|
6
|
+
GraphStorageResult,
|
|
7
|
+
ImpactAnalysisResult,
|
|
8
|
+
)
|
|
9
|
+
from src.domain.repositories.i_embedding_provider import IEmbeddingProvider
|
|
10
|
+
from src.domain.repositories.i_dependency_extractor import IDependencyExtractor
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"ICodeParser",
|
|
14
|
+
"ParseResult",
|
|
15
|
+
"IVectorRepository",
|
|
16
|
+
"VectorStorageResult",
|
|
17
|
+
"IGraphRepository",
|
|
18
|
+
"GraphStorageResult",
|
|
19
|
+
"ImpactAnalysisResult",
|
|
20
|
+
"IEmbeddingProvider",
|
|
21
|
+
"IDependencyExtractor",
|
|
22
|
+
]
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""ICodeParser interface - contract for AST parsing implementations."""
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import Protocol, Any, runtime_checkable
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class ParseResult:
|
|
9
|
+
"""
|
|
10
|
+
ParseResult containing extracted AST structures.
|
|
11
|
+
|
|
12
|
+
Attributes:
|
|
13
|
+
file_path: Path to the parsed file
|
|
14
|
+
classes: List of extracted class information
|
|
15
|
+
methods: List of extracted method information
|
|
16
|
+
imports: List of extracted import statements
|
|
17
|
+
method_calls: List of extracted method calls
|
|
18
|
+
string_literals: List of string literals found in code
|
|
19
|
+
"""
|
|
20
|
+
file_path: Path
|
|
21
|
+
classes: list[Any] = field(default_factory=list)
|
|
22
|
+
methods: list[Any] = field(default_factory=list)
|
|
23
|
+
imports: list[Any] = field(default_factory=list)
|
|
24
|
+
method_calls: list[Any] = field(default_factory=list)
|
|
25
|
+
string_literals: list[str] = field(default_factory=list)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@runtime_checkable
|
|
29
|
+
class ICodeParser(Protocol):
|
|
30
|
+
"""
|
|
31
|
+
Interface for code parsers (Tree-sitter, etc.).
|
|
32
|
+
|
|
33
|
+
Implementations must parse source code files and extract
|
|
34
|
+
AST structures like classes, methods, imports, and method calls.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
def parse_file(self, file_path: Path) -> ParseResult:
|
|
38
|
+
"""
|
|
39
|
+
Parse a source code file and extract AST structures.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
file_path: Path to source file to parse
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
ParseResult with extracted structures
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
ParseError: If parsing fails
|
|
49
|
+
"""
|
|
50
|
+
...
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""IDependencyExtractor interface - contract for dependency extraction implementations."""
|
|
2
|
+
from typing import Protocol, runtime_checkable
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@runtime_checkable
|
|
6
|
+
class IDependencyExtractor(Protocol):
|
|
7
|
+
"""
|
|
8
|
+
Interface for dependency extractors.
|
|
9
|
+
|
|
10
|
+
Implementations must extract dependencies from AST nodes,
|
|
11
|
+
build files, and configuration files.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def extract_dependencies(
|
|
15
|
+
self,
|
|
16
|
+
ast_nodes: list, # list[ASTNode]
|
|
17
|
+
build_files: dict[str, str],
|
|
18
|
+
config_files: dict[str, str]
|
|
19
|
+
): # -> DependencyGraph
|
|
20
|
+
"""
|
|
21
|
+
Extract internal and external dependencies from multiple sources.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
ast_nodes: Parsed AST from source files
|
|
25
|
+
build_files: Content of pom.xml, build.gradle, etc (filename -> content)
|
|
26
|
+
config_files: Content of application.properties, .env, etc (filename -> content)
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
DependencyGraph with nodes (classes, methods, libs, APIs, DBs)
|
|
30
|
+
and edges (calls, imports, uses)
|
|
31
|
+
|
|
32
|
+
Raises:
|
|
33
|
+
DependencyExtractionError: If critical extraction fails
|
|
34
|
+
"""
|
|
35
|
+
...
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""IEmbeddingProvider interface - contract for embedding generation implementations."""
|
|
2
|
+
from typing import Protocol, runtime_checkable
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@runtime_checkable
|
|
6
|
+
class IEmbeddingProvider(Protocol):
|
|
7
|
+
"""
|
|
8
|
+
Interface for embedding providers (OpenAI, etc.).
|
|
9
|
+
|
|
10
|
+
Implementations must generate embeddings for text chunks.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
async def embed_batch(
|
|
14
|
+
self,
|
|
15
|
+
texts: list[str],
|
|
16
|
+
batch_size: int = 10
|
|
17
|
+
) -> list[list[float]]:
|
|
18
|
+
"""
|
|
19
|
+
Generate embeddings for batch of texts.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
texts: List of text chunks to embed
|
|
23
|
+
batch_size: Number of texts per API call (default 10)
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
List of embedding vectors (1536 floats each)
|
|
27
|
+
|
|
28
|
+
Raises:
|
|
29
|
+
EmbeddingProviderError: If API fails after retries
|
|
30
|
+
"""
|
|
31
|
+
...
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""IGraphRepository interface - contract for graph storage implementations."""
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Protocol, Any, runtime_checkable
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class GraphStorageResult:
|
|
8
|
+
"""
|
|
9
|
+
GraphStorageResult containing storage statistics.
|
|
10
|
+
|
|
11
|
+
Attributes:
|
|
12
|
+
nodes_created: Number of nodes created in graph
|
|
13
|
+
relationships_created: Number of relationships created
|
|
14
|
+
"""
|
|
15
|
+
nodes_created: int
|
|
16
|
+
relationships_created: int
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class ImpactAnalysisResult:
|
|
21
|
+
"""
|
|
22
|
+
ImpactAnalysisResult containing impact analysis query results.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
target: Target entity being analyzed (repo, class, API)
|
|
26
|
+
query_type: Type of analysis performed
|
|
27
|
+
affected_components: List of affected components
|
|
28
|
+
"""
|
|
29
|
+
target: str
|
|
30
|
+
query_type: str
|
|
31
|
+
affected_components: list[Any]
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@runtime_checkable
|
|
35
|
+
class IGraphRepository(Protocol):
|
|
36
|
+
"""
|
|
37
|
+
Interface for graph storage repositories (Neo4j, etc.).
|
|
38
|
+
|
|
39
|
+
Implementations must store dependency graphs and support
|
|
40
|
+
impact analysis queries.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
async def store_dependency_graph(
|
|
44
|
+
self,
|
|
45
|
+
graph, # DependencyGraph
|
|
46
|
+
repository_name: str
|
|
47
|
+
) -> GraphStorageResult:
|
|
48
|
+
"""
|
|
49
|
+
Store complete dependency graph in graph database.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
graph: DependencyGraph with nodes and edges
|
|
53
|
+
repository_name: Name of repository being indexed
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
GraphStorageResult with counts (nodes_created, relationships_created)
|
|
57
|
+
|
|
58
|
+
Raises:
|
|
59
|
+
GraphStorageError: If storage fails
|
|
60
|
+
"""
|
|
61
|
+
...
|
|
62
|
+
|
|
63
|
+
async def query_impact_analysis(
|
|
64
|
+
self,
|
|
65
|
+
query_type: str,
|
|
66
|
+
params: dict[str, Any]
|
|
67
|
+
) -> ImpactAnalysisResult:
|
|
68
|
+
"""
|
|
69
|
+
Execute impact analysis query.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
query_type: Type of analysis (REPO_DEPENDENTS, CLASS_IMPACT, etc)
|
|
73
|
+
params: Query parameters (repo_name, class_name, etc)
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
ImpactAnalysisResult with affected components
|
|
77
|
+
"""
|
|
78
|
+
...
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""IVectorRepository interface - contract for vector storage implementations."""
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from typing import Protocol, runtime_checkable
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass
|
|
7
|
+
class VectorStorageResult:
|
|
8
|
+
"""
|
|
9
|
+
VectorStorageResult containing upsert statistics.
|
|
10
|
+
|
|
11
|
+
Attributes:
|
|
12
|
+
points_upserted: Number of vector points upserted
|
|
13
|
+
"""
|
|
14
|
+
points_upserted: int
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@runtime_checkable
|
|
18
|
+
class IVectorRepository(Protocol):
|
|
19
|
+
"""
|
|
20
|
+
Interface for vector storage repositories (Qdrant, etc.).
|
|
21
|
+
|
|
22
|
+
Implementations must store embeddings with metadata and
|
|
23
|
+
support querying unique repositories.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
async def upsert_batch(
|
|
27
|
+
self,
|
|
28
|
+
chunks: list,
|
|
29
|
+
embeddings: list[list[float]],
|
|
30
|
+
batch_size: int = 1000
|
|
31
|
+
) -> VectorStorageResult:
|
|
32
|
+
"""
|
|
33
|
+
Upsert batch of embeddings with metadata to vector storage.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
chunks: Code chunks with metadata
|
|
37
|
+
embeddings: Corresponding embeddings (1536-dim)
|
|
38
|
+
batch_size: Points per upsert call (default 1000)
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
VectorStorageResult with count of points upserted
|
|
42
|
+
|
|
43
|
+
Raises:
|
|
44
|
+
VectorStorageError: If upsert fails
|
|
45
|
+
"""
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
async def get_unique_repositories(self) -> list[str]:
|
|
49
|
+
"""
|
|
50
|
+
Get list of unique repository names indexed.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
List of repository names
|
|
54
|
+
"""
|
|
55
|
+
...
|