Skip to content

Commit

Permalink
Fixes Set handling in filterWhere (#44)
Browse files Browse the repository at this point in the history
* Fixes #43 by upgrading SOQl.cls to API version 58, where Set<T> always implements Iterable<T> to simplify string joining for Set operators

* Bumped all metadata to API v58.0 (Summer '23 release)

* Updated all references to classes & enums in the Schema & System namespaces to explicitly include the namespaces
  • Loading branch information
jamessimone authored Sep 18, 2023
1 parent 293bec3 commit 269a787
Show file tree
Hide file tree
Showing 18 changed files with 93 additions and 88 deletions.
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,38 @@

A dynamic SOQL query & SOSL search library for Salesforce Apex

## Unlocked Package - no namespace - v3.1.1
## Unlocked Package - no namespace - v3.1.2

[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001TsMOQA0)
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001TsMOQA0)
[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001TsbQQAS)
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001TsbQQAS)

Install with SF CLI:

```shell
sf package install --apex-compile package --wait 20 --security-type AdminsOnly --package 04t5Y000001TsMOQA0
sf package install --apex-compile package --wait 20 --security-type AdminsOnly --package 04t5Y000001TsbQQAS
```

Install with SFDX CLI:

```shell
sfdx force:package:install --apexcompile package --wait 20 --securitytype AdminsOnly --package 04t5Y000001TsMOQA0
sfdx force:package:install --apexcompile package --wait 20 --securitytype AdminsOnly --package 04t5Y000001TsbQQAS
```

## Unlocked Package - `Nebula` namespace - v3.1.1
## Unlocked Package - `Nebula` namespace - v3.1.2

[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001TsMTQA0)
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001TsMTQA0)
[![Install Unlocked Package in a Sandbox](./images/btn-install-unlocked-package-sandbox.png)](https://test.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001TsbVQAS)
[![Install Unlocked Package in Production](./images/btn-install-unlocked-package-production.png)](https://login.salesforce.com/packaging/installPackage.apexp?p0=04t5Y000001TsbVQAS)

Install with SF CLI:

```shell
sf package install --apex-compile package --wait 20 --security-type AdminsOnly --package 04t5Y000001TsMTQA0
sf package install --apex-compile package --wait 20 --security-type AdminsOnly --package 04t5Y000001TsbVQAS
```

Install with SFDX CLI:

```shell
sfdx force:package:install --apexcompile package --wait 20 --securitytype AdminsOnly --package 04t5Y000001TsMTQA0
sfdx force:package:install --apexcompile package --wait 20 --securitytype AdminsOnly --package 04t5Y000001TsbVQAS
```

## Features
Expand Down
2 changes: 1 addition & 1 deletion nebula-query-and-search/main/classes/AggregateQuery.cls
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ global class AggregateQuery extends SOQL {
super.doGetLimitCountString() +
super.doGetOffetString();

System.debug(LoggingLevel.FINEST, this.query);
System.debug(System.LoggingLevel.FINEST, this.query);
return this.query;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<apiVersion>58.0</apiVersion>
<status>Active</status>
</ApexClass>
8 changes: 4 additions & 4 deletions nebula-query-and-search/main/classes/Query.cls
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ global class Query extends SOQL {
// If additional builder methods are later called, the builder methods will set hasChanged = true
this.hasChanged = false;

System.debug(LoggingLevel.FINEST, this.query);
System.debug(System.LoggingLevel.FINEST, this.query);
return this.query;
}

Expand Down Expand Up @@ -361,7 +361,7 @@ global class Query extends SOQL {
super.doGetLimitCountString() +
')';

System.debug(LoggingLevel.FINEST, childQuery);
System.debug(System.LoggingLevel.FINEST, childQuery);
return childQuery;
}

Expand All @@ -378,7 +378,7 @@ global class Query extends SOQL {
super.doGetLimitCountString() +
')';

System.debug(LoggingLevel.FINEST, subquery);
System.debug(System.LoggingLevel.FINEST, subquery);
return subquery;
}

Expand All @@ -391,7 +391,7 @@ global class Query extends SOQL {

String searchQuery = this.getSObjectType() + sobjectTypeOptions;

System.debug(LoggingLevel.FINEST, searchQuery);
System.debug(System.LoggingLevel.FINEST, searchQuery);
return searchQuery;
}

Expand Down
2 changes: 1 addition & 1 deletion nebula-query-and-search/main/classes/Query.cls-meta.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<apiVersion>58.0</apiVersion>
<status>Active</status>
</ApexClass>
2 changes: 1 addition & 1 deletion nebula-query-and-search/main/classes/RecordSearch.cls
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ global class RecordSearch extends SOSL {
// If additional builder methods are later called, the builder methods will set hasChanged = true
this.hasChanged = false;

System.debug(LoggingLevel.FINEST, this.searchQuery);
System.debug(System.LoggingLevel.FINEST, this.searchQuery);
return this.searchQuery;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<apiVersion>58.0</apiVersion>
<status>Active</status>
</ApexClass>
27 changes: 9 additions & 18 deletions nebula-query-and-search/main/classes/SOQL.cls
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ global abstract class SOQL implements Comparable {
private final String isoCurrency;

public IsoCurrency(String isoCode, Decimal currencyAmount) {
if (!UserInfo.isMultiCurrencyOrganization()) {
if (!System.UserInfo.isMultiCurrencyOrganization()) {
throw new SOQLException('IsoCurrency is only supported in multi-currency orgs');
}
this.isoCurrency = isoCode + currencyAmount;
Expand Down Expand Up @@ -522,7 +522,7 @@ global abstract class SOQL implements Comparable {
Integer lastFieldIndex = fields.size() - 1;
List<String> queryFieldPieces = new List<String>();
for (Integer i = 0; i < fields.size(); i++) {
SObjectField field = fields[i];
Schema.SObjectField field = fields[i];
// If any field in the chain is not accessible, then the user cant access the data, so return an empty list
if (!field.getDescribe().isAccessible()) {
return null;
Expand Down Expand Up @@ -619,10 +619,8 @@ global abstract class SOQL implements Comparable {
private String formatObjectForQueryString(Object valueToFormat) {
if (valueToFormat == null) {
return null;
} else if (valueToFormat instanceof List<Object>) {
return this.convertListToQueryString((List<Object>) valueToFormat);
} else if (valueToFormat instanceof Set<Object>) {
return this.convertSetToQueryString(valueToFormat);
} else if (valueToFormat instanceof Iterable<Object>) {
return this.convertIterableToQueryString((Iterable<Object>) valueToFormat);
} else if (valueToFormat instanceof Map<Object, Object>) {
return this.convertMapToQueryString(valueToFormat);
} else if (valueToFormat instanceof Date) {
Expand Down Expand Up @@ -653,26 +651,19 @@ global abstract class SOQL implements Comparable {
return input;
}

private String convertListToQueryString(List<Object> valueList) {
private String convertIterableToQueryString(Iterable<Object> valueIterable) {
List<String> parsedValueList = new List<String>();
for (Object value : valueList) {
Iterator<Object> valueIterator = valueIterable.iterator();
while (valueIterator.hasNext()) {
Object value = valueIterator.next();
parsedValueList.add(this.formatObjectForQueryString(value));
}
return '(' + String.join(parsedValueList, ', ') + ')';
}

private String convertSetToQueryString(Object valueSet) {
String unformattedString = String.valueOf(valueSet).replace('{', '').replace('}', '');
List<String> parsedValueList = new List<String>();
for (String collectionItem : unformattedString.split(',')) {
parsedValueList.add(this.formatObjectForQueryString(collectionItem));
}
return '(' + String.join(parsedValueList, ', ') + ')';
}

private String convertMapToQueryString(Object valueMap) {
Map<String, Object> untypedMap = (Map<String, Object>) Json.deserializeUntyped(Json.serialize(valueMap));
return this.convertSetToQueryString(untypedMap.keySet());
return this.convertIterableToQueryString(untypedMap.keySet());
}
}
}
2 changes: 1 addition & 1 deletion nebula-query-and-search/main/classes/SOQL.cls-meta.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<apiVersion>58.0</apiVersion>
<status>Active</status>
</ApexClass>
2 changes: 1 addition & 1 deletion nebula-query-and-search/main/classes/SOSL.cls-meta.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<apiVersion>58.0</apiVersion>
<status>Active</status>
</ApexClass>
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,13 @@ private class AggregateQuery_Tests {
static void it_should_cache_results() {
AggregateQuery aggregateQuery = new AggregateQuery(Schema.Opportunity.SObjectType);
aggregateQuery.cacheResults();
System.assertEquals(0, Limits.getQueries());
System.assertEquals(0, System.Limits.getQueries());

for (Integer i = 0; i < 3; i++) {
aggregateQuery.getResults();
}

System.assertEquals(1, Limits.getQueries());
System.assertEquals(1, System.Limits.getQueries());
}

@IsTest
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<apiVersion>58.0</apiVersion>
<status>Active</status>
</ApexClass>
34 changes: 23 additions & 11 deletions nebula-query-and-search/tests/classes/Query_Tests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ private class Query_Tests {
List<Account> accounts = simpleAccountQuery.getResults();
}

@IsTest
static void it_should_correctly_represent_sets_in_query_filters() {
String expectedName = 'someName';
String expectedQueryString = 'SELECT Id, Name FROM Account WHERE Name IN (\'' + expectedName + '\')';

String actualQuery = new Query(Schema.Account.SObjectType)
.filterWhere(Schema.Account.Name, SOQL.Operator.IS_IN, new Set<String>{ expectedName })
.getQuery();

System.Assert.areEqual(expectedQueryString, actualQuery);
}

@IsTest
static void it_should_return_results_for_an_advanced_query() {
Datetime now = System.now();
Expand All @@ -31,11 +43,11 @@ private class Query_Tests {
' AND LastModifiedDate <= ' +
now.format('yyyy-MM-dd\'T\'HH:mm:ss\'Z\'', 'Greenwich Mean Time') +
' AND Profile.Id != \'' +
UserInfo.getProfileId() +
System.UserInfo.getProfileId() +
'\'' +
' ORDER BY Profile.CreatedBy.LastModifiedDate ASC NULLS FIRST, Name ASC NULLS FIRST, Email ASC NULLS FIRST' +
' LIMIT 100 OFFSET 1 FOR VIEW';
List<SObjectField> fieldsToQuery = new List<SObjectField>{ Schema.User.IsActive, Schema.User.Alias };
List<Schema.SObjectField> fieldsToQuery = new List<Schema.SObjectField>{ Schema.User.IsActive, Schema.User.Alias };

Query userQuery = new Query(Schema.User.SObjectType)
.addFields(fieldsToQuery)
Expand All @@ -47,7 +59,7 @@ private class Query_Tests {
.includeFormattedValues()
.usingScope(SOQL.Scope.MINE)
.filterWhere(Schema.User.IsActive, SOQL.Operator.EQUALS, true)
.filterWhere(new SOQL.QueryField(Schema.User.SObjectType, 'Profile.Id'), SOQL.Operator.NOT_EQUAL_TO, UserInfo.getProfileId())
.filterWhere(new SOQL.QueryField(Schema.User.SObjectType, 'Profile.Id'), SOQL.Operator.NOT_EQUAL_TO, System.UserInfo.getProfileId())
.filterWhere(Schema.User.LastModifiedDate, SOQL.Operator.LESS_THAN_OR_EQUAL_TO, now)
.filterWhere(Schema.User.LastLoginDate, SOQL.Operator.GREATER_THAN_OR_EQUAL_TO, new SOQL.DateLiteral(SOQL.RelativeDateLiteral.LAST_N_DAYS, 3))
.filterWhere(Schema.User.CreatedDate, SOQL.Operator.LESS_THAN_OR_EQUAL_TO, new SOQL.DateLiteral(SOQL.FixedDateLiteral.LAST_WEEK))
Expand Down Expand Up @@ -118,7 +130,7 @@ private class Query_Tests {
' END' +
' FROM Task';

Test.startTest();
System.Test.startTest();

Map<Schema.SObjectType, List<Schema.SObjectField>> fieldsBySObjectType = new Map<Schema.SObjectType, List<Schema.SObjectField>>();

Expand All @@ -133,7 +145,7 @@ private class Query_Tests {
// Query the task object
Query taskQuery = new Query(Schema.Task.SObjectType).addPolymorphicFields(Schema.Task.WhoId, fieldsBySObjectType);

Test.stopTest();
System.Test.stopTest();

System.assertEquals(expectedQuery, taskQuery.getQuery());
}
Expand Down Expand Up @@ -232,7 +244,7 @@ private class Query_Tests {
@IsTest
static void it_should_return_results_when_filtering_with_iso_currency() {
// If multi-currency isn't enabled, then we cannot use IsoCurrency, so skip running this test
if (!UserInfo.isMultiCurrencyOrganization()) {
if (!System.UserInfo.isMultiCurrencyOrganization()) {
return;
}

Expand All @@ -249,20 +261,20 @@ private class Query_Tests {
Query userQuery = new Query(Schema.User.SObjectType).limitTo(1);

// First, verify that caching is not enabled by default
System.assertEquals(0, Limits.getQueries());
System.assertEquals(0, System.Limits.getQueries());
for (Integer i = 0; i < loops; i++) {
userQuery.getResults();
}
System.assertEquals(loops, Limits.getQueries());
System.assertEquals(loops, System.Limits.getQueries());

Test.startTest();
System.Test.startTest();

userQuery.cacheResults();
for (Integer i = 0; i < loops; i++) {
userQuery.getResults();
}
System.assertEquals(1, Limits.getQueries());
System.assertEquals(1, System.Limits.getQueries());

Test.stopTest();
System.Test.stopTest();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<apiVersion>58.0</apiVersion>
<status>Active</status>
</ApexClass>
Loading

0 comments on commit 269a787

Please sign in to comment.