everysk-lib 1.10.2__cp312-cp312-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- everysk/__init__.py +30 -0
- everysk/_version.py +683 -0
- everysk/api/__init__.py +61 -0
- everysk/api/api_requestor.py +167 -0
- everysk/api/api_resources/__init__.py +23 -0
- everysk/api/api_resources/api_resource.py +371 -0
- everysk/api/api_resources/calculation.py +779 -0
- everysk/api/api_resources/custom_index.py +42 -0
- everysk/api/api_resources/datastore.py +81 -0
- everysk/api/api_resources/file.py +42 -0
- everysk/api/api_resources/market_data.py +223 -0
- everysk/api/api_resources/parser.py +66 -0
- everysk/api/api_resources/portfolio.py +43 -0
- everysk/api/api_resources/private_security.py +42 -0
- everysk/api/api_resources/report.py +65 -0
- everysk/api/api_resources/report_template.py +39 -0
- everysk/api/api_resources/tests.py +115 -0
- everysk/api/api_resources/worker_execution.py +64 -0
- everysk/api/api_resources/workflow.py +65 -0
- everysk/api/api_resources/workflow_execution.py +93 -0
- everysk/api/api_resources/workspace.py +42 -0
- everysk/api/http_client.py +63 -0
- everysk/api/tests.py +32 -0
- everysk/api/utils.py +262 -0
- everysk/config.py +451 -0
- everysk/core/_tests/serialize/test_json.py +336 -0
- everysk/core/_tests/serialize/test_orjson.py +295 -0
- everysk/core/_tests/serialize/test_pickle.py +48 -0
- everysk/core/cloud_function/main.py +78 -0
- everysk/core/cloud_function/tests.py +86 -0
- everysk/core/compress.py +245 -0
- everysk/core/datetime/__init__.py +12 -0
- everysk/core/datetime/calendar.py +144 -0
- everysk/core/datetime/date.py +424 -0
- everysk/core/datetime/date_expression.py +299 -0
- everysk/core/datetime/date_mixin.py +1475 -0
- everysk/core/datetime/date_settings.py +30 -0
- everysk/core/datetime/datetime.py +713 -0
- everysk/core/exceptions.py +435 -0
- everysk/core/fields.py +1176 -0
- everysk/core/firestore.py +555 -0
- everysk/core/fixtures/_settings.py +29 -0
- everysk/core/fixtures/other/_settings.py +18 -0
- everysk/core/fixtures/user_agents.json +88 -0
- everysk/core/http.py +691 -0
- everysk/core/lists.py +92 -0
- everysk/core/log.py +709 -0
- everysk/core/number.py +37 -0
- everysk/core/object.py +1469 -0
- everysk/core/redis.py +1021 -0
- everysk/core/retry.py +51 -0
- everysk/core/serialize.py +674 -0
- everysk/core/sftp.py +414 -0
- everysk/core/signing.py +53 -0
- everysk/core/slack.py +127 -0
- everysk/core/string.py +199 -0
- everysk/core/tests.py +240 -0
- everysk/core/threads.py +199 -0
- everysk/core/undefined.py +70 -0
- everysk/core/unittests.py +73 -0
- everysk/core/workers.py +241 -0
- everysk/sdk/__init__.py +23 -0
- everysk/sdk/base.py +98 -0
- everysk/sdk/brutils/cnpj.py +391 -0
- everysk/sdk/brutils/cnpj_pd.py +129 -0
- everysk/sdk/engines/__init__.py +26 -0
- everysk/sdk/engines/cache.py +185 -0
- everysk/sdk/engines/compliance.py +37 -0
- everysk/sdk/engines/cryptography.py +69 -0
- everysk/sdk/engines/expression.cp312-win_amd64.pyd +0 -0
- everysk/sdk/engines/expression.pyi +55 -0
- everysk/sdk/engines/helpers.cp312-win_amd64.pyd +0 -0
- everysk/sdk/engines/helpers.pyi +26 -0
- everysk/sdk/engines/lock.py +120 -0
- everysk/sdk/engines/market_data.py +244 -0
- everysk/sdk/engines/settings.py +19 -0
- everysk/sdk/entities/__init__.py +23 -0
- everysk/sdk/entities/base.py +784 -0
- everysk/sdk/entities/base_list.py +131 -0
- everysk/sdk/entities/custom_index/base.py +209 -0
- everysk/sdk/entities/custom_index/settings.py +29 -0
- everysk/sdk/entities/datastore/base.py +160 -0
- everysk/sdk/entities/datastore/settings.py +17 -0
- everysk/sdk/entities/fields.py +375 -0
- everysk/sdk/entities/file/base.py +215 -0
- everysk/sdk/entities/file/settings.py +63 -0
- everysk/sdk/entities/portfolio/base.py +248 -0
- everysk/sdk/entities/portfolio/securities.py +241 -0
- everysk/sdk/entities/portfolio/security.py +580 -0
- everysk/sdk/entities/portfolio/settings.py +97 -0
- everysk/sdk/entities/private_security/base.py +226 -0
- everysk/sdk/entities/private_security/settings.py +17 -0
- everysk/sdk/entities/query.py +603 -0
- everysk/sdk/entities/report/base.py +214 -0
- everysk/sdk/entities/report/settings.py +23 -0
- everysk/sdk/entities/script.py +310 -0
- everysk/sdk/entities/secrets/base.py +128 -0
- everysk/sdk/entities/secrets/script.py +119 -0
- everysk/sdk/entities/secrets/settings.py +17 -0
- everysk/sdk/entities/settings.py +48 -0
- everysk/sdk/entities/tags.py +174 -0
- everysk/sdk/entities/worker_execution/base.py +307 -0
- everysk/sdk/entities/worker_execution/settings.py +63 -0
- everysk/sdk/entities/workflow_execution/base.py +113 -0
- everysk/sdk/entities/workflow_execution/settings.py +32 -0
- everysk/sdk/entities/workspace/base.py +99 -0
- everysk/sdk/entities/workspace/settings.py +27 -0
- everysk/sdk/settings.py +67 -0
- everysk/sdk/tests.py +105 -0
- everysk/sdk/worker_base.py +47 -0
- everysk/server/__init__.py +9 -0
- everysk/server/applications.py +63 -0
- everysk/server/endpoints.py +516 -0
- everysk/server/example_api.py +69 -0
- everysk/server/middlewares.py +80 -0
- everysk/server/requests.py +62 -0
- everysk/server/responses.py +119 -0
- everysk/server/routing.py +64 -0
- everysk/server/settings.py +36 -0
- everysk/server/tests.py +36 -0
- everysk/settings.py +98 -0
- everysk/sql/__init__.py +9 -0
- everysk/sql/connection.py +232 -0
- everysk/sql/model.py +376 -0
- everysk/sql/query.py +417 -0
- everysk/sql/row_factory.py +63 -0
- everysk/sql/settings.py +49 -0
- everysk/sql/utils.py +129 -0
- everysk/tests.py +23 -0
- everysk/utils.py +81 -0
- everysk/version.py +15 -0
- everysk_lib-1.10.2.dist-info/.gitignore +5 -0
- everysk_lib-1.10.2.dist-info/METADATA +326 -0
- everysk_lib-1.10.2.dist-info/RECORD +137 -0
- everysk_lib-1.10.2.dist-info/WHEEL +5 -0
- everysk_lib-1.10.2.dist-info/licenses/LICENSE.txt +9 -0
- everysk_lib-1.10.2.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,603 @@
|
|
|
1
|
+
# -*- coding: utf_8 -*-
|
|
2
|
+
###############################################################################
|
|
3
|
+
#
|
|
4
|
+
# (C) Copyright 2023 EVERYSK TECHNOLOGIES
|
|
5
|
+
#
|
|
6
|
+
# This is an unpublished work containing confidential and proprietary
|
|
7
|
+
# information of EVERYSK TECHNOLOGIES. Disclosure, use, or reproduction
|
|
8
|
+
# without authorization of EVERYSK TECHNOLOGIES is prohibited.
|
|
9
|
+
#
|
|
10
|
+
###############################################################################
|
|
11
|
+
from typing import Any, Self, Generator, TypedDict, Callable
|
|
12
|
+
from inspect import isclass
|
|
13
|
+
|
|
14
|
+
from everysk.config import settings
|
|
15
|
+
from everysk.core.datetime import Date, DateTime
|
|
16
|
+
from everysk.core.exceptions import SDKValueError, FieldValueError, SDKTypeError
|
|
17
|
+
from everysk.core.fields import StrField, IntField, ListField, BoolField
|
|
18
|
+
from everysk.core.object import BaseDict, BaseDictConfig
|
|
19
|
+
from everysk.core.string import is_string_object, normalize_string_to_search, import_from_string
|
|
20
|
+
from everysk.sdk.base import BaseSDK
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
###############################################################################
|
|
24
|
+
# QueryPage Class Implementation
|
|
25
|
+
###############################################################################
|
|
26
|
+
class QueryPage(TypedDict):
|
|
27
|
+
"""
|
|
28
|
+
A dictionary containing the paginated list of entities and a next page token.
|
|
29
|
+
|
|
30
|
+
Attributes:
|
|
31
|
+
entities (list[Any]): The list of entities for the current page.
|
|
32
|
+
next_page_token (str): The token representing the next page of results.
|
|
33
|
+
"""
|
|
34
|
+
entities: list[Any] = None
|
|
35
|
+
next_page_token: str = None
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
###############################################################################
|
|
39
|
+
# Query Class Implementation
|
|
40
|
+
###############################################################################
|
|
41
|
+
class Query(BaseDict, BaseSDK):
|
|
42
|
+
"""
|
|
43
|
+
This class allows you to build a query to retrieve entities from the data source
|
|
44
|
+
based on certain conditions. The query can be executed to retrieve a single entity,
|
|
45
|
+
a list of entities, or a paginated list of entities.
|
|
46
|
+
|
|
47
|
+
Attributes:
|
|
48
|
+
_klass (Any): The class of the entity to be queried.
|
|
49
|
+
_clean_order (set): The set of properties by which to sort the query.
|
|
50
|
+
_find_or_fail (bool): A boolean value indicating whether the query should return an error if no entity is found.
|
|
51
|
+
filters (list): The list of filter conditions for the query.
|
|
52
|
+
order (list): The list of properties by which to sort the query.
|
|
53
|
+
projection (list): The list of properties to include or exclude in the query result.
|
|
54
|
+
distinct_on (list): The list of properties for which the resulting entities should be distinct.
|
|
55
|
+
limit (int): The maximum number of entities to retrieve.
|
|
56
|
+
offset (int): The number of initial entities to skip before starting retrieval.
|
|
57
|
+
page_size (int): The number of entities to retrieve per page.
|
|
58
|
+
page_token (str): The token representing the desired page of results.
|
|
59
|
+
|
|
60
|
+
Example:
|
|
61
|
+
To create a query to retrieve a single entity:
|
|
62
|
+
entity = Query(MyEntity).where('property_name', 'value').load()
|
|
63
|
+
|
|
64
|
+
To create a query to retrieve a list of entities:
|
|
65
|
+
entities = Query(MyEntity).where('property_name', 'value').loads()
|
|
66
|
+
|
|
67
|
+
To create a query to retrieve a paginated list of entities:
|
|
68
|
+
entities_page = Query(MyEntity).where('property_name', 'value').page()
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
class Config(BaseDictConfig):
|
|
72
|
+
exclude_keys: frozenset[str] = frozenset(['_is_frozen', '_silent', '_errors', '_orderable_attributes'])
|
|
73
|
+
|
|
74
|
+
_klass: Callable = None
|
|
75
|
+
_config: Config = None
|
|
76
|
+
_clean_order: set = None
|
|
77
|
+
_find_or_fail = BoolField(default=False)
|
|
78
|
+
|
|
79
|
+
# QUERY PARAMETERS
|
|
80
|
+
filters = ListField()
|
|
81
|
+
order = ListField()
|
|
82
|
+
projection = ListField()
|
|
83
|
+
|
|
84
|
+
# LOAD / LOADS PARAMETERS
|
|
85
|
+
limit = IntField()
|
|
86
|
+
offset = IntField()
|
|
87
|
+
|
|
88
|
+
# PAGE / PAGES PARAMETERS
|
|
89
|
+
page_size = IntField()
|
|
90
|
+
page_token = StrField()
|
|
91
|
+
|
|
92
|
+
def __init__(self, _klass: Callable, filters: list | None = None, order: list | None = None, projection: list | None = None, distinct_on: list | None = None,
|
|
93
|
+
limit: int | None = None, offset: int | None = None, page_size: int | None = None, page_token: str | None = None, **kwargs):
|
|
94
|
+
|
|
95
|
+
_clean_order = kwargs.pop('_clean_order', None)
|
|
96
|
+
|
|
97
|
+
# Initialize the query with the provided parameters, setting each parameter to None. Each parameter is
|
|
98
|
+
# associated with a respective function that will assign its value and perform validation.
|
|
99
|
+
super().__init__(_klass=None, filters=None, order=None, projection=None, distinct_on=None, limit=None,
|
|
100
|
+
offset=None, page_size=None, page_token=None, **kwargs)
|
|
101
|
+
|
|
102
|
+
if _klass is not None and not isclass(_klass):
|
|
103
|
+
try:
|
|
104
|
+
_klass = import_from_string(settings.EVERYSK_SDK_ENTITIES_MODULES_PATH[_klass])
|
|
105
|
+
except KeyError:
|
|
106
|
+
raise FieldValueError(f"The _klass value '{_klass}' must be a class or a string with the class name") from KeyError
|
|
107
|
+
|
|
108
|
+
self._klass = _klass
|
|
109
|
+
self._clean_order = set()
|
|
110
|
+
|
|
111
|
+
order = [] if order is None else order
|
|
112
|
+
self.order = []
|
|
113
|
+
for property_name in order:
|
|
114
|
+
self.sort_by(property_name)
|
|
115
|
+
|
|
116
|
+
if _clean_order and not isinstance(_clean_order, (list, set)):
|
|
117
|
+
raise FieldValueError(f'Key _clean_order must be {set}')
|
|
118
|
+
elif _clean_order:
|
|
119
|
+
self._clean_order = self._clean_order.union( _clean_order)
|
|
120
|
+
|
|
121
|
+
filters = [] if filters is None else filters
|
|
122
|
+
self.filters = []
|
|
123
|
+
for filter_set in filters:
|
|
124
|
+
self.where(*filter_set)
|
|
125
|
+
|
|
126
|
+
if projection is not None:
|
|
127
|
+
self.set_projection(projection)
|
|
128
|
+
|
|
129
|
+
distinct_on = [] if distinct_on is None else distinct_on
|
|
130
|
+
self.set_distinct_on(distinct_on)
|
|
131
|
+
|
|
132
|
+
if limit is not None:
|
|
133
|
+
self.set_limit(limit)
|
|
134
|
+
|
|
135
|
+
if offset is not None:
|
|
136
|
+
self.set_offset(offset)
|
|
137
|
+
|
|
138
|
+
if page_size is not None:
|
|
139
|
+
self.set_page_size(page_size)
|
|
140
|
+
|
|
141
|
+
if page_token is not None:
|
|
142
|
+
self.set_page_token(page_token)
|
|
143
|
+
|
|
144
|
+
def _process__klass(self, value: Any) -> Any:
|
|
145
|
+
"""
|
|
146
|
+
This method is used to process the '_klass' attribute.
|
|
147
|
+
"""
|
|
148
|
+
return value.__name__
|
|
149
|
+
|
|
150
|
+
def where(self, *args) -> Self:
|
|
151
|
+
"""
|
|
152
|
+
Adds a filter condition to the query.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
*args: Variable number of arguments. Expected formats are:
|
|
156
|
+
- (property_name, value)
|
|
157
|
+
- (property_name, operator, value)
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
self: The Query object with the added filter condition.
|
|
161
|
+
|
|
162
|
+
Raises:
|
|
163
|
+
ValueError: If the number of arguments is not 2 or 3, indicating an incorrect format.
|
|
164
|
+
ValueError: If the operator is not '=' and property_name is not one of ('date', 'created_on', 'updated_on').
|
|
165
|
+
|
|
166
|
+
Example:
|
|
167
|
+
To create a query with a filter condition:
|
|
168
|
+
query = Query(MyEntity).where('property_name', 'value')
|
|
169
|
+
|
|
170
|
+
To create a query with a filter condition using an operator:
|
|
171
|
+
query = Query(MyEntity).where('property_name', '>', 'value')
|
|
172
|
+
"""
|
|
173
|
+
property_name: str = args[0]
|
|
174
|
+
operator: str | None = None
|
|
175
|
+
value: str | None = None
|
|
176
|
+
|
|
177
|
+
if len(args) == 2:
|
|
178
|
+
operator = '='
|
|
179
|
+
value = args[1]
|
|
180
|
+
elif len(args) == 3:
|
|
181
|
+
operator = args[1]
|
|
182
|
+
value = args[2]
|
|
183
|
+
else:
|
|
184
|
+
raise SDKValueError('Query \'where\' function expects 2 or 3 arguments')
|
|
185
|
+
|
|
186
|
+
if operator not in settings.QUERY_OPERATORS:
|
|
187
|
+
raise SDKValueError(f'Invalid operator: {operator} for property {property_name}')
|
|
188
|
+
|
|
189
|
+
# Validate the operator for certain properties
|
|
190
|
+
if operator != '=' and property_name not in self._klass._allowed_query_attributes_for_all_operators:
|
|
191
|
+
raise SDKValueError(f"Filter by {property_name} operator must be '='")
|
|
192
|
+
|
|
193
|
+
if not value:
|
|
194
|
+
# Handle special case for searching null values like link_uid or date
|
|
195
|
+
self.filters.append((property_name, operator, value))
|
|
196
|
+
return self
|
|
197
|
+
|
|
198
|
+
# Handle special case for 'tags' property
|
|
199
|
+
if property_name == 'tags':
|
|
200
|
+
if isinstance(value, list):
|
|
201
|
+
self.filters.extend([('tags', '=', tag.lower().strip()) for tag in value])
|
|
202
|
+
elif isinstance(value, str):
|
|
203
|
+
self.filters.append(('tags', '=', value.lower().strip()))
|
|
204
|
+
else:
|
|
205
|
+
raise SDKTypeError('The tags value must be a string or a list of strings')
|
|
206
|
+
|
|
207
|
+
return self
|
|
208
|
+
|
|
209
|
+
# Handle special case for 'date' property
|
|
210
|
+
if property_name == 'date':
|
|
211
|
+
if is_string_object(value):
|
|
212
|
+
value = DateTime.fromisoformat(value).replace(hour=12, minute=0, second=0, microsecond=0)
|
|
213
|
+
|
|
214
|
+
elif Date.is_date(value):
|
|
215
|
+
value = DateTime.date_to_date_time(value)
|
|
216
|
+
|
|
217
|
+
if operator == '=':
|
|
218
|
+
start = value.replace(hour=0, minute=0, second=0, microsecond=0)
|
|
219
|
+
end = value.replace(hour=23, minute=59, second=59, microsecond=999999)
|
|
220
|
+
|
|
221
|
+
self.filters.append(('date', '>=', start))
|
|
222
|
+
self.filters.append(('date', '<=', end))
|
|
223
|
+
|
|
224
|
+
else:
|
|
225
|
+
if operator in ('>', '>='):
|
|
226
|
+
value = value.replace(hour=0, minute=0, second=0, microsecond=0)
|
|
227
|
+
|
|
228
|
+
elif operator in ('<', '<='):
|
|
229
|
+
value = value.replace(hour=23, minute=59, second=59, microsecond=999999)
|
|
230
|
+
|
|
231
|
+
self.filters.append((property_name, operator, value))
|
|
232
|
+
|
|
233
|
+
return self
|
|
234
|
+
|
|
235
|
+
# Handle special case for 'name' property
|
|
236
|
+
if property_name == 'name' and operator == '=':
|
|
237
|
+
value = normalize_string_to_search(value)
|
|
238
|
+
|
|
239
|
+
limit: str = f'{value[:-1]}{chr(ord(value[-1]) + 1)}'
|
|
240
|
+
self.filters.append((property_name, '<', limit))
|
|
241
|
+
self.filters.append((property_name, '>=', value))
|
|
242
|
+
|
|
243
|
+
return self
|
|
244
|
+
|
|
245
|
+
# Regular filter condition
|
|
246
|
+
self.filters.append((property_name, operator, value))
|
|
247
|
+
|
|
248
|
+
return self
|
|
249
|
+
|
|
250
|
+
def sort_by(self, property_name: str) -> Self:
|
|
251
|
+
"""
|
|
252
|
+
Add a property by which to sort the query and return the instance.
|
|
253
|
+
This method updates the query's order based on the provided property_name.
|
|
254
|
+
|
|
255
|
+
Args:
|
|
256
|
+
- property_name (str): The name of the property to sort by. It can optionally
|
|
257
|
+
contain hyphens, which will be removed.
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
- Query: The instance of the current object.
|
|
261
|
+
|
|
262
|
+
Raises:
|
|
263
|
+
- ValueError: If the provided property_name is not sortable or if the
|
|
264
|
+
property_name is duplicated in the current order.
|
|
265
|
+
|
|
266
|
+
Example:
|
|
267
|
+
To create a query with a sort condition:
|
|
268
|
+
>>> query = Query(MyEntity).sort_by('property_name')
|
|
269
|
+
|
|
270
|
+
"""
|
|
271
|
+
clean_name: str = property_name.replace('-', '')
|
|
272
|
+
|
|
273
|
+
if clean_name not in self._klass._orderable_attributes: # pylint: disable=protected-access
|
|
274
|
+
raise ValueError(f'{clean_name} is not sortable')
|
|
275
|
+
|
|
276
|
+
if clean_name in self._clean_order:
|
|
277
|
+
raise ValueError(f'Duplicated order property: {clean_name} in {self.order}')
|
|
278
|
+
|
|
279
|
+
self.order.append(property_name)
|
|
280
|
+
self._clean_order.add(clean_name)
|
|
281
|
+
|
|
282
|
+
return self
|
|
283
|
+
|
|
284
|
+
def set_projection(self, projection: list | str) -> Self:
|
|
285
|
+
"""
|
|
286
|
+
Set the projection attributes for the query and return the instance.
|
|
287
|
+
|
|
288
|
+
This method sets the desired properties that should be returned in the query result.
|
|
289
|
+
The properties can either be set to include (using the property name) or to exclude
|
|
290
|
+
(prefixing the property name with '-'). Both inclusion and exclusion should not be set
|
|
291
|
+
in the same query.
|
|
292
|
+
|
|
293
|
+
Args:
|
|
294
|
+
- projection (Union[List, str]): A property name as a string or a list of property names
|
|
295
|
+
indicating which properties to include or exclude in the query result.
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
- Query: The instance of the current object.
|
|
299
|
+
|
|
300
|
+
Raises:
|
|
301
|
+
- ValueError: If both projection and inverse projection are set in the same query or
|
|
302
|
+
if the projection properties do not belong to the entity kind.
|
|
303
|
+
|
|
304
|
+
Example:
|
|
305
|
+
To create a query with a projection condition:
|
|
306
|
+
>>> query = Query(MyEntity).set_projection('property_name')
|
|
307
|
+
|
|
308
|
+
To create a query with an inverse projection condition:
|
|
309
|
+
>>> query = Query(MyEntity).set_projection('-property_name')
|
|
310
|
+
|
|
311
|
+
To create a query with a projection condition using a list:
|
|
312
|
+
>>> query = Query(MyEntity).set_projection(['property_name_1', 'property_name_2'])
|
|
313
|
+
"""
|
|
314
|
+
self.projection = self._klass._normalize_projection(projection) # pylint: disable=protected-access
|
|
315
|
+
return self
|
|
316
|
+
|
|
317
|
+
def set_distinct_on(self, distinct_on: list | str) -> Self:
|
|
318
|
+
"""
|
|
319
|
+
Set the attributes for which the query results should be distinct.
|
|
320
|
+
|
|
321
|
+
This method allows you to specify properties such that the resulting entities
|
|
322
|
+
of the query are distinct with respect to these properties.
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
- distinct_on (Union[List, str]): A property name as a string or a list of property names
|
|
326
|
+
for which the resulting entities should be distinct.
|
|
327
|
+
|
|
328
|
+
Returns:
|
|
329
|
+
- Query: The instance of the current object, allowing for method chaining.
|
|
330
|
+
|
|
331
|
+
Example:
|
|
332
|
+
To create a query with a distinct condition:
|
|
333
|
+
>>> query = Query(MyEntity).set_distinct_on('property_name')
|
|
334
|
+
|
|
335
|
+
To create a query with a distinct condition using a list:
|
|
336
|
+
>>> query = Query(MyEntity).set_distinct_on(['property_name_1', 'property_name_2'])
|
|
337
|
+
"""
|
|
338
|
+
|
|
339
|
+
if is_string_object(distinct_on):
|
|
340
|
+
distinct_on = [distinct_on]
|
|
341
|
+
|
|
342
|
+
self.distinct_on = distinct_on
|
|
343
|
+
return self
|
|
344
|
+
|
|
345
|
+
def set_limit(self, limit: int) -> Self:
|
|
346
|
+
"""
|
|
347
|
+
Set the maximum number of results the query should return.
|
|
348
|
+
|
|
349
|
+
This method defines the maximum number of entities to retrieve from the database
|
|
350
|
+
when the query is executed.
|
|
351
|
+
|
|
352
|
+
Args:
|
|
353
|
+
- limit (int): The maximum number of results to retrieve.
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
- Query: The instance of the current object, allowing for method chaining.
|
|
357
|
+
|
|
358
|
+
Example:
|
|
359
|
+
To create a query with a limit condition:
|
|
360
|
+
>>> query = Query(MyEntity).set_limit(10)
|
|
361
|
+
"""
|
|
362
|
+
if not isinstance(limit, int):
|
|
363
|
+
raise SDKValueError('The limit value must be an integer.')
|
|
364
|
+
if isinstance(limit, int) and limit < 0:
|
|
365
|
+
raise SDKValueError('The limit value must be greater than or equal to 0.')
|
|
366
|
+
|
|
367
|
+
self.limit = limit
|
|
368
|
+
return self
|
|
369
|
+
|
|
370
|
+
def set_offset(self, offset: int) -> Self:
|
|
371
|
+
"""
|
|
372
|
+
Set the starting point from which to retrieve the results in the query.
|
|
373
|
+
|
|
374
|
+
This method specifies the number of initial results to skip before starting to
|
|
375
|
+
retrieve entities when the query is executed.
|
|
376
|
+
|
|
377
|
+
Args:
|
|
378
|
+
- offset (int): The number of results to skip before retrieval begins.
|
|
379
|
+
|
|
380
|
+
Returns:
|
|
381
|
+
- Query: The instance of the current object, allowing for method chaining.
|
|
382
|
+
|
|
383
|
+
Example:
|
|
384
|
+
To create a query with an offset condition:
|
|
385
|
+
>>> query = Query(MyEntity).set_offset(10)
|
|
386
|
+
"""
|
|
387
|
+
if not isinstance(offset, int):
|
|
388
|
+
raise SDKValueError('The offset value must be an integer.')
|
|
389
|
+
if isinstance(offset, int) and offset < 0:
|
|
390
|
+
raise SDKValueError('The offset value must be greater than or equal to 0.')
|
|
391
|
+
|
|
392
|
+
self.offset = offset
|
|
393
|
+
return self
|
|
394
|
+
|
|
395
|
+
def set_page_size(self, page_size: int) -> Self:
|
|
396
|
+
"""
|
|
397
|
+
Set the number of results to be returned per page for the query.
|
|
398
|
+
|
|
399
|
+
This method determines how many entities are retrieved at once in a paginated
|
|
400
|
+
manner when the query is executed.
|
|
401
|
+
|
|
402
|
+
Args:
|
|
403
|
+
- page_size (int): The number of results to retrieve per page.
|
|
404
|
+
|
|
405
|
+
Returns:
|
|
406
|
+
- Query: The instance of the current object, allowing for method chaining.
|
|
407
|
+
|
|
408
|
+
Example:
|
|
409
|
+
To create a query with a page size condition:
|
|
410
|
+
>>> query = Query(MyEntity).set_page_size(10)
|
|
411
|
+
"""
|
|
412
|
+
if not isinstance(page_size, int):
|
|
413
|
+
raise SDKValueError('The page_size value must be an integer.')
|
|
414
|
+
if isinstance(page_size, int) and page_size < 0:
|
|
415
|
+
raise SDKValueError('The page_size value must be greater than or equal to 0.')
|
|
416
|
+
|
|
417
|
+
self.page_size = page_size
|
|
418
|
+
return self
|
|
419
|
+
|
|
420
|
+
def set_page_token(self, page_token: str) -> Self:
|
|
421
|
+
"""
|
|
422
|
+
Set the token representing a specific page of results in the query.
|
|
423
|
+
|
|
424
|
+
This method determines the starting point for retrieving entities based on the
|
|
425
|
+
provided page token when the query is executed.
|
|
426
|
+
|
|
427
|
+
Args:
|
|
428
|
+
- page_token (str): The token representing the desired page of results.
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
- Query: The instance of the current object, allowing for method chaining.
|
|
432
|
+
|
|
433
|
+
Example:
|
|
434
|
+
To create a query with a page token condition:
|
|
435
|
+
>>> query = Query(MyEntity).set_page_token('page_token')
|
|
436
|
+
"""
|
|
437
|
+
self.page_token = page_token
|
|
438
|
+
return self
|
|
439
|
+
|
|
440
|
+
def set_find_or_fail(self, find_or_fail: bool) -> Self:
|
|
441
|
+
"""
|
|
442
|
+
Set the find_or_fail attribute for the query and return the instance.
|
|
443
|
+
|
|
444
|
+
This method sets the desired find_or_fail attribute that should be returned in the query result.
|
|
445
|
+
|
|
446
|
+
Args:
|
|
447
|
+
- find_or_fail (bool): A boolean value indicating whether the query should return an error if no entity is found.
|
|
448
|
+
|
|
449
|
+
Returns:
|
|
450
|
+
- Query: The instance of the current object.
|
|
451
|
+
|
|
452
|
+
Example:
|
|
453
|
+
To create a query with a find_or_fail condition:
|
|
454
|
+
>>> query = Query(MyEntity).set_find_or_fail(True)
|
|
455
|
+
"""
|
|
456
|
+
self._find_or_fail = find_or_fail
|
|
457
|
+
return self
|
|
458
|
+
|
|
459
|
+
def load(self, offset: int = Undefined) -> Any:
|
|
460
|
+
"""
|
|
461
|
+
Fetch a single entity based on the query with an optional offset.
|
|
462
|
+
|
|
463
|
+
This method retrieves a single entity from the data source based on the conditions
|
|
464
|
+
specified in the query. An optional offset can be provided to skip a certain number
|
|
465
|
+
of results before fetching the desired entity.
|
|
466
|
+
|
|
467
|
+
Args:
|
|
468
|
+
- offset (int, optional): The number of results to skip before fetching the entity.
|
|
469
|
+
Defaults to None, meaning no results are skipped.
|
|
470
|
+
|
|
471
|
+
Returns:
|
|
472
|
+
- Any: An instance of the entity, or None if no entity matches the query.
|
|
473
|
+
|
|
474
|
+
Example:
|
|
475
|
+
To create a query with a load condition:
|
|
476
|
+
>>> entity = Query(MyEntity).where('property_name', 'value').load()
|
|
477
|
+
"""
|
|
478
|
+
entity: Any | None = self.get_response(self_obj=self, params={'offset': offset})
|
|
479
|
+
|
|
480
|
+
if entity is not None:
|
|
481
|
+
entity = self._klass(**entity)
|
|
482
|
+
|
|
483
|
+
return entity
|
|
484
|
+
|
|
485
|
+
def loads(self, limit: int = Undefined, offset: int = Undefined) -> list[Any]:
|
|
486
|
+
"""
|
|
487
|
+
Fetch a list of entities based on the query with optional limit and offset.
|
|
488
|
+
|
|
489
|
+
This method retrieves multiple entities from the data source based on the conditions
|
|
490
|
+
specified in the query. Optional limit and offset parameters can be provided to control
|
|
491
|
+
the number of returned entities and the starting point, respectively.
|
|
492
|
+
|
|
493
|
+
Args:
|
|
494
|
+
- limit (int, optional): The maximum number of entities to retrieve. Defaults to None,
|
|
495
|
+
meaning there's no specific limit.
|
|
496
|
+
- offset (int, optional): The number of initial entities to skip before starting retrieval.
|
|
497
|
+
Defaults to None, meaning no entities are skipped.
|
|
498
|
+
|
|
499
|
+
Returns:
|
|
500
|
+
- List[Any]: A list of instances of the entity. Returns an empty list if no entities match
|
|
501
|
+
the query.
|
|
502
|
+
|
|
503
|
+
Example:
|
|
504
|
+
To create a query with a loads condition:
|
|
505
|
+
>>> entities = Query(MyEntity).where('property_name', 'value').loads()
|
|
506
|
+
"""
|
|
507
|
+
entities: list[dict] = self.get_response(self_obj=self, params={'limit': limit, 'offset': offset})
|
|
508
|
+
|
|
509
|
+
entities: list[Any] = [self._klass(**entity) for entity in entities]
|
|
510
|
+
|
|
511
|
+
return entities
|
|
512
|
+
|
|
513
|
+
def page(self, page_size: int = Undefined, page_token: str = Undefined) -> QueryPage:
|
|
514
|
+
"""
|
|
515
|
+
Fetch a paginated list of entities based on the query.
|
|
516
|
+
|
|
517
|
+
This method retrieves a paginated set of entities from the data source based on the conditions
|
|
518
|
+
specified in the query. A specific page size and an optional page token can be provided to
|
|
519
|
+
control pagination.
|
|
520
|
+
|
|
521
|
+
Args:
|
|
522
|
+
- page_size (int, optional): The number of entities to retrieve per page. Defaults to 20.
|
|
523
|
+
- page_token (str, optional): The token representing the desired page of results. Defaults to None,
|
|
524
|
+
meaning the first page is retrieved.
|
|
525
|
+
|
|
526
|
+
Returns:
|
|
527
|
+
- Any: A dictionary containing the paginated list of entities and potentially other metadata
|
|
528
|
+
related to pagination.
|
|
529
|
+
|
|
530
|
+
Example:
|
|
531
|
+
To create a query with a page condition:
|
|
532
|
+
>>> entities_page = Query(MyEntity).where('property_name', 'value').page()
|
|
533
|
+
"""
|
|
534
|
+
response: QueryPage = self.get_response(self_obj=self, params={'page_size': page_size, 'page_token': page_token})
|
|
535
|
+
|
|
536
|
+
response['entities'] = [self._klass(**entity) for entity in response['entities']]
|
|
537
|
+
|
|
538
|
+
return response
|
|
539
|
+
|
|
540
|
+
def pages(self, page_size: int = Undefined) -> Generator[list[Any | None], None, None]:
|
|
541
|
+
"""
|
|
542
|
+
Fetch paginated lists of entities based on the query.
|
|
543
|
+
|
|
544
|
+
This method retrieves multiple pages of entities from the data source based on the conditions
|
|
545
|
+
specified in the query. Each page will contain up to `page_size` entities. This function yields
|
|
546
|
+
each page of entities as they are retrieved.
|
|
547
|
+
|
|
548
|
+
Args:
|
|
549
|
+
- page_size (int, optional): The number of entities to retrieve per page. Defaults to 20.
|
|
550
|
+
|
|
551
|
+
Yields:
|
|
552
|
+
- List[Any]: A list of entities for the current page.
|
|
553
|
+
|
|
554
|
+
Note:
|
|
555
|
+
This generator function will continue to fetch and yield pages until no more pages are available.
|
|
556
|
+
|
|
557
|
+
Example:
|
|
558
|
+
To create a query with a pages condition:
|
|
559
|
+
>>> for entities in Query(MyEntity).where('property_name', 'value').pages():
|
|
560
|
+
... print(entities)
|
|
561
|
+
"""
|
|
562
|
+
next_page_token: str = Undefined
|
|
563
|
+
|
|
564
|
+
while True:
|
|
565
|
+
result: QueryPage = self.page(page_size=page_size, page_token=next_page_token)
|
|
566
|
+
yield result['entities']
|
|
567
|
+
|
|
568
|
+
if not result['next_page_token']:
|
|
569
|
+
break
|
|
570
|
+
|
|
571
|
+
next_page_token = result['next_page_token']
|
|
572
|
+
|
|
573
|
+
def fetch_ids(self, limit: int = Undefined, offset: int = Undefined) -> list[str]:
|
|
574
|
+
"""
|
|
575
|
+
Fetch a list of entity IDs based on the query.
|
|
576
|
+
|
|
577
|
+
This method retrieves a list of entity IDs from the data source based on the conditions
|
|
578
|
+
specified in the query.
|
|
579
|
+
|
|
580
|
+
Returns:
|
|
581
|
+
- List[str]: A list of entity IDs. Returns an empty list if no entities match the query.
|
|
582
|
+
|
|
583
|
+
Example:
|
|
584
|
+
To create a query with a fetch_ids condition:
|
|
585
|
+
>>> entity_ids = Query(MyEntity).where('property_name', 'value').fetch_ids()
|
|
586
|
+
"""
|
|
587
|
+
return self.get_response(self_obj=self, params={'limit': limit, 'offset': offset})
|
|
588
|
+
|
|
589
|
+
def fetch_id(self, offset: int = Undefined) -> str | None:
|
|
590
|
+
"""
|
|
591
|
+
Load a single entity matching the query and return its id.
|
|
592
|
+
|
|
593
|
+
Args:
|
|
594
|
+
offset (int, optional): The offset of the entity to load. Defaults to DEFAULT_QUERY_OFFSET.
|
|
595
|
+
|
|
596
|
+
Returns:
|
|
597
|
+
str: The id of the entity, or None if no entity is found.
|
|
598
|
+
|
|
599
|
+
Example:
|
|
600
|
+
To create a query with a fetch_id condition:
|
|
601
|
+
>>> entity_id = Query(MyEntity).where('property_name', 'value').fetch_id()
|
|
602
|
+
"""
|
|
603
|
+
return self.get_response(self_obj=self, params={'offset': offset})
|