BuildScopeForRecord
Overview
Step 1 of the programmatic access pipeline. Given a Salesforce record ID, resolves which records are "in scope" for communications using the BuildCommunicationScopeForRecord strategy. The strategy determines — for any given context record (e.g. an Opportunity) — which related records should be searched for phone numbers and activity links (e.g. the Opportunity itself plus its related Account and Contacts).
The result is a RecordRefSets — an immutable collection of record references grouped by SObject type. Use getScope() to inspect it, excluding(Id) to narrow it, then call one of the conversion methods to continue:
toGatherPhoneNumbersRequest()→ feeds step 2 of the call path (GatherPhoneNumbersInScope)toGetEmailMessageIdsRequest()→ feeds step 3 of the email path (GetEmailMessageIds) — emails are record-scoped, not phone-number-scoped
The same scope response can feed both paths independently.
Request
Construct the Request directly and pass it to the handler:
BuildScopeForRecord.IHandler handler =
BuildScopeForRecord.construct(SharingRule.WithSharing);
BuildScopeForRecord.Response scopeResult =
handler.execute(new BuildScopeForRecord.Request(recordId));
| Parameter | Type | Required | Description |
|---|---|---|---|
recordId |
Id |
Yes | The Salesforce record to resolve scope for. Must not be null. |
The SharingRule passed to construct() is forwarded to the BuildCommunicationScopeForRecord strategy — use WithSharing to respect the running user's CRM record visibility when the strategy queries related records.
Response
| Member | Type | Description |
|---|---|---|
getScope() |
RecordRefSets |
In-scope records, grouped by SObject type. |
excluding(Id recordId) |
Response |
Removes a record from scope. Narrowing only — callers cannot add records not produced by the strategy. Fluent. |
toGatherPhoneNumbersRequest() |
GatherPhoneNumbersInScope.Request |
Converts to a request for step 2 of the call path. |
toGetEmailMessageIdsRequest() |
GetEmailMessageIds.Request |
Converts to a request for step 3 of the email path. |
Both conversion methods can be called on the same Response independently — the scope is not consumed.
Testing
MockBuildScopeForRecord is a package-provided test double. Call use() to install it for the current test transaction, then returning() to configure the scope it will produce. The real strategy and scope-building logic are bypassed entirely.
@isTest
static void myTest() {
MockBuildScopeForRecord.use()
.returning(RecordRefSets.empty());
// Your code that calls BuildScopeForRecord receives the configured scope.
MyService.run(someRecordId);
}
The mock ignores the input record ID and always returns the configured RecordRefSets. Use RecordRefSets.empty() when scope contents do not affect the assertion being made, or supply a populated scope to drive downstream behaviour.
| Method | Description |
|---|---|
use() |
Installs this instance as the handler for the current test transaction. Returns the instance for chaining. |
returning(RecordRefSets scope) |
Configures the scope returned by execute(). Passing null is equivalent to RecordRefSets.empty(). |