From 2659b94cc777207d1e4d66a0a1880476ae536e07 Mon Sep 17 00:00:00 2001 From: Piotr PG Gajek Date: Tue, 17 Dec 2024 11:34:49 +0100 Subject: [PATCH] calculate total number of queries issued Signed-off-by: Piotr PG Gajek --- force-app/main/default/classes/SOQL.cls | 18 +++ force-app/main/default/classes/SOQL_Test.cls | 150 +++++++++++++++---- 2 files changed, 141 insertions(+), 27 deletions(-) diff --git a/force-app/main/default/classes/SOQL.cls b/force-app/main/default/classes/SOQL.cls index 7ed6810..0fb16d8 100644 --- a/force-app/main/default/classes/SOQL.cls +++ b/force-app/main/default/classes/SOQL.cls @@ -328,6 +328,7 @@ public virtual inherited sharing class SOQL implements Queryable { private static Mock mock = new Mock(); private static Binder binder = new Binder(); + private static Integer queriesIssued = 0; private QueryBuilder builder; private Executor executor; @@ -2189,6 +2190,8 @@ public virtual inherited sharing class SOQL implements Queryable { } public List toList() { + calculateTotalNumberOfQueriesIssued(); + if (mock.hasMock(mockId)) { return mock.getSObjectsMock(mockId); } @@ -2262,6 +2265,8 @@ public virtual inherited sharing class SOQL implements Queryable { } public Integer toInteger() { + calculateTotalNumberOfQueriesIssued(); + if (mock.hasCountMock(mockId)) { return mock.getCountMock(mockId); } @@ -2270,8 +2275,21 @@ public virtual inherited sharing class SOQL implements Queryable { } public Database.QueryLocator toQueryLocator() { + calculateTotalNumberOfQueriesIssued(); return sharingExecutor.toQueryLocator(builder.toString(), binder.getBindingMap(), accessMode); } + + private void calculateTotalNumberOfQueriesIssued() { + queriesIssued++; + + if (Test.isRunningTest()) { + Boolean isAsynchronous = System.isBatch() || System.isFuture() || System.isQueueable() || System.isScheduled(); + + if ((queriesIssued > 100 && !isAsynchronous) || (queriesIssued > 200 && isAsynchronous)) { + throw new QueryException('Too many SOQL queries.'); + } + } + } } private interface DatabaseQuery { diff --git a/force-app/main/default/classes/SOQL_Test.cls b/force-app/main/default/classes/SOQL_Test.cls index 3d9a31f..6b14ff5 100644 --- a/force-app/main/default/classes/SOQL_Test.cls +++ b/force-app/main/default/classes/SOQL_Test.cls @@ -3335,6 +3335,129 @@ private class SOQL_Test { } } + @IsTest + static void querySynchronousLimitExceptionWithMocking() { + // Setup + Exception queryException = null; + + // Test + SOQL.setMock('mockingQuery', new List{ + new Account(Name = 'Test 1'), + new Account(Name = 'Test 2') + }); + + try { + for (Integer i = 0 ; i < 102 ; i++) { + SOQL.of(Account.SObjectType).mockId('mockingQuery').toList(); + } + } catch (Exception e) { + queryException = e; + } + + // Verify + Assert.areEqual('Too many SOQL queries.', queryException.getMessage()); + } + + @IsTest + static void queryAsynchronousLimitExceptionWithMocking() { + // Setup + Exception queryException = null; + + // Test + SOQL.setMock('mockingQuery', new List{ + new Account(Name = 'Test 1'), + new Account(Name = 'Test 2') + }); + + try { + Test.startTest(); + asynchronousQueriesWithMocking(); + Test.stopTest(); + } catch (Exception e) { + queryException = e; + } + + // Verify + Assert.areEqual('Too many SOQL queries.', queryException.getMessage()); + } + + @IsTest + static void querySynchronousLimitExceptionWithoutMocking() { + // Setup + Exception queryException = null; + + // Test + try { + for (Integer i = 0 ; i < 102 ; i++) { + SOQL.of(Account.SObjectType).toList(); + } + } catch (Exception e) { + queryException = e; + } + + // Verify + Assert.areEqual('Too many SOQL queries.', queryException.getMessage()); + } + + @IsTest + static void queryAsynchronousLimitExceptionWithoutMocking() { + // Setup + Exception queryException = null; + + // Test + try { + Test.startTest(); + asynchronousQueriesWithoutMocking(); + Test.stopTest(); + } catch (Exception e) { + queryException = e; + } + + // Verify + Assert.areEqual('Too many SOQL queries.', queryException.getMessage()); + } + + @SuppressWarnings('PMD.ApexUnitTestClassShouldHaveAsserts') + @IsTest + static void preview() { + // Test + SOQL.of(Account.SObjectType).preview().toList(); + } + + @SuppressWarnings('PMD.ApexUnitTestClassShouldHaveAsserts') + @IsTest + static void previewWithConditions() { + // Test + SOQL.of(Account.SObjectType) + .whereAre(SOQL.FilterGroup + .add(SOQL.Filter.with(Account.Name).equal('Test')) + .add(SOQL.Filter.with(Account.Industry).equal('IT')) + ) + .preview() + .toList(); + } + + @SuppressWarnings('PMD.ApexUnitTestClassShouldHaveAsserts') + @IsTest + static void previewCount() { + // Test + SOQL.of(Account.SObjectType).count().preview().toInteger(); + } + + @future + static void asynchronousQueriesWithMocking() { + for (Integer i = 0 ; i < 202 ; i++) { + SOQL.of(Account.SObjectType).mockId('mockingQuery').toList(); + } + } + + @future + static void asynchronousQueriesWithoutMocking() { + for (Integer i = 0 ; i < 202 ; i++) { + SOQL.of(Account.SObjectType).toList(); + } + } + static List insertAccounts() { List accounts = new List{ new Account(Name = 'Test 1'), @@ -3373,31 +3496,4 @@ private class SOQL_Test { UserName = 'queryselector@testorg.com' ); } - - @SuppressWarnings('PMD.ApexUnitTestClassShouldHaveAsserts') - @IsTest - static void preview() { - // Test - SOQL.of(Account.SObjectType).preview().toList(); - } - - @SuppressWarnings('PMD.ApexUnitTestClassShouldHaveAsserts') - @IsTest - static void previewWithConditions() { - // Test - SOQL.of(Account.SObjectType) - .whereAre(SOQL.FilterGroup - .add(SOQL.Filter.with(Account.Name).equal('Test')) - .add(SOQL.Filter.with(Account.Industry).equal('IT')) - ) - .preview() - .toList(); - } - - @SuppressWarnings('PMD.ApexUnitTestClassShouldHaveAsserts') - @IsTest - static void previewCount() { - // Test - SOQL.of(Account.SObjectType).count().preview().toInteger(); - } }