Skip to content

v6.7.0

Latest

Choose a tag to compare

@pgajek2 pgajek2 released this 20 Jan 21:09

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() and notIn() 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() and notIn() 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();