From 6a6ba9f725d778af501071276032ad859c926a10 Mon Sep 17 00:00:00 2001 From: Robert Baillie Date: Tue, 8 Mar 2022 14:44:22 +0000 Subject: [PATCH] Sketching out the idea of the sobject cache --- .../{ => caching}/CachedSoqlExecutor.cls | 144 +----------------- .../CachedSoqlExecutor.cls-meta.xml | 0 .../fflib-extension/caching/ICacheAdaptor.cls | 11 ++ .../ICacheAdaptor.cls-meta.xml} | 0 .../fflib-extension/caching/NullCache.cls | 40 +++++ .../caching/NullCache.cls-meta.xml | 5 + .../fflib-extension/caching/OrgCache.cls | 42 +++++ .../caching/OrgCache.cls-meta.xml | 5 + .../fflib-extension/caching/SessionCache.cls | 42 +++++ .../caching/SessionCache.cls-meta.xml | 5 + .../fflib-extension/caching/SobjectCache.cls | 94 ++++++++++++ .../caching/SobjectCache.cls-meta.xml | 5 + .../tests/CachedSoqlExecutorTest.cls | 0 .../tests/CachedSoqlExecutorTest.cls-meta.xml | 5 + 14 files changed, 256 insertions(+), 142 deletions(-) rename framework/default/ortoo-core/default/classes/fflib-extension/{ => caching}/CachedSoqlExecutor.cls (60%) rename framework/default/ortoo-core/default/classes/fflib-extension/{ => caching}/CachedSoqlExecutor.cls-meta.xml (100%) create mode 100644 framework/default/ortoo-core/default/classes/fflib-extension/caching/ICacheAdaptor.cls rename framework/default/ortoo-core/default/classes/fflib-extension/{tests/CachedSoqlExecutorTest.cls-meta.xml => caching/ICacheAdaptor.cls-meta.xml} (100%) create mode 100644 framework/default/ortoo-core/default/classes/fflib-extension/caching/NullCache.cls create mode 100644 framework/default/ortoo-core/default/classes/fflib-extension/caching/NullCache.cls-meta.xml create mode 100644 framework/default/ortoo-core/default/classes/fflib-extension/caching/OrgCache.cls create mode 100644 framework/default/ortoo-core/default/classes/fflib-extension/caching/OrgCache.cls-meta.xml create mode 100644 framework/default/ortoo-core/default/classes/fflib-extension/caching/SessionCache.cls create mode 100644 framework/default/ortoo-core/default/classes/fflib-extension/caching/SessionCache.cls-meta.xml create mode 100644 framework/default/ortoo-core/default/classes/fflib-extension/caching/SobjectCache.cls create mode 100644 framework/default/ortoo-core/default/classes/fflib-extension/caching/SobjectCache.cls-meta.xml rename framework/default/ortoo-core/default/classes/fflib-extension/{ => caching}/tests/CachedSoqlExecutorTest.cls (100%) create mode 100644 framework/default/ortoo-core/default/classes/fflib-extension/caching/tests/CachedSoqlExecutorTest.cls-meta.xml diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/CachedSoqlExecutor.cls b/framework/default/ortoo-core/default/classes/fflib-extension/caching/CachedSoqlExecutor.cls similarity index 60% rename from framework/default/ortoo-core/default/classes/fflib-extension/CachedSoqlExecutor.cls rename to framework/default/ortoo-core/default/classes/fflib-extension/caching/CachedSoqlExecutor.cls index 64870241990..c53f3c25ae6 100644 --- a/framework/default/ortoo-core/default/classes/fflib-extension/CachedSoqlExecutor.cls +++ b/framework/default/ortoo-core/default/classes/fflib-extension/caching/CachedSoqlExecutor.cls @@ -10,8 +10,9 @@ public inherited sharing class CachedSoqlExecutor //NOPMD: incorrect report of t { public class CacheAccessViolationException extends Exceptions.DeveloperException {} // this looks like a config exception, but actually the system should be built // in such a way that it's never possible to get this exception + public enum CacheScope { NONE, ORG, SESSION } - CacheWrapper cacheWrapper = new OrgCache(); // by default, configure the cache to use the org version + ICacheAdaptor cacheWrapper = new OrgCache(); // by default, configure the cache to use the org version private final static String SOQL_PARTITION_NAME = 'soql'; private final static Integer CACHE_LIFESPAN_SECONDS = 28800; // TODO: soft setting / option @@ -32,8 +33,6 @@ public inherited sharing class CachedSoqlExecutor //NOPMD: incorrect report of t set; } - public enum CacheScope { NONE, ORG, SESSION } - public CachedSoqlExecutor setScope( CacheScope scope ) { Contract.requires( scope != null, 'setScope called with a null scope' ); @@ -172,143 +171,4 @@ public inherited sharing class CachedSoqlExecutor //NOPMD: incorrect report of t { return cacheWrapper.createFullyQualifiedKey( PackageUtils.NAMESPACE_PREFIX, SOQL_PARTITION_NAME, subkey ); } - - private interface CacheWrapper - { - Boolean isACache(); - Object get( String key ); - void put( String key, Object value, Integer lifespan ); - Set getKeys(); - Boolean contains( String key ); - void remove( String key ); - String createFullyQualifiedPartitionName( String namespace, String partitionName ); - String createFullyQualifiedKey( String namespace, String partitionName, String subKey ); - } - - private class OrgCache implements CacheWrapper - { - public Boolean isACache() - { - return true; - } - - public Object get( String key ) - { - return Cache.Org.get( key ); - } - - public void put( String key, Object value, Integer lifespan ) - { - Cache.Org.put( key, value, lifespan, Cache.Visibility.NAMESPACE, true ); // immutable results - } - - public Set getKeys() - { - return Cache.Org.getKeys(); - } - - public Boolean contains( String key ) - { - return Cache.Org.contains( key ); - } - - public void remove( String key ) - { - Cache.Org.remove( key ); - } - - public String createFullyQualifiedPartitionName( String namespace, String partitionName ) - { - return Cache.OrgPartition.createFullyQualifiedPartition( namespace, partitionName ); - } - - public String createFullyQualifiedKey( String namespace, String partitionName, String subKey ) - { - return Cache.OrgPartition.createFullyQualifiedKey( PackageUtils.NAMESPACE_PREFIX, SOQL_PARTITION_NAME, subkey ); - } - } - - private class SessionCache implements CacheWrapper - { - public Boolean isACache() - { - return true; - } - - public Object get( String key ) - { - return Cache.Session.get( key ); - } - - public void put( String key, Object value, Integer lifespan ) - { - Cache.Session.put( key, value, lifespan, Cache.Visibility.NAMESPACE, true ); // immutable results - } - - public Set getKeys() - { - return Cache.Session.getKeys(); - } - - public Boolean contains( String key ) - { - return Cache.Session.contains( key ); - } - - public void remove( String key ) - { - Cache.Session.remove( key ); - } - - public String createFullyQualifiedPartitionName( String namespace, String partitionName ) - { - return Cache.SessionPartition.createFullyQualifiedPartition( namespace, partitionName ); - } - - public String createFullyQualifiedKey( String namespace, String partitionName, String subKey ) - { - return Cache.SessionPartition.createFullyQualifiedKey( PackageUtils.NAMESPACE_PREFIX, SOQL_PARTITION_NAME, subkey ); - } - } - - private class NullCache implements CacheWrapper - { - public Boolean isACache() - { - return false; - } - - public Object get( String key ) - { - return null; - } - - public void put( String key, Object value, Integer lifespan ) // NOPMD: Intentionally left empty, as this should do nothing in a NullCache - { - } - - public Set getKeys() - { - return new Set(); - } - - public Boolean contains( String key ) - { - return false; - } - - public void remove( String key ) // NOPMD: Intentionally left empty, as this should do nothing in a NullCache - { - } - - public String createFullyQualifiedPartitionName( String namespace, String partitionName ) - { - return namespace + '.' + partitionName; - } - - public String createFullyQualifiedKey( String namespace, String partitionName, String subKey ) - { - return namespace + '.' + partitionName + '.' + subkey; - } - } } \ No newline at end of file diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/CachedSoqlExecutor.cls-meta.xml b/framework/default/ortoo-core/default/classes/fflib-extension/caching/CachedSoqlExecutor.cls-meta.xml similarity index 100% rename from framework/default/ortoo-core/default/classes/fflib-extension/CachedSoqlExecutor.cls-meta.xml rename to framework/default/ortoo-core/default/classes/fflib-extension/caching/CachedSoqlExecutor.cls-meta.xml diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/caching/ICacheAdaptor.cls b/framework/default/ortoo-core/default/classes/fflib-extension/caching/ICacheAdaptor.cls new file mode 100644 index 00000000000..a1d3bc557bf --- /dev/null +++ b/framework/default/ortoo-core/default/classes/fflib-extension/caching/ICacheAdaptor.cls @@ -0,0 +1,11 @@ +public interface ICacheAdaptor +{ + Boolean isACache(); + Object get( String key ); + void put( String key, Object value, Integer lifespan ); + Set getKeys(); + Boolean contains( String key ); + void remove( String key ); + String createFullyQualifiedPartitionName( String namespace, String partitionName ); + String createFullyQualifiedKey( String namespace, String partitionName, String subKey ); +} \ No newline at end of file diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/tests/CachedSoqlExecutorTest.cls-meta.xml b/framework/default/ortoo-core/default/classes/fflib-extension/caching/ICacheAdaptor.cls-meta.xml similarity index 100% rename from framework/default/ortoo-core/default/classes/fflib-extension/tests/CachedSoqlExecutorTest.cls-meta.xml rename to framework/default/ortoo-core/default/classes/fflib-extension/caching/ICacheAdaptor.cls-meta.xml diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/caching/NullCache.cls b/framework/default/ortoo-core/default/classes/fflib-extension/caching/NullCache.cls new file mode 100644 index 00000000000..7c844dc2ee0 --- /dev/null +++ b/framework/default/ortoo-core/default/classes/fflib-extension/caching/NullCache.cls @@ -0,0 +1,40 @@ +public class NullCache implements ICacheAdaptor +{ + public Boolean isACache() + { + return false; + } + + public Object get( String key ) + { + return null; + } + + public void put( String key, Object value, Integer lifespan ) // NOPMD: Intentionally left empty, as this should do nothing in a NullCache + { + } + + public Set getKeys() + { + return new Set(); + } + + public Boolean contains( String key ) + { + return false; + } + + public void remove( String key ) // NOPMD: Intentionally left empty, as this should do nothing in a NullCache + { + } + + public String createFullyQualifiedPartitionName( String namespace, String partitionName ) + { + return namespace + '.' + partitionName; + } + + public String createFullyQualifiedKey( String namespace, String partitionName, String subKey ) + { + return namespace + '.' + partitionName + '.' + subkey; + } +} \ No newline at end of file diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/caching/NullCache.cls-meta.xml b/framework/default/ortoo-core/default/classes/fflib-extension/caching/NullCache.cls-meta.xml new file mode 100644 index 00000000000..dd61d1f917e --- /dev/null +++ b/framework/default/ortoo-core/default/classes/fflib-extension/caching/NullCache.cls-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + Active + diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/caching/OrgCache.cls b/framework/default/ortoo-core/default/classes/fflib-extension/caching/OrgCache.cls new file mode 100644 index 00000000000..2a4716803f2 --- /dev/null +++ b/framework/default/ortoo-core/default/classes/fflib-extension/caching/OrgCache.cls @@ -0,0 +1,42 @@ +public class OrgCache implements ICacheAdaptor +{ + public Boolean isACache() + { + return true; + } + + public Object get( String key ) + { + return Cache.Org.get( key ); + } + + public void put( String key, Object value, Integer lifespan ) + { + Cache.Org.put( key, value, lifespan, Cache.Visibility.NAMESPACE, true ); // immutable outside of namespace + } + + public Set getKeys() + { + return Cache.Org.getKeys(); + } + + public Boolean contains( String key ) + { + return Cache.Org.contains( key ); + } + + public void remove( String key ) + { + Cache.Org.remove( key ); + } + + public String createFullyQualifiedPartitionName( String namespace, String partitionName ) + { + return Cache.OrgPartition.createFullyQualifiedPartition( namespace, partitionName ); + } + + public String createFullyQualifiedKey( String namespace, String partitionName, String subKey ) + { + return Cache.OrgPartition.createFullyQualifiedKey( namespace, partitionName, subkey ); + } +} \ No newline at end of file diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/caching/OrgCache.cls-meta.xml b/framework/default/ortoo-core/default/classes/fflib-extension/caching/OrgCache.cls-meta.xml new file mode 100644 index 00000000000..dd61d1f917e --- /dev/null +++ b/framework/default/ortoo-core/default/classes/fflib-extension/caching/OrgCache.cls-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + Active + diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/caching/SessionCache.cls b/framework/default/ortoo-core/default/classes/fflib-extension/caching/SessionCache.cls new file mode 100644 index 00000000000..94a1dedc2d7 --- /dev/null +++ b/framework/default/ortoo-core/default/classes/fflib-extension/caching/SessionCache.cls @@ -0,0 +1,42 @@ +public class SessionCache implements ICacheAdaptor +{ + public Boolean isACache() + { + return true; + } + + public Object get( String key ) + { + return Cache.Session.get( key ); + } + + public void put( String key, Object value, Integer lifespan ) + { + Cache.Session.put( key, value, lifespan, Cache.Visibility.NAMESPACE, true ); // immutable outside of namespace + } + + public Set getKeys() + { + return Cache.Session.getKeys(); + } + + public Boolean contains( String key ) + { + return Cache.Session.contains( key ); + } + + public void remove( String key ) + { + Cache.Session.remove( key ); + } + + public String createFullyQualifiedPartitionName( String namespace, String partitionName ) + { + return Cache.SessionPartition.createFullyQualifiedPartition( namespace, partitionName ); + } + + public String createFullyQualifiedKey( String namespace, String partitionName, String subKey ) + { + return Cache.SessionPartition.createFullyQualifiedKey( namespace, partitionName, subkey ); + } +} \ No newline at end of file diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/caching/SessionCache.cls-meta.xml b/framework/default/ortoo-core/default/classes/fflib-extension/caching/SessionCache.cls-meta.xml new file mode 100644 index 00000000000..dd61d1f917e --- /dev/null +++ b/framework/default/ortoo-core/default/classes/fflib-extension/caching/SessionCache.cls-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + Active + diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/caching/SobjectCache.cls b/framework/default/ortoo-core/default/classes/fflib-extension/caching/SobjectCache.cls new file mode 100644 index 00000000000..12160c9d986 --- /dev/null +++ b/framework/default/ortoo-core/default/classes/fflib-extension/caching/SobjectCache.cls @@ -0,0 +1,94 @@ +public with sharing class SobjectCache +{ + // TODO: try writing something that gets some things from the cache, then deals with the difference. + // TODO: maybe we need a return object that contains a list of the cache misses. + + public class CacheAccessViolationException extends Exceptions.DeveloperException {} // this looks like a config exception, but actually the system should be built + // in such a way that it's never possible to get this exception + public enum CacheScope { ORG, SESSION } + + ICacheAdaptor cacheWrapper = new OrgCache(); // by default, configure the cache to use the org version + + private final static String PARTITION_NAME = 'soql'; // TODO: same partition? + private final static Integer CACHE_LIFESPAN_SECONDS = 28800; // TODO: soft setting / option + + @testVisible + private final static String CAN_ACCESS_SOQL_CACHE_PERMISSION = 'ProcessesCanAccessSOQLCache'; // TODO: same permission? + + private Boolean hasAccessToCache + { + get + { + if ( hasAccessToCache == null ) + { + hasAccessToCache = PermissionsService.hasPermission( CAN_ACCESS_SOQL_CACHE_PERMISSION ); + } + return hasAccessToCache; + } + set; + } + + public SobjectCache setScope( CacheScope scope ) + { + Contract.requires( scope != null, 'setScope called with a null scope' ); + + switch on scope + { + when ORG + { + cacheWrapper = new OrgCache(); + } + when SESSION + { + cacheWrapper = new SessionCache(); + } + } + + return this; + } + + // returns as many of the objects from the cache as can be returned + public CacheRetrieval get( String key, Set ids ) + { + return new CacheRetrieval(); + } + + public SobjectCache put( String key, String idField, List sobjects ) + { + return this; + } + + public SobjectCache clear( String key ) + { + return this; + } + + public SobjectCache clear( String key, Set ids ) + { + return this; + } + + public class CacheRetrieval + { + public Map cacheHits { get; private set; } + public Set cacheMisses { get; private set; } + + private CacheRetrieval() + { + cacheHits = new Map(); + cacheMisses = new Set(); + } + + private CacheRetrieval addCacheMiss( Id id ) + { + cacheMisses.add( id ); + return this; + } + + private CacheRetrieval addCacheHit( Id id, Sobject value ) + { + cacheHits.put( id, value ); + return this; + } + } +} diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/caching/SobjectCache.cls-meta.xml b/framework/default/ortoo-core/default/classes/fflib-extension/caching/SobjectCache.cls-meta.xml new file mode 100644 index 00000000000..dd61d1f917e --- /dev/null +++ b/framework/default/ortoo-core/default/classes/fflib-extension/caching/SobjectCache.cls-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + Active + diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/tests/CachedSoqlExecutorTest.cls b/framework/default/ortoo-core/default/classes/fflib-extension/caching/tests/CachedSoqlExecutorTest.cls similarity index 100% rename from framework/default/ortoo-core/default/classes/fflib-extension/tests/CachedSoqlExecutorTest.cls rename to framework/default/ortoo-core/default/classes/fflib-extension/caching/tests/CachedSoqlExecutorTest.cls diff --git a/framework/default/ortoo-core/default/classes/fflib-extension/caching/tests/CachedSoqlExecutorTest.cls-meta.xml b/framework/default/ortoo-core/default/classes/fflib-extension/caching/tests/CachedSoqlExecutorTest.cls-meta.xml new file mode 100644 index 00000000000..dd61d1f917e --- /dev/null +++ b/framework/default/ortoo-core/default/classes/fflib-extension/caching/tests/CachedSoqlExecutorTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 52.0 + Active +