Skip to main content

Basic Features

Dynamic SOSL

The SOSL.cls class provides methods for building SOSL clauses dynamically.

// SELECT Id FROM Account LIMIT 100
SOSL.of(Account.SObjectType)
.with(Account.Id, Account.Name)
.setLimit(100)
.toList();

Control FLS

AccessLevel Class

Object permissions and field-level security are controlled by the lib. Developers can change FLS settings to match business requirements.

User mode

By default, all queries are executed in AccessLevel.USER_MODE.

The object permissions, field-level security, and sharing rules of the current user are enforced.

System mode

Developers can change the mode to AccessLevel.SYSTEM_MODE by using the .systemMode() method.

The object and field-level permissions of the current user are ignored, and the record sharing rules are controlled by the sharingMode.

// SELECT Id FROM Account - skip FLS
SOSL.of(Account.SObjectType)
.with(Account.Id, Account.Name)
.systemMode()
.toList();

Control Sharings

Apex Sharing

Use the with sharing or without sharing keywords on a class to specify whether sharing rules must be enforced. Use the inherited sharing keyword on a class to run the class in the sharing mode of the class that called it.

with sharing

By default, all queries are executed with sharing, enforced by AccessLevel.USER_MODE.

AccessLevel.USER_MODE enforces object permissions and field-level security.

Developer can skip FLS by adding .systemMode() and .withSharing().

// Query executed in without sharing
SOSL.of(Account.SObjectType)
.with(Account.Id, Account.Name)
.systemMode()
.withSharing()
.toList();

without sharing

Developer can control sharing rules by adding .systemMode() (record sharing rules are controlled by the sharingMode) and .withoutSharing().

// Query executed in with sharing
SOSL.of(Account.SObjectType)
.with(Account.Id, Account.Name)
.systemMode()
.withoutSharing()
.toList();

inherited sharing

Developer can control sharing rules by adding .systemMode() (record sharing rules are controlled by the sharingMode) by default it is inherited sharing.

// Query executed in inherited sharing
SOSL.of(Account.SObjectType)
.with(Account.Id, Account.Name)
.systemMode()
.toList();

Mocking

Mocking provides a way to substitute records from a Database search with some prepared data. Data can be prepared in form of list of lists (similar to SOSL return) List<List<SObject>>, in this format you can set multiple SObject types that will be passed to SOSL class. Or you can provide fixed ids, as to out of the box SOSL in form of List<Id>.

In case of preset results SOSL won't make any SOSL's queries and simply return data set in method definition, mock will ignore all filters and relations, what is returned depends solely on data provided to the method. Mocking is working only during test execution. If fixed Ids are provided to SOSL class it will use standard Test.setFixedSearchResults method, to make sure expected results are returned.

To mock SOSL query, use .mockId(id) method to make it identifiable. If you mark more than one query with the same ID, all marked queries will return the same data.

public with sharing class ExampleController {

public static List<Account> searchAccountsByName(String accountName) {
return SOSL.find(accountName)
.inAllFields()
.returning(
SOSL.returning(Account.SObjectType)
)
.mockId('MockingExample')
.toSearchList()
.get(0);
}
}

If you want to use search and don't want to insert any records to database, you can simply set mock data with SOSL.setMock(String mockId, List<List<SObject>> data) method.

If you need to use find or it doesn't matter if records are in database, you can set fixed results by providing records ids with SOSL.setMock(String mockId, List<Id> ids) method.

Then during execution Selector will return desired data.

List of records

@IsTest
private class ExampleControllerTest {

@IsTest
static void getPartnerAccounts() {
List<Account> accounts = new List<Account>{
new Account(Name = 'MyAccount 1'),
new Account(Name = 'MyAccount 2')
};

SOSL.setMock('ExampleController.getPartnerAccounts', accounts);

// Test
List<Account> result = ExampleController.getPartnerAccounts('MyAccount');

Assert.areEqual(accounts, result);
}
}

Dynamic conditions

Build your conditions in a dynamic way.

Ignore condition

Ignore condition when logic expression evaluate to true.

// SELECT Id FROM Account WHERE BillingCity = 'Krakow'

String accountName = '';

SOSL.of(Account.SObjectType)
.whereAre(SOSL.FilterGroup
.add(SOSL.Filter.with(Account.BillingCity).equal('Krakow'))
.add(SOSL.Filter.name().contains(accountName).ignoreWhen(String.isEmpty(accountName)))
).toList();

Filter Group

Create SOSL.FilterGroup and assign conditions dynamically based on your own criteria.

public List<Account> getAccounts() {
SOSL.FilterGroup filterGroup;

if (UserInfo.getUserType() == 'PowerPartner')
filterGroup = SOSL.FilterGroup
.add(SOSL.Filter.with(Account.Name).equal('Test'));
.add(SOSL.Filter.with(Account.BillingCity).equal('Krakow'));
} else {
filterGroup = SOSL.FilterGroup
.add(SOSL.Filter.with(Account.Name).equal('Other Test'));
}

return SOSL.of(Account.SObjectType)
.whereAre(filterGroup)
.toList();
}