ffbb-data-client 2.0.0__py3-none-any.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.
Files changed (207) hide show
  1. ffbb_api_client_v3/__init__.py +25 -0
  2. ffbb_data_client/__init__.py +175 -0
  3. ffbb_data_client/clients/__init__.py +13 -0
  4. ffbb_data_client/clients/api_ffbb_app_client.py +2475 -0
  5. ffbb_data_client/clients/ffbb_data_client.py +2789 -0
  6. ffbb_data_client/clients/meilisearch_client.py +218 -0
  7. ffbb_data_client/clients/meilisearch_ffbb_client.py +647 -0
  8. ffbb_data_client/config.py +153 -0
  9. ffbb_data_client/data/__init__.py +25 -0
  10. ffbb_data_client/data/collections.json +1364 -0
  11. ffbb_data_client/data/endpoint_discovery.json +1875 -0
  12. ffbb_data_client/data/indexes.json +501 -0
  13. ffbb_data_client/data/openapi.json +35713 -0
  14. ffbb_data_client/data/openapi_full.json +37622 -0
  15. ffbb_data_client/helpers/__init__.py +27 -0
  16. ffbb_data_client/helpers/http_requests_helper.py +73 -0
  17. ffbb_data_client/helpers/http_requests_utils.py +502 -0
  18. ffbb_data_client/helpers/meilisearch_client_extension.py +153 -0
  19. ffbb_data_client/helpers/multi_search_query_helper.py +35 -0
  20. ffbb_data_client/models/__init__.py +241 -0
  21. ffbb_data_client/models/affiche.py +45 -0
  22. ffbb_data_client/models/cartographie.py +82 -0
  23. ffbb_data_client/models/categorie.py +55 -0
  24. ffbb_data_client/models/categorie_type.py +42 -0
  25. ffbb_data_client/models/clock.py +38 -0
  26. ffbb_data_client/models/club_contacts.py +77 -0
  27. ffbb_data_client/models/code.py +7 -0
  28. ffbb_data_client/models/commune.py +66 -0
  29. ffbb_data_client/models/competition_fields.py +309 -0
  30. ffbb_data_client/models/competition_id.py +116 -0
  31. ffbb_data_client/models/competition_id_categorie.py +31 -0
  32. ffbb_data_client/models/competition_id_sexe.py +31 -0
  33. ffbb_data_client/models/competition_id_type_competition.py +27 -0
  34. ffbb_data_client/models/competition_id_type_competition_generique.py +24 -0
  35. ffbb_data_client/models/competition_origine.py +69 -0
  36. ffbb_data_client/models/competition_origine_categorie.py +23 -0
  37. ffbb_data_client/models/competition_origine_type_competition.py +14 -0
  38. ffbb_data_client/models/competition_origine_type_competition_generique.py +24 -0
  39. ffbb_data_client/models/competition_type.py +6 -0
  40. ffbb_data_client/models/competitions_facet_distribution.py +65 -0
  41. ffbb_data_client/models/competitions_facet_stats.py +14 -0
  42. ffbb_data_client/models/competitions_hit.py +232 -0
  43. ffbb_data_client/models/competitions_multi_search_query.py +40 -0
  44. ffbb_data_client/models/competitions_query.py +11 -0
  45. ffbb_data_client/models/configuration_models.py +5 -0
  46. ffbb_data_client/models/contact_info.py +18 -0
  47. ffbb_data_client/models/content_multi_search_query.py +93 -0
  48. ffbb_data_client/models/coordonnees.py +27 -0
  49. ffbb_data_client/models/coordonnees_type.py +5 -0
  50. ffbb_data_client/models/document_flyer.py +205 -0
  51. ffbb_data_client/models/document_flyer_type.py +6 -0
  52. ffbb_data_client/models/engagement_contacts.py +97 -0
  53. ffbb_data_client/models/engagements_facet_distribution.py +59 -0
  54. ffbb_data_client/models/engagements_facet_stats.py +14 -0
  55. ffbb_data_client/models/engagements_hit.py +192 -0
  56. ffbb_data_client/models/engagements_multi_search_query.py +41 -0
  57. ffbb_data_client/models/etat.py +6 -0
  58. ffbb_data_client/models/external_competition_id.py +42 -0
  59. ffbb_data_client/models/external_id.py +72 -0
  60. ffbb_data_client/models/facet_distribution.py +13 -0
  61. ffbb_data_client/models/facet_stats.py +13 -0
  62. ffbb_data_client/models/field_set.py +10 -0
  63. ffbb_data_client/models/folder.py +35 -0
  64. ffbb_data_client/models/formation_session.py +60 -0
  65. ffbb_data_client/models/formations_facet_distribution.py +61 -0
  66. ffbb_data_client/models/formations_facet_stats.py +14 -0
  67. ffbb_data_client/models/formations_hit.py +277 -0
  68. ffbb_data_client/models/formations_multi_search_query.py +41 -0
  69. ffbb_data_client/models/game_stats_model.py +57 -0
  70. ffbb_data_client/models/game_stats_models.py +5 -0
  71. ffbb_data_client/models/generic_search.py +92 -0
  72. ffbb_data_client/models/geo.py +27 -0
  73. ffbb_data_client/models/geo_sort_order.py +6 -0
  74. ffbb_data_client/models/get_commune_response.py +18 -0
  75. ffbb_data_client/models/get_competition_response.py +523 -0
  76. ffbb_data_client/models/get_configuration_response.py +45 -0
  77. ffbb_data_client/models/get_engagement_response.py +23 -0
  78. ffbb_data_client/models/get_entraineur_response.py +18 -0
  79. ffbb_data_client/models/get_formation_response.py +28 -0
  80. ffbb_data_client/models/get_officiel_response.py +18 -0
  81. ffbb_data_client/models/get_organisme_response.py +476 -0
  82. ffbb_data_client/models/get_poule_response.py +68 -0
  83. ffbb_data_client/models/get_pratique_response.py +18 -0
  84. ffbb_data_client/models/get_rencontre_response.py +93 -0
  85. ffbb_data_client/models/get_saisons_response.py +56 -0
  86. ffbb_data_client/models/get_salle_response.py +20 -0
  87. ffbb_data_client/models/get_terrain_response.py +16 -0
  88. ffbb_data_client/models/get_tournoi_response.py +16 -0
  89. ffbb_data_client/models/gradient_color.py +27 -0
  90. ffbb_data_client/models/hit.py +16 -0
  91. ffbb_data_client/models/id_engagement_equipe.py +32 -0
  92. ffbb_data_client/models/id_organisme_equipe.py +51 -0
  93. ffbb_data_client/models/id_organisme_equipe1_logo.py +28 -0
  94. ffbb_data_client/models/id_poule.py +27 -0
  95. ffbb_data_client/models/jour.py +11 -0
  96. ffbb_data_client/models/label.py +15 -0
  97. ffbb_data_client/models/labellisation.py +30 -0
  98. ffbb_data_client/models/live.py +192 -0
  99. ffbb_data_client/models/lives.py +6 -0
  100. ffbb_data_client/models/logo.py +28 -0
  101. ffbb_data_client/models/multi_search_queries.py +24 -0
  102. ffbb_data_client/models/multi_search_query.py +96 -0
  103. ffbb_data_client/models/multi_search_result_competitions.py +14 -0
  104. ffbb_data_client/models/multi_search_result_engagements.py +14 -0
  105. ffbb_data_client/models/multi_search_result_formations.py +12 -0
  106. ffbb_data_client/models/multi_search_result_organismes.py +12 -0
  107. ffbb_data_client/models/multi_search_result_pratiques.py +12 -0
  108. ffbb_data_client/models/multi_search_result_rencontres.py +12 -0
  109. ffbb_data_client/models/multi_search_result_salles.py +12 -0
  110. ffbb_data_client/models/multi_search_result_terrains.py +12 -0
  111. ffbb_data_client/models/multi_search_result_tournois.py +12 -0
  112. ffbb_data_client/models/multi_search_results.py +103 -0
  113. ffbb_data_client/models/multi_search_results_class.py +96 -0
  114. ffbb_data_client/models/nature_sol.py +57 -0
  115. ffbb_data_client/models/niveau.py +10 -0
  116. ffbb_data_client/models/niveau_class.py +27 -0
  117. ffbb_data_client/models/niveau_extractor.py +214 -0
  118. ffbb_data_client/models/niveau_info.py +64 -0
  119. ffbb_data_client/models/niveau_models.py +14 -0
  120. ffbb_data_client/models/niveau_type.py +10 -0
  121. ffbb_data_client/models/objectif.py +7 -0
  122. ffbb_data_client/models/organisateur.py +197 -0
  123. ffbb_data_client/models/organisateur_type.py +6 -0
  124. ffbb_data_client/models/organisme_fields.py +327 -0
  125. ffbb_data_client/models/organisme_id_pere.py +177 -0
  126. ffbb_data_client/models/organismes_facet_distribution.py +46 -0
  127. ffbb_data_client/models/organismes_facet_stats.py +14 -0
  128. ffbb_data_client/models/organismes_hit.py +196 -0
  129. ffbb_data_client/models/organismes_multi_search_query.py +41 -0
  130. ffbb_data_client/models/organismes_query.py +8 -0
  131. ffbb_data_client/models/phase_code.py +23 -0
  132. ffbb_data_client/models/poule.py +35 -0
  133. ffbb_data_client/models/poule_fields.py +261 -0
  134. ffbb_data_client/models/poule_rencontre_item_model.py +69 -0
  135. ffbb_data_client/models/poules_models.py +6 -0
  136. ffbb_data_client/models/poules_query.py +9 -0
  137. ffbb_data_client/models/pratique.py +7 -0
  138. ffbb_data_client/models/pratiques_facet_distribution.py +29 -0
  139. ffbb_data_client/models/pratiques_facet_stats.py +14 -0
  140. ffbb_data_client/models/pratiques_hit.py +310 -0
  141. ffbb_data_client/models/pratiques_hit_type.py +9 -0
  142. ffbb_data_client/models/pratiques_multi_search_query.py +41 -0
  143. ffbb_data_client/models/pratiques_type_class.py +45 -0
  144. ffbb_data_client/models/publication_internet.py +6 -0
  145. ffbb_data_client/models/purple_logo.py +24 -0
  146. ffbb_data_client/models/query_fields_manager.py +75 -0
  147. ffbb_data_client/models/ranking_engagement.py +41 -0
  148. ffbb_data_client/models/rankings_models.py +6 -0
  149. ffbb_data_client/models/rencontres_engagement.py +23 -0
  150. ffbb_data_client/models/rencontres_facet_distribution.py +65 -0
  151. ffbb_data_client/models/rencontres_facet_stats.py +14 -0
  152. ffbb_data_client/models/rencontres_hit.py +271 -0
  153. ffbb_data_client/models/rencontres_multi_search_query.py +41 -0
  154. ffbb_data_client/models/saison.py +23 -0
  155. ffbb_data_client/models/saison_fields.py +36 -0
  156. ffbb_data_client/models/saisons_models.py +6 -0
  157. ffbb_data_client/models/saisons_query.py +9 -0
  158. ffbb_data_client/models/salle.py +56 -0
  159. ffbb_data_client/models/salles_facet_distribution.py +14 -0
  160. ffbb_data_client/models/salles_facet_stats.py +14 -0
  161. ffbb_data_client/models/salles_hit.py +153 -0
  162. ffbb_data_client/models/salles_multi_search_query.py +40 -0
  163. ffbb_data_client/models/sexe.py +9 -0
  164. ffbb_data_client/models/sexe_class.py +31 -0
  165. ffbb_data_client/models/source.py +5 -0
  166. ffbb_data_client/models/status.py +5 -0
  167. ffbb_data_client/models/team_engagement.py +56 -0
  168. ffbb_data_client/models/team_ranking.py +108 -0
  169. ffbb_data_client/models/terrains_categorie_championnat_3x3_libelle.py +5 -0
  170. ffbb_data_client/models/terrains_facet_distribution.py +41 -0
  171. ffbb_data_client/models/terrains_facet_stats.py +14 -0
  172. ffbb_data_client/models/terrains_hit.py +223 -0
  173. ffbb_data_client/models/terrains_multi_search_query.py +42 -0
  174. ffbb_data_client/models/terrains_name.py +5 -0
  175. ffbb_data_client/models/terrains_sexe_enum.py +7 -0
  176. ffbb_data_client/models/terrains_storage.py +5 -0
  177. ffbb_data_client/models/tournoi_type_class.py +35 -0
  178. ffbb_data_client/models/tournoi_type_enum.py +7 -0
  179. ffbb_data_client/models/tournoi_types_3x3.py +43 -0
  180. ffbb_data_client/models/tournoi_types_3x3_libelle.py +60 -0
  181. ffbb_data_client/models/tournoi_types_3x3_libelle_enum.py +10 -0
  182. ffbb_data_client/models/tournois_facet_distribution.py +41 -0
  183. ffbb_data_client/models/tournois_facet_stats.py +14 -0
  184. ffbb_data_client/models/tournois_hit.py +132 -0
  185. ffbb_data_client/models/tournois_hit_type.py +5 -0
  186. ffbb_data_client/models/tournois_libelle.py +7 -0
  187. ffbb_data_client/models/tournois_multi_search_query.py +40 -0
  188. ffbb_data_client/models/type_association.py +23 -0
  189. ffbb_data_client/models/type_association_libelle.py +30 -0
  190. ffbb_data_client/models/type_class.py +23 -0
  191. ffbb_data_client/models/type_competition.py +8 -0
  192. ffbb_data_client/models/type_competition_generique.py +31 -0
  193. ffbb_data_client/models/type_enum.py +7 -0
  194. ffbb_data_client/models/type_league.py +6 -0
  195. ffbb_data_client/py.typed +0 -0
  196. ffbb_data_client/utils/__init__.py +27 -0
  197. ffbb_data_client/utils/cache_manager.py +393 -0
  198. ffbb_data_client/utils/converter_utils.py +329 -0
  199. ffbb_data_client/utils/input_validation.py +360 -0
  200. ffbb_data_client/utils/retry_utils.py +478 -0
  201. ffbb_data_client/utils/secure_logging.py +153 -0
  202. ffbb_data_client/utils/token_manager.py +115 -0
  203. ffbb_data_client-2.0.0.dist-info/METADATA +339 -0
  204. ffbb_data_client-2.0.0.dist-info/RECORD +207 -0
  205. ffbb_data_client-2.0.0.dist-info/WHEEL +5 -0
  206. ffbb_data_client-2.0.0.dist-info/licenses/LICENSE.txt +201 -0
  207. ffbb_data_client-2.0.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,2789 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from collections.abc import Sequence
5
+ from typing import Any, cast
6
+
7
+ import httpx
8
+ from httpx import Client
9
+
10
+ from ..helpers.multi_search_query_helper import generate_queries
11
+ from ..models.club_contacts import (
12
+ ClubContacts,
13
+ extract_club_info,
14
+ extract_membres_contacts,
15
+ )
16
+ from ..models.competitions_multi_search_query import CompetitionsMultiSearchQuery
17
+ from ..models.configuration_models import GetConfigurationResponse
18
+ from ..models.content_multi_search_query import (
19
+ GaleriesMultiSearchQuery,
20
+ NewsMultiSearchQuery,
21
+ RssMultiSearchQuery,
22
+ YoutubeVideosMultiSearchQuery,
23
+ )
24
+ from ..models.engagement_contacts import (
25
+ EngagementContacts,
26
+ extract_correspondant,
27
+ extract_entraineur_contact,
28
+ )
29
+ from ..models.engagements_multi_search_query import EngagementsMultiSearchQuery
30
+ from ..models.formations_multi_search_query import FormationsMultiSearchQuery
31
+ from ..models.generic_search import (
32
+ GaleriesMultiSearchResult,
33
+ NewsMultiSearchResult,
34
+ RssMultiSearchResult,
35
+ YoutubeVideosMultiSearchResult,
36
+ )
37
+ from ..models.geo_sort_order import GeoSortOrder
38
+ from ..models.get_commune_response import GetCommuneResponse
39
+ from ..models.get_competition_response import GetCompetitionResponse
40
+ from ..models.get_engagement_response import GetEngagementResponse
41
+ from ..models.get_entraineur_response import GetEntraineurResponse
42
+ from ..models.get_formation_response import GetFormationResponse
43
+ from ..models.get_officiel_response import GetOfficielResponse
44
+ from ..models.get_organisme_response import GetOrganismeResponse
45
+ from ..models.get_pratique_response import GetPratiqueResponse
46
+ from ..models.get_rencontre_response import GetRencontreResponse
47
+ from ..models.get_salle_response import GetSalleResponse
48
+ from ..models.get_terrain_response import GetTerrainResponse
49
+ from ..models.get_tournoi_response import GetTournoiResponse
50
+ from ..models.lives import Live
51
+ from ..models.multi_search_query import MultiSearchQuery
52
+ from ..models.multi_search_result_competitions import CompetitionsMultiSearchResult
53
+ from ..models.multi_search_result_engagements import EngagementsMultiSearchResult
54
+ from ..models.multi_search_result_formations import FormationsMultiSearchResult
55
+ from ..models.multi_search_result_organismes import OrganismesMultiSearchResult
56
+ from ..models.multi_search_result_pratiques import PratiquesMultiSearchResult
57
+ from ..models.multi_search_result_rencontres import RencontresMultiSearchResult
58
+ from ..models.multi_search_result_salles import SallesMultiSearchResult
59
+ from ..models.multi_search_result_terrains import TerrainsMultiSearchResult
60
+ from ..models.multi_search_result_tournois import TournoisMultiSearchResult
61
+ from ..models.multi_search_results import MultiSearchResult
62
+ from ..models.multi_search_results_class import MultiSearchResults
63
+ from ..models.organismes_multi_search_query import OrganismesMultiSearchQuery
64
+ from ..models.poules_models import GetPouleResponse
65
+ from ..models.pratiques_multi_search_query import PratiquesMultiSearchQuery
66
+ from ..models.rencontres_multi_search_query import RencontresMultiSearchQuery
67
+ from ..models.saisons_models import GetSaisonsResponse
68
+ from ..models.salles_multi_search_query import SallesMultiSearchQuery
69
+ from ..models.team_ranking import TeamRanking
70
+ from ..models.terrains_multi_search_query import TerrainsMultiSearchQuery
71
+ from ..models.tournois_multi_search_query import TournoisMultiSearchQuery
72
+ from ..utils.cache_manager import CacheManager
73
+ from ..utils.input_validation import (
74
+ validate_boolean,
75
+ validate_filter_criteria,
76
+ validate_offset,
77
+ validate_search_query,
78
+ validate_string_list,
79
+ validate_token,
80
+ )
81
+ from ..utils.token_manager import TokenManager
82
+ from .api_ffbb_app_client import ApiFFBBAppClient
83
+ from .meilisearch_ffbb_client import MeilisearchFFBBClient
84
+
85
+
86
+ class FFBBDataClient:
87
+
88
+ def __init__(
89
+ self,
90
+ api_ffbb_client: ApiFFBBAppClient,
91
+ meilisearch_ffbb_client: MeilisearchFFBBClient,
92
+ ):
93
+ self.api_ffbb_client = api_ffbb_client
94
+ self.meilisearch_ffbb_client = meilisearch_ffbb_client
95
+ self.cached_session = api_ffbb_client.cached_session
96
+ self.async_cached_session = api_ffbb_client.async_cached_session
97
+
98
+ def get_organisme_for_search(
99
+ self,
100
+ organisme_id: int,
101
+ cached_session: Client | None = None,
102
+ ) -> GetOrganismeResponse | None:
103
+ """Version allégée de get_organisme() pour les contextes de recherche.
104
+ Retourne 31 champs au lieu de 77 (exclut membres, labellisation, salle).
105
+ """
106
+ return self.api_ffbb_client.get_organisme_for_search(
107
+ organisme_id=organisme_id,
108
+ cached_session=cached_session,
109
+ )
110
+
111
+ async def get_organisme_for_search_async(
112
+ self,
113
+ organisme_id: int,
114
+ cached_session: httpx.AsyncClient | None = None,
115
+ ) -> GetOrganismeResponse | None:
116
+ """Version async allégée de get_organisme() pour les contextes de recherche."""
117
+ return await self.api_ffbb_client.get_organisme_for_search_async(
118
+ organisme_id=organisme_id,
119
+ cached_session=cached_session,
120
+ )
121
+
122
+ _BATCH_CHUNK_SIZE = 50
123
+
124
+ @staticmethod
125
+ def _chunked(items: list[int], size: int) -> list[list[int]]:
126
+ return [items[i : i + size] for i in range(0, len(items), size)]
127
+
128
+ @staticmethod
129
+ def create(
130
+ meilisearch_bearer_token: str | None = None,
131
+ api_bearer_token: str | None = None,
132
+ debug: bool = False,
133
+ cached_session: Client | None = None,
134
+ async_cached_session: httpx.AsyncClient | None = None,
135
+ ) -> FFBBDataClient:
136
+ """
137
+ Create a new FFBB Data Client instance with comprehensive input validation.
138
+
139
+ Args:
140
+ meilisearch_bearer_token (str, optional): Bearer token for Meilisearch API.
141
+ If None, resolved via TokenManager.
142
+ api_bearer_token (str, optional): Bearer token for FFBB API.
143
+ If None, resolved via TokenManager.
144
+ debug (bool, optional): Enable debug logging. Defaults to False.
145
+ cached_session (Client, optional): HTTP cache session
146
+ async_cached_session (AsyncClient, optional): Async HTTP cache session
147
+
148
+ Returns:
149
+ FFBBDataClient: Configured API client instance
150
+
151
+ Raises:
152
+ ValidationError: If any input parameter is invalid
153
+ """
154
+ # Resolve tokens if not provided
155
+ if meilisearch_bearer_token is None or api_bearer_token is None:
156
+ tokens = TokenManager.get_tokens()
157
+ if meilisearch_bearer_token is None:
158
+ meilisearch_bearer_token = tokens.meilisearch_token
159
+ if api_bearer_token is None:
160
+ api_bearer_token = tokens.api_token
161
+
162
+ # Validate inputs with comprehensive checks
163
+ validated_meilisearch_token = validate_token(
164
+ meilisearch_bearer_token, "meilisearch_bearer_token"
165
+ )
166
+ validated_api_token = validate_token(api_bearer_token, "api_bearer_token")
167
+ validated_debug = validate_boolean(debug, "debug")
168
+
169
+ # Use singleton session if not provided
170
+ cache_manager = CacheManager()
171
+ if cached_session is None:
172
+ cached_session = cache_manager.session
173
+
174
+ if async_cached_session is None:
175
+ async_cached_session = cache_manager.async_session
176
+
177
+ # Create API clients with validated parameters
178
+ api_ffbb_client = ApiFFBBAppClient(
179
+ validated_api_token,
180
+ debug=validated_debug,
181
+ cached_session=cached_session,
182
+ async_cached_session=async_cached_session,
183
+ )
184
+
185
+ meilisearch_ffbb_client: MeilisearchFFBBClient = MeilisearchFFBBClient(
186
+ validated_meilisearch_token,
187
+ debug=validated_debug,
188
+ cached_session=cached_session,
189
+ async_cached_session=async_cached_session,
190
+ )
191
+
192
+ return FFBBDataClient(api_ffbb_client, meilisearch_ffbb_client)
193
+
194
+ # -------------------------------------------------------------------------
195
+ # REST API — api.ffbb.app
196
+ # -------------------------------------------------------------------------
197
+
198
+ def get_configuration(
199
+ self, cached_session: Client | None = None
200
+ ) -> GetConfigurationResponse | None:
201
+ """
202
+ Retrieves the API configuration including bearer tokens.
203
+
204
+ Returns:
205
+ GetConfigurationResponse: Configuration data with tokens (key_dh, key_ms)
206
+ """
207
+ return self.api_ffbb_client.get_configuration(cached_session=cached_session)
208
+
209
+ async def get_configuration_async(self) -> GetConfigurationResponse | None:
210
+ """Retrieves the API configuration including bearer tokens asynchronously."""
211
+ return await self.api_ffbb_client.get_configuration_async()
212
+
213
+ def get_competition(
214
+ self,
215
+ competition_id: int,
216
+ deep_limit: str | None = "1000",
217
+ fields: list[str] | None = None,
218
+ cached_session: Client | None = None,
219
+ ) -> GetCompetitionResponse | None:
220
+ """
221
+ Retrieves detailed information about a competition.
222
+
223
+ Args:
224
+ competition_id (int): The ID of the competition
225
+ deep_limit (str, optional): Limit for nested rencontres.
226
+ Defaults to "1000".
227
+ fields (List[str], optional): List of fields to retrieve
228
+ cached_session (Client, optional): The cached session to use
229
+
230
+ Returns:
231
+ GetCompetitionResponse: Competition data with nested phases,
232
+ poules, and rencontres
233
+ """
234
+ return self.api_ffbb_client.get_competition(
235
+ competition_id=competition_id,
236
+ deep_limit=deep_limit,
237
+ fields=fields,
238
+ cached_session=cached_session,
239
+ )
240
+
241
+ def list_competitions(
242
+ self,
243
+ limit: int = 10,
244
+ fields: list[str] | None = None,
245
+ cached_session: Client | None = None,
246
+ ) -> list[GetCompetitionResponse | None]:
247
+ """
248
+ Lists competitions with optional field selection.
249
+
250
+ Args:
251
+ limit (int): Maximum number of competitions to return. Defaults to 10.
252
+ fields (List[str], optional): List of fields to retrieve.
253
+ If None, uses basic fields (id, nom).
254
+ cached_session (Client, optional): The cached session to use
255
+
256
+ Returns:
257
+ list[GetCompetitionResponse]: List of competition data
258
+ """
259
+ return self.api_ffbb_client.list_competitions(
260
+ limit=limit,
261
+ fields=fields,
262
+ cached_session=cached_session,
263
+ )
264
+
265
+ def get_lives(self, cached_session: Client | None = None) -> list[Live] | None:
266
+ """
267
+ Retrieves a list of live events.
268
+
269
+ Args:
270
+ cached_session (Client, optional): The cached session to use
271
+
272
+ Returns:
273
+ list[Live]: A list of Live objects representing the live events.
274
+ """
275
+ return self.api_ffbb_client.get_lives(cached_session)
276
+
277
+ def get_organisme(
278
+ self,
279
+ organisme_id: int,
280
+ fields: list[str] | None = None,
281
+ cached_session: Client | None = None,
282
+ ) -> GetOrganismeResponse | None:
283
+ """
284
+ Retrieves detailed information about an organisme.
285
+
286
+ Args:
287
+ organisme_id (int): The ID of the organisme
288
+ fields (List[str], optional): List of fields to retrieve
289
+ cached_session (Client, optional): The cached session to use
290
+
291
+ Returns:
292
+ GetOrganismeResponse: Organisme data with members, competitions, etc.
293
+ """
294
+ return self.api_ffbb_client.get_organisme(
295
+ organisme_id=organisme_id,
296
+ fields=fields,
297
+ cached_session=cached_session,
298
+ )
299
+
300
+ def get_club_contacts(
301
+ self, organisme_id: int, cached_session: Client | None = None
302
+ ) -> ClubContacts | None:
303
+ """Return club contact information (club-level + membres) for an organisme.
304
+
305
+ This method delegates to `get_organisme()` and uses the extractor helpers
306
+ to produce a compact `ClubContacts` object.
307
+ """
308
+ organisme = self.get_organisme(organisme_id, cached_session=cached_session)
309
+ if not organisme:
310
+ return None
311
+ club_contact = extract_club_info(organisme)
312
+ membres = extract_membres_contacts(organisme)
313
+ return ClubContacts(
314
+ organisme=organisme, club_contact=club_contact, membres=membres
315
+ )
316
+
317
+ def get_poule(
318
+ self,
319
+ poule_id: int,
320
+ deep_limit: str | None = "1000",
321
+ fields: list[str] | None = None,
322
+ cached_session: Client | None = None,
323
+ ) -> GetPouleResponse | None:
324
+ """
325
+ Retrieves detailed information about a poule.
326
+
327
+ Args:
328
+ poule_id (int): The ID of the poule
329
+ deep_limit (str, optional): Limit for nested rencontres.
330
+ Defaults to "1000".
331
+ fields (List[str], optional): List of fields to retrieve
332
+ cached_session (Client, optional): The cached session to use
333
+
334
+ Returns:
335
+ GetPouleResponse: Poule data with rencontres
336
+ """
337
+ return self.api_ffbb_client.get_poule(
338
+ poule_id=poule_id,
339
+ deep_limit=deep_limit,
340
+ fields=fields,
341
+ cached_session=cached_session,
342
+ )
343
+
344
+ def get_saisons(
345
+ self,
346
+ fields: list[str] | None = None,
347
+ filter_criteria: str | None = '{"actif":{"_eq":true}}',
348
+ cached_session: Client | None = None,
349
+ ) -> list[GetSaisonsResponse] | None:
350
+ """
351
+ Retrieves list of seasons with comprehensive input validation.
352
+
353
+ Args:
354
+ fields (List[str], optional): List of fields to retrieve.
355
+ Defaults to ["id"].
356
+ filter_criteria (str, optional): JSON filter criteria.
357
+ Defaults to active seasons.
358
+ cached_session (Client, optional): The cached session to use
359
+
360
+ Returns:
361
+ List[GetSaisonsResponse]: List of season data
362
+
363
+ Raises:
364
+ ValidationError: If input parameters are invalid
365
+ """
366
+ validated_fields = validate_string_list(fields, "fields")
367
+ validated_filter = validate_filter_criteria(filter_criteria, "filter_criteria")
368
+
369
+ return self.api_ffbb_client.get_saisons(
370
+ fields=validated_fields,
371
+ filter_criteria=validated_filter,
372
+ cached_session=cached_session,
373
+ )
374
+
375
+ # -------------------------------------------------------------------------
376
+ # REST API — async
377
+ # -------------------------------------------------------------------------
378
+
379
+ async def get_lives_async(self) -> list[Live] | None:
380
+ """Retrieves a list of live events asynchronously."""
381
+ return await self.api_ffbb_client.get_lives_async()
382
+
383
+ async def get_saisons_async(
384
+ self,
385
+ fields: list[str] | None = None,
386
+ filter_criteria: str | None = '{"actif":{"_eq":true}}',
387
+ cached_session: httpx.AsyncClient | None = None,
388
+ ) -> list[GetSaisonsResponse]:
389
+ """Retrieves list of seasons asynchronously with input validation."""
390
+ validated_fields = validate_string_list(fields, "fields")
391
+ validated_filter = validate_filter_criteria(filter_criteria, "filter_criteria")
392
+ return await self.api_ffbb_client.get_saisons_async(
393
+ fields=validated_fields,
394
+ filter_criteria=validated_filter,
395
+ cached_session=cached_session,
396
+ )
397
+
398
+ async def get_competition_async(
399
+ self,
400
+ competition_id: int,
401
+ deep_limit: str | None = "1000",
402
+ fields: list[str] | None = None,
403
+ cached_session: httpx.AsyncClient | None = None,
404
+ ) -> GetCompetitionResponse | None:
405
+ """Retrieves detailed information about a competition asynchronously."""
406
+ validated_fields = validate_string_list(fields, "fields")
407
+ return await self.api_ffbb_client.get_competition_async(
408
+ competition_id=competition_id,
409
+ deep_limit=deep_limit,
410
+ fields=validated_fields,
411
+ cached_session=cached_session,
412
+ )
413
+
414
+ async def list_competitions_async(
415
+ self,
416
+ limit: int = 10,
417
+ fields: list[str] | None = None,
418
+ ) -> list[GetCompetitionResponse | None]:
419
+ """Lists competitions asynchronously."""
420
+ return await self.api_ffbb_client.list_competitions_async(
421
+ limit=limit,
422
+ fields=fields,
423
+ )
424
+
425
+ async def get_organisme_async(
426
+ self,
427
+ organisme_id: int,
428
+ fields: list[str] | None = None,
429
+ cached_session: httpx.AsyncClient | None = None,
430
+ ) -> GetOrganismeResponse | None:
431
+ """Retrieves detailed information about an organisme asynchronously."""
432
+ validated_fields = validate_string_list(fields, "fields")
433
+ return await self.api_ffbb_client.get_organisme_async(
434
+ organisme_id=organisme_id,
435
+ fields=validated_fields,
436
+ cached_session=cached_session,
437
+ )
438
+
439
+ async def get_poule_async(
440
+ self, poule_id: int, deep_limit: str | None = "1000"
441
+ ) -> GetPouleResponse | None:
442
+ """Retrieves detailed information about a poule asynchronously."""
443
+ return await self.api_ffbb_client.get_poule_async(
444
+ poule_id, deep_limit=deep_limit
445
+ )
446
+
447
+ def get_classement(
448
+ self, poule_id: int, cached_session: Client | None = None
449
+ ) -> list[TeamRanking] | None:
450
+ """Retrieves ONLY the ranking (classement) for a specific poule."""
451
+ return self.api_ffbb_client.get_classement(
452
+ poule_id, cached_session=cached_session
453
+ )
454
+
455
+ async def get_classement_async(self, poule_id: int) -> list[TeamRanking] | None:
456
+ """Retrieves ONLY the ranking (classement) for a specific poule asynchronously."""
457
+ return await self.api_ffbb_client.get_classement_async(poule_id)
458
+
459
+ def get_equipes(
460
+ self, organisme_id: int, cached_session: Client | None = None
461
+ ) -> list[GetOrganismeResponse.EngagementsitemModel] | None:
462
+ """Retrieves ONLY the team commitments (engagements) for a specific club."""
463
+ return self.api_ffbb_client.get_equipes(
464
+ organisme_id, cached_session=cached_session
465
+ )
466
+
467
+ async def get_equipes_async(
468
+ self, organisme_id: int
469
+ ) -> list[GetOrganismeResponse.EngagementsitemModel] | None:
470
+ """Retrieves ONLY the team commitments (engagements) for a specific club asynchronously."""
471
+ return await self.api_ffbb_client.get_equipes_async(organisme_id)
472
+
473
+ def get_rencontre(
474
+ self, id: str, cached_session: Client | None = None
475
+ ) -> GetRencontreResponse | None:
476
+ """Retrieves detailed information about a rencontre."""
477
+ return self.api_ffbb_client.get_rencontre(id, cached_session=cached_session)
478
+
479
+ async def get_rencontre_async(
480
+ self, id: str, cached_session: httpx.AsyncClient | None = None
481
+ ) -> GetRencontreResponse | None:
482
+ """Asynchronously retrieves detailed information about a rencontre."""
483
+ return await self.api_ffbb_client.get_rencontre_async(
484
+ id, cached_session=cached_session
485
+ )
486
+
487
+ def get_engagement(
488
+ self, id: str, cached_session: Client | None = None
489
+ ) -> GetEngagementResponse | None:
490
+ """Retrieves detailed information about an engagement."""
491
+ return self.api_ffbb_client.get_engagement(id, cached_session=cached_session)
492
+
493
+ async def get_engagement_async(
494
+ self, id: str, cached_session: httpx.AsyncClient | None = None
495
+ ) -> GetEngagementResponse | None:
496
+ """Asynchronously retrieves detailed information about an engagement."""
497
+ return await self.api_ffbb_client.get_engagement_async(
498
+ id, cached_session=cached_session
499
+ )
500
+
501
+ def get_engagement_contacts(
502
+ self, id: str, cached_session: Client | None = None
503
+ ) -> EngagementContacts | None:
504
+ """Return compact contact information for an engagement.
505
+
506
+ The implementation is defensive: it tries several common attribute
507
+ names for entraineur/correspondant fields and returns the best-effort
508
+ `EngagementContacts` object.
509
+ """
510
+ engagement = self.get_engagement(id, cached_session=cached_session)
511
+ if not engagement:
512
+ return None
513
+
514
+ correspondant = extract_correspondant(engagement)
515
+
516
+ # Try multiple possible attribute names for entraineur id
517
+ entraineur_id = (
518
+ getattr(engagement, "idEntraineur", None)
519
+ or getattr(engagement, "entraineur", None)
520
+ or getattr(engagement, "id_entraineur", None)
521
+ )
522
+ entraineur = (
523
+ self.get_entraineur(str(entraineur_id), cached_session=cached_session)
524
+ if entraineur_id
525
+ else None
526
+ )
527
+ entraineur_contact = extract_entraineur_contact(entraineur, "entraineur")
528
+
529
+ entraineur_adjoint_id = (
530
+ getattr(engagement, "idEntraineurAdjoint", None)
531
+ or getattr(engagement, "entraineurAdjoint", None)
532
+ or getattr(engagement, "id_entraineur_adjoint", None)
533
+ or getattr(engagement, "entraineur_adjoint", None)
534
+ )
535
+ entraineur_adjoint = (
536
+ self.get_entraineur(
537
+ str(entraineur_adjoint_id), cached_session=cached_session
538
+ )
539
+ if entraineur_adjoint_id
540
+ else None
541
+ )
542
+ entraineur_adjoint_contact = extract_entraineur_contact(
543
+ entraineur_adjoint, "entraineur_adjoint"
544
+ )
545
+
546
+ return EngagementContacts(
547
+ engagement=engagement,
548
+ correspondant=correspondant,
549
+ entraineur=entraineur_contact,
550
+ entraineur_adjoint=entraineur_adjoint_contact,
551
+ )
552
+
553
+ def get_formation(
554
+ self, id: str, cached_session: Client | None = None
555
+ ) -> GetFormationResponse | None:
556
+ """Retrieves detailed information about a formation."""
557
+ return self.api_ffbb_client.get_formation(id, cached_session=cached_session)
558
+
559
+ async def get_formation_async(
560
+ self, id: str, cached_session: httpx.AsyncClient | None = None
561
+ ) -> GetFormationResponse | None:
562
+ """Asynchronously retrieves detailed information about a formation."""
563
+ return await self.api_ffbb_client.get_formation_async(
564
+ id, cached_session=cached_session
565
+ )
566
+
567
+ def get_entraineur(
568
+ self, id: str, cached_session: Client | None = None
569
+ ) -> GetEntraineurResponse | None:
570
+ """Retrieves detailed information about an entraineur."""
571
+ return self.api_ffbb_client.get_entraineur(id, cached_session=cached_session)
572
+
573
+ async def get_entraineur_async(
574
+ self, id: str, cached_session: httpx.AsyncClient | None = None
575
+ ) -> GetEntraineurResponse | None:
576
+ """Asynchronously retrieves detailed information about an entraineur."""
577
+ return await self.api_ffbb_client.get_entraineur_async(
578
+ id, cached_session=cached_session
579
+ )
580
+
581
+ def get_commune(
582
+ self, id: str, cached_session: Client | None = None
583
+ ) -> GetCommuneResponse | None:
584
+ """Retrieves detailed information about a commune."""
585
+ return self.api_ffbb_client.get_commune(id, cached_session=cached_session)
586
+
587
+ async def get_commune_async(
588
+ self, id: str, cached_session: httpx.AsyncClient | None = None
589
+ ) -> GetCommuneResponse | None:
590
+ """Asynchronously retrieves detailed information about a commune."""
591
+ return await self.api_ffbb_client.get_commune_async(
592
+ id, cached_session=cached_session
593
+ )
594
+
595
+ def get_officiel(
596
+ self, id: str, cached_session: Client | None = None
597
+ ) -> GetOfficielResponse | None:
598
+ """Retrieves detailed information about an officiel."""
599
+ return self.api_ffbb_client.get_officiel(id, cached_session=cached_session)
600
+
601
+ async def get_officiel_async(
602
+ self, id: str, cached_session: httpx.AsyncClient | None = None
603
+ ) -> GetOfficielResponse | None:
604
+ """Asynchronously retrieves detailed information about an officiel."""
605
+ return await self.api_ffbb_client.get_officiel_async(
606
+ id, cached_session=cached_session
607
+ )
608
+
609
+ def get_salle(
610
+ self, id: str, cached_session: Client | None = None
611
+ ) -> GetSalleResponse | None:
612
+ """Retrieves detailed information about a salle."""
613
+ return self.api_ffbb_client.get_salle(id, cached_session=cached_session)
614
+
615
+ async def get_salle_async(
616
+ self, id: str, cached_session: httpx.AsyncClient | None = None
617
+ ) -> GetSalleResponse | None:
618
+ """Asynchronously retrieves detailed information about a salle."""
619
+ return await self.api_ffbb_client.get_salle_async(
620
+ id, cached_session=cached_session
621
+ )
622
+
623
+ def get_terrain(
624
+ self, id: str, cached_session: Client | None = None
625
+ ) -> GetTerrainResponse | None:
626
+ """Retrieves detailed information about a terrain."""
627
+ return self.api_ffbb_client.get_terrain(id, cached_session=cached_session)
628
+
629
+ async def get_terrain_async(
630
+ self, id: str, cached_session: httpx.AsyncClient | None = None
631
+ ) -> GetTerrainResponse | None:
632
+ """Asynchronously retrieves detailed information about a terrain."""
633
+ return await self.api_ffbb_client.get_terrain_async(
634
+ id, cached_session=cached_session
635
+ )
636
+
637
+ def get_tournoi(
638
+ self, id: str, cached_session: Client | None = None
639
+ ) -> GetTournoiResponse | None:
640
+ """Retrieves detailed information about a tournoi."""
641
+ return self.api_ffbb_client.get_tournoi(id, cached_session=cached_session)
642
+
643
+ async def get_tournoi_async(
644
+ self, id: str, cached_session: httpx.AsyncClient | None = None
645
+ ) -> GetTournoiResponse | None:
646
+ """Asynchronously retrieves detailed information about a tournoi."""
647
+ return await self.api_ffbb_client.get_tournoi_async(
648
+ id, cached_session=cached_session
649
+ )
650
+
651
+ def get_pratique(
652
+ self, id: str, cached_session: Client | None = None
653
+ ) -> GetPratiqueResponse | None:
654
+ """Retrieves detailed information about a pratique."""
655
+ return self.api_ffbb_client.get_pratique(id, cached_session=cached_session)
656
+
657
+ async def get_pratique_async(
658
+ self, id: str, cached_session: httpx.AsyncClient | None = None
659
+ ) -> GetPratiqueResponse | None:
660
+ """Asynchronously retrieves detailed information about a pratique."""
661
+ return await self.api_ffbb_client.get_pratique_async(
662
+ id, cached_session=cached_session
663
+ )
664
+
665
+ def get_openapi_spec(self) -> dict[str, Any] | None:
666
+ """Retrieves the current Directus OpenAPI specification."""
667
+ return self.api_ffbb_client.get_openapi_spec()
668
+
669
+ def get_session(
670
+ self, id: str, fields: list[str] | None = None
671
+ ) -> dict[str, Any] | None:
672
+ """Retrieves detailed information about a formation session."""
673
+ return self.api_ffbb_client.get_session(id, fields=fields)
674
+
675
+ def list_sessions(
676
+ self,
677
+ limit: int = 10,
678
+ fields: list[str] | None = None,
679
+ filter_criteria: str | None = None,
680
+ sort: str | list[str] | None = None,
681
+ ) -> list[dict[str, Any]]:
682
+ """Lists formation sessions."""
683
+ return self.api_ffbb_client.list_sessions(
684
+ limit=limit, fields=fields, filter_criteria=filter_criteria, sort=sort
685
+ )
686
+
687
+ async def get_session_async(
688
+ self, id: str, fields: list[str] | None = None
689
+ ) -> dict[str, Any] | None:
690
+ """Asynchronously retrieves detailed information about a formation session."""
691
+ return await self.api_ffbb_client.get_session_async(id, fields=fields)
692
+
693
+ async def list_sessions_async(
694
+ self,
695
+ limit: int = 10,
696
+ fields: list[str] | None = None,
697
+ filter_criteria: str | None = None,
698
+ sort: str | list[str] | None = None,
699
+ ) -> list[dict[str, Any]]:
700
+ """Asynchronously lists formation sessions."""
701
+ return await self.api_ffbb_client.list_sessions_async(
702
+ limit=limit, fields=fields, filter_criteria=filter_criteria, sort=sort
703
+ )
704
+
705
+ def get_genius_sport_match(
706
+ self, id: str, fields: list[str] | None = None
707
+ ) -> dict[str, Any] | None:
708
+ """Retrieves detailed Genius Sports match statistics."""
709
+ return self.api_ffbb_client.get_genius_sport_match(id, fields=fields)
710
+
711
+ def list_genius_sport_matches(
712
+ self,
713
+ limit: int = 10,
714
+ fields: list[str] | None = None,
715
+ filter_criteria: str | None = None,
716
+ sort: str | list[str] | None = None,
717
+ ) -> list[dict[str, Any]]:
718
+ """Lists Genius Sports match statistics."""
719
+ return self.api_ffbb_client.list_genius_sport_matches(
720
+ limit=limit, fields=fields, filter_criteria=filter_criteria, sort=sort
721
+ )
722
+
723
+ def list_genius_sports_live_logs(
724
+ self,
725
+ limit: int = 10,
726
+ fields: list[str] | None = None,
727
+ filter_criteria: str | None = None,
728
+ sort: str | list[str] | None = None,
729
+ ) -> list[dict[str, Any]]:
730
+ """Lists Genius Sports live logs."""
731
+ return self.api_ffbb_client.list_genius_sports_live_logs(
732
+ limit=limit, fields=fields, filter_criteria=filter_criteria, sort=sort
733
+ )
734
+
735
+ async def get_genius_sport_match_async(
736
+ self, id: str, fields: list[str] | None = None
737
+ ) -> dict[str, Any] | None:
738
+ """Asynchronously retrieves detailed Genius Sports match statistics."""
739
+ return await self.api_ffbb_client.get_genius_sport_match_async(
740
+ id, fields=fields
741
+ )
742
+
743
+ async def list_genius_sport_matches_async(
744
+ self,
745
+ limit: int = 10,
746
+ fields: list[str] | None = None,
747
+ filter_criteria: str | None = None,
748
+ sort: str | list[str] | None = None,
749
+ ) -> list[dict[str, Any]]:
750
+ """Asynchronously lists Genius Sports match statistics."""
751
+ return await self.api_ffbb_client.list_genius_sport_matches_async(
752
+ limit=limit, fields=fields, filter_criteria=filter_criteria, sort=sort
753
+ )
754
+
755
+ def get_rematch_video(
756
+ self, id: str, fields: list[str] | None = None
757
+ ) -> dict[str, Any] | None:
758
+ """Retrieves a Rematch video linked to FFBB data."""
759
+ return self.api_ffbb_client.get_rematch_video(id, fields=fields)
760
+
761
+ def list_rematch_videos(
762
+ self,
763
+ limit: int = 10,
764
+ fields: list[str] | None = None,
765
+ filter_criteria: str | None = None,
766
+ sort: str | list[str] | None = None,
767
+ ) -> list[dict[str, Any]]:
768
+ """Lists Rematch videos linked to FFBB data."""
769
+ return self.api_ffbb_client.list_rematch_videos(
770
+ limit=limit, fields=fields, filter_criteria=filter_criteria, sort=sort
771
+ )
772
+
773
+ async def get_rematch_video_async(
774
+ self, id: str, fields: list[str] | None = None
775
+ ) -> dict[str, Any] | None:
776
+ """Asynchronously retrieves a Rematch video linked to FFBB data."""
777
+ return await self.api_ffbb_client.get_rematch_video_async(id, fields=fields)
778
+
779
+ async def list_rematch_videos_async(
780
+ self,
781
+ limit: int = 10,
782
+ fields: list[str] | None = None,
783
+ filter_criteria: str | None = None,
784
+ sort: str | list[str] | None = None,
785
+ ) -> list[dict[str, Any]]:
786
+ """Asynchronously lists Rematch videos linked to FFBB data."""
787
+ return await self.api_ffbb_client.list_rematch_videos_async(
788
+ limit=limit, fields=fields, filter_criteria=filter_criteria, sort=sort
789
+ )
790
+
791
+ def get_edf_match(
792
+ self, id: str | int, fields: list[str] | None = None
793
+ ) -> dict[str, Any] | None:
794
+ """Retrieves an Equipe de France match."""
795
+ return self.api_ffbb_client.get_edf_match(id, fields=fields)
796
+
797
+ def list_edf_matches(
798
+ self,
799
+ limit: int = 10,
800
+ fields: list[str] | None = None,
801
+ filter_criteria: str | None = None,
802
+ sort: str | list[str] | None = None,
803
+ ) -> list[dict[str, Any]]:
804
+ """Lists Equipe de France matches."""
805
+ return self.api_ffbb_client.list_edf_matches(
806
+ limit=limit, fields=fields, filter_criteria=filter_criteria, sort=sort
807
+ )
808
+
809
+ def get_edf_player(
810
+ self, id: str | int, fields: list[str] | None = None
811
+ ) -> dict[str, Any] | None:
812
+ """Retrieves an Equipe de France player."""
813
+ return self.api_ffbb_client.get_edf_player(id, fields=fields)
814
+
815
+ def list_edf_players(
816
+ self,
817
+ limit: int = 10,
818
+ fields: list[str] | None = None,
819
+ filter_criteria: str | None = None,
820
+ sort: str | list[str] | None = None,
821
+ ) -> list[dict[str, Any]]:
822
+ """Lists Equipe de France players."""
823
+ return self.api_ffbb_client.list_edf_players(
824
+ limit=limit, fields=fields, filter_criteria=filter_criteria, sort=sort
825
+ )
826
+
827
+ def list_edf_teams(
828
+ self,
829
+ limit: int = 10,
830
+ fields: list[str] | None = None,
831
+ filter_criteria: str | None = None,
832
+ sort: str | list[str] | None = None,
833
+ ) -> list[dict[str, Any]]:
834
+ """Lists Equipe de France teams."""
835
+ return self.api_ffbb_client.list_edf_teams(
836
+ limit=limit, fields=fields, filter_criteria=filter_criteria, sort=sort
837
+ )
838
+
839
+ def list_edf_rosters(
840
+ self,
841
+ limit: int = 10,
842
+ fields: list[str] | None = None,
843
+ filter_criteria: str | None = None,
844
+ sort: str | list[str] | None = None,
845
+ ) -> list[dict[str, Any]]:
846
+ """Lists Equipe de France rosters."""
847
+ return self.api_ffbb_client.list_edf_rosters(
848
+ limit=limit, fields=fields, filter_criteria=filter_criteria, sort=sort
849
+ )
850
+
851
+ # ---------------------------------------------------------------------
852
+ # Directus list delegations (typed)
853
+ # ---------------------------------------------------------------------
854
+
855
+ def list_rencontres(
856
+ self,
857
+ limit: int = 10,
858
+ filter_criteria: str | None = None,
859
+ sort: list[str] | None = None,
860
+ offset: int | None = None,
861
+ search: str | None = None,
862
+ cached_session: Client | None = None,
863
+ ) -> list[GetRencontreResponse]:
864
+ return self.api_ffbb_client.list_rencontres(
865
+ limit=limit,
866
+ filter_criteria=validate_filter_criteria(
867
+ filter_criteria, "filter_criteria"
868
+ ),
869
+ sort=validate_string_list(sort, "sort"),
870
+ offset=validate_offset(offset),
871
+ search=validate_search_query(search, "search"),
872
+ cached_session=cached_session,
873
+ )
874
+
875
+ def list_salles(
876
+ self,
877
+ limit: int = 10,
878
+ filter_criteria: str | None = None,
879
+ sort: list[str] | None = None,
880
+ offset: int | None = None,
881
+ search: str | None = None,
882
+ cached_session: Client | None = None,
883
+ ) -> list[GetSalleResponse]:
884
+ return self.api_ffbb_client.list_salles(
885
+ limit=limit,
886
+ filter_criteria=validate_filter_criteria(
887
+ filter_criteria, "filter_criteria"
888
+ ),
889
+ sort=validate_string_list(sort, "sort"),
890
+ offset=validate_offset(offset),
891
+ search=validate_search_query(search, "search"),
892
+ cached_session=cached_session,
893
+ )
894
+
895
+ def list_terrains(
896
+ self,
897
+ limit: int = 10,
898
+ filter_criteria: str | None = None,
899
+ sort: list[str] | None = None,
900
+ offset: int | None = None,
901
+ search: str | None = None,
902
+ cached_session: Client | None = None,
903
+ ) -> list[GetTerrainResponse]:
904
+ return self.api_ffbb_client.list_terrains(
905
+ limit=limit,
906
+ filter_criteria=validate_filter_criteria(
907
+ filter_criteria, "filter_criteria"
908
+ ),
909
+ sort=validate_string_list(sort, "sort"),
910
+ offset=validate_offset(offset),
911
+ search=validate_search_query(search, "search"),
912
+ cached_session=cached_session,
913
+ )
914
+
915
+ def list_tournois(
916
+ self,
917
+ limit: int = 10,
918
+ filter_criteria: str | None = None,
919
+ sort: list[str] | None = None,
920
+ offset: int | None = None,
921
+ search: str | None = None,
922
+ cached_session: Client | None = None,
923
+ ) -> list[GetTournoiResponse]:
924
+ return self.api_ffbb_client.list_tournois(
925
+ limit=limit,
926
+ filter_criteria=validate_filter_criteria(
927
+ filter_criteria, "filter_criteria"
928
+ ),
929
+ sort=validate_string_list(sort, "sort"),
930
+ offset=validate_offset(offset),
931
+ search=validate_search_query(search, "search"),
932
+ cached_session=cached_session,
933
+ )
934
+
935
+ def list_engagements(
936
+ self,
937
+ limit: int = 10,
938
+ filter_criteria: str | None = None,
939
+ sort: list[str] | None = None,
940
+ offset: int | None = None,
941
+ search: str | None = None,
942
+ cached_session: Client | None = None,
943
+ ) -> list[GetEngagementResponse]:
944
+ return self.api_ffbb_client.list_engagements(
945
+ limit=limit,
946
+ filter_criteria=validate_filter_criteria(
947
+ filter_criteria, "filter_criteria"
948
+ ),
949
+ sort=validate_string_list(sort, "sort"),
950
+ offset=validate_offset(offset),
951
+ search=validate_search_query(search, "search"),
952
+ cached_session=cached_session,
953
+ )
954
+
955
+ def list_formations(
956
+ self,
957
+ limit: int = 10,
958
+ filter_criteria: str | None = None,
959
+ sort: list[str] | None = None,
960
+ offset: int | None = None,
961
+ search: str | None = None,
962
+ cached_session: Client | None = None,
963
+ ) -> list[GetFormationResponse]:
964
+ return self.api_ffbb_client.list_formations(
965
+ limit=limit,
966
+ filter_criteria=validate_filter_criteria(
967
+ filter_criteria, "filter_criteria"
968
+ ),
969
+ sort=validate_string_list(sort, "sort"),
970
+ offset=validate_offset(offset),
971
+ search=validate_search_query(search, "search"),
972
+ cached_session=cached_session,
973
+ )
974
+
975
+ def list_entraineurs(
976
+ self,
977
+ limit: int = 10,
978
+ filter_criteria: str | None = None,
979
+ sort: list[str] | None = None,
980
+ offset: int | None = None,
981
+ search: str | None = None,
982
+ cached_session: Client | None = None,
983
+ ) -> list[GetEntraineurResponse]:
984
+ return self.api_ffbb_client.list_entraineurs(
985
+ limit=limit,
986
+ filter_criteria=validate_filter_criteria(
987
+ filter_criteria, "filter_criteria"
988
+ ),
989
+ sort=validate_string_list(sort, "sort"),
990
+ offset=validate_offset(offset),
991
+ search=validate_search_query(search, "search"),
992
+ cached_session=cached_session,
993
+ )
994
+
995
+ def list_communes(
996
+ self,
997
+ limit: int = 10,
998
+ filter_criteria: str | None = None,
999
+ sort: list[str] | None = None,
1000
+ offset: int | None = None,
1001
+ search: str | None = None,
1002
+ cached_session: Client | None = None,
1003
+ ) -> list[GetCommuneResponse]:
1004
+ return self.api_ffbb_client.list_communes(
1005
+ limit=limit,
1006
+ filter_criteria=validate_filter_criteria(
1007
+ filter_criteria, "filter_criteria"
1008
+ ),
1009
+ sort=validate_string_list(sort, "sort"),
1010
+ offset=validate_offset(offset),
1011
+ search=validate_search_query(search, "search"),
1012
+ cached_session=cached_session,
1013
+ )
1014
+
1015
+ def list_officiels(
1016
+ self,
1017
+ limit: int = 10,
1018
+ filter_criteria: str | None = None,
1019
+ sort: list[str] | None = None,
1020
+ offset: int | None = None,
1021
+ search: str | None = None,
1022
+ cached_session: Client | None = None,
1023
+ ) -> list[GetOfficielResponse]:
1024
+ return self.api_ffbb_client.list_officiels(
1025
+ limit=limit,
1026
+ filter_criteria=validate_filter_criteria(
1027
+ filter_criteria, "filter_criteria"
1028
+ ),
1029
+ sort=validate_string_list(sort, "sort"),
1030
+ offset=validate_offset(offset),
1031
+ search=validate_search_query(search, "search"),
1032
+ cached_session=cached_session,
1033
+ )
1034
+
1035
+ def list_pratiques(
1036
+ self,
1037
+ limit: int = 10,
1038
+ filter_criteria: str | None = None,
1039
+ sort: list[str] | None = None,
1040
+ offset: int | None = None,
1041
+ search: str | None = None,
1042
+ cached_session: Client | None = None,
1043
+ ) -> list[GetPratiqueResponse]:
1044
+ return self.api_ffbb_client.list_pratiques(
1045
+ limit=limit,
1046
+ filter_criteria=validate_filter_criteria(
1047
+ filter_criteria, "filter_criteria"
1048
+ ),
1049
+ sort=validate_string_list(sort, "sort"),
1050
+ offset=validate_offset(offset),
1051
+ search=validate_search_query(search, "search"),
1052
+ cached_session=cached_session,
1053
+ )
1054
+
1055
+ async def list_rencontres_async(
1056
+ self,
1057
+ limit: int = 10,
1058
+ filter_criteria: str | None = None,
1059
+ sort: list[str] | None = None,
1060
+ offset: int | None = None,
1061
+ search: str | None = None,
1062
+ cached_session: httpx.AsyncClient | None = None,
1063
+ ) -> list[GetRencontreResponse]:
1064
+ return await self.api_ffbb_client.list_rencontres_async(
1065
+ limit=limit,
1066
+ filter_criteria=validate_filter_criteria(
1067
+ filter_criteria, "filter_criteria"
1068
+ ),
1069
+ sort=validate_string_list(sort, "sort"),
1070
+ offset=validate_offset(offset),
1071
+ search=validate_search_query(search, "search"),
1072
+ cached_session=cached_session,
1073
+ )
1074
+
1075
+ async def list_salles_async(
1076
+ self,
1077
+ limit: int = 10,
1078
+ filter_criteria: str | None = None,
1079
+ sort: list[str] | None = None,
1080
+ offset: int | None = None,
1081
+ search: str | None = None,
1082
+ cached_session: httpx.AsyncClient | None = None,
1083
+ ) -> list[GetSalleResponse]:
1084
+ return await self.api_ffbb_client.list_salles_async(
1085
+ limit=limit,
1086
+ filter_criteria=validate_filter_criteria(
1087
+ filter_criteria, "filter_criteria"
1088
+ ),
1089
+ sort=validate_string_list(sort, "sort"),
1090
+ offset=validate_offset(offset),
1091
+ search=validate_search_query(search, "search"),
1092
+ cached_session=cached_session,
1093
+ )
1094
+
1095
+ async def list_terrains_async(
1096
+ self,
1097
+ limit: int = 10,
1098
+ filter_criteria: str | None = None,
1099
+ sort: list[str] | None = None,
1100
+ offset: int | None = None,
1101
+ search: str | None = None,
1102
+ cached_session: httpx.AsyncClient | None = None,
1103
+ ) -> list[GetTerrainResponse]:
1104
+ return await self.api_ffbb_client.list_terrains_async(
1105
+ limit=limit,
1106
+ filter_criteria=validate_filter_criteria(
1107
+ filter_criteria, "filter_criteria"
1108
+ ),
1109
+ sort=validate_string_list(sort, "sort"),
1110
+ offset=validate_offset(offset),
1111
+ search=validate_search_query(search, "search"),
1112
+ cached_session=cached_session,
1113
+ )
1114
+
1115
+ async def list_tournois_async(
1116
+ self,
1117
+ limit: int = 10,
1118
+ filter_criteria: str | None = None,
1119
+ sort: list[str] | None = None,
1120
+ offset: int | None = None,
1121
+ search: str | None = None,
1122
+ cached_session: httpx.AsyncClient | None = None,
1123
+ ) -> list[GetTournoiResponse]:
1124
+ return await self.api_ffbb_client.list_tournois_async(
1125
+ limit=limit,
1126
+ filter_criteria=validate_filter_criteria(
1127
+ filter_criteria, "filter_criteria"
1128
+ ),
1129
+ sort=validate_string_list(sort, "sort"),
1130
+ offset=validate_offset(offset),
1131
+ search=validate_search_query(search, "search"),
1132
+ cached_session=cached_session,
1133
+ )
1134
+
1135
+ async def list_engagements_async(
1136
+ self,
1137
+ limit: int = 10,
1138
+ filter_criteria: str | None = None,
1139
+ sort: list[str] | None = None,
1140
+ offset: int | None = None,
1141
+ search: str | None = None,
1142
+ cached_session: httpx.AsyncClient | None = None,
1143
+ ) -> list[GetEngagementResponse]:
1144
+ return await self.api_ffbb_client.list_engagements_async(
1145
+ limit=limit,
1146
+ filter_criteria=validate_filter_criteria(
1147
+ filter_criteria, "filter_criteria"
1148
+ ),
1149
+ sort=validate_string_list(sort, "sort"),
1150
+ offset=validate_offset(offset),
1151
+ search=validate_search_query(search, "search"),
1152
+ cached_session=cached_session,
1153
+ )
1154
+
1155
+ async def list_formations_async(
1156
+ self,
1157
+ limit: int = 10,
1158
+ filter_criteria: str | None = None,
1159
+ sort: list[str] | None = None,
1160
+ offset: int | None = None,
1161
+ search: str | None = None,
1162
+ cached_session: httpx.AsyncClient | None = None,
1163
+ ) -> list[GetFormationResponse]:
1164
+ return await self.api_ffbb_client.list_formations_async(
1165
+ limit=limit,
1166
+ filter_criteria=validate_filter_criteria(
1167
+ filter_criteria, "filter_criteria"
1168
+ ),
1169
+ sort=validate_string_list(sort, "sort"),
1170
+ offset=validate_offset(offset),
1171
+ search=validate_search_query(search, "search"),
1172
+ cached_session=cached_session,
1173
+ )
1174
+
1175
+ async def list_entraineurs_async(
1176
+ self,
1177
+ limit: int = 10,
1178
+ filter_criteria: str | None = None,
1179
+ sort: list[str] | None = None,
1180
+ offset: int | None = None,
1181
+ search: str | None = None,
1182
+ cached_session: httpx.AsyncClient | None = None,
1183
+ ) -> list[GetEntraineurResponse]:
1184
+ return await self.api_ffbb_client.list_entraineurs_async(
1185
+ limit=limit,
1186
+ filter_criteria=validate_filter_criteria(
1187
+ filter_criteria, "filter_criteria"
1188
+ ),
1189
+ sort=validate_string_list(sort, "sort"),
1190
+ offset=validate_offset(offset),
1191
+ search=validate_search_query(search, "search"),
1192
+ cached_session=cached_session,
1193
+ )
1194
+
1195
+ async def list_communes_async(
1196
+ self,
1197
+ limit: int = 10,
1198
+ filter_criteria: str | None = None,
1199
+ sort: list[str] | None = None,
1200
+ offset: int | None = None,
1201
+ search: str | None = None,
1202
+ cached_session: httpx.AsyncClient | None = None,
1203
+ ) -> list[GetCommuneResponse]:
1204
+ return await self.api_ffbb_client.list_communes_async(
1205
+ limit=limit,
1206
+ filter_criteria=validate_filter_criteria(
1207
+ filter_criteria, "filter_criteria"
1208
+ ),
1209
+ sort=validate_string_list(sort, "sort"),
1210
+ offset=validate_offset(offset),
1211
+ search=validate_search_query(search, "search"),
1212
+ cached_session=cached_session,
1213
+ )
1214
+
1215
+ async def list_officiels_async(
1216
+ self,
1217
+ limit: int = 10,
1218
+ filter_criteria: str | None = None,
1219
+ sort: list[str] | None = None,
1220
+ offset: int | None = None,
1221
+ search: str | None = None,
1222
+ cached_session: httpx.AsyncClient | None = None,
1223
+ ) -> list[GetOfficielResponse]:
1224
+ return await self.api_ffbb_client.list_officiels_async(
1225
+ limit=limit,
1226
+ filter_criteria=validate_filter_criteria(
1227
+ filter_criteria, "filter_criteria"
1228
+ ),
1229
+ sort=validate_string_list(sort, "sort"),
1230
+ offset=validate_offset(offset),
1231
+ search=validate_search_query(search, "search"),
1232
+ cached_session=cached_session,
1233
+ )
1234
+
1235
+ async def list_pratiques_async(
1236
+ self,
1237
+ limit: int = 10,
1238
+ filter_criteria: str | None = None,
1239
+ sort: list[str] | None = None,
1240
+ offset: int | None = None,
1241
+ search: str | None = None,
1242
+ cached_session: httpx.AsyncClient | None = None,
1243
+ ) -> list[GetPratiqueResponse]:
1244
+ return await self.api_ffbb_client.list_pratiques_async(
1245
+ limit=limit,
1246
+ filter_criteria=validate_filter_criteria(
1247
+ filter_criteria, "filter_criteria"
1248
+ ),
1249
+ sort=validate_string_list(sort, "sort"),
1250
+ offset=validate_offset(offset),
1251
+ search=validate_search_query(search, "search"),
1252
+ cached_session=cached_session,
1253
+ )
1254
+
1255
+ # ---------------------------------------------------------------------
1256
+ # list_all delegations
1257
+ # ---------------------------------------------------------------------
1258
+
1259
+ def list_all_rencontres(
1260
+ self,
1261
+ filter_criteria: str | None = None,
1262
+ sort: list[str] | None = None,
1263
+ search: str | None = None,
1264
+ page_size: int = 100,
1265
+ max_items: int = 10000,
1266
+ cached_session: Client | None = None,
1267
+ ) -> list[GetRencontreResponse]:
1268
+ return self.api_ffbb_client.list_all_rencontres(
1269
+ filter_criteria=validate_filter_criteria(
1270
+ filter_criteria, "filter_criteria"
1271
+ ),
1272
+ sort=validate_string_list(sort, "sort"),
1273
+ search=validate_search_query(search, "search"),
1274
+ page_size=page_size,
1275
+ max_items=max_items,
1276
+ cached_session=cached_session,
1277
+ )
1278
+
1279
+ def list_all_salles(
1280
+ self,
1281
+ filter_criteria: str | None = None,
1282
+ sort: list[str] | None = None,
1283
+ search: str | None = None,
1284
+ page_size: int = 100,
1285
+ max_items: int = 10000,
1286
+ cached_session: Client | None = None,
1287
+ ) -> list[GetSalleResponse]:
1288
+ return self.api_ffbb_client.list_all_salles(
1289
+ filter_criteria=validate_filter_criteria(
1290
+ filter_criteria, "filter_criteria"
1291
+ ),
1292
+ sort=validate_string_list(sort, "sort"),
1293
+ search=validate_search_query(search, "search"),
1294
+ page_size=page_size,
1295
+ max_items=max_items,
1296
+ cached_session=cached_session,
1297
+ )
1298
+
1299
+ def list_all_terrains(
1300
+ self,
1301
+ filter_criteria: str | None = None,
1302
+ sort: list[str] | None = None,
1303
+ search: str | None = None,
1304
+ page_size: int = 100,
1305
+ max_items: int = 10000,
1306
+ cached_session: Client | None = None,
1307
+ ) -> list[GetTerrainResponse]:
1308
+ return self.api_ffbb_client.list_all_terrains(
1309
+ filter_criteria=validate_filter_criteria(
1310
+ filter_criteria, "filter_criteria"
1311
+ ),
1312
+ sort=validate_string_list(sort, "sort"),
1313
+ search=validate_search_query(search, "search"),
1314
+ page_size=page_size,
1315
+ max_items=max_items,
1316
+ cached_session=cached_session,
1317
+ )
1318
+
1319
+ def list_all_tournois(
1320
+ self,
1321
+ filter_criteria: str | None = None,
1322
+ sort: list[str] | None = None,
1323
+ search: str | None = None,
1324
+ page_size: int = 100,
1325
+ max_items: int = 10000,
1326
+ cached_session: Client | None = None,
1327
+ ) -> list[GetTournoiResponse]:
1328
+ return self.api_ffbb_client.list_all_tournois(
1329
+ filter_criteria=validate_filter_criteria(
1330
+ filter_criteria, "filter_criteria"
1331
+ ),
1332
+ sort=validate_string_list(sort, "sort"),
1333
+ search=validate_search_query(search, "search"),
1334
+ page_size=page_size,
1335
+ max_items=max_items,
1336
+ cached_session=cached_session,
1337
+ )
1338
+
1339
+ def list_all_engagements(
1340
+ self,
1341
+ filter_criteria: str | None = None,
1342
+ sort: list[str] | None = None,
1343
+ search: str | None = None,
1344
+ page_size: int = 100,
1345
+ max_items: int = 10000,
1346
+ cached_session: Client | None = None,
1347
+ ) -> list[GetEngagementResponse]:
1348
+ return self.api_ffbb_client.list_all_engagements(
1349
+ filter_criteria=validate_filter_criteria(
1350
+ filter_criteria, "filter_criteria"
1351
+ ),
1352
+ sort=validate_string_list(sort, "sort"),
1353
+ search=validate_search_query(search, "search"),
1354
+ page_size=page_size,
1355
+ max_items=max_items,
1356
+ cached_session=cached_session,
1357
+ )
1358
+
1359
+ def list_all_formations(
1360
+ self,
1361
+ filter_criteria: str | None = None,
1362
+ sort: list[str] | None = None,
1363
+ search: str | None = None,
1364
+ page_size: int = 100,
1365
+ max_items: int = 10000,
1366
+ cached_session: Client | None = None,
1367
+ ) -> list[GetFormationResponse]:
1368
+ return self.api_ffbb_client.list_all_formations(
1369
+ filter_criteria=validate_filter_criteria(
1370
+ filter_criteria, "filter_criteria"
1371
+ ),
1372
+ sort=validate_string_list(sort, "sort"),
1373
+ search=validate_search_query(search, "search"),
1374
+ page_size=page_size,
1375
+ max_items=max_items,
1376
+ cached_session=cached_session,
1377
+ )
1378
+
1379
+ def list_all_entraineurs(
1380
+ self,
1381
+ filter_criteria: str | None = None,
1382
+ sort: list[str] | None = None,
1383
+ search: str | None = None,
1384
+ page_size: int = 100,
1385
+ max_items: int = 10000,
1386
+ cached_session: Client | None = None,
1387
+ ) -> list[GetEntraineurResponse]:
1388
+ return self.api_ffbb_client.list_all_entraineurs(
1389
+ filter_criteria=validate_filter_criteria(
1390
+ filter_criteria, "filter_criteria"
1391
+ ),
1392
+ sort=validate_string_list(sort, "sort"),
1393
+ search=validate_search_query(search, "search"),
1394
+ page_size=page_size,
1395
+ max_items=max_items,
1396
+ cached_session=cached_session,
1397
+ )
1398
+
1399
+ def list_all_communes(
1400
+ self,
1401
+ filter_criteria: str | None = None,
1402
+ sort: list[str] | None = None,
1403
+ search: str | None = None,
1404
+ page_size: int = 100,
1405
+ max_items: int = 10000,
1406
+ cached_session: Client | None = None,
1407
+ ) -> list[GetCommuneResponse]:
1408
+ return self.api_ffbb_client.list_all_communes(
1409
+ filter_criteria=validate_filter_criteria(
1410
+ filter_criteria, "filter_criteria"
1411
+ ),
1412
+ sort=validate_string_list(sort, "sort"),
1413
+ search=validate_search_query(search, "search"),
1414
+ page_size=page_size,
1415
+ max_items=max_items,
1416
+ cached_session=cached_session,
1417
+ )
1418
+
1419
+ def list_all_officiels(
1420
+ self,
1421
+ filter_criteria: str | None = None,
1422
+ sort: list[str] | None = None,
1423
+ search: str | None = None,
1424
+ page_size: int = 100,
1425
+ max_items: int = 10000,
1426
+ cached_session: Client | None = None,
1427
+ ) -> list[GetOfficielResponse]:
1428
+ return self.api_ffbb_client.list_all_officiels(
1429
+ filter_criteria=validate_filter_criteria(
1430
+ filter_criteria, "filter_criteria"
1431
+ ),
1432
+ sort=validate_string_list(sort, "sort"),
1433
+ search=validate_search_query(search, "search"),
1434
+ page_size=page_size,
1435
+ max_items=max_items,
1436
+ cached_session=cached_session,
1437
+ )
1438
+
1439
+ def list_all_pratiques(
1440
+ self,
1441
+ filter_criteria: str | None = None,
1442
+ sort: list[str] | None = None,
1443
+ search: str | None = None,
1444
+ page_size: int = 100,
1445
+ max_items: int = 10000,
1446
+ cached_session: Client | None = None,
1447
+ ) -> list[GetPratiqueResponse]:
1448
+ return self.api_ffbb_client.list_all_pratiques(
1449
+ filter_criteria=validate_filter_criteria(
1450
+ filter_criteria, "filter_criteria"
1451
+ ),
1452
+ sort=validate_string_list(sort, "sort"),
1453
+ search=validate_search_query(search, "search"),
1454
+ page_size=page_size,
1455
+ max_items=max_items,
1456
+ cached_session=cached_session,
1457
+ )
1458
+
1459
+ async def list_all_rencontres_async(
1460
+ self,
1461
+ filter_criteria: str | None = None,
1462
+ sort: list[str] | None = None,
1463
+ search: str | None = None,
1464
+ page_size: int = 100,
1465
+ max_items: int = 10000,
1466
+ cached_session: httpx.AsyncClient | None = None,
1467
+ ) -> list[GetRencontreResponse]:
1468
+ return await self.api_ffbb_client.list_all_rencontres_async(
1469
+ filter_criteria=validate_filter_criteria(
1470
+ filter_criteria, "filter_criteria"
1471
+ ),
1472
+ sort=validate_string_list(sort, "sort"),
1473
+ search=validate_search_query(search, "search"),
1474
+ page_size=page_size,
1475
+ max_items=max_items,
1476
+ cached_session=cached_session,
1477
+ )
1478
+
1479
+ async def list_all_salles_async(
1480
+ self,
1481
+ filter_criteria: str | None = None,
1482
+ sort: list[str] | None = None,
1483
+ search: str | None = None,
1484
+ page_size: int = 100,
1485
+ max_items: int = 10000,
1486
+ cached_session: httpx.AsyncClient | None = None,
1487
+ ) -> list[GetSalleResponse]:
1488
+ return await self.api_ffbb_client.list_all_salles_async(
1489
+ filter_criteria=validate_filter_criteria(
1490
+ filter_criteria, "filter_criteria"
1491
+ ),
1492
+ sort=validate_string_list(sort, "sort"),
1493
+ search=validate_search_query(search, "search"),
1494
+ page_size=page_size,
1495
+ max_items=max_items,
1496
+ cached_session=cached_session,
1497
+ )
1498
+
1499
+ async def list_all_terrains_async(
1500
+ self,
1501
+ filter_criteria: str | None = None,
1502
+ sort: list[str] | None = None,
1503
+ search: str | None = None,
1504
+ page_size: int = 100,
1505
+ max_items: int = 10000,
1506
+ cached_session: httpx.AsyncClient | None = None,
1507
+ ) -> list[GetTerrainResponse]:
1508
+ return await self.api_ffbb_client.list_all_terrains_async(
1509
+ filter_criteria=validate_filter_criteria(
1510
+ filter_criteria, "filter_criteria"
1511
+ ),
1512
+ sort=validate_string_list(sort, "sort"),
1513
+ search=validate_search_query(search, "search"),
1514
+ page_size=page_size,
1515
+ max_items=max_items,
1516
+ cached_session=cached_session,
1517
+ )
1518
+
1519
+ async def list_all_tournois_async(
1520
+ self,
1521
+ filter_criteria: str | None = None,
1522
+ sort: list[str] | None = None,
1523
+ search: str | None = None,
1524
+ page_size: int = 100,
1525
+ max_items: int = 10000,
1526
+ cached_session: httpx.AsyncClient | None = None,
1527
+ ) -> list[GetTournoiResponse]:
1528
+ return await self.api_ffbb_client.list_all_tournois_async(
1529
+ filter_criteria=validate_filter_criteria(
1530
+ filter_criteria, "filter_criteria"
1531
+ ),
1532
+ sort=validate_string_list(sort, "sort"),
1533
+ search=validate_search_query(search, "search"),
1534
+ page_size=page_size,
1535
+ max_items=max_items,
1536
+ cached_session=cached_session,
1537
+ )
1538
+
1539
+ async def list_all_engagements_async(
1540
+ self,
1541
+ filter_criteria: str | None = None,
1542
+ sort: list[str] | None = None,
1543
+ search: str | None = None,
1544
+ page_size: int = 100,
1545
+ max_items: int = 10000,
1546
+ cached_session: httpx.AsyncClient | None = None,
1547
+ ) -> list[GetEngagementResponse]:
1548
+ return await self.api_ffbb_client.list_all_engagements_async(
1549
+ filter_criteria=validate_filter_criteria(
1550
+ filter_criteria, "filter_criteria"
1551
+ ),
1552
+ sort=validate_string_list(sort, "sort"),
1553
+ search=validate_search_query(search, "search"),
1554
+ page_size=page_size,
1555
+ max_items=max_items,
1556
+ cached_session=cached_session,
1557
+ )
1558
+
1559
+ async def list_all_formations_async(
1560
+ self,
1561
+ filter_criteria: str | None = None,
1562
+ sort: list[str] | None = None,
1563
+ search: str | None = None,
1564
+ page_size: int = 100,
1565
+ max_items: int = 10000,
1566
+ cached_session: httpx.AsyncClient | None = None,
1567
+ ) -> list[GetFormationResponse]:
1568
+ return await self.api_ffbb_client.list_all_formations_async(
1569
+ filter_criteria=validate_filter_criteria(
1570
+ filter_criteria, "filter_criteria"
1571
+ ),
1572
+ sort=validate_string_list(sort, "sort"),
1573
+ search=validate_search_query(search, "search"),
1574
+ page_size=page_size,
1575
+ max_items=max_items,
1576
+ cached_session=cached_session,
1577
+ )
1578
+
1579
+ async def list_all_entraineurs_async(
1580
+ self,
1581
+ filter_criteria: str | None = None,
1582
+ sort: list[str] | None = None,
1583
+ search: str | None = None,
1584
+ page_size: int = 100,
1585
+ max_items: int = 10000,
1586
+ cached_session: httpx.AsyncClient | None = None,
1587
+ ) -> list[GetEntraineurResponse]:
1588
+ return await self.api_ffbb_client.list_all_entraineurs_async(
1589
+ filter_criteria=validate_filter_criteria(
1590
+ filter_criteria, "filter_criteria"
1591
+ ),
1592
+ sort=validate_string_list(sort, "sort"),
1593
+ search=validate_search_query(search, "search"),
1594
+ page_size=page_size,
1595
+ max_items=max_items,
1596
+ cached_session=cached_session,
1597
+ )
1598
+
1599
+ async def list_all_communes_async(
1600
+ self,
1601
+ filter_criteria: str | None = None,
1602
+ sort: list[str] | None = None,
1603
+ search: str | None = None,
1604
+ page_size: int = 100,
1605
+ max_items: int = 10000,
1606
+ cached_session: httpx.AsyncClient | None = None,
1607
+ ) -> list[GetCommuneResponse]:
1608
+ return await self.api_ffbb_client.list_all_communes_async(
1609
+ filter_criteria=validate_filter_criteria(
1610
+ filter_criteria, "filter_criteria"
1611
+ ),
1612
+ sort=validate_string_list(sort, "sort"),
1613
+ search=validate_search_query(search, "search"),
1614
+ page_size=page_size,
1615
+ max_items=max_items,
1616
+ cached_session=cached_session,
1617
+ )
1618
+
1619
+ async def list_all_officiels_async(
1620
+ self,
1621
+ filter_criteria: str | None = None,
1622
+ sort: list[str] | None = None,
1623
+ search: str | None = None,
1624
+ page_size: int = 100,
1625
+ max_items: int = 10000,
1626
+ cached_session: httpx.AsyncClient | None = None,
1627
+ ) -> list[GetOfficielResponse]:
1628
+ return await self.api_ffbb_client.list_all_officiels_async(
1629
+ filter_criteria=validate_filter_criteria(
1630
+ filter_criteria, "filter_criteria"
1631
+ ),
1632
+ sort=validate_string_list(sort, "sort"),
1633
+ search=validate_search_query(search, "search"),
1634
+ page_size=page_size,
1635
+ max_items=max_items,
1636
+ cached_session=cached_session,
1637
+ )
1638
+
1639
+ async def list_all_pratiques_async(
1640
+ self,
1641
+ filter_criteria: str | None = None,
1642
+ sort: list[str] | None = None,
1643
+ search: str | None = None,
1644
+ page_size: int = 100,
1645
+ max_items: int = 10000,
1646
+ cached_session: httpx.AsyncClient | None = None,
1647
+ ) -> list[GetPratiqueResponse]:
1648
+ return await self.api_ffbb_client.list_all_pratiques_async(
1649
+ filter_criteria=validate_filter_criteria(
1650
+ filter_criteria, "filter_criteria"
1651
+ ),
1652
+ sort=validate_string_list(sort, "sort"),
1653
+ search=validate_search_query(search, "search"),
1654
+ page_size=page_size,
1655
+ max_items=max_items,
1656
+ cached_session=cached_session,
1657
+ )
1658
+
1659
+ # ---------------------------------------------------------------------
1660
+ # Batch helpers
1661
+ # ---------------------------------------------------------------------
1662
+
1663
+ def list_engagements_by_ids(
1664
+ self, ids: list[int], cached_session: Client | None = None
1665
+ ) -> list[GetEngagementResponse]:
1666
+ results: list[GetEngagementResponse] = []
1667
+ for chunk in self._chunked(ids, self._BATCH_CHUNK_SIZE):
1668
+ fc = json.dumps({"id": {"_in": chunk}})
1669
+ results.extend(
1670
+ self.list_engagements(
1671
+ limit=len(chunk), filter_criteria=fc, cached_session=cached_session
1672
+ )
1673
+ )
1674
+ return results
1675
+
1676
+ def list_engagements_by_poule(
1677
+ self, poule_id: int, cached_session: Client | None = None
1678
+ ) -> list[GetEngagementResponse]:
1679
+ return self.list_engagements(
1680
+ limit=250,
1681
+ filter_criteria=json.dumps({"idPoule": {"_eq": poule_id}}),
1682
+ cached_session=cached_session,
1683
+ )
1684
+
1685
+ def list_engagements_by_poules(
1686
+ self, poule_ids: list[int], cached_session: Client | None = None
1687
+ ) -> list[GetEngagementResponse]:
1688
+ results: list[GetEngagementResponse] = []
1689
+ for chunk in self._chunked(poule_ids, self._BATCH_CHUNK_SIZE):
1690
+ fc = json.dumps({"idPoule": {"_in": chunk}})
1691
+ results.extend(
1692
+ self.list_engagements(
1693
+ limit=250, filter_criteria=fc, cached_session=cached_session
1694
+ )
1695
+ )
1696
+ return results
1697
+
1698
+ def list_rencontres_by_poule(
1699
+ self, poule_id: int, cached_session: Client | None = None
1700
+ ) -> list[GetRencontreResponse]:
1701
+ return self.list_rencontres(
1702
+ limit=500,
1703
+ filter_criteria=json.dumps({"idPoule": {"_eq": poule_id}}),
1704
+ cached_session=cached_session,
1705
+ )
1706
+
1707
+ def list_rencontres_by_poules(
1708
+ self, poule_ids: list[int], cached_session: Client | None = None
1709
+ ) -> list[GetRencontreResponse]:
1710
+ results: list[GetRencontreResponse] = []
1711
+ for chunk in self._chunked(poule_ids, self._BATCH_CHUNK_SIZE):
1712
+ fc = json.dumps({"idPoule": {"_in": chunk}})
1713
+ results.extend(
1714
+ self.list_rencontres(
1715
+ limit=500, filter_criteria=fc, cached_session=cached_session
1716
+ )
1717
+ )
1718
+ return results
1719
+
1720
+ def list_entraineurs_by_ids(
1721
+ self, ids: list[int], cached_session: Client | None = None
1722
+ ) -> list[GetEntraineurResponse]:
1723
+ results: list[GetEntraineurResponse] = []
1724
+ for chunk in self._chunked(ids, self._BATCH_CHUNK_SIZE):
1725
+ str_ids = [str(i) for i in chunk]
1726
+ fc = json.dumps({"idLicence": {"_in": str_ids}})
1727
+ results.extend(
1728
+ self.list_entraineurs(
1729
+ limit=len(chunk), filter_criteria=fc, cached_session=cached_session
1730
+ )
1731
+ )
1732
+ return results
1733
+
1734
+ # -------------------------------------------------------------------------
1735
+ # Meilisearch — multi-search
1736
+ # -------------------------------------------------------------------------
1737
+
1738
+ async def multi_search_async(
1739
+ self, queries: Sequence[MultiSearchQuery] | None = None
1740
+ ) -> MultiSearchResults | None:
1741
+ """Performs a smart multi-search asynchronously."""
1742
+ return await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
1743
+ queries
1744
+ )
1745
+
1746
+ def multi_search(
1747
+ self, name: str | None = None, cached_session: Client | None = None
1748
+ ) -> list[MultiSearchResult] | None:
1749
+ """
1750
+ Perform multi-search across all resource types with input validation.
1751
+
1752
+ Args:
1753
+ name (str, optional): Search query string
1754
+ cached_session (Client, optional): HTTP cache session
1755
+
1756
+ Returns:
1757
+ list[MultiSearchResult]: Search results across all resource types
1758
+
1759
+ Raises:
1760
+ ValidationError: If search query is invalid
1761
+ """
1762
+ validated_name = validate_search_query(name, "name")
1763
+ queries = generate_queries(validated_name)
1764
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
1765
+ queries, cached_session=cached_session
1766
+ )
1767
+
1768
+ return results.results if results else None
1769
+
1770
+ # -------------------------------------------------------------------------
1771
+ # Meilisearch — competitions
1772
+ # -------------------------------------------------------------------------
1773
+
1774
+ def search_competitions(
1775
+ self,
1776
+ name: str | None = None,
1777
+ filter: list[str] | None = None,
1778
+ sort: list[str] | None = None,
1779
+ limit: int | None = 10,
1780
+ cached_session: Client | None = None,
1781
+ ) -> CompetitionsMultiSearchResult | None:
1782
+ results = self.search_multiple_competitions(
1783
+ [name] if name is not None else None,
1784
+ filter=filter,
1785
+ sort=sort,
1786
+ limit=limit,
1787
+ cached_session=cached_session,
1788
+ )
1789
+ return results[0] if results else None
1790
+
1791
+ def search_multiple_competitions(
1792
+ self,
1793
+ names: list[str | None] | None = None,
1794
+ filter: list[str] | None = None,
1795
+ sort: list[str] | None = None,
1796
+ limit: int | None = 10,
1797
+ cached_session: Client | None = None,
1798
+ ) -> list[CompetitionsMultiSearchResult] | None:
1799
+ if not names:
1800
+ return None
1801
+
1802
+ queries = [
1803
+ CompetitionsMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
1804
+ for name in names
1805
+ ]
1806
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
1807
+ queries, cached_session
1808
+ )
1809
+
1810
+ return (
1811
+ cast(list[CompetitionsMultiSearchResult], results.results)
1812
+ if results
1813
+ else None
1814
+ )
1815
+
1816
+ async def search_competitions_async(
1817
+ self, name: str | None = None
1818
+ ) -> CompetitionsMultiSearchResult | None:
1819
+ """Search for competitions asynchronously."""
1820
+ if not name:
1821
+ return None
1822
+ queries = [CompetitionsMultiSearchQuery(name)]
1823
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
1824
+ queries
1825
+ )
1826
+ return (
1827
+ cast(CompetitionsMultiSearchResult, results.results[0])
1828
+ if results and results.results
1829
+ else None
1830
+ )
1831
+
1832
+ async def search_multiple_competitions_async(
1833
+ self,
1834
+ names: list[str | None] | None = None,
1835
+ filter: list[str] | None = None,
1836
+ sort: list[str] | None = None,
1837
+ limit: int | None = 10,
1838
+ ) -> list[CompetitionsMultiSearchResult] | None:
1839
+ """Search for multiple competitions asynchronously."""
1840
+ if not names:
1841
+ return None
1842
+ queries = [
1843
+ CompetitionsMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
1844
+ for name in names
1845
+ ]
1846
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
1847
+ queries
1848
+ )
1849
+ return (
1850
+ cast(list[CompetitionsMultiSearchResult], results.results)
1851
+ if results
1852
+ else None
1853
+ )
1854
+
1855
+ # -------------------------------------------------------------------------
1856
+ # Meilisearch — organismes
1857
+ # -------------------------------------------------------------------------
1858
+
1859
+ def search_organismes(
1860
+ self,
1861
+ name: str | None = None,
1862
+ filter: list[str] | None = None,
1863
+ sort: list[str] | None = None,
1864
+ limit: int | None = 10,
1865
+ cached_session: Client | None = None,
1866
+ ) -> OrganismesMultiSearchResult | None:
1867
+ results = self.search_multiple_organismes(
1868
+ [name] if name is not None else None,
1869
+ filter=filter,
1870
+ sort=sort,
1871
+ limit=limit,
1872
+ cached_session=cached_session,
1873
+ )
1874
+ return results[0] if results else None
1875
+
1876
+ def search_organismes_by_geo(
1877
+ self,
1878
+ lat: float,
1879
+ lng: float,
1880
+ radius_km: float = 10.0,
1881
+ q: str = "",
1882
+ limit: int | None = 20,
1883
+ geo_sort: GeoSortOrder = GeoSortOrder.NEAREST_FIRST,
1884
+ cached_session: Client | None = None,
1885
+ ) -> OrganismesMultiSearchResult | None:
1886
+ return self.meilisearch_ffbb_client.search_organismes_by_geo(
1887
+ lat=lat,
1888
+ lng=lng,
1889
+ radius_km=radius_km,
1890
+ q=q,
1891
+ limit=limit,
1892
+ geo_sort=geo_sort,
1893
+ cached_session=cached_session,
1894
+ )
1895
+
1896
+ def search_organismes_by_city(
1897
+ self,
1898
+ city_name: str,
1899
+ q: str = "",
1900
+ limit: int = 200,
1901
+ cached_session: Client | None = None,
1902
+ ) -> OrganismesMultiSearchResult | None:
1903
+ return self.meilisearch_ffbb_client.search_organismes_by_city(
1904
+ city_name, q=q, limit=limit, cached_session=cached_session
1905
+ )
1906
+
1907
+ def search_multiple_organismes(
1908
+ self,
1909
+ names: list[str | None] | None = None,
1910
+ filter: list[str] | None = None,
1911
+ sort: list[str] | None = None,
1912
+ limit: int | None = 10,
1913
+ cached_session: Client | None = None,
1914
+ ) -> list[OrganismesMultiSearchResult] | None:
1915
+ if not names:
1916
+ return None
1917
+
1918
+ queries = [
1919
+ OrganismesMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
1920
+ for name in names
1921
+ ]
1922
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
1923
+ queries, cached_session
1924
+ )
1925
+
1926
+ return (
1927
+ cast(list[OrganismesMultiSearchResult], results.results)
1928
+ if results
1929
+ else None
1930
+ )
1931
+
1932
+ async def search_organismes_async(
1933
+ self, name: str | None = None
1934
+ ) -> OrganismesMultiSearchResult | None:
1935
+ """Search for organismes asynchronously."""
1936
+ if not name:
1937
+ return None
1938
+ queries = [OrganismesMultiSearchQuery(name)]
1939
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
1940
+ queries
1941
+ )
1942
+ return (
1943
+ cast(OrganismesMultiSearchResult, results.results[0])
1944
+ if results and results.results
1945
+ else None
1946
+ )
1947
+
1948
+ async def search_multiple_organismes_async(
1949
+ self,
1950
+ names: list[str | None] | None = None,
1951
+ filter: list[str] | None = None,
1952
+ sort: list[str] | None = None,
1953
+ limit: int | None = 10,
1954
+ ) -> list[OrganismesMultiSearchResult] | None:
1955
+ """Search for multiple organismes asynchronously."""
1956
+ if not names:
1957
+ return None
1958
+ queries = [
1959
+ OrganismesMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
1960
+ for name in names
1961
+ ]
1962
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
1963
+ queries
1964
+ )
1965
+ return (
1966
+ cast(list[OrganismesMultiSearchResult], results.results)
1967
+ if results
1968
+ else None
1969
+ )
1970
+
1971
+ # -------------------------------------------------------------------------
1972
+ # Meilisearch — pratiques
1973
+ # -------------------------------------------------------------------------
1974
+
1975
+ def search_pratiques(
1976
+ self,
1977
+ name: str | None = None,
1978
+ filter: list[str] | None = None,
1979
+ sort: list[str] | None = None,
1980
+ limit: int | None = 10,
1981
+ cached_session: Client | None = None,
1982
+ ) -> PratiquesMultiSearchResult | None:
1983
+ results = self.search_multiple_pratiques(
1984
+ [name] if name is not None else None,
1985
+ filter=filter,
1986
+ sort=sort,
1987
+ limit=limit,
1988
+ cached_session=cached_session,
1989
+ )
1990
+ return results[0] if results else None
1991
+
1992
+ def search_multiple_pratiques(
1993
+ self,
1994
+ names: list[str | None] | None = None,
1995
+ filter: list[str] | None = None,
1996
+ sort: list[str] | None = None,
1997
+ limit: int | None = 10,
1998
+ cached_session: Client | None = None,
1999
+ ) -> list[PratiquesMultiSearchResult] | None:
2000
+ if not names:
2001
+ return None
2002
+
2003
+ queries = [
2004
+ PratiquesMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2005
+ for name in names
2006
+ ]
2007
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
2008
+ queries, cached_session
2009
+ )
2010
+
2011
+ return (
2012
+ cast(list[PratiquesMultiSearchResult], results.results) if results else None
2013
+ )
2014
+
2015
+ async def search_pratiques_async(
2016
+ self, name: str | None = None
2017
+ ) -> PratiquesMultiSearchResult | None:
2018
+ """Search for pratiques asynchronously."""
2019
+ if not name:
2020
+ return None
2021
+ queries = [PratiquesMultiSearchQuery(name)]
2022
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
2023
+ queries
2024
+ )
2025
+ return (
2026
+ cast(PratiquesMultiSearchResult, results.results[0])
2027
+ if results and results.results
2028
+ else None
2029
+ )
2030
+
2031
+ async def search_multiple_pratiques_async(
2032
+ self,
2033
+ names: list[str | None] | None = None,
2034
+ filter: list[str] | None = None,
2035
+ sort: list[str] | None = None,
2036
+ limit: int | None = 10,
2037
+ ) -> list[PratiquesMultiSearchResult] | None:
2038
+ """Search for multiple pratiques asynchronously."""
2039
+ if not names:
2040
+ return None
2041
+ queries = [
2042
+ PratiquesMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2043
+ for name in names
2044
+ ]
2045
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
2046
+ queries
2047
+ )
2048
+ return (
2049
+ cast(list[PratiquesMultiSearchResult], results.results) if results else None
2050
+ )
2051
+
2052
+ # -------------------------------------------------------------------------
2053
+ # Meilisearch — rencontres
2054
+ # -------------------------------------------------------------------------
2055
+
2056
+ def search_rencontres(
2057
+ self,
2058
+ name: str | None = None,
2059
+ categorie: str | None = None,
2060
+ filter: list[str] | None = None,
2061
+ sort: list[str] | None = None,
2062
+ limit: int | None = 10,
2063
+ cached_session: Client | None = None,
2064
+ ) -> RencontresMultiSearchResult | None:
2065
+ results = self.search_multiple_rencontres(
2066
+ [name] if name is not None else None,
2067
+ categorie,
2068
+ filter=filter,
2069
+ sort=sort,
2070
+ limit=limit,
2071
+ cached_session=cached_session,
2072
+ )
2073
+ return results[0] if results else None
2074
+
2075
+ def search_multiple_rencontres(
2076
+ self,
2077
+ names: list[str | None] | None = None,
2078
+ categorie: str | None = None,
2079
+ filter: list[str] | None = None,
2080
+ sort: list[str] | None = None,
2081
+ limit: int | None = 10,
2082
+ cached_session: Client | None = None,
2083
+ ) -> list[RencontresMultiSearchResult] | None:
2084
+ if not names:
2085
+ return None
2086
+
2087
+ queries = [
2088
+ RencontresMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2089
+ for name in names
2090
+ ]
2091
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
2092
+ queries, cached_session
2093
+ )
2094
+
2095
+ if not results or not results.results:
2096
+ return None
2097
+
2098
+ rencontres_results = cast(list[RencontresMultiSearchResult], results.results)
2099
+
2100
+ if categorie:
2101
+ for res in rencontres_results:
2102
+ if res.hits:
2103
+ filtered_hits = []
2104
+ for hit in res.hits:
2105
+ comp = hit.competition_id
2106
+ cat = comp.categorie if comp else None
2107
+ if (
2108
+ comp
2109
+ and cat
2110
+ and (cat.code == categorie or cat.libelle == categorie)
2111
+ ):
2112
+ filtered_hits.append(hit)
2113
+ res.hits = filtered_hits
2114
+ res.estimated_total_hits = len(filtered_hits)
2115
+
2116
+ return rencontres_results
2117
+
2118
+ async def search_rencontres_async(
2119
+ self, name: str | None = None, categorie: str | None = None
2120
+ ) -> RencontresMultiSearchResult | None:
2121
+ """Search for rencontres asynchronously."""
2122
+ if not name:
2123
+ return None
2124
+ results = await self.search_multiple_rencontres_async([name], categorie)
2125
+ return results[0] if results else None
2126
+
2127
+ async def search_multiple_rencontres_async(
2128
+ self,
2129
+ names: list[str | None] | None = None,
2130
+ categorie: str | None = None,
2131
+ ) -> list[RencontresMultiSearchResult] | None:
2132
+ """Search for multiple rencontres asynchronously."""
2133
+ if not names:
2134
+ return None
2135
+
2136
+ queries = [RencontresMultiSearchQuery(name) for name in names]
2137
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
2138
+ queries
2139
+ )
2140
+
2141
+ if not results or not results.results:
2142
+ return None
2143
+
2144
+ rencontres_results = cast(list[RencontresMultiSearchResult], results.results)
2145
+
2146
+ if categorie:
2147
+ for res in rencontres_results:
2148
+ if res.hits:
2149
+ # ⚡ Bolt optimization: Use walrus operator to avoid redundant attribute access (~14% speedup)
2150
+ filtered_hits = [
2151
+ hit
2152
+ for hit in res.hits
2153
+ if (comp := hit.competition_id)
2154
+ and (cat := comp.categorie)
2155
+ and (cat.code == categorie or cat.libelle == categorie)
2156
+ ]
2157
+ res.hits = filtered_hits
2158
+ res.estimated_total_hits = len(filtered_hits)
2159
+
2160
+ return rencontres_results
2161
+
2162
+ # -------------------------------------------------------------------------
2163
+ # Meilisearch — salles
2164
+ # -------------------------------------------------------------------------
2165
+
2166
+ def search_salles(
2167
+ self,
2168
+ name: str | None = None,
2169
+ filter: list[str] | None = None,
2170
+ sort: list[str] | None = None,
2171
+ limit: int | None = 10,
2172
+ cached_session: Client | None = None,
2173
+ ) -> SallesMultiSearchResult | None:
2174
+ results = self.search_multiple_salles(
2175
+ [name] if name is not None else None,
2176
+ filter=filter,
2177
+ sort=sort,
2178
+ limit=limit,
2179
+ cached_session=cached_session,
2180
+ )
2181
+ return results[0] if results else None
2182
+
2183
+ def search_salles_by_geo(
2184
+ self,
2185
+ lat: float,
2186
+ lng: float,
2187
+ radius_km: float = 10.0,
2188
+ q: str = "",
2189
+ limit: int | None = 20,
2190
+ geo_sort: GeoSortOrder = GeoSortOrder.NEAREST_FIRST,
2191
+ cached_session: Client | None = None,
2192
+ ) -> SallesMultiSearchResult | None:
2193
+ return self.meilisearch_ffbb_client.search_salles_by_geo(
2194
+ lat=lat,
2195
+ lng=lng,
2196
+ radius_km=radius_km,
2197
+ q=q,
2198
+ limit=limit,
2199
+ geo_sort=geo_sort,
2200
+ cached_session=cached_session,
2201
+ )
2202
+
2203
+ def search_multiple_salles(
2204
+ self,
2205
+ names: list[str | None] | None = None,
2206
+ filter: list[str] | None = None,
2207
+ sort: list[str] | None = None,
2208
+ limit: int | None = 10,
2209
+ cached_session: Client | None = None,
2210
+ ) -> list[SallesMultiSearchResult] | None:
2211
+ if not names:
2212
+ return None
2213
+
2214
+ queries = [
2215
+ SallesMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2216
+ for name in names
2217
+ ]
2218
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
2219
+ queries, cached_session
2220
+ )
2221
+
2222
+ return cast(list[SallesMultiSearchResult], results.results) if results else None
2223
+
2224
+ async def search_salles_async(
2225
+ self, name: str | None = None
2226
+ ) -> SallesMultiSearchResult | None:
2227
+ """Search for salles asynchronously."""
2228
+ if not name:
2229
+ return None
2230
+ queries = [SallesMultiSearchQuery(name)]
2231
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
2232
+ queries
2233
+ )
2234
+ return (
2235
+ cast(SallesMultiSearchResult, results.results[0])
2236
+ if results and results.results
2237
+ else None
2238
+ )
2239
+
2240
+ async def search_multiple_salles_async(
2241
+ self,
2242
+ names: list[str | None] | None = None,
2243
+ filter: list[str] | None = None,
2244
+ sort: list[str] | None = None,
2245
+ limit: int | None = 10,
2246
+ ) -> list[SallesMultiSearchResult] | None:
2247
+ """Search for multiple salles asynchronously."""
2248
+ if not names:
2249
+ return None
2250
+ queries = [
2251
+ SallesMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2252
+ for name in names
2253
+ ]
2254
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
2255
+ queries
2256
+ )
2257
+ return cast(list[SallesMultiSearchResult], results.results) if results else None
2258
+
2259
+ # -------------------------------------------------------------------------
2260
+ # Meilisearch — terrains
2261
+ # -------------------------------------------------------------------------
2262
+
2263
+ def search_terrains(
2264
+ self,
2265
+ name: str | None = None,
2266
+ filter: list[str] | None = None,
2267
+ sort: list[str] | None = None,
2268
+ limit: int | None = 10,
2269
+ cached_session: Client | None = None,
2270
+ ) -> TerrainsMultiSearchResult | None:
2271
+ results = self.search_multiple_terrains(
2272
+ [name] if name is not None else None,
2273
+ filter=filter,
2274
+ sort=sort,
2275
+ limit=limit,
2276
+ cached_session=cached_session,
2277
+ )
2278
+ return results[0] if results else None
2279
+
2280
+ def search_multiple_terrains(
2281
+ self,
2282
+ names: list[str | None] | None = None,
2283
+ filter: list[str] | None = None,
2284
+ sort: list[str] | None = None,
2285
+ limit: int | None = 10,
2286
+ cached_session: Client | None = None,
2287
+ ) -> list[TerrainsMultiSearchResult] | None:
2288
+ if not names:
2289
+ return None
2290
+
2291
+ queries = [
2292
+ TerrainsMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2293
+ for name in names
2294
+ ]
2295
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
2296
+ queries, cached_session
2297
+ )
2298
+
2299
+ return (
2300
+ cast(list[TerrainsMultiSearchResult], results.results) if results else None
2301
+ )
2302
+
2303
+ async def search_terrains_async(
2304
+ self, name: str | None = None
2305
+ ) -> TerrainsMultiSearchResult | None:
2306
+ """Search for terrains asynchronously."""
2307
+ if not name:
2308
+ return None
2309
+ queries = [TerrainsMultiSearchQuery(name)]
2310
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
2311
+ queries
2312
+ )
2313
+ return (
2314
+ cast(TerrainsMultiSearchResult, results.results[0])
2315
+ if results and results.results
2316
+ else None
2317
+ )
2318
+
2319
+ async def search_multiple_terrains_async(
2320
+ self,
2321
+ names: list[str | None] | None = None,
2322
+ filter: list[str] | None = None,
2323
+ sort: list[str] | None = None,
2324
+ limit: int | None = 10,
2325
+ ) -> list[TerrainsMultiSearchResult] | None:
2326
+ """Search for multiple terrains asynchronously."""
2327
+ if not names:
2328
+ return None
2329
+ queries = [
2330
+ TerrainsMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2331
+ for name in names
2332
+ ]
2333
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
2334
+ queries
2335
+ )
2336
+ return (
2337
+ cast(list[TerrainsMultiSearchResult], results.results) if results else None
2338
+ )
2339
+
2340
+ # -------------------------------------------------------------------------
2341
+ # Meilisearch — tournois
2342
+ # -------------------------------------------------------------------------
2343
+
2344
+ def search_tournois(
2345
+ self,
2346
+ name: str | None = None,
2347
+ filter: list[str] | None = None,
2348
+ sort: list[str] | None = None,
2349
+ limit: int | None = 10,
2350
+ cached_session: Client | None = None,
2351
+ ) -> TournoisMultiSearchResult | None:
2352
+ results = self.search_multiple_tournois(
2353
+ [name] if name is not None else None,
2354
+ filter=filter,
2355
+ sort=sort,
2356
+ limit=limit,
2357
+ cached_session=cached_session,
2358
+ )
2359
+ return results[0] if results else None
2360
+
2361
+ def search_multiple_tournois(
2362
+ self,
2363
+ names: list[str | None] | None = None,
2364
+ filter: list[str] | None = None,
2365
+ sort: list[str] | None = None,
2366
+ limit: int | None = 10,
2367
+ cached_session: Client | None = None,
2368
+ ) -> list[TournoisMultiSearchResult] | None:
2369
+ if not names:
2370
+ return None
2371
+
2372
+ queries = [
2373
+ TournoisMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2374
+ for name in names
2375
+ ]
2376
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
2377
+ queries, cached_session
2378
+ )
2379
+
2380
+ return (
2381
+ cast(list[TournoisMultiSearchResult], results.results) if results else None
2382
+ )
2383
+
2384
+ async def search_tournois_async(
2385
+ self, name: str | None = None
2386
+ ) -> TournoisMultiSearchResult | None:
2387
+ """Search for tournois asynchronously."""
2388
+ if not name:
2389
+ return None
2390
+ queries = [TournoisMultiSearchQuery(name)]
2391
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
2392
+ queries
2393
+ )
2394
+ return (
2395
+ cast(TournoisMultiSearchResult, results.results[0])
2396
+ if results and results.results
2397
+ else None
2398
+ )
2399
+
2400
+ async def search_multiple_tournois_async(
2401
+ self,
2402
+ names: list[str | None] | None = None,
2403
+ filter: list[str] | None = None,
2404
+ sort: list[str] | None = None,
2405
+ limit: int | None = 10,
2406
+ ) -> list[TournoisMultiSearchResult] | None:
2407
+ """Search for multiple tournois asynchronously."""
2408
+ if not names:
2409
+ return None
2410
+ queries = [
2411
+ TournoisMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2412
+ for name in names
2413
+ ]
2414
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
2415
+ queries
2416
+ )
2417
+ return (
2418
+ cast(list[TournoisMultiSearchResult], results.results) if results else None
2419
+ )
2420
+
2421
+ # -------------------------------------------------------------------------
2422
+ # Meilisearch — engagements
2423
+ # -------------------------------------------------------------------------
2424
+
2425
+ def search_engagements(
2426
+ self,
2427
+ name: str | None = None,
2428
+ filter: list[str] | None = None,
2429
+ sort: list[str] | None = None,
2430
+ limit: int | None = 10,
2431
+ cached_session: Client | None = None,
2432
+ ) -> EngagementsMultiSearchResult | None:
2433
+ results = self.search_multiple_engagements(
2434
+ [name] if name is not None else None,
2435
+ filter=filter,
2436
+ sort=sort,
2437
+ limit=limit,
2438
+ cached_session=cached_session,
2439
+ )
2440
+ return results[0] if results else None
2441
+
2442
+ def search_engagements_by_geo(
2443
+ self,
2444
+ lat: float,
2445
+ lng: float,
2446
+ radius_km: float = 10.0,
2447
+ q: str = "",
2448
+ limit: int | None = 20,
2449
+ geo_sort: GeoSortOrder = GeoSortOrder.NEAREST_FIRST,
2450
+ cached_session: Client | None = None,
2451
+ ) -> EngagementsMultiSearchResult | None:
2452
+ return self.meilisearch_ffbb_client.search_engagements_by_geo(
2453
+ lat=lat,
2454
+ lng=lng,
2455
+ radius_km=radius_km,
2456
+ q=q,
2457
+ limit=limit,
2458
+ geo_sort=geo_sort,
2459
+ cached_session=cached_session,
2460
+ )
2461
+
2462
+ def search_engagements_filtered(
2463
+ self,
2464
+ lat: float,
2465
+ lng: float,
2466
+ radius_km: float = 10.0,
2467
+ q: str = "",
2468
+ limit: int | None = 5000,
2469
+ sexes: list[str] | None = None,
2470
+ niveau_codes: list[str] | None = None,
2471
+ cached_session: Client | None = None,
2472
+ ) -> EngagementsMultiSearchResult | None:
2473
+ return self.meilisearch_ffbb_client.search_engagements_filtered(
2474
+ lat=lat,
2475
+ lng=lng,
2476
+ radius_km=radius_km,
2477
+ q=q,
2478
+ limit=limit,
2479
+ sexes=sexes,
2480
+ niveau_codes=niveau_codes,
2481
+ cached_session=cached_session,
2482
+ )
2483
+
2484
+ def search_multiple_engagements(
2485
+ self,
2486
+ names: list[str | None] | None = None,
2487
+ filter: list[str] | None = None,
2488
+ sort: list[str] | None = None,
2489
+ limit: int | None = 10,
2490
+ cached_session: Client | None = None,
2491
+ ) -> list[EngagementsMultiSearchResult] | None:
2492
+ if not names:
2493
+ return None
2494
+
2495
+ queries = [
2496
+ EngagementsMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2497
+ for name in names
2498
+ ]
2499
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
2500
+ queries, cached_session
2501
+ )
2502
+
2503
+ return (
2504
+ cast(list[EngagementsMultiSearchResult], results.results)
2505
+ if results
2506
+ else None
2507
+ )
2508
+
2509
+ async def search_engagements_async(
2510
+ self, name: str | None = None
2511
+ ) -> EngagementsMultiSearchResult | None:
2512
+ """Search for engagements asynchronously."""
2513
+ if not name:
2514
+ return None
2515
+ queries = [EngagementsMultiSearchQuery(name)]
2516
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
2517
+ queries
2518
+ )
2519
+ return (
2520
+ cast(EngagementsMultiSearchResult, results.results[0])
2521
+ if results and results.results
2522
+ else None
2523
+ )
2524
+
2525
+ async def search_multiple_engagements_async(
2526
+ self,
2527
+ names: list[str | None] | None = None,
2528
+ filter: list[str] | None = None,
2529
+ sort: list[str] | None = None,
2530
+ limit: int | None = 10,
2531
+ ) -> list[EngagementsMultiSearchResult] | None:
2532
+ """Search for multiple engagements asynchronously."""
2533
+ if not names:
2534
+ return None
2535
+ queries = [
2536
+ EngagementsMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2537
+ for name in names
2538
+ ]
2539
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
2540
+ queries
2541
+ )
2542
+ return (
2543
+ cast(list[EngagementsMultiSearchResult], results.results)
2544
+ if results
2545
+ else None
2546
+ )
2547
+
2548
+ # -------------------------------------------------------------------------
2549
+ # Meilisearch — formations
2550
+ # -------------------------------------------------------------------------
2551
+
2552
+ def search_formations(
2553
+ self,
2554
+ name: str | None = None,
2555
+ filter: list[str] | None = None,
2556
+ sort: list[str] | None = None,
2557
+ limit: int | None = 10,
2558
+ cached_session: Client | None = None,
2559
+ ) -> FormationsMultiSearchResult | None:
2560
+ results = self.search_multiple_formations(
2561
+ [name] if name is not None else None,
2562
+ filter=filter,
2563
+ sort=sort,
2564
+ limit=limit,
2565
+ cached_session=cached_session,
2566
+ )
2567
+ return results[0] if results else None
2568
+
2569
+ def search_multiple_formations(
2570
+ self,
2571
+ names: list[str | None] | None = None,
2572
+ filter: list[str] | None = None,
2573
+ sort: list[str] | None = None,
2574
+ limit: int | None = 10,
2575
+ cached_session: Client | None = None,
2576
+ ) -> list[FormationsMultiSearchResult] | None:
2577
+ if not names:
2578
+ return None
2579
+
2580
+ queries = [
2581
+ FormationsMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2582
+ for name in names
2583
+ ]
2584
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
2585
+ queries, cached_session
2586
+ )
2587
+
2588
+ return (
2589
+ cast(list[FormationsMultiSearchResult], results.results)
2590
+ if results
2591
+ else None
2592
+ )
2593
+
2594
+ async def search_formations_async(
2595
+ self, name: str | None = None
2596
+ ) -> FormationsMultiSearchResult | None:
2597
+ """Search for formations asynchronously."""
2598
+ if not name:
2599
+ return None
2600
+ queries = [FormationsMultiSearchQuery(name)]
2601
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
2602
+ queries
2603
+ )
2604
+ return (
2605
+ cast(FormationsMultiSearchResult, results.results[0])
2606
+ if results and results.results
2607
+ else None
2608
+ )
2609
+
2610
+ async def search_multiple_formations_async(
2611
+ self,
2612
+ names: list[str | None] | None = None,
2613
+ filter: list[str] | None = None,
2614
+ sort: list[str] | None = None,
2615
+ limit: int | None = 10,
2616
+ ) -> list[FormationsMultiSearchResult] | None:
2617
+ """Search for multiple formations asynchronously."""
2618
+ if not names:
2619
+ return None
2620
+ queries = [
2621
+ FormationsMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2622
+ for name in names
2623
+ ]
2624
+ results = await self.meilisearch_ffbb_client.recursive_smart_multi_search_async(
2625
+ queries
2626
+ )
2627
+ return (
2628
+ cast(list[FormationsMultiSearchResult], results.results)
2629
+ if results
2630
+ else None
2631
+ )
2632
+
2633
+ # -------------------------------------------------------------------------
2634
+ # Meilisearch — content indexes
2635
+ # -------------------------------------------------------------------------
2636
+
2637
+ def search_news(
2638
+ self,
2639
+ name: str | None = None,
2640
+ filter: list[str] | None = None,
2641
+ sort: list[str] | None = None,
2642
+ limit: int | None = 10,
2643
+ cached_session: Client | None = None,
2644
+ ) -> NewsMultiSearchResult | None:
2645
+ results = self.search_multiple_news(
2646
+ [name] if name is not None else None,
2647
+ filter=filter,
2648
+ sort=sort,
2649
+ limit=limit,
2650
+ cached_session=cached_session,
2651
+ )
2652
+ return results[0] if results else None
2653
+
2654
+ def search_multiple_news(
2655
+ self,
2656
+ names: list[str | None] | None = None,
2657
+ filter: list[str] | None = None,
2658
+ sort: list[str] | None = None,
2659
+ limit: int | None = 10,
2660
+ cached_session: Client | None = None,
2661
+ ) -> list[NewsMultiSearchResult] | None:
2662
+ if not names:
2663
+ return None
2664
+
2665
+ queries = [
2666
+ NewsMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2667
+ for name in names
2668
+ ]
2669
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
2670
+ queries, cached_session
2671
+ )
2672
+ return cast(list[NewsMultiSearchResult], results.results) if results else None
2673
+
2674
+ def search_youtube_videos(
2675
+ self,
2676
+ name: str | None = None,
2677
+ filter: list[str] | None = None,
2678
+ sort: list[str] | None = None,
2679
+ limit: int | None = 10,
2680
+ cached_session: Client | None = None,
2681
+ ) -> YoutubeVideosMultiSearchResult | None:
2682
+ results = self.search_multiple_youtube_videos(
2683
+ [name] if name is not None else None,
2684
+ filter=filter,
2685
+ sort=sort,
2686
+ limit=limit,
2687
+ cached_session=cached_session,
2688
+ )
2689
+ return results[0] if results else None
2690
+
2691
+ def search_multiple_youtube_videos(
2692
+ self,
2693
+ names: list[str | None] | None = None,
2694
+ filter: list[str] | None = None,
2695
+ sort: list[str] | None = None,
2696
+ limit: int | None = 10,
2697
+ cached_session: Client | None = None,
2698
+ ) -> list[YoutubeVideosMultiSearchResult] | None:
2699
+ if not names:
2700
+ return None
2701
+
2702
+ queries = [
2703
+ YoutubeVideosMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2704
+ for name in names
2705
+ ]
2706
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
2707
+ queries, cached_session
2708
+ )
2709
+ return (
2710
+ cast(list[YoutubeVideosMultiSearchResult], results.results)
2711
+ if results
2712
+ else None
2713
+ )
2714
+
2715
+ def search_rss(
2716
+ self,
2717
+ name: str | None = None,
2718
+ filter: list[str] | None = None,
2719
+ sort: list[str] | None = None,
2720
+ limit: int | None = 10,
2721
+ cached_session: Client | None = None,
2722
+ ) -> RssMultiSearchResult | None:
2723
+ results = self.search_multiple_rss(
2724
+ [name] if name is not None else None,
2725
+ filter=filter,
2726
+ sort=sort,
2727
+ limit=limit,
2728
+ cached_session=cached_session,
2729
+ )
2730
+ return results[0] if results else None
2731
+
2732
+ def search_multiple_rss(
2733
+ self,
2734
+ names: list[str | None] | None = None,
2735
+ filter: list[str] | None = None,
2736
+ sort: list[str] | None = None,
2737
+ limit: int | None = 10,
2738
+ cached_session: Client | None = None,
2739
+ ) -> list[RssMultiSearchResult] | None:
2740
+ if not names:
2741
+ return None
2742
+
2743
+ queries = [
2744
+ RssMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2745
+ for name in names
2746
+ ]
2747
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
2748
+ queries, cached_session
2749
+ )
2750
+ return cast(list[RssMultiSearchResult], results.results) if results else None
2751
+
2752
+ def search_galeries(
2753
+ self,
2754
+ name: str | None = None,
2755
+ filter: list[str] | None = None,
2756
+ sort: list[str] | None = None,
2757
+ limit: int | None = 10,
2758
+ cached_session: Client | None = None,
2759
+ ) -> GaleriesMultiSearchResult | None:
2760
+ results = self.search_multiple_galeries(
2761
+ [name] if name is not None else None,
2762
+ filter=filter,
2763
+ sort=sort,
2764
+ limit=limit,
2765
+ cached_session=cached_session,
2766
+ )
2767
+ return results[0] if results else None
2768
+
2769
+ def search_multiple_galeries(
2770
+ self,
2771
+ names: list[str | None] | None = None,
2772
+ filter: list[str] | None = None,
2773
+ sort: list[str] | None = None,
2774
+ limit: int | None = 10,
2775
+ cached_session: Client | None = None,
2776
+ ) -> list[GaleriesMultiSearchResult] | None:
2777
+ if not names:
2778
+ return None
2779
+
2780
+ queries = [
2781
+ GaleriesMultiSearchQuery(name, limit=limit, filter=filter, sort=sort)
2782
+ for name in names
2783
+ ]
2784
+ results = self.meilisearch_ffbb_client.recursive_smart_multi_search(
2785
+ queries, cached_session
2786
+ )
2787
+ return (
2788
+ cast(list[GaleriesMultiSearchResult], results.results) if results else None
2789
+ )