Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ If the record collection is null, empty, or the field value is null, the respons
- Works with **any SObject**
- Field selection via **dynamic Field API Name**
- Null-safe for records and field values
- Bulk-safe: each request is processed independently — one invalid field name or bad request does not fail others
- Per-request error reporting via the `errorMessage` output variable
- No DML or SOQL
- Uses `with sharing` to respect org security

Expand All @@ -36,8 +38,10 @@ If the record collection is null, empty, or the field value is null, the respons
## Behavior Notes

- The first record is determined by the **existing collection order**
- No sorting or validation of the field API name is performed
- If the field does not exist or the value is null, the response is `null`
- If `fieldApiName` is blank, `response` is `null` and `errorMessage` is populated
- If the field does not exist on the SObject, `response` is `null` and `errorMessage` contains the exception detail
- If the field value is `null`, `response` is `null` and `errorMessage` is also `null`
- All returned values are converted to **String**
- When multiple requests are passed (bulk invocation), each is processed independently so that one failing request does not affect the others

---
21 changes: 18 additions & 3 deletions force-app/main/default/classes/CollectionGetFirstValue_Records.cls
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,22 @@ public with sharing class CollectionGetFirstValue_Records {
continue;
}

SObject firstRecord = req.records[0];
Object fieldValue = firstRecord.get(req.fieldApiName);
if (String.isBlank(req.fieldApiName)) {
resp.response = null;
resp.errorMessage = 'The fieldApiName parameter is required and cannot be blank.';
results.add(resp);
continue;
}

try {
SObject firstRecord = req.records[0];
Object fieldValue = firstRecord.get(req.fieldApiName);
resp.response = (fieldValue == null) ? null : String.valueOf(fieldValue);
} catch (SObjectException e) {
resp.response = null;
resp.errorMessage = e.getMessage();
}

resp.response = (fieldValue == null) ? null : String.valueOf(fieldValue);
results.add(resp);
}

Expand All @@ -34,5 +46,8 @@ public with sharing class CollectionGetFirstValue_Records {
public class Response {
@InvocableVariable(label='Response' description='Single text response containing the first field value')
public String response;

@InvocableVariable(label='Error Message' description='Contains error details if the field value could not be retrieved; null when successful.')
public String errorMessage;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,55 @@ public with sharing class CollectionGetFirstValue_RecordsTest {
System.assertEquals(null, responses[0].response, 'Null records should result in null response');
}

@IsTest
static void testGetFirstValue_BlankFieldApiName() {
Account a = new Account(Name = 'Test Account');

CollectionGetFirstValue_Records.Request req = new CollectionGetFirstValue_Records.Request();
req.records = new List<SObject>{ a };
req.fieldApiName = '';

List<CollectionGetFirstValue_Records.Request> requests = new List<CollectionGetFirstValue_Records.Request>{ req };

List<CollectionGetFirstValue_Records.Response> responses = CollectionGetFirstValue_Records.getFirstValue(requests);

System.assertEquals(1, responses.size());
System.assertEquals(null, responses[0].response, 'Blank fieldApiName should result in null response');
System.assertNotEquals(null, responses[0].errorMessage, 'Blank fieldApiName should populate errorMessage');
}

@IsTest
static void testGetFirstValue_InvalidFieldApiName_DoesNotBreakBatch() {
Account testAccount = new Account(Name = 'Good Account');

// Request 1: valid field
CollectionGetFirstValue_Records.Request reqGood = new CollectionGetFirstValue_Records.Request();
reqGood.records = new List<SObject>{ testAccount };
reqGood.fieldApiName = 'Name';

// Request 2: invalid field — should not cause Request 1 or 3 to fail
CollectionGetFirstValue_Records.Request reqBad = new CollectionGetFirstValue_Records.Request();
reqBad.records = new List<SObject>{ testAccount };
reqBad.fieldApiName = 'NonExistentField__xyz';

// Request 3: another valid field
CollectionGetFirstValue_Records.Request reqGood2 = new CollectionGetFirstValue_Records.Request();
reqGood2.records = new List<SObject>{ testAccount };
reqGood2.fieldApiName = 'Name';

List<CollectionGetFirstValue_Records.Request> requests = new List<CollectionGetFirstValue_Records.Request>{ reqGood, reqBad, reqGood2 };

Test.startTest();
List<CollectionGetFirstValue_Records.Response> responses = CollectionGetFirstValue_Records.getFirstValue(requests);
Test.stopTest();

System.assertEquals(3, responses.size(), 'Should return a response for each request even when one has an invalid field');
System.assertEquals('Good Account', responses[0].response, 'Valid request before the bad one should succeed');
System.assertEquals(null, responses[0].errorMessage, 'Valid request should have no error');
System.assertEquals(null, responses[1].response, 'Invalid field should result in null response');
System.assertNotEquals(null, responses[1].errorMessage, 'Invalid field should populate errorMessage');
System.assertEquals('Good Account', responses[2].response, 'Valid request after the bad one should succeed');
System.assertEquals(null, responses[2].errorMessage, 'Valid request should have no error');
}

}