Coverage for functions \ flipdare \ search \ factory \ dare_search_factory.py: 93%

59 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2026-05-08 12:22 +1000

1#!/usr/bin/env python 

2# Copyright (c) 2026 Flipdare Pty Ltd. All rights reserved. 

3# 

4# This file is part of Flipdare's proprietary software and contains 

5# confidential and copyrighted material. Unauthorised copying, 

6# modification, distribution, or use of this file is strictly 

7# prohibited without prior written permission from Flipdare Pty Ltd. 

8# 

9# This software includes third-party components licensed under MIT, 

10# BSD, and Apache 2.0 licences. See THIRD_PARTY_NOTICES for details. 

11# 

12 

13 

14from typing import Any, override 

15from flipdare.app_log import LOG 

16from flipdare.constants import IS_DEBUG 

17from flipdare.core.tokenizer import Tokenizer 

18from flipdare.firestore.context.dare_context import DareContext 

19from flipdare.generated.model.group_model import GroupModel 

20from flipdare.generated.model.user_model import UserModel 

21from flipdare.generated.shared.search.search_obj_type import SearchObjType 

22from flipdare.search.core.search_score import SearchScore 

23from flipdare.search.doc._search_document import SearchDocument 

24from flipdare.search.doc.general_document import GeneralDocument 

25from flipdare.search.factory._search_document_factory import SearchDocumentFactory 

26from flipdare.util.time_util import TypesenseTime 

27 

28__all__ = ["DareSearchFactory"] 

29 

30 

31class DareSearchFactory(SearchDocumentFactory): 

32 

33 def __init__(self, dare_context: DareContext, tokenizer: Tokenizer | None = None) -> None: 

34 if not dare_context.valid: 

35 raise ValueError( 

36 f"DareContext must be valid to create DareModelTag.\n{dare_context.error_str}", 

37 ) 

38 self.dare_context = dare_context 

39 super().__init__(tokenizer=tokenizer) 

40 

41 @property 

42 @override 

43 def obj_type(self) -> SearchObjType: 

44 dare = self.dare_context.dare 

45 if dare.model.is_group_dare: 

46 return SearchObjType.GROUP_DARE 

47 return SearchObjType.DARE 

48 

49 @override 

50 def get_documents(self) -> list[SearchDocument[Any]] | None: 

51 dare_context = self.dare_context 

52 

53 dare = dare_context.dare 

54 from_user = dare_context.from_user 

55 assert from_user.doc_id # narrowing 

56 assert dare.doc_id # narrowing 

57 

58 to_obj = dare_context.to_obj 

59 

60 from_name = from_user.model.contact_name 

61 to_name: str = "" 

62 score = 1.0 

63 

64 to_model = to_obj.model 

65 if isinstance(to_model, UserModel): 

66 to_name = to_model.safe_name 

67 else: 

68 assert isinstance(to_model, GroupModel) # narrowing 

69 to_name = to_model.name 

70 

71 score = SearchScore.score_dare(dare, from_user, to_obj) 

72 values: list[str] = dare.searchable_values() 

73 values.append(f"{from_name} to {to_name}") 

74 

75 token_result = self.tokenizer.create_tokens(values) 

76 

77 obj_id = dare.doc_id 

78 created_at = TypesenseTime.from_firestore(dare.created_at_db) 

79 updated_at = TypesenseTime.from_firestore(dare.updated_at_db) 

80 

81 creator_id = dare.from_uid 

82 views = dare.model.view_stats.views 

83 obj_type = self.obj_type 

84 token_score = token_result.token_score.score 

85 tag_score = token_score * score 

86 

87 if IS_DEBUG: 

88 msg = ( 

89 f"Creating DareSearchDocument with obj_id={obj_id}, creator_id={creator_id}, " 

90 f"obj_type={obj_type}, values={values}, " 

91 f"score={score}, token_score={token_score}, tag_score={tag_score}, views={views}, " 

92 f"created_at={created_at}, updated_at={updated_at}, tokens={token_result.tokens}, " 

93 ) 

94 LOG().debug(msg) 

95 

96 return [ 

97 GeneralDocument.create( 

98 obj_id=obj_id, 

99 uid=creator_id, 

100 obj_type=obj_type, 

101 keywords=values, 

102 score=score, 

103 views=views, 

104 created_at=created_at, 

105 updated_at=updated_at, 

106 tags=token_result.tokens, 

107 tag_score=tag_score, 

108 ), 

109 ]