@@ -231,6 +231,163 @@ def test_get_concept_relationships_with_options(
231231 assert "vocabulary_ids=SNOMED" in url_str
232232 assert "include_invalid=true" in url_str
233233
234+ @respx .mock
235+ def test_get_concept_relationships_with_all_options (
236+ self , sync_client : OMOPHub , base_url : str
237+ ) -> None :
238+ """Test relationships with all filter options including standard_only and include_reverse."""
239+ route = respx .get (f"{ base_url } /concepts/201826/relationships" ).mock (
240+ return_value = Response (
241+ 200 , json = {"success" : True , "data" : {"relationships" : []}}
242+ )
243+ )
244+
245+ sync_client .concepts .relationships (
246+ 201826 ,
247+ relationship_ids = ["Is a" , "Maps to" ],
248+ vocabulary_ids = ["SNOMED" , "ICD10CM" ],
249+ domain_ids = ["Condition" , "Drug" ],
250+ include_invalid = True ,
251+ standard_only = True ,
252+ include_reverse = True ,
253+ vocab_release = "2025.1" ,
254+ )
255+
256+ url_str = str (route .calls [0 ].request .url )
257+ assert "relationship_ids=Is+a%2CMaps+to" in url_str
258+ assert "vocabulary_ids=SNOMED%2CICD10CM" in url_str
259+ assert "domain_ids=Condition%2CDrug" in url_str
260+ assert "include_invalid=true" in url_str
261+ assert "standard_only=true" in url_str
262+ assert "include_reverse=true" in url_str
263+ assert "vocab_release=2025.1" in url_str
264+
265+ @respx .mock
266+ def test_recommended_concepts (self , sync_client : OMOPHub , base_url : str ) -> None :
267+ """Test getting recommended concepts."""
268+ recommended_response = {
269+ "success" : True ,
270+ "data" : {
271+ "recommendations" : [
272+ {"concept_id" : 201820 , "score" : 0.95 },
273+ ],
274+ "meta" : {"total" : 1 },
275+ },
276+ }
277+ respx .post (f"{ base_url } /concepts/recommended" ).mock (
278+ return_value = Response (200 , json = recommended_response )
279+ )
280+
281+ result = sync_client .concepts .recommended ([201826 ])
282+ assert "recommendations" in result
283+
284+ @respx .mock
285+ def test_recommended_concepts_with_options (
286+ self , sync_client : OMOPHub , base_url : str
287+ ) -> None :
288+ """Test recommended concepts with all options."""
289+ route = respx .post (f"{ base_url } /concepts/recommended" ).mock (
290+ return_value = Response (
291+ 200 , json = {"success" : True , "data" : {"recommendations" : []}}
292+ )
293+ )
294+
295+ sync_client .concepts .recommended (
296+ [201826 , 1112807 ],
297+ relationship_types = ["Is a" , "Maps to" ],
298+ vocabulary_ids = ["SNOMED" ],
299+ domain_ids = ["Condition" ],
300+ standard_only = False ,
301+ include_invalid = True ,
302+ page = 2 ,
303+ page_size = 50 ,
304+ )
305+
306+ # Verify POST body was sent
307+ assert route .calls [0 ].request .content
308+
309+ @respx .mock
310+ def test_get_concept_with_hierarchy (
311+ self , sync_client : OMOPHub , mock_api_response : dict , base_url : str
312+ ) -> None :
313+ """Test getting a concept with hierarchy option."""
314+ route = respx .get (f"{ base_url } /concepts/201826" ).mock (
315+ return_value = Response (200 , json = mock_api_response )
316+ )
317+
318+ sync_client .concepts .get (201826 , include_hierarchy = True )
319+
320+ url_str = str (route .calls [0 ].request .url )
321+ assert "include_hierarchy=true" in url_str
322+
323+ @respx .mock
324+ def test_get_concept_with_vocab_release (
325+ self , sync_client : OMOPHub , mock_api_response : dict , base_url : str
326+ ) -> None :
327+ """Test getting a concept with vocab_release option."""
328+ route = respx .get (f"{ base_url } /concepts/201826" ).mock (
329+ return_value = Response (200 , json = mock_api_response )
330+ )
331+
332+ sync_client .concepts .get (201826 , vocab_release = "2025.1" )
333+
334+ url_str = str (route .calls [0 ].request .url )
335+ assert "vocab_release=2025.1" in url_str
336+
337+ @respx .mock
338+ def test_get_by_code_with_all_options (
339+ self , sync_client : OMOPHub , mock_api_response : dict , base_url : str
340+ ) -> None :
341+ """Test getting concept by code with all options."""
342+ route = respx .get (f"{ base_url } /concepts/by-code/SNOMED/44054006" ).mock (
343+ return_value = Response (200 , json = mock_api_response )
344+ )
345+
346+ sync_client .concepts .get_by_code (
347+ "SNOMED" ,
348+ "44054006" ,
349+ include_relationships = True ,
350+ include_synonyms = True ,
351+ include_hierarchy = True ,
352+ vocab_release = "2025.1" ,
353+ )
354+
355+ url_str = str (route .calls [0 ].request .url )
356+ assert "include_relationships=true" in url_str
357+ assert "include_synonyms=true" in url_str
358+ assert "include_hierarchy=true" in url_str
359+ assert "vocab_release=2025.1" in url_str
360+
361+ @respx .mock
362+ def test_suggest_concepts_with_vocab_release (
363+ self , sync_client : OMOPHub , base_url : str
364+ ) -> None :
365+ """Test suggest with vocab_release option."""
366+ route = respx .get (f"{ base_url } /concepts/suggest" ).mock (
367+ return_value = Response (200 , json = {"success" : True , "data" : []})
368+ )
369+
370+ sync_client .concepts .suggest ("diabetes" , vocab_release = "2025.1" )
371+
372+ url_str = str (route .calls [0 ].request .url )
373+ assert "vocab_release=2025.1" in url_str
374+
375+ @respx .mock
376+ def test_related_concepts_with_vocab_release (
377+ self , sync_client : OMOPHub , base_url : str
378+ ) -> None :
379+ """Test related concepts with vocab_release option."""
380+ route = respx .get (f"{ base_url } /concepts/201826/related" ).mock (
381+ return_value = Response (
382+ 200 , json = {"success" : True , "data" : {"related_concepts" : []}}
383+ )
384+ )
385+
386+ sync_client .concepts .related (201826 , vocab_release = "2025.1" )
387+
388+ url_str = str (route .calls [0 ].request .url )
389+ assert "vocab_release=2025.1" in url_str
390+
234391
235392class TestAsyncConceptsResource :
236393 """Tests for the asynchronous concepts resource."""
@@ -440,3 +597,169 @@ async def test_async_get_relationships_with_options(
440597 assert "relationship_ids=Maps+to" in url_str
441598 assert "vocabulary_ids=ICD10CM" in url_str
442599 assert "include_invalid=true" in url_str
600+
601+ @pytest .mark .asyncio
602+ @respx .mock
603+ async def test_async_get_relationships_with_all_options (
604+ self , async_client : omophub .AsyncOMOPHub , base_url : str
605+ ) -> None :
606+ """Test async relationships with all options."""
607+ route = respx .get (f"{ base_url } /concepts/201826/relationships" ).mock (
608+ return_value = Response (
609+ 200 , json = {"success" : True , "data" : {"relationships" : []}}
610+ )
611+ )
612+
613+ await async_client .concepts .relationships (
614+ 201826 ,
615+ relationship_ids = ["Is a" ],
616+ vocabulary_ids = ["SNOMED" ],
617+ domain_ids = ["Condition" ],
618+ include_invalid = True ,
619+ standard_only = True ,
620+ include_reverse = True ,
621+ vocab_release = "2025.1" ,
622+ )
623+
624+ url_str = str (route .calls [0 ].request .url )
625+ assert "domain_ids=Condition" in url_str
626+ assert "standard_only=true" in url_str
627+ assert "include_reverse=true" in url_str
628+ assert "vocab_release=2025.1" in url_str
629+
630+ @pytest .mark .asyncio
631+ @respx .mock
632+ async def test_async_recommended_concepts (
633+ self , async_client : omophub .AsyncOMOPHub , base_url : str
634+ ) -> None :
635+ """Test async getting recommended concepts."""
636+ recommended_response = {
637+ "success" : True ,
638+ "data" : {
639+ "recommendations" : [{"concept_id" : 201820 }],
640+ },
641+ }
642+ respx .post (f"{ base_url } /concepts/recommended" ).mock (
643+ return_value = Response (200 , json = recommended_response )
644+ )
645+
646+ result = await async_client .concepts .recommended ([201826 ])
647+ assert "recommendations" in result
648+
649+ @pytest .mark .asyncio
650+ @respx .mock
651+ async def test_async_recommended_concepts_with_options (
652+ self , async_client : omophub .AsyncOMOPHub , base_url : str
653+ ) -> None :
654+ """Test async recommended with all options."""
655+ route = respx .post (f"{ base_url } /concepts/recommended" ).mock (
656+ return_value = Response (
657+ 200 , json = {"success" : True , "data" : {"recommendations" : []}}
658+ )
659+ )
660+
661+ await async_client .concepts .recommended (
662+ [201826 , 1112807 ],
663+ relationship_types = ["Is a" ],
664+ vocabulary_ids = ["SNOMED" ],
665+ domain_ids = ["Condition" ],
666+ standard_only = False ,
667+ include_invalid = True ,
668+ page = 1 ,
669+ page_size = 100 ,
670+ )
671+
672+ assert route .calls [0 ].request .content
673+
674+ @pytest .mark .asyncio
675+ @respx .mock
676+ async def test_async_get_concept_with_hierarchy (
677+ self , async_client : omophub .AsyncOMOPHub , base_url : str
678+ ) -> None :
679+ """Test async get concept with hierarchy option."""
680+ route = respx .get (f"{ base_url } /concepts/201826" ).mock (
681+ return_value = Response (
682+ 200 , json = {"success" : True , "data" : {"concept_id" : 201826 }}
683+ )
684+ )
685+
686+ await async_client .concepts .get (201826 , include_hierarchy = True )
687+
688+ url_str = str (route .calls [0 ].request .url )
689+ assert "include_hierarchy=true" in url_str
690+
691+ @pytest .mark .asyncio
692+ @respx .mock
693+ async def test_async_get_concept_with_vocab_release (
694+ self , async_client : omophub .AsyncOMOPHub , base_url : str
695+ ) -> None :
696+ """Test async get concept with vocab_release option."""
697+ route = respx .get (f"{ base_url } /concepts/201826" ).mock (
698+ return_value = Response (
699+ 200 , json = {"success" : True , "data" : {"concept_id" : 201826 }}
700+ )
701+ )
702+
703+ await async_client .concepts .get (201826 , vocab_release = "2025.1" )
704+
705+ url_str = str (route .calls [0 ].request .url )
706+ assert "vocab_release=2025.1" in url_str
707+
708+ @pytest .mark .asyncio
709+ @respx .mock
710+ async def test_async_get_by_code_with_all_options (
711+ self , async_client : omophub .AsyncOMOPHub , base_url : str
712+ ) -> None :
713+ """Test async get by code with all options."""
714+ route = respx .get (f"{ base_url } /concepts/by-code/SNOMED/44054006" ).mock (
715+ return_value = Response (
716+ 200 , json = {"success" : True , "data" : {"concept_id" : 201826 }}
717+ )
718+ )
719+
720+ await async_client .concepts .get_by_code (
721+ "SNOMED" ,
722+ "44054006" ,
723+ include_relationships = True ,
724+ include_synonyms = True ,
725+ include_hierarchy = True ,
726+ vocab_release = "2025.1" ,
727+ )
728+
729+ url_str = str (route .calls [0 ].request .url )
730+ assert "include_relationships=true" in url_str
731+ assert "include_synonyms=true" in url_str
732+ assert "include_hierarchy=true" in url_str
733+ assert "vocab_release=2025.1" in url_str
734+
735+ @pytest .mark .asyncio
736+ @respx .mock
737+ async def test_async_suggest_with_vocab_release (
738+ self , async_client : omophub .AsyncOMOPHub , base_url : str
739+ ) -> None :
740+ """Test async suggest with vocab_release option."""
741+ route = respx .get (f"{ base_url } /concepts/suggest" ).mock (
742+ return_value = Response (200 , json = {"success" : True , "data" : []})
743+ )
744+
745+ await async_client .concepts .suggest ("diabetes" , vocab_release = "2025.1" )
746+
747+ url_str = str (route .calls [0 ].request .url )
748+ assert "vocab_release=2025.1" in url_str
749+
750+ @pytest .mark .asyncio
751+ @respx .mock
752+ async def test_async_related_with_vocab_release (
753+ self , async_client : omophub .AsyncOMOPHub , base_url : str
754+ ) -> None :
755+ """Test async related with vocab_release option."""
756+ route = respx .get (f"{ base_url } /concepts/201826/related" ).mock (
757+ return_value = Response (
758+ 200 , json = {"success" : True , "data" : {"related_concepts" : []}}
759+ )
760+ )
761+
762+ await async_client .concepts .related (201826 , vocab_release = "2025.1" )
763+
764+ url_str = str (route .calls [0 ].request .url )
765+ assert "vocab_release=2025.1" in url_str
0 commit comments