Skip to content

v6.10.0

Choose a tag to compare

@pgajek2 pgajek2 released this 12 May 18:48
db9807d

v6.10.0 - 12-May-2026

Scope

  • New Feature: @NamespaceAccessible Support for Managed Packages
  • Enhancement: CacheManager Fallback to Apex Transaction Cache
  • Fix: Cache.Session Availability Handling
  • Fix: Mocking with Schema-Prefixed SObject Types
  • Fix: Encrypted Field Usage in Tests
  • Maintenance: PMD Suppressions, Prettier Formatting, Dependency Bumps

SOQL, SOQLCache, SOQLEvaluator, and CacheManager

  • Added @NamespaceAccessible annotation to public access points across SOQL, SOQLCache, and SOQLEvaluator
  • CacheManager now falls back to in-memory Apex transaction cache when the platform cache partition is unavailable
  • Hardened Cache.Session and Cache.Org partition retrieval against exceptions and unavailable session contexts

New Feature: @NamespaceAccessible Support for Managed Packages

All public access points of SOQL, SOQLCache, and SOQLEvaluator are now annotated with @NamespaceAccessible. This allows the library to be consumed from other Apex code in subscriber orgs when distributed as a managed package, without requiring global visibility.

Affected public surface (examples)

@NamespaceAccessible
public virtual inherited sharing class SOQLCache implements Cacheable {
    @NamespaceAccessible
    public interface Selector {
        Cacheable query();
    }

    @NamespaceAccessible
    public static Cacheable of(SObjectType ofObject) {
        return new SOQLCache(ofObject);
    }
    // ...
}

The annotation has been applied to:

  • Static factory methods (SOQL.of(...), SOQLCache.of(...), SOQLEvaluator.of(...))
  • Public interfaces (Selector, Queryable, Cacheable, Mockable, etc.)
  • Public constructors and entry-point methods (mock, removeFromCache, fluent builders)

No behavioral change for unmanaged usage — the annotation only affects access from outside the package namespace.

Enhancement: CacheManager Fallback to Apex Transaction Cache

CacheManager (v1.1.0) now gracefully degrades when a platform cache partition is unavailable (e.g. partition not provisioned, no cache capacity allocated, or session cache not available in the current context). Instead of throwing an exception, reads and writes are transparently routed to an in-memory ApexTransactionCache fallback for the lifetime of the transaction.

What changed

  • Added a private fallback field of type ApexTransactionCache to the abstract PlatformCache class
  • All Cacheable operations (contains, getKeys, get, put, remove) check isAvailable() and route to either the platform partition or the fallback
  • OrgPlatformCache.getPartition(...) now catches Cache.Org.OrgCacheException and returns null
  • SessionPlatformCache.getPartition(...) now checks Cache.Session.isAvailable() and catches Cache.Session.SessionCacheException, returning null on either condition

Behavior

// When the SOQL cache partition is missing or session cache is unavailable,
// SOQLCache continues to function — caching happens in-memory for the current transaction.
SOQLCache.of(Account.SObjectType)
    .cacheInSessionCache()
    .whereEqual(Account.Name, 'Test')
    .toObject();

Fix: Cache.Session Availability Handling

Refactored SessionPlatformCache.getPartition(...) so that the Cache.Session.isAvailable() check is performed inside the try block. This ensures consistent null handling when the session cache is genuinely unavailable (e.g. in contexts where no default cache partition is configured).

Before

public override Cache.Partition getPartition(String partitionName) {
    if (!Cache.Session.isAvailable()) {
        return null;
    }
    try {
        return Cache.Session.getPartition(partitionName);
    } catch (Cache.Session.SessionCacheException e) {
        return null;
    }
}

After

public override Cache.Partition getPartition(String partitionName) {
    try {
        if (!Cache.Session.isAvailable()) {
            return null;
        }
        return Cache.Session.getPartition(partitionName);
    } catch (Cache.Session.SessionCacheException e) {
        return null;
    }
}

Fix: Mocking with Schema-Prefixed SObject Types

Fixed an issue in SOQL.stripAdditionalFields(...) where constructing the cleaned record list via Type.forName('List<' + objectTypeName + '>') could fail to resolve the SObject type in certain namespaces or when the type token did not round-trip through Type.forName. The list type is now built using the explicit Schema. prefix for known SObject types.

Before

List<SObject> cleanedRecords = (List<SObject>) Type.forName('List<' + objectTypeName + ' >').newInstance();

After

List<SObject> cleanedRecords = (List<SObject>) Type.forName(
    'List<' + (this.sObjectType != null ? 'Schema.' + this.sObjectType.toString() : 'SObject') + ' >'
).newInstance();

Fix: Encrypted Field Usage in Tests

Updated tests that previously filtered or projected on Account.Name and Account.Industry in scenarios where the record was expected not to exist. These tests now use Account.DunsNumber and Account.Industry instead, avoiding flakiness in orgs that have classic encryption (or platform encryption) enabled on the Name field.

Affected tests in SOQL_Test / SOQL_Full_Test:

  • toValueOfWhenRecordNotExist
  • toValuesOfRelationshipFieldWhenRelatedRecordNotExist
  • previewWithConditions

Maintenance

PMD Suppressions

  • Added PMD.NcssCount to the suppressed warnings on the SOQL class to align with existing PMD.NcssTypeCount suppression (the library intentionally lives in a single class for fluent usage).

Prettier Formatting

  • Repository-wide reformatting with Prettier (incl. prettier-plugin-apex and @prettier/plugin-xml).
  • Added a root package.json declaring the Prettier toolchain as dev dependencies:
{
    "name": "soql-lib",
    "private": true,
    "version": "1.0.0",
    "devDependencies": {
        "@prettier/plugin-xml": "^3.4.1",
        "prettier": "^3.4.2",
        "prettier-plugin-apex": "^2.2.1"
    }
}