Coverage for src/qdrant_loader_mcp_server/search/models.py: 100%
67 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-04 05:45 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-06-04 05:45 +0000
1"""Search result models."""
3from pydantic import BaseModel
6class SearchResult(BaseModel):
7 """Search result model."""
9 score: float
10 text: str
11 source_type: str
12 source_title: str
13 source_url: str | None = None
14 file_path: str | None = None
15 repo_name: str | None = None
17 # Project information (for multi-project support)
18 project_id: str | None = None
19 project_name: str | None = None
20 project_description: str | None = None
21 collection_name: str | None = None
23 # Hierarchy information (primarily for Confluence)
24 parent_id: str | None = None
25 parent_title: str | None = None
26 breadcrumb_text: str | None = None
27 depth: int | None = None
28 children_count: int | None = None
29 hierarchy_context: str | None = None
31 # Attachment information (for files attached to documents)
32 is_attachment: bool = False
33 parent_document_id: str | None = None
34 parent_document_title: str | None = None
35 attachment_id: str | None = None
36 original_filename: str | None = None
37 file_size: int | None = None
38 mime_type: str | None = None
39 attachment_author: str | None = None
40 attachment_context: str | None = None
42 def get_display_title(self) -> str:
43 """Get the display title with hierarchy context if available."""
44 if self.breadcrumb_text and self.source_type == "confluence":
45 return f"{self.source_title} ({self.breadcrumb_text})"
46 return self.source_title
48 def get_project_info(self) -> str | None:
49 """Get formatted project information for display."""
50 if not self.project_id:
51 return None
53 project_info = f"Project: {self.project_name or self.project_id}"
54 if self.project_description:
55 project_info += f" - {self.project_description}"
56 if self.collection_name:
57 project_info += f" (Collection: {self.collection_name})"
58 return project_info
60 def get_hierarchy_info(self) -> str | None:
61 """Get formatted hierarchy information for display."""
62 if self.source_type != "confluence" or not self.hierarchy_context:
63 return None
64 return self.hierarchy_context
66 def is_root_document(self) -> bool:
67 """Check if this is a root document (no parent)."""
68 return self.parent_id is None
70 def has_children(self) -> bool:
71 """Check if this document has children."""
72 return self.children_count is not None and self.children_count > 0
74 def get_attachment_info(self) -> str | None:
75 """Get formatted attachment information for display."""
76 if not self.is_attachment or not self.attachment_context:
77 return None
78 return self.attachment_context
80 def is_file_attachment(self) -> bool:
81 """Check if this is a file attachment."""
82 return self.is_attachment
84 def get_file_type(self) -> str | None:
85 """Get the file type from MIME type or filename."""
86 if self.mime_type:
87 return self.mime_type
88 elif self.original_filename:
89 # Extract extension from filename
90 import os
92 _, ext = os.path.splitext(self.original_filename)
93 return ext.lower().lstrip(".") if ext else None
94 return None
96 def belongs_to_project(self, project_id: str) -> bool:
97 """Check if this result belongs to a specific project."""
98 return self.project_id == project_id
100 def belongs_to_any_project(self, project_ids: list[str]) -> bool:
101 """Check if this result belongs to any of the specified projects."""
102 return self.project_id is not None and self.project_id in project_ids