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
« 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#
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
28__all__ = ["DareSearchFactory"]
31class DareSearchFactory(SearchDocumentFactory):
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)
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
49 @override
50 def get_documents(self) -> list[SearchDocument[Any]] | None:
51 dare_context = self.dare_context
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
58 to_obj = dare_context.to_obj
60 from_name = from_user.model.contact_name
61 to_name: str = ""
62 score = 1.0
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
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}")
75 token_result = self.tokenizer.create_tokens(values)
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)
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
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)
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 ]