Skip to content

Commit 9bd0ff4

Browse files
authored
Merge pull request #300 from ynput/enhancement/advanced-filtering
Entities: Advanced filtering
2 parents a1afd48 + 380dfb5 commit 9bd0ff4

10 files changed

Lines changed: 150 additions & 36 deletions

File tree

ayon_api/_api.py

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
ActionModeType,
8585
StreamType,
8686
EntityListAttributeDefinitionDict,
87+
AdvancedFilterDict,
8788
)
8889
from ._api_helpers.links import CreateLinkData
8990

@@ -4218,6 +4219,7 @@ def get_folders(
42184219
tags: Optional[Iterable[str]] = None,
42194220
active: Optional[bool] = True,
42204221
has_links: Optional[bool] = None,
4222+
filters: Optional[AdvancedFilterDict] = None,
42214223
fields: Optional[Iterable[str]] = None,
42224224
own_attributes: bool = False,
42234225
) -> Generator[FolderDict, None, None]:
@@ -4259,6 +4261,7 @@ def get_folders(
42594261
Both are returned if is set to None.
42604262
has_links (Optional[Literal[IN, OUT, ANY]]): Filter
42614263
representations with IN/OUT/ANY links.
4264+
filters (Optional[AdvancedFilterDict]): Advanced filtering options.
42624265
fields (Optional[Iterable[str]]): Fields to be queried for
42634266
folder. All possible folder fields are returned
42644267
if 'None' is passed.
@@ -4286,6 +4289,7 @@ def get_folders(
42864289
tags=tags,
42874290
active=active,
42884291
has_links=has_links,
4292+
filters=filters,
42894293
fields=fields,
42904294
own_attributes=own_attributes,
42914295
)
@@ -4571,6 +4575,7 @@ def get_tasks(
45714575
statuses: Optional[Iterable[str]] = None,
45724576
tags: Optional[Iterable[str]] = None,
45734577
active: Optional[bool] = True,
4578+
filters: Optional[AdvancedFilterDict] = None,
45744579
fields: Optional[Iterable[str]] = None,
45754580
own_attributes: bool = False,
45764581
) -> Generator[TaskDict, None, None]:
@@ -4595,6 +4600,7 @@ def get_tasks(
45954600
filtering.
45964601
active (Optional[bool]): Filter active/inactive tasks.
45974602
Both are returned if is set to None.
4603+
filters (Optional[AdvancedFilterDict]): Advanced filtering options.
45984604
fields (Optional[Iterable[str]]): Fields to be queried for
45994605
folder. All possible folder fields are returned
46004606
if 'None' is passed.
@@ -4617,6 +4623,7 @@ def get_tasks(
46174623
statuses=statuses,
46184624
tags=tags,
46194625
active=active,
4626+
filters=filters,
46204627
fields=fields,
46214628
own_attributes=own_attributes,
46224629
)
@@ -4695,6 +4702,7 @@ def get_tasks_by_folder_paths(
46954702
statuses: Optional[Iterable[str]] = None,
46964703
tags: Optional[Iterable[str]] = None,
46974704
active: Optional[bool] = True,
4705+
filters: Optional[AdvancedFilterDict] = None,
46984706
fields: Optional[Iterable[str]] = None,
46994707
own_attributes: bool = False,
47004708
) -> dict[str, list[TaskDict]]:
@@ -4717,6 +4725,7 @@ def get_tasks_by_folder_paths(
47174725
filtering.
47184726
active (Optional[bool]): Filter active/inactive tasks.
47194727
Both are returned if is set to None.
4728+
filters (Optional[AdvancedFilterDict]): Advanced filtering options.
47204729
fields (Optional[Iterable[str]]): Fields to be queried for
47214730
folder. All possible folder fields are returned
47224731
if 'None' is passed.
@@ -4739,6 +4748,7 @@ def get_tasks_by_folder_paths(
47394748
statuses=statuses,
47404749
tags=tags,
47414750
active=active,
4751+
filters=filters,
47424752
fields=fields,
47434753
own_attributes=own_attributes,
47444754
)
@@ -4988,6 +4998,7 @@ def get_products(
49884998
statuses: Optional[Iterable[str]] = None,
49894999
tags: Optional[Iterable[str]] = None,
49905000
active: Optional[bool] = True,
5001+
filters: Optional[AdvancedFilterDict] = None,
49915002
fields: Optional[Iterable[str]] = None,
49925003
own_attributes=_PLACEHOLDER,
49935004
) -> Generator[ProductDict, None, None]:
@@ -5019,6 +5030,7 @@ def get_products(
50195030
for filtering.
50205031
active (Optional[bool]): Filter active/inactive products.
50215032
Both are returned if is set to None.
5033+
filters (Optional[AdvancedFilterDict]): Advanced filtering options.
50225034
fields (Optional[Iterable[str]]): Fields to be queried for
50235035
folder. All possible folder fields are returned
50245036
if 'None' is passed.
@@ -5043,6 +5055,7 @@ def get_products(
50435055
statuses=statuses,
50445056
tags=tags,
50455057
active=active,
5058+
filters=filters,
50465059
fields=fields,
50475060
own_attributes=own_attributes,
50485061
)
@@ -5325,6 +5338,7 @@ def get_versions(
53255338
statuses: Optional[Iterable[str]] = None,
53265339
tags: Optional[Iterable[str]] = None,
53275340
active: Optional[bool] = True,
5341+
filters: Optional[AdvancedFilterDict] = None,
53285342
fields: Optional[Iterable[str]] = None,
53295343
own_attributes=_PLACEHOLDER,
53305344
) -> Generator[VersionDict, None, None]:
@@ -5351,6 +5365,7 @@ def get_versions(
53515365
for filtering.
53525366
active (Optional[bool]): Receive active/inactive entities.
53535367
Both are returned when 'None' is passed.
5368+
filters (Optional[AdvancedFilterDict]): Advanced filtering options.
53545369
fields (Optional[Iterable[str]]): Fields to be queried
53555370
for version. All possible folder fields are returned
53565371
if 'None' is passed.
@@ -5374,6 +5389,7 @@ def get_versions(
53745389
statuses=statuses,
53755390
tags=tags,
53765391
active=active,
5392+
filters=filters,
53775393
fields=fields,
53785394
own_attributes=own_attributes,
53795395
)
@@ -5819,6 +5835,7 @@ def get_representations(
58195835
tags: Optional[Iterable[str]] = None,
58205836
active: Optional[bool] = True,
58215837
has_links: Optional[str] = None,
5838+
filters: Optional[AdvancedFilterDict] = None,
58225839
fields: Optional[Iterable[str]] = None,
58235840
own_attributes=_PLACEHOLDER,
58245841
) -> Generator[RepresentationDict, None, None]:
@@ -5849,6 +5866,7 @@ def get_representations(
58495866
Both are returned when 'None' is passed.
58505867
has_links (Optional[Literal[IN, OUT, ANY]]): Filter
58515868
representations with IN/OUT/ANY links.
5869+
filters (Optional[AdvancedFilterDict]): Advanced filtering options.
58525870
fields (Optional[Iterable[str]]): Fields to be queried for
58535871
representation. All possible fields are returned if 'None' is
58545872
passed.
@@ -5871,6 +5889,7 @@ def get_representations(
58715889
tags=tags,
58725890
active=active,
58735891
has_links=has_links,
5892+
filters=filters,
58745893
fields=fields,
58755894
own_attributes=own_attributes,
58765895
)
@@ -7282,7 +7301,15 @@ def get_entity_lists(
72827301
active: Optional[bool] = None,
72837302
fields: Optional[Iterable[str]] = None,
72847303
) -> Generator[dict[str, Any], None, None]:
7285-
"""Fetch entity lists from server.
7304+
"""Fetch entity lists from AYON server.
7305+
7306+
Warnings:
7307+
You can't get list items for lists with different 'entityType' in
7308+
one call.
7309+
7310+
Notes:
7311+
To get list items, you have to pass 'items' field or
7312+
'items.{sub-fields you want}' to 'fields' argument.
72867313
72877314
Args:
72887315
project_name (str): Project name where entity lists are.

ayon_api/_api_helpers/base.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import logging
44
import typing
5-
from typing import Optional, Any, Iterable
5+
from typing import Optional, Any, Iterable, Union
66

77
import requests
88

@@ -142,6 +142,11 @@ def _prepare_fields(
142142
):
143143
raise NotImplementedError()
144144

145+
def _prepare_advanced_filters(
146+
self, filters: Union[str, dict[str, Any], None]
147+
) -> Optional[str]:
148+
raise NotImplementedError()
149+
145150
def _convert_entity_data(self, entity: AnyEntityDict):
146151
raise NotImplementedError()
147152

ayon_api/_api_helpers/folders.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
FolderDict,
2222
FlatFolderDict,
2323
ProjectHierarchyDict,
24+
AdvancedFilterDict,
2425
)
2526

2627

@@ -216,6 +217,7 @@ def get_folders(
216217
tags: Optional[Iterable[str]] = None,
217218
active: Optional[bool] = True,
218219
has_links: Optional[bool] = None,
220+
filters: Optional[AdvancedFilterDict] = None,
219221
fields: Optional[Iterable[str]] = None,
220222
own_attributes: bool = False
221223
) -> Generator[FolderDict, None, None]:
@@ -257,6 +259,7 @@ def get_folders(
257259
Both are returned if is set to None.
258260
has_links (Optional[Literal[IN, OUT, ANY]]): Filter
259261
representations with IN/OUT/ANY links.
262+
filters (Optional[AdvancedFilterDict]): Advanced filtering options.
260263
fields (Optional[Iterable[str]]): Fields to be queried for
261264
folder. All possible folder fields are returned
262265
if 'None' is passed.
@@ -270,11 +273,11 @@ def get_folders(
270273
if not project_name:
271274
return
272275

273-
filters = {
276+
graphql_filters = {
274277
"projectName": project_name
275278
}
276279
if not prepare_list_filters(
277-
filters,
280+
graphql_filters,
278281
("folderIds", folder_ids),
279282
("folderPaths", folder_paths),
280283
("folderNames", folder_names),
@@ -291,9 +294,10 @@ def get_folders(
291294
("folderHasTasks", has_tasks),
292295
("folderHasLinks", has_links),
293296
("folderHasChildren", has_children),
297+
("filter", self._prepare_advanced_filters(filters)),
294298
):
295299
if filter_value is not None:
296-
filters[filter_key] = filter_value
300+
graphql_filters[filter_key] = filter_value
297301

298302
if parent_ids is not None:
299303
parent_ids = set(parent_ids)
@@ -313,7 +317,7 @@ def get_folders(
313317
parent_ids.remove(project_name)
314318
parent_ids.add("root")
315319

316-
filters["parentFolderIds"] = list(parent_ids)
320+
graphql_filters["parentFolderIds"] = list(parent_ids)
317321

318322
if not fields:
319323
fields = self.get_default_fields_for_type("folder")
@@ -328,7 +332,7 @@ def get_folders(
328332
fields.add("ownAttrib")
329333

330334
query = folders_graphql_query(fields)
331-
for attr, filter_value in filters.items():
335+
for attr, filter_value in graphql_filters.items():
332336
query.set_variable_value(attr, filter_value)
333337

334338
for parsed_data in query.continuous_query(self):

ayon_api/_api_helpers/products.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
from .base import BaseServerAPI, _PLACEHOLDER
1919

2020
if typing.TYPE_CHECKING:
21-
from ayon_api.typing import ProductDict, ProductTypeDict
21+
from ayon_api.typing import (
22+
ProductDict,
23+
ProductTypeDict,
24+
AdvancedFilterDict,
25+
)
2226

2327

2428
class ProductsAPI(BaseServerAPI):
@@ -43,6 +47,7 @@ def get_products(
4347
statuses: Optional[Iterable[str]] = None,
4448
tags: Optional[Iterable[str]] = None,
4549
active: Optional[bool] = True,
50+
filters: Optional[AdvancedFilterDict] = None,
4651
fields: Optional[Iterable[str]] = None,
4752
own_attributes=_PLACEHOLDER
4853
) -> Generator[ProductDict, None, None]:
@@ -74,6 +79,7 @@ def get_products(
7479
for filtering.
7580
active (Optional[bool]): Filter active/inactive products.
7681
Both are returned if is set to None.
82+
filters (Optional[AdvancedFilterDict]): Advanced filtering options.
7783
fields (Optional[Iterable[str]]): Fields to be queried for
7884
folder. All possible folder fields are returned
7985
if 'None' is passed.
@@ -145,18 +151,18 @@ def get_products(
145151
fields.add("folderId")
146152

147153
# Prepare filters for query
148-
filters = {
154+
graphql_filters = {
149155
"projectName": project_name
150156
}
151157

152158
if filter_folder_ids:
153-
filters["folderIds"] = list(filter_folder_ids)
159+
graphql_filters["folderIds"] = list(filter_folder_ids)
154160

155161
if filter_product_names:
156-
filters["productNames"] = list(filter_product_names)
162+
graphql_filters["productNames"] = list(filter_product_names)
157163

158164
if not prepare_list_filters(
159-
filters,
165+
graphql_filters,
160166
("productIds", product_ids),
161167
("productTypes", product_types),
162168
("productBaseTypes", product_base_types),
@@ -168,12 +174,13 @@ def get_products(
168174
for filter_key, filter_value in (
169175
("productNameRegex", product_name_regex),
170176
("productPathRegex", product_path_regex),
177+
("filter", self._prepare_advanced_filters(filters)),
171178
):
172179
if filter_value:
173-
filters[filter_key] = filter_value
180+
graphql_filters[filter_key] = filter_value
174181

175182
query = products_graphql_query(fields)
176-
for attr, filter_value in filters.items():
183+
for attr, filter_value in graphql_filters.items():
177184
query.set_variable_value(attr, filter_value)
178185

179186
parsed_data = query.query(self)

0 commit comments

Comments
 (0)