Coverage for src/paperap/models/mixins/queryset.py: 64%

1"""

2----------------------------------------------------------------------------

3

4 METADATA:

5

6 File: queryset.py

7 Project: paperap

8 Created: 2025-03-05

9 Version: 0.0.5

10 Author: Jess Mann

11 Email: jess@jmann.me

12 Copyright (c) 2025 Jess Mann

13

14----------------------------------------------------------------------------

15

16 LAST MODIFIED:

17

18 2025-03-05 By Jess Mann

19

20"""

21

22 from __future__ import annotations

23

24 from typing import TYPE_CHECKING, Any, Protocol, Self

25

26 if TYPE_CHECKING:

27 from paperap.models.abstract.queryset import BaseQuerySet, StandardQuerySet

28

29

30 class QuerySetProtocol(Protocol):

31 """

32 Protocol for querysets.

33

34 Used primarily for type hinting.

35 """

36

37 def all(self) -> Self: ... # pylint: disable=missing-function-docstring

38 def filter(self, **kwargs: Any) -> Self: ... # pylint: disable=missing-function-docstring

39 def filter_field_by_str( # pylint: disable=missing-function-docstring

40 self, field: str, value: str, *, exact: bool = True, case_insensitive: bool = True

41 ) -> Self: ...

42

43

44 class HasDocumentCount(QuerySetProtocol):

45 """

46 Mixin for querysets that have a document_count field.

47 """

48

49 def document_count(self, count: int) -> Self:

50 """

51 Filter models by document count.

52

53 Args:

54 count: The document count to filter by

55

56 Returns:

57 Filtered QuerySet

58

59 """

60 return self.filter(document_count=count)

61

62 def document_count_over(self, count: int) -> Self:

63 """

64 Filter models by document count greater than a value.

65

66 Args:

67 count: The document count to filter by

68

69 Returns:

70 Filtered QuerySet

71

72 """

73 return self.filter(document_count__gt=count)

74

75 def document_count_under(self, count: int) -> Self:

76 """

77 Filter models by document count less than a value.

78

79 Args:

80 count: The document count to filter by

81

82 Returns:

83 Filtered QuerySet

84

85 """

86 return self.filter(document_count__lt=count)

87

88 def document_count_between(self, lower: int, upper: int) -> Self:

89 """

90 Filter models by document count between two values.

91

92 Args:

93 lower: The lower document count to filter by

94 upper: The upper document count to filter by

95

96 Returns:

97 Filtered QuerySet

98

99 """

100 return self.filter(document_count__range=(lower, upper))

101

102

103 class HasOwner(QuerySetProtocol):

104 """

105 Mixin for querysets that have an owner field.

106 """

107

108 def owner(self, owner: int | list[int] | None) -> Self:

109 """

110 Filter models by owner.

111

112 Args:

113 owner: The owner to filter by

114

115 Returns:

116 Filtered QuerySet

117

118 """

119 if isinstance(owner, list):

120 return self.filter(owner__in=owner)

121 return self.filter(owner=owner)

122

123

124 class HasStandard(HasOwner, HasDocumentCount):

125 """

126 Mixin for querysets that have standard fields: owner, document_count, name, slug

127 """

128

129 def name(self, value: str, *, exact: bool = True, case_insensitive: bool = True) -> Self:

130 """

131 Filter models where name is value

132

133 Args:

134 value (str): The value to compare against

135 exact (bool): Whether the comparison should be exact

136 case_sensitive (bool): Whether the comparison should be case insensitive

137

138 Returns:

139 Filtered QuerySet

140

141 """

142 return self.filter_field_by_str("name", value, exact=exact, case_insensitive=case_insensitive)

143

144 def slug(self, value: str, *, exact: bool = True, case_insensitive: bool = True) -> Self:

145 """

146 Filter models where slug is value

147

148 Args:

149 value (str): The value to compare against

150 exact (bool): Whether the comparison should be exact

151 case_sensitive (bool): Whether the comparison should be case insensitive

152

153 Returns:

154 Filtered QuerySet

155

156 """

157 return self.filter_field_by_str("slug", value, exact=exact, case_insensitive=case_insensitive)