global with sharing class BK_FilterCollectionByField { global class FilterException extends Exception {} @InvocableMethod(label='Filter Collection By Field') global static List<Result> filterRecordsByField(List<Request> requests) { List<Result> results = new List<Result>(); for(Request request : requests) { // Validate inputs if (request.allowEmptyCollection != true && (request.inputRecords == null || request.inputRecords.isEmpty())) { throw new FilterException('Input record collection is required but empty.'); } if (request.filterValues == null || request.filterValues.isEmpty()) { throw new FilterException('Filter values are required but empty.'); } if (String.isBlank(request.fieldAPIName)) { throw new FilterException('Field to filter by is required but empty.'); } List<SObject> filteredRecords = new List<SObject>(); if (request.allowEmptyCollection == true && (request.inputRecords == null || request.inputRecords.isEmpty())) { // Return empty result if allowed filteredRecords = new List<SObject>{}; } else { // Prepare the set or list for filter values based on case sensitivity Set<String> filterValuesSet = new Set<String>(); if(request.caseSensitive == true) { filterValuesSet.addAll(request.filterValues); } else { for(String value : request.filterValues) { if(value != null) { filterValuesSet.add(value.toLowerCase()); } } } // Filter records for(SObject record : request.inputRecords) { Object fieldValueObj = record.get(request.fieldAPIName); if(fieldValueObj != null) { String fieldValue = String.valueOf(fieldValueObj); if(request.caseSensitive == true) { if(filterValuesSet.contains(fieldValue)) { filteredRecords.add(record); } } else { if(filterValuesSet.contains(fieldValue.toLowerCase())) { filteredRecords.add(record); } } } } } Result result = new Result(); result.filteredRecords = filteredRecords; results.add(result); } return results; } global class Request { @InvocableVariable(label='Input Records' description='Collection of records to filter' required=true) global List<SObject> inputRecords; @InvocableVariable(label='Filter Values' description='Collection of string values to filter by' required=true) global List<String> filterValues; @InvocableVariable(label='Field API Name' description='API name of the field to filter by' required=true) global String fieldAPIName; @InvocableVariable(label='Allow Empty Collection' description='Allow the input record collection to be empty? Default is false') global Boolean allowEmptyCollection = false; @InvocableVariable(label='Case Sensitive' description='Perform case-sensitive matching? Default is false') global Boolean caseSensitive = false; } global class Result { @InvocableVariable(label='Filtered Records' description='Collection of records that match the filter criteria') global List<SObject> filteredRecords; } } Test class: @isTest private class BK_FilterCollectionByFieldTest { @isTest static void testFilterRecordsByField() { // Create sample accounts Account acc1 = new Account(Name = 'Test Account 1', AccountNumber = '123'); Account acc2 = new Account(Name = 'Test Account 2', AccountNumber = '456'); Account acc3 = new Account(Name = 'Test Account 3', AccountNumber = '789'); insert new List<Account>{acc1, acc2, acc3}; // Prepare request BK_FilterCollectionByField.Request request = new BK_FilterCollectionByField.Request(); request.inputRecords = new List<SObject>{acc1, acc2, acc3}; request.filterValues = new List<String>{'123', '789'}; request.fieldAPIName = 'AccountNumber'; request.caseSensitive = true; // Call the method List<BK_FilterCollectionByField.Result> results = BK_FilterCollectionByField.filterRecordsByField( new List<BK_FilterCollectionByField.Request>{request} ); // Assert the results System.assertEquals(1, results.size(), 'Should return one result object'); System.assertEquals(2, results[0].filteredRecords.size(), 'Should return two filtered records'); Set<Id> expectedIds = new Set<Id>{acc1.Id, acc3.Id}; Set<Id> resultIds = new Set<Id>(); for(SObject sobj : results[0].filteredRecords) { resultIds.add(sobj.Id); } System.assertEquals(expectedIds, resultIds, 'Filtered records should match expected accounts'); } @isTest static void testFilterRecordsByField_CaseInsensitive() { // Create sample accounts with varying case in AccountNumber Account acc1 = new Account(Name = 'Test Account 1', AccountNumber = 'abc'); Account acc2 = new Account(Name = 'Test Account 2', AccountNumber = 'DEF'); Account acc3 = new Account(Name = 'Test Account 3', AccountNumber = 'GHI'); insert new List<Account>{acc1, acc2, acc3}; // Prepare request BK_FilterCollectionByField.Request request = new BK_FilterCollectionByField.Request(); request.inputRecords = new List<SObject>{acc1, acc2, acc3}; request.filterValues = new List<String>{'Abc', 'def'}; request.fieldAPIName = 'AccountNumber'; request.caseSensitive = false; // Call the method List<BK_FilterCollectionByField.Result> results = BK_FilterCollectionByField.filterRecordsByField( new List<BK_FilterCollectionByField.Request>{request} ); // Assert the results System.assertEquals(1, results.size(), 'Should return one result object'); System.assertEquals(2, results[0].filteredRecords.size(), 'Should return two filtered records'); Set<Id> expectedIds = new Set<Id>{acc1.Id, acc2.Id}; Set<Id> resultIds = new Set<Id>(); for(SObject sobj : results[0].filteredRecords) { resultIds.add(sobj.Id); } System.assertEquals(expectedIds, resultIds, 'Filtered records should match expected accounts'); } @isTest static void testFilterRecordsByField_EmptyCollectionAllowed() { // Prepare request with empty inputRecords BK_FilterCollectionByField.Request request = new BK_FilterCollectionByField.Request(); request.inputRecords = new List<SObject>(); request.filterValues = new List<String>{'123', '789'}; request.fieldAPIName = 'AccountNumber'; request.allowEmptyCollection = true; // Call the method List<BK_FilterCollectionByField.Result> results = BK_FilterCollectionByField.filterRecordsByField( new List<BK_FilterCollectionByField.Request>{request} ); // Assert the results System.assertEquals(1, results.size(), 'Should return one result object'); System.assertEquals(0, results[0].filteredRecords.size(), 'Should return zero filtered records'); } @isTest static void testFilterRecordsByField_ExceptionOnEmptyCollection() { // Prepare request with empty inputRecords BK_FilterCollectionByField.Request request = new BK_FilterCollectionByField.Request(); request.inputRecords = new List<SObject>(); request.filterValues = new List<String>{'123', '789'}; request.fieldAPIName = 'AccountNumber'; request.allowEmptyCollection = false; // Call the method and expect exception try { List<BK_FilterCollectionByField.Result> results = BK_FilterCollectionByField.filterRecordsByField( new List<BK_FilterCollectionByField.Request>{request} ); System.assert(false, 'Expected an exception due to empty inputRecords'); } catch (Exception ex) { System.assert(ex instanceof BK_FilterCollectionByField.FilterException, 'Expected a FilterException'); System.assertEquals('Input record collection is required but empty.', ex.getMessage()); } } @isTest static void testFilterRecordsByField_ExceptionOnEmptyFilterValues() { // Create sample accounts Account acc1 = new Account(Name = 'Test Account 1', AccountNumber = '123'); insert acc1; // Prepare request with empty filterValues BK_FilterCollectionByField.Request request = new BK_FilterCollectionByField.Request(); request.inputRecords = new List<SObject>{acc1}; request.filterValues = new List<String>(); request.fieldAPIName = 'AccountNumber'; // Call the method and expect exception try { List<BK_FilterCollectionByField.Result> results = BK_FilterCollectionByField.filterRecordsByField( new List<BK_FilterCollectionByField.Request>{request} ); System.assert(false, 'Expected an exception due to empty filterValues'); } catch (Exception ex) { System.assert(ex instanceof BK_FilterCollectionByField.FilterException, 'Expected a FilterException'); System.assertEquals('Filter values are required but empty.', ex.getMessage()); } } @isTest static void testFilterRecordsByField_ExceptionOnEmptyFieldAPIName() { // Create sample accounts Account acc1 = new Account(Name = 'Test Account 1', AccountNumber = '123'); insert acc1; // Prepare request with empty fieldAPIName BK_FilterCollectionByField.Request request = new BK_FilterCollectionByField.Request(); request.inputRecords = new List<SObject>{acc1}; request.filterValues = new List<String>{'123'}; request.fieldAPIName = ''; // Call the method and expect exception try { List<BK_FilterCollectionByField.Result> results = BK_FilterCollectionByField.filterRecordsByField( new List<BK_FilterCollectionByField.Request>{request} ); System.assert(false, 'Expected an exception due to empty fieldAPIName'); } catch (Exception ex) { System.assert(ex instanceof BK_FilterCollectionByField.FilterException, 'Expected a FilterException'); System.assertEquals('Field to filter by is required but empty.', ex.getMessage()); } } }