-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathsearch_request.py
More file actions
141 lines (109 loc) · 4.52 KB
/
search_request.py
File metadata and controls
141 lines (109 loc) · 4.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
from enum import Enum
from typing import Annotated
from typing import Optional
from pydantic import field_validator
from pydantic import model_validator
from ..annotations import Required
from ..utils import validate_scim_path_syntax
from .error import Error
from .message import Message
class SearchRequest(Message):
"""SearchRequest object defined at RFC7644.
https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.3
"""
schemas: Annotated[list[str], Required.true] = [
"urn:ietf:params:scim:api:messages:2.0:SearchRequest"
]
attributes: Optional[list[str]] = None
"""A multi-valued list of strings indicating the names of resource
attributes to return in the response, overriding the set of attributes that
would be returned by default."""
@field_validator("attributes")
@classmethod
def validate_attributes_syntax(cls, v: Optional[list[str]]) -> Optional[list[str]]:
"""Validate syntax of attribute paths."""
if v is None:
return v
for attr in v:
if not validate_scim_path_syntax(attr):
raise ValueError(Error.make_invalid_path_error().detail)
return v
excluded_attributes: Optional[list[str]] = None
"""A multi-valued list of strings indicating the names of resource
attributes to be removed from the default set of attributes to return."""
@field_validator("excluded_attributes")
@classmethod
def validate_excluded_attributes_syntax(
cls, v: Optional[list[str]]
) -> Optional[list[str]]:
"""Validate syntax of excluded attribute paths."""
if v is None:
return v
for attr in v:
if not validate_scim_path_syntax(attr):
raise ValueError(Error.make_invalid_path_error().detail)
return v
filter: Optional[str] = None
"""The filter string used to request a subset of resources."""
sort_by: Optional[str] = None
"""A string indicating the attribute whose value SHALL be used to order the
returned responses."""
@field_validator("sort_by")
@classmethod
def validate_sort_by_syntax(cls, v: Optional[str]) -> Optional[str]:
"""Validate syntax of sort_by attribute path.
:param v: The sort_by attribute path to validate
:type v: Optional[str]
:return: The validated sort_by attribute path
:rtype: Optional[str]
:raises ValueError: If sort_by attribute path has invalid syntax
"""
if v is None:
return v
if not validate_scim_path_syntax(v):
raise ValueError(Error.make_invalid_path_error().detail)
return v
class SortOrder(str, Enum):
ascending = "ascending"
descending = "descending"
sort_order: Optional[SortOrder] = None
"""A string indicating the order in which the "sortBy" parameter is
applied."""
start_index: Optional[int] = None
"""An integer indicating the 1-based index of the first query result."""
@field_validator("start_index")
@classmethod
def start_index_floor(cls, value: Optional[int]) -> Optional[int]:
"""According to :rfc:`RFC7644 §3.4.2 <7644#section-3.4.2.4>, start_index values less than 1 are interpreted as 1.
A value less than 1 SHALL be interpreted as 1.
"""
return None if value is None else max(1, value)
count: Optional[int] = None
"""An integer indicating the desired maximum number of query results per
page."""
@field_validator("count")
@classmethod
def count_floor(cls, value: Optional[int]) -> Optional[int]:
"""According to :rfc:`RFC7644 §3.4.2 <7644#section-3.4.2.4>, count values less than 0 are interpreted as 0.
A negative value SHALL be interpreted as 0.
"""
return None if value is None else max(0, value)
@model_validator(mode="after")
def attributes_validator(self) -> "SearchRequest":
if self.attributes and self.excluded_attributes:
raise ValueError(
"'attributes' and 'excluded_attributes' are mutually exclusive"
)
return self
@property
def start_index_0(self) -> Optional[int]:
"""The 0 indexed start index."""
return self.start_index - 1 if self.start_index is not None else None
@property
def stop_index_0(self) -> Optional[int]:
"""The 0 indexed stop index."""
return (
self.start_index_0 + self.count
if self.start_index_0 is not None and self.count is not None
else None
)