@@ -166,153 +166,182 @@ async def _create_order(
166166 )
167167
168168 def get_product (self : Self , request : Request ) -> Product :
169- return self .product .with_links (
170- links = [
171- Link (
172- href = str (
173- request .url_for (
174- f"{ self .root_router .name } :{ self .product .id } :get-product" ,
175- ),
169+ links = [
170+ Link (
171+ href = str (
172+ request .url_for (
173+ f"{ self .root_router .name } :{ self .product .id } :get-product" ,
176174 ),
177- rel = "self" ,
178- type = TYPE_JSON ,
179175 ),
180- Link (
181- href = str (
182- request .url_for (
183- f"{ self .root_router .name } :{ self .product .id } :get-constraints" ,
184- ),
176+ rel = "self" ,
177+ type = TYPE_JSON ,
178+ ),
179+ Link (
180+ href = str (
181+ request .url_for (
182+ f"{ self .root_router .name } :{ self .product .id } :get-constraints" ,
185183 ),
186- rel = "constraints" ,
187- type = TYPE_JSON ,
188184 ),
189- Link (
190- href = str (
191- request .url_for (
192- f"{ self .root_router .name } :{ self .product .id } :get-order-parameters" ,
193- ),
185+ rel = "constraints" ,
186+ type = TYPE_JSON ,
187+ ),
188+ Link (
189+ href = str (
190+ request .url_for (
191+ f"{ self .root_router .name } :{ self .product .id } :get-order-parameters" ,
194192 ),
195- rel = "order-parameters" ,
196- type = TYPE_JSON ,
197193 ),
198- Link (
199- href = str (
200- request .url_for (
201- f"{ self .root_router .name } :{ self .product .id } :search-opportunities" ,
202- ),
194+ rel = "order-parameters" ,
195+ type = TYPE_JSON ,
196+ ),
197+ Link (
198+ href = str (
199+ request .url_for (
200+ f"{ self .root_router .name } :{ self .product .id } :create-order" ,
203201 ),
204- rel = "opportunities" ,
205- type = TYPE_JSON ,
206202 ),
203+ rel = "create-order" ,
204+ type = TYPE_JSON ,
205+ ),
206+ ]
207+
208+ if (
209+ self .product .supports_opportunity_search
210+ or self .root_router .supports_async_opportunity_search
211+ ):
212+ links .append (
207213 Link (
208214 href = str (
209215 request .url_for (
210- f"{ self .root_router .name } :{ self .product .id } :create-order " ,
216+ f"{ self .root_router .name } :{ self .product .id } :search-opportunities " ,
211217 ),
212218 ),
213- rel = "create-order " ,
219+ rel = "opportunities " ,
214220 type = TYPE_JSON ,
215221 ),
216- ],
217- )
222+ )
218223
219- async def search_opportunities ( # noqa: C901
224+ return self .product .with_links (links = links )
225+
226+ async def search_opportunities (
220227 self : Self ,
221228 search : OpportunityRequest ,
222229 request : Request ,
223230 response : Response ,
224231 next : Annotated [str | None , Body ()] = None ,
225232 limit : Annotated [int , Body ()] = 10 ,
226- prefer : str | None = Depends (get_preference ),
233+ prefer : Prefer | None = Depends (get_preference ),
227234 ) -> OpportunityCollection | Response :
228235 """
229236 Explore the opportunities available for a particular set of constraints
230237 """
231- # synchronous opportunities search
232- if (
233- not self .root_router .supports_async_opportunity_search
234- or prefer is Prefer .wait
238+ # sync
239+ if not self .root_router .supports_async_opportunity_search or (
240+ prefer is Prefer .wait and self .product .supports_opportunity_search
235241 ):
236- links : list [Link ] = []
237- match await self .product ._search_opportunities (
238- self ,
242+ return await self .search_opportunities_sync (
239243 search ,
244+ request ,
245+ response ,
246+ prefer ,
240247 next ,
241248 limit ,
242- request ,
243- ):
244- case Success ((features , Some (pagination_token ))):
245- links .append (self .order_link (request ))
246- body = {
247- "search" : search .model_dump (mode = "json" ),
248- "next" : pagination_token ,
249- "limit" : limit ,
250- }
251- links .append (self .pagination_link (request , body ))
252- case Success ((features , Nothing )): # noqa: F841
253- links .append (self .order_link (request ))
254- case Failure (e ) if isinstance (e , ConstraintsException ):
255- raise e
256- case Failure (e ):
257- logger .error (
258- "An error occurred while searching opportunities: %s" ,
259- traceback .format_exception (e ),
260- )
261- raise HTTPException (
262- status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
263- detail = "Error searching opportunities" ,
264- )
265- case x :
266- raise AssertionError (f"Expected code to be unreachable { x } " )
267-
268- if (
269- prefer is Prefer .wait
270- and self .root_router .supports_async_opportunity_search
271- ):
272- response .headers ["Preference-Applied" ] = "wait"
273-
274- return OpportunityCollection (features = features , links = links )
249+ )
275250
276- # asynchronous opportunities search
251+ # async
277252 if (
278253 prefer is None
279254 or prefer is Prefer .respond_async
280255 or (prefer is Prefer .wait and not self .product .supports_opportunity_search )
281256 ):
282- match await self .product ._search_opportunities_async (self , search , request ):
283- case Success (search_record ):
284- self .root_router .add_opportunity_search_record_self_link (
285- search_record , request
286- )
287- headers = {}
288- headers ["Location" ] = str (
289- self .root_router .generate_opportunity_search_record_href (
290- request , search_record .id
291- )
292- )
293- if prefer is not None :
294- headers ["Preference-Applied" ] = "respond-async"
295- return JSONResponse (
296- status_code = 201 ,
297- content = search_record .model_dump (mode = "json" ),
298- headers = headers ,
299- )
300- case Failure (e ) if isinstance (e , ConstraintsException ):
301- raise e
302- case Failure (e ):
303- logger .error (
304- "An error occurred while initiating an asynchronous opportunity search: %s" ,
305- traceback .format_exception (e ),
306- )
307- raise HTTPException (
308- status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
309- detail = "Error initiating an asynchronous opportunity search" ,
310- )
311- case y :
312- raise AssertionError (f"Expected code to be unreachable: { y } " )
257+ return await self .search_opportunities_async (search , request , prefer )
313258
314259 raise AssertionError ("Expected code to be unreachable" )
315260
261+ async def search_opportunities_sync (
262+ self : Self ,
263+ search : OpportunityRequest ,
264+ request : Request ,
265+ response : Response ,
266+ prefer : Prefer | None ,
267+ next : Annotated [str | None , Body ()] = None ,
268+ limit : Annotated [int , Body ()] = 10 ,
269+ ) -> OpportunityCollection :
270+ links : list [Link ] = []
271+ match await self .product ._search_opportunities (
272+ self ,
273+ search ,
274+ next ,
275+ limit ,
276+ request ,
277+ ):
278+ case Success ((features , Some (pagination_token ))):
279+ links .append (self .order_link (request ))
280+ body = {
281+ "search" : search .model_dump (mode = "json" ),
282+ "next" : pagination_token ,
283+ "limit" : limit ,
284+ }
285+ links .append (self .pagination_link (request , body ))
286+ case Success ((features , Nothing )): # noqa: F841
287+ links .append (self .order_link (request ))
288+ case Failure (e ) if isinstance (e , ConstraintsException ):
289+ raise e
290+ case Failure (e ):
291+ logger .error (
292+ "An error occurred while searching opportunities: %s" ,
293+ traceback .format_exception (e ),
294+ )
295+ raise HTTPException (
296+ status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
297+ detail = "Error searching opportunities" ,
298+ )
299+ case x :
300+ raise AssertionError (f"Expected code to be unreachable { x } " )
301+
302+ if prefer is Prefer .wait and self .root_router .supports_async_opportunity_search :
303+ response .headers ["Preference-Applied" ] = "wait"
304+
305+ return OpportunityCollection (features = features , links = links )
306+
307+ async def search_opportunities_async (
308+ self : Self ,
309+ search : OpportunityRequest ,
310+ request : Request ,
311+ prefer : Prefer | None ,
312+ ) -> JSONResponse :
313+ match await self .product ._search_opportunities_async (self , search , request ):
314+ case Success (search_record ):
315+ self .root_router .add_opportunity_search_record_self_link (
316+ search_record , request
317+ )
318+ headers = {}
319+ headers ["Location" ] = str (
320+ self .root_router .generate_opportunity_search_record_href (
321+ request , search_record .id
322+ )
323+ )
324+ if prefer is not None :
325+ headers ["Preference-Applied" ] = "respond-async"
326+ return JSONResponse (
327+ status_code = 201 ,
328+ content = search_record .model_dump (mode = "json" ),
329+ headers = headers ,
330+ )
331+ case Failure (e ) if isinstance (e , ConstraintsException ):
332+ raise e
333+ case Failure (e ):
334+ logger .error (
335+ "An error occurred while initiating an asynchronous opportunity search: %s" ,
336+ traceback .format_exception (e ),
337+ )
338+ raise HTTPException (
339+ status_code = status .HTTP_500_INTERNAL_SERVER_ERROR ,
340+ detail = "Error initiating an asynchronous opportunity search" ,
341+ )
342+ case x :
343+ raise AssertionError (f"Expected code to be unreachable: { x } " )
344+
316345 def get_product_constraints (self : Self ) -> JsonSchemaModel :
317346 """
318347 Return supported constraints of a specific product
0 commit comments