@@ -1965,3 +1965,61 @@ def test_string_export_fields_still_works(self, mock_fetch_api) -> None:
19651965 fetch_data ("fake_token" , "field1,field2" )
19661966 request_data = mock_fetch_api .call_args [0 ][2 ]
19671967 assert request_data .get ("fields" ) == "field1,field2"
1968+
1969+
1970+ class TestFetchDataRegression :
1971+ """Ensure backward compatibility and correct filter logic construction."""
1972+
1973+ @patch ("hbnmigration.from_redcap.from_redcap.fetch_api_data" )
1974+ @patch ("hbnmigration.from_redcap.from_redcap.redcap_variables" )
1975+ def test_fetch_data_does_not_inject_mandatory_and_filters (
1976+ self , mock_vars : MagicMock , mock_fetch_api : MagicMock
1977+ ) -> None :
1978+ """
1979+ Verify that fetch_data does not automatically inject AND conditions.
1980+
1981+ v1.12.1 introduced a regression where requesting multiple fields
1982+ appended 'AND [field] != ""' for every field, causing REDCap to
1983+ return zero records (and thus NoData) if any single field was empty.
1984+
1985+ Parameters
1986+ ----------
1987+ mock_vars
1988+ Mocked REDCap configuration variables.
1989+ mock_fetch_api
1990+ Mocked API execution function.
1991+
1992+ """
1993+ # 1. Setup Mock: REDCap headers
1994+ mock_vars .headers = {"Content-Type" : "application/x-www-form-urlencoded" }
1995+
1996+ # 2. Define expected behavior:
1997+ # Even if we ask for field1 and field2, if a record exists with only field1
1998+ # populated, we expect to get that row back.
1999+ mock_data = pd .DataFrame ([{"record_id" : "1" , "field1" : "val1" , "field2" : "" }])
2000+ mock_fetch_api .return_value = mock_data
2001+
2002+ # 3. Execution: Request multiple fields
2003+ # In the BROKEN version, this will inject:
2004+ # filterLogic: ([field1] != '') AND ([field2] != '')
2005+ # causing the REAL REDCap API to return nothing, though our mock
2006+ # specifically tests the logic construction.
2007+
2008+ try :
2009+ result = fetch_data (
2010+ "fake_token" , {"fields" : "field1,field2" }, all_or_any = "all"
2011+ )
2012+ except Exception as e :
2013+ pytest .fail (f"fetch_data raised an exception: { e } " )
2014+
2015+ # 4. Assertions on the constructed logic
2016+ # We need to inspect what was actually sent to the API mock
2017+ sent_payload = mock_fetch_api .call_args [0 ][2 ]
2018+ filter_logic = sent_payload .get ("filterLogic" , "" )
2019+
2020+ assert "AND" not in filter_logic , (
2021+ "Regression Found: fetch_data is forcing 'AND' filters on all fields: "
2022+ f"{ filter_logic } . This causes records with partial data to be excluded "
2023+ "from the fetch."
2024+ )
2025+ assert not result .empty
0 commit comments