Skip to content

Commit 7f9b410

Browse files
authored
Merge pull request #241 from beyond-the-cloud-dev/release/v6.7.0
Release/v6.7.0
2 parents 7e4984a + e7dd674 commit 7f9b410

14 files changed

Lines changed: 589 additions & 18 deletions

File tree

‎force-app/main/default/classes/cached-soql/SOQLCache.cls‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright (c) 2025 Beyond The Cloud Sp. z o.o. (BeyondTheCloud.Dev)
33
* Licensed under the MIT License (https://github.com/beyond-the-cloud-dev/soql-lib/blob/main/LICENSE)
44
*
5-
* v6.6.0
5+
* v6.7.0
66
*
77
* PMD False Positives:
88
* - ExcessivePublicCount: It is a library class and exposes all necessary methods to construct a query
@@ -86,6 +86,10 @@ global virtual inherited sharing class SOQLCache implements Cacheable {
8686
void thenReturn(SObject record);
8787
}
8888

89+
global static Mockable mock(SObjectType ofObject) {
90+
return mock(ofObject.toString().hashCode().toString());
91+
}
92+
8993
global static Mockable mock(String mockId) {
9094
if (!SOQLCache.queryIdToMock.containsKey(mockId)) {
9195
SOQLCache.queryIdToMock.put(mockId, new List<SoqlMock>());
@@ -138,6 +142,8 @@ global virtual inherited sharing class SOQLCache implements Cacheable {
138142
this.cache.filterGroup.setAdditionalAllowedConditionFields(this.additionalAllowedConditionFields());
139143
this.executor = new Executor(this.currentQuery, this.cache);
140144

145+
this.mockId(ofObject.hashCode().toString());
146+
141147
this.with('Id');
142148
}
143149

‎force-app/main/default/classes/cached-soql/SOQLCache_Test.cls‎

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Copyright (c) 2025 Beyond The Cloud Sp. z o.o. (BeyondTheCloud.Dev)
44
* Licensed under the MIT License (https://github.com/beyond-the-cloud-dev/soql-lib/blob/main/LICENSE)
55
*
6-
* v6.6.0
6+
* v6.7.0
77
*
88
* PMD False Positives:
99
* - CyclomaticComplexity: It is a library and we tried to put everything into ONE test class
@@ -778,6 +778,37 @@ private class SOQLCache_Test {
778778
Assert.areEqual(SYSTEM_ADMINISTRATOR, profile.Name, 'The profile name should be the same as the name assigned to the profile cache.');
779779
}
780780

781+
@IsTest
782+
static void mockWithoutMockId() {
783+
// Setup
784+
SOQLCache.mock(Profile.SObjectType).thenReturn(new Profile(Name = SYSTEM_ADMINISTRATOR));
785+
786+
// Test
787+
Profile profile = (Profile) SOQLCache.of(Profile.SObjectType).whereEqual(Profile.Name, SYSTEM_ADMINISTRATOR).toObject();
788+
789+
// Verify
790+
Assert.areEqual(SYSTEM_ADMINISTRATOR, profile.Name, 'The profile name should be the same as the name assigned to the profile cache.');
791+
}
792+
793+
@IsTest
794+
static void mockWithMockIdAndSObjectMock() {
795+
// Setup
796+
Id profileId1 = SOQL.IdGenerator.get(Profile.SObjectType);
797+
SOQLCache.mock('ProfileQuery').thenReturn(new Profile(Id = profileId1, Name = SYSTEM_ADMINISTRATOR));
798+
799+
Id profileId2 = SOQL.IdGenerator.get(Profile.SObjectType);
800+
SOQLCache.mock(Profile.SObjectType).thenReturn(new Profile(Id = profileId2, Name = SYSTEM_ADMINISTRATOR));
801+
802+
SOQLCache.Cacheable query = SOQLCache.of(Profile.SObjectType);
803+
804+
Profile profile1 = (Profile) query.mockId('ProfileQuery').whereEqual(Profile.Name, SYSTEM_ADMINISTRATOR).toObject();
805+
Profile profile2 = (Profile) query.mockId('ProfileQuery').whereEqual(Profile.Name, SYSTEM_ADMINISTRATOR).toObject();
806+
807+
// Verify
808+
Assert.areEqual(profileId1, profile1.Id, 'The mockId should override the SObject mock.');
809+
Assert.areEqual(profileId1, profile2.Id, 'The mockId should override the SObject mock.');
810+
}
811+
781812
@IsTest
782813
static void mockStack() {
783814
// Setup

‎force-app/main/default/classes/soql-evaluator/SOQLEvaluator.cls‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright (c) 2025 Beyond The Cloud Sp. z o.o. (BeyondTheCloud.Dev)
33
* Licensed under the MIT License (https://github.com/beyond-the-cloud-dev/soql-lib/blob/main/LICENSE)
44
*
5-
* v6.6.0
5+
* v6.7.0
66
*
77
* PMD False Positives:
88
* - CognitiveComplexity: It is a library and we tried to put everything into ONE class

‎force-app/main/default/classes/soql-evaluator/SOQLEvaluator_Test.cls‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Copyright (c) 2025 Beyond The Cloud Sp. z o.o. (BeyondTheCloud.Dev)
44
* Licensed under the MIT License (https://github.com/beyond-the-cloud-dev/soql-lib/blob/main/LICENSE)
55
*
6-
* v6.6.0
6+
* v6.7.0
77
*
88
* PMD False Positives:
99
* - CyclomaticComplexity: It is a library and we tried to put everything into ONE test class

‎force-app/main/default/classes/standard-soql/SOQL.cls‎

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright (c) 2025 Beyond The Cloud Sp. z o.o. (BeyondTheCloud.Dev)
33
* Licensed under the MIT License (https://github.com/beyond-the-cloud-dev/soql-lib/blob/main/LICENSE)
44
*
5-
* v6.6.0
5+
* v6.7.0
66
*
77
* PMD False Positives:
88
* - ExcessivePublicCount: It is a library class and exposes all necessary methods to construct a query
@@ -159,6 +159,8 @@ global virtual inherited sharing class SOQL implements Queryable {
159159
Integer toInteger();
160160
// QUERY LOCATOR
161161
Database.QueryLocator toQueryLocator();
162+
// CURSOR
163+
Database.Cursor toCursor();
162164
// DO EXIST
163165
Boolean doExist();
164166
// AGGREGATE RESULTS
@@ -273,8 +275,10 @@ global virtual inherited sharing class SOQL implements Queryable {
273275
Filter notStartsWith(String value);
274276
Filter isIn(Iterable<Object> iterable);
275277
Filter isIn(InnerJoin joinQuery);
278+
Filter isIn(Iterable<SObject> sourceRecords, SObjectField sourceKeyField);
276279
Filter notIn(Iterable<Object> iterable);
277280
Filter notIn(InnerJoin joinQuery);
281+
Filter notIn(Iterable<SObject> sourceRecords, SObjectField sourceKeyField);
278282
Filter includesAll(Iterable<String> values);
279283
Filter includesSome(Iterable<String> values);
280284
Filter excludesAll(Iterable<String> values);
@@ -397,6 +401,10 @@ global virtual inherited sharing class SOQL implements Queryable {
397401

398402
// Mocking
399403

404+
global static Mockable mock(SObjectType ofObject) {
405+
return mock(ofObject.toString().hashCode().toString());
406+
}
407+
400408
global static Mockable mock(String mockId) {
401409
if (!SOQL.queryIdToMock.containsKey(mockId)) {
402410
SOQL.queryIdToMock.put(mockId, new List<SoqlMock>());
@@ -463,6 +471,8 @@ global virtual inherited sharing class SOQL implements Queryable {
463471
this.builder = new SoqlBuilder(ofObject);
464472
this.executor = new Executor(builder);
465473
this.converter = new Converter(ofObject);
474+
475+
this.mockId(ofObject.hashCode().toString());
466476
}
467477

468478
global Queryable with(SObjectField field) {
@@ -1100,6 +1110,10 @@ global virtual inherited sharing class SOQL implements Queryable {
11001110
return this.executor.toQueryLocator();
11011111
}
11021112

1113+
global Database.Cursor toCursor() {
1114+
return this.executor.toCursor();
1115+
}
1116+
11031117
global Queryable byId(SObject record) {
11041118
return this.byId(record.Id);
11051119
}
@@ -1858,6 +1872,10 @@ global virtual inherited sharing class SOQL implements Queryable {
18581872
return this.set('IN', joinQuery);
18591873
}
18601874

1875+
public Filter isIn(Iterable<SObject> sourceRecords, SObjectField sourceKeyField) {
1876+
return this.isIn(this.extractValues(sourceRecords, sourceKeyField));
1877+
}
1878+
18611879
private Filter notLike() {
18621880
this.wrapper = '(NOT {0})';
18631881
return this;
@@ -1872,6 +1890,24 @@ global virtual inherited sharing class SOQL implements Queryable {
18721890
return this.set('NOT IN', joinQuery);
18731891
}
18741892

1893+
public Filter notIn(Iterable<SObject> sourceRecords, SObjectField sourceKeyField) {
1894+
return this.notIn(this.extractValues(sourceRecords, sourceKeyField));
1895+
}
1896+
1897+
private List<String> extractValues(Iterable<SObject> sourceRecords, SObjectField sourceKeyField) {
1898+
List<String> values = new List<String>();
1899+
1900+
for (SObject sourceRecord: sourceRecords) {
1901+
if (sourceRecord?.get(sourceKeyField) == null) {
1902+
continue;
1903+
}
1904+
1905+
values.add(sourceRecord.get(sourceKeyField).toString());
1906+
}
1907+
1908+
return values;
1909+
}
1910+
18751911
public Filter includesAll(Iterable<String> iterable) {
18761912
return this.setMultipicklistFilter('INCLUDES', iterable, ';');
18771913
}
@@ -2772,6 +2808,11 @@ global virtual inherited sharing class SOQL implements Queryable {
27722808
return this.sharingExecutor.toQueryLocator(this.builder.toString(), binder.getBindingMap(), this.accessMode);
27732809
}
27742810

2811+
public Database.Cursor toCursor() {
2812+
this.incrementQueryIssued();
2813+
return sharingExecutor.toCursor(builder.toString(), binder.getBindingMap(), accessMode);
2814+
}
2815+
27752816
private void incrementQueryIssued() {
27762817
// This counter is used only in unit tests to also track mocked queries.
27772818
if (!System.Test.isRunningTest() || System.isBatch() || System.isFuture() || System.isQueueable() || System.isScheduled()) {
@@ -2792,6 +2833,7 @@ global virtual inherited sharing class SOQL implements Queryable {
27922833
List<SObject> toSObjects(String query, Map<String, Object> binding, AccessLevel accessLevel);
27932834
Integer toInteger(String query, Map<String, Object> binding, AccessLevel accessLevel);
27942835
Database.QueryLocator toQueryLocator(String query, Map<String, Object> binding, AccessLevel accessLevel);
2836+
Database.Cursor toCursor(String query, Map<String, Object> binding, AccessLevel accessLevel);
27952837
}
27962838

27972839
private inherited sharing class InheritedSharing implements DatabaseQuery {
@@ -2806,6 +2848,10 @@ global virtual inherited sharing class SOQL implements Queryable {
28062848
public Database.QueryLocator toQueryLocator(String query, Map<String, Object> binding, AccessLevel accessLevel) {
28072849
return Database.getQueryLocatorWithBinds(query, binding, accessLevel);
28082850
}
2851+
2852+
public Database.Cursor toCursor(String query, Map<String, Object> binding, AccessLevel accessLevel) {
2853+
return Database.getCursorWithBinds(query, binding, accessLevel);
2854+
}
28092855
}
28102856

28112857
private without sharing class WithoutSharing implements DatabaseQuery {
@@ -2820,6 +2866,10 @@ global virtual inherited sharing class SOQL implements Queryable {
28202866
public Database.QueryLocator toQueryLocator(String query, Map<String, Object> binding, AccessLevel accessLevel) {
28212867
return Database.getQueryLocatorWithBinds(query, binding, accessLevel);
28222868
}
2869+
2870+
public Database.Cursor toCursor(String query, Map<String, Object> binding, AccessLevel accessLevel) {
2871+
return Database.getCursorWithBinds(query, binding, accessLevel);
2872+
}
28232873
}
28242874

28252875
private with sharing class WithSharing implements DatabaseQuery {
@@ -2834,6 +2884,10 @@ global virtual inherited sharing class SOQL implements Queryable {
28342884
public Database.QueryLocator toQueryLocator(String query, Map<String, Object> binding, AccessLevel accessLevel) {
28352885
return Database.getQueryLocatorWithBinds(query, binding, accessLevel);
28362886
}
2887+
2888+
public Database.Cursor toCursor(String query, Map<String, Object> binding, AccessLevel accessLevel) {
2889+
return Database.getCursorWithBinds(query, binding, accessLevel);
2890+
}
28372891
}
28382892

28392893
public inherited sharing class Converter {

0 commit comments

Comments
 (0)