Coverage for functions \ flipdare \ search \ doc \ general_document.py: 92%
77 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#
13from __future__ import annotations
15from typing import Any, cast, override
17from flipdare.app_types import SearchDict
18from flipdare.generated.schema.search.general_document_schema import (
19 GeneralDocumentKey,
20 GeneralDocumentSchema,
21)
22from flipdare.generated.shared.model.token_score import TokenScore
23from flipdare.generated.shared.search.search_obj_type import SearchObjType
24from flipdare.search.doc._search_document import TS_C, SearchDocument
25from flipdare.util.time_util import TypesenseTime
27__all__ = ["GeneralDocument"]
30class GeneralDocument(SearchDocument[GeneralDocumentSchema]):
32 SCHEMA_CLASS = GeneralDocumentSchema
34 def __init__(self, data: GeneralDocumentSchema, doc_id: str | None = None) -> None:
35 super().__init__(data=data, doc_id=doc_id)
37 @classmethod
38 def create(
39 cls,
40 keywords: list[str],
41 tags: list[str],
42 obj_id: str,
43 uid: str,
44 obj_type: SearchObjType,
45 updated_at: TS_C,
46 created_at: TS_C,
47 group_id: str | None = None,
48 score: float = 1.0,
49 tag_score: float = TokenScore.LOW.score,
50 views: int = 0,
51 ) -> GeneralDocument:
53 data: GeneralDocumentSchema = {
54 "updated_at": TypesenseTime.from_any(updated_at),
55 "created_at": TypesenseTime.from_any(created_at),
56 "score": score,
57 "uid": uid,
58 "obj_id": obj_id,
59 "obj_type": obj_type,
60 "keywords": keywords,
61 "views": views,
62 "tags": tags,
63 "tag_score": tag_score,
64 }
66 if group_id is not None:
67 data["group_id"] = group_id
69 return cls(data=data)
71 @classmethod
72 @override
73 def from_payload(
74 cls,
75 doc_id: str,
76 payload: SearchDict,
77 original: SearchDocument[Any] | None = None,
78 ) -> GeneralDocument:
79 schema_data = cls.parse(cls.SCHEMA_CLASS, payload, original)
80 return cls(data=schema_data, doc_id=doc_id)
82 @property
83 @override
84 def uid(self) -> str:
85 return self._data["uid"]
87 @property
88 @override
89 def created_at(self) -> int:
90 return self._data["created_at"]
92 @property
93 @override
94 def updated_at(self) -> int:
95 return self._data["updated_at"]
97 @property
98 def obj_id(self) -> str:
99 return self._data["obj_id"]
101 @property
102 @override
103 def obj_type(self) -> SearchObjType:
104 return self._data["obj_type"]
106 @property
107 def keywords(self) -> str | list[str]:
108 return self._data["keywords"]
110 @property
111 def views(self) -> int:
112 return self._data["views"]
114 @property
115 def group_id(self) -> str | None:
116 return self._data.get("group_id")
118 @property
119 def tags(self) -> str | list[str]:
120 return self._data["tags"]
122 @property
123 def score(self) -> float:
124 return self._data["score"]
126 @property
127 def tag_score(self) -> float:
128 return self._data["tag_score"]
130 def update_views(self, views: int, score: float, updated_at: int) -> None:
131 values = {
132 GeneralDocumentKey.VIEWS: views,
133 GeneralDocumentKey.SCORE: score,
134 }
135 self.update_payload(
136 payload_values=cast("SearchDict", values),
137 updated_at=updated_at,
138 )
140 def update_keywords(
141 self,
142 keywords: list[str],
143 score: float,
144 updated_at: int,
145 tags: list[str] | None = None,
146 tag_score: float | None = None,
147 ) -> None:
148 data = {
149 GeneralDocumentKey.KEYWORDS: keywords,
150 GeneralDocumentKey.SCORE: score,
151 }
152 if tags is not None:
153 data[GeneralDocumentKey.TAGS] = tags
154 if tag_score is not None:
155 data[GeneralDocumentKey.TAG_SCORE] = tag_score
157 self.update_payload(
158 payload_values=cast("SearchDict", data),
159 updated_at=updated_at,
160 )
162 @override
163 def __str__(self) -> str:
164 return (
165 f"GeneralDocument(doc_id={self.doc_id}, uid={self.uid}, "
166 f"obj_id={self.obj_id}, obj_type={self.obj_type})"
167 )
169 @override
170 def __repr__(self) -> str:
171 return self.__str__()