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

1"""Search result models.""" 

2 

3from pydantic import BaseModel 

4 

5 

6class SearchResult(BaseModel): 

7 """Search result model.""" 

8 

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 

16 

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 

22 

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 

30 

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 

41 

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 

47 

48 def get_project_info(self) -> str | None: 

49 """Get formatted project information for display.""" 

50 if not self.project_id: 

51 return None 

52 

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 

59 

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 

65 

66 def is_root_document(self) -> bool: 

67 """Check if this is a root document (no parent).""" 

68 return self.parent_id is None 

69 

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 

73 

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 

79 

80 def is_file_attachment(self) -> bool: 

81 """Check if this is a file attachment.""" 

82 return self.is_attachment 

83 

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 

91 

92 _, ext = os.path.splitext(self.original_filename) 

93 return ext.lower().lstrip(".") if ext else None 

94 return None 

95 

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 

99 

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