v6.7.0 - 20-January-2026
Scope
- New Feature: Database Cursor Support
- Mocking Improvements
- Filter Enhancements
SOQL
- Added
toCursor()method for Database Cursor support - Simplified mocking with automatic SObjectType-based mocking
- Enhanced
isIn()andnotIn()filters to accept SObject collections - Improved mocking documentation and examples
New Feature: Database Cursor Support
SOQL Lib now supports Database Cursors, enabling efficient processing of large datasets with reduced memory footprint. Cursors are ideal for batch operations and handling millions of records.
Example: Basic Cursor Usage
Database.Cursor queryCursor = SOQL.of(Account.SObjectType)
.with(Account.Id, Account.Name)
.toCursor();
System.debug('Total Records: ' + queryCursor.getNumRecords());Example: Cursor with Sharing Mode
// Respect sharing rules
Database.Cursor queryCursor = SOQL.of(Task.SObjectType)
.systemMode()
.withSharing()
.toCursor();
// Bypass sharing rules
Database.Cursor queryCursor = SOQL.of(Task.SObjectType)
.systemMode()
.withoutSharing()
.toCursor();Mocking Improvements
Automatic SObjectType-Based Mocking
Previously, every query required a unique mockId() to be set. Now, SOQL Lib automatically uses the SObjectType for mocking, eliminating the need for explicit mock IDs in most cases.
Before (v6.6.0)
// Controller
public static List<Account> getAllAccounts() {
return SOQL.of(Account.SObjectType)
.with(Account.Name)
.mockId('ExampleController.getAllAccounts') // Required
.toList();
}
// Test
SOQL.mock('ExampleController.getAllAccounts').thenReturn(mockAccounts);After (v6.7.0)
// Controller - No mockId() needed!
public static List<Account> getAllAccounts() {
return SOQL.of(Account.SObjectType)
.with(Account.Name)
.toList();
}
// Test - Mock by SObjectType
SOQL.mock(Account.SObjectType).thenReturn(mockAccounts);How It Works:
- Every query automatically gets a default mock ID based on its SObjectType hash
- You can still use explicit
mockId()when you need different mocks for the same SObjectType - Explicit
mockId()always takes precedence over SObjectType-based mocking
Example: Using Both Approaches
SOQL.mock('specificQuery').thenReturn(specificMock);
SOQL.mock(Account.SObjectType).thenReturn(defaultMock);
// This uses the specific mock
queryable.mockId('specificQuery').toList();
// This uses the SObjectType mock
SOQL.of(Account.SObjectType).toList();Filter Enhancements
Skip Collection Looping with isIn() and notIn()
New overloaded methods for isIn() and notIn() that accept SObject collections, eliminating the need for manual collection iteration and value extraction.
Before (v6.6.0)
Set<String> accountNames = new Set<String>();
for (Account acc : accounts) {
accountNames.add(acc.Name);
}
List<Contact> contacts = SOQL.of(Contact.SObjectType)
.whereAre(SOQL.Filter.with(Contact.AccountName__c).isIn(accountNames))
.toList();After (v6.7.0)
List<Contact> contacts = SOQL.of(Contact.SObjectType)
.whereAre(SOQL.Filter.with(Contact.AccountName__c).isIn(accounts, Account.Name))
.toList();Key Features:
- Automatically extracts values from the specified field
- Skips null values to prevent query errors
- Works with any SObjectField
- Supports both
isIn()andnotIn()filters
Example: Filtering with Null Handling
// Even if some accounts have null Names, the query works correctly
List<Account> accounts = new List<Account>{
new Account(Name = 'Account 1'),
new Account(Name = 'Account 2'),
new Account(Name = null) // Automatically skipped
};
List<Contact> contacts = SOQL.of(Contact.SObjectType)
.whereAre(SOQL.Filter.with(Contact.AccountName__c).isIn(accounts, Account.Name))
.toList();