Skip to content

Commit

Permalink
Fixes #40 and ports some changes from internal version over to public…
Browse files Browse the repository at this point in the history
… repo
  • Loading branch information
jamessimone committed Oct 1, 2024
1 parent b9db66f commit 20c18d3
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 84 deletions.
30 changes: 28 additions & 2 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
{
"trailingComma": "none",
"singleQuote": true,
"tabWidth": 2,
"printWidth": 120,
"tabWidth": 2
}
"arrowParens": "avoid",
"overrides": [
{
"files": "**/lwc/**/*.html",
"options": {
"parser": "lwc"
}
},
{
"files": "*.{cmp,page,component}",
"options": {
"parser": "html"
}
},
{
"files": "*.{cls, apex}",
"options": {
"parser": "apex"
}
}
],
"plugins": [
"prettier-plugin-apex"
],
"$schema": "https://json.schemastore.org/prettierrc"
}
16 changes: 13 additions & 3 deletions force-app/factory/RepoFactoryMock.cls
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,20 @@ public class RepoFactoryMock {
return this.results;
}

public override List<List<SObject>> getSosl(String searchTerm, List<Query> queries, List<AdditionalSoslObject> additionalSoslObjects) {
public override List<List<SObject>> getSosl(
String searchTerm,
List<Query> queries,
List<AdditionalSoslObject> additionalSoslObjects
) {
QueriesMade.addAll(queries);
this.clearState();
return new List<List<SObject>>{ this.results };
List<List<SObject>> results = new List<List<SObject>>{ this.results };
for (AdditionalSoslObject additionalSoslObject : additionalSoslObjects) {
if (additionalSoslObject.objectType != this.repoType) {
results.add(getResults(additionalSoslObject.objectType));
QueriesMade.addAll(additionalSoslObject.queryFilters);
}
}
return results;
}

public override Integer count(List<Query> queries) {
Expand Down
10 changes: 5 additions & 5 deletions force-app/repository/IRepository.cls
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@ public interface IRepository extends IDML {

List<List<SObject>> getSosl(String searchTerm, Query query);
List<List<SObject>> getSosl(String searchTerm, List<Query> queries);
List<List<SObject>> getSosl(
String searchTerm,
List<Query> queries,
List<AdditionalSoslObject> additionalSoslObjects
);
List<List<SObject>> getSosl(String searchTerm, List<Query> queries, List<AdditionalSoslObject> additionalSoslObjects);
IRepository setSearchGroup(SearchGroup searchGroup);

IRepository clearBindVars();
IRepository setAccessLevel(System.AccessLevel accessLevel);
IRepository setLimit(Integer limitAmount);
IRepository addSortOrder(Schema.SObjectField fieldToken, RepositorySortOrder sortOrder);
IRepository addSortOrder(List<Schema.SObjectField> fieldChain, RepositorySortOrder sortOrder);

IRepository addBaseFields(List<Schema.SObjectField> fields);
IRepository addParentFields(List<Schema.SObjectField> relationshipFields, List<Schema.SObjectField> parentFields);
IRepository addChildFields(Schema.SObjectField childFieldToken, List<SObjectField> childFields);
IRepository addChildFields(
Expand Down
15 changes: 12 additions & 3 deletions force-app/repository/Query.cls
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
public virtual class Query {
private Boolean isSoslEmpty = false;

public enum Operator {
EQUALS,
NOT_EQUALS,
Expand All @@ -20,6 +22,10 @@ public virtual class Query {
private static final String BIND_VAR_MERGE = 'bindVar{0}';
private static Integer BIND_VAR_NUMBER = 0;

public Boolean isSoslEmpty() {
return this.isSoslEmpty;
}

public Query usingParent(Schema.SObjectField parentField) {
return this.usingParent(new List<Schema.SObjectField>{ parentField });
}
Expand Down Expand Up @@ -238,6 +244,9 @@ public virtual class Query {
startingString = startingString.replace(operatorToReplace, newOperator);
}
}
if (startingString.endsWith('()')) {
this.isSoslEmpty = true;
}
return startingString;
}

Expand Down Expand Up @@ -303,16 +312,16 @@ public virtual class Query {
} else if (predicate instanceof Iterable<Object>) {
Iterable<Object> localPredicates = (Iterable<Object>) predicate;
if (localPredicates.iterator().hasNext() == false) {
return '';
return '()';
}
List<String> innerStrings = new List<String>();
for (Object innerPred : localPredicates) {
// recurse for string value
String innerString = this.getSoslPredicate(innerPred);
innerStrings.add(innerString);
}
String start = innerStrings.size() > 1 ? '(' : '';
String ending = innerStrings.size() > 1 ? ')' : '';
String start = '(' ;
String ending = ')' ;
return start + String.join(innerStrings, ',') + ending;
} else if (predicate instanceof String) {
String input = (String) predicate;
Expand Down
24 changes: 12 additions & 12 deletions force-app/repository/QueryTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,7 @@ private class QueryTests {
Id nullId = null;
String expectedQuery = '(Id = null OR Id != null)';

Query orQuery = Query.orQuery(
Query.equals(Account.Id, nullId),
Query.notEquals(Account.Id, nullId)
);
Query orQuery = Query.orQuery(Query.equals(Account.Id, nullId), Query.notEquals(Account.Id, nullId));

System.assertEquals(expectedQuery, orQuery.toString());
}
Expand All @@ -100,10 +97,7 @@ private class QueryTests {
Query.equals(Contact.LastName, 'asb'),
Query.andQuery(
Query.equals(Contact.FirstName, 'John'),
Query.orQuery(
Query.notEquals(Contact.LastName, 'a'),
Query.notEquals(Contact.LastName, 'b')
)
Query.orQuery(Query.notEquals(Contact.LastName, 'a'), Query.notEquals(Contact.LastName, 'b'))
)
}
)
Expand Down Expand Up @@ -180,10 +174,7 @@ private class QueryTests {
Query.equals(Account.AnnualRevenue, 50),
Query.equals(Account.Industry, 'Tech'),
Query.orQuery(
new List<Query>{
Query.equals(Account.NumberOfEmployees, 1),
Query.equals(Account.Site, 'web3')
}
new List<Query>{ Query.equals(Account.NumberOfEmployees, 1), Query.equals(Account.Site, 'web3') }
)
}
)
Expand Down Expand Up @@ -218,4 +209,13 @@ private class QueryTests {

Assert.areEqual('Id IN (\'' + String.join(fakeAccountIds, '\',\'') + '\')', query.toSoslString());
}

@IsTest
static void it_works_for_singular_value_in_collections() {
List<Id> fakeAccountIds = new List<Id>{ TestingUtils.generateId(Account.SObjectType) };

Query query = Query.equals(Account.Id, fakeAccountIds);

Assert.areEqual('Id IN (\'' + String.join(fakeAccountIds, '\',\'') + '\')', query.toSoslString());
}
}
65 changes: 35 additions & 30 deletions force-app/repository/Repository.cls
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@ public virtual without sharing class Repository implements IRepository {
private Integer limitAmount;
private SearchGroup soslSearchGroup = SearchGroup.ALL_FIELDS;

public Repository(
Schema.SObjectType repoType,
List<Schema.SObjectField> queryFields,
RepoFactory repoFactory
) {
public Repository(Schema.SObjectType repoType, List<Schema.SObjectField> queryFields, RepoFactory repoFactory) {
this.dml = repoFactory.getDml();
this.queryFields = queryFields;
this.repoType = repoType;
Expand Down Expand Up @@ -69,18 +65,20 @@ public virtual without sharing class Repository implements IRepository {
return this;
}

public Repository addSortOrder(
List<Schema.SObjectField> parentFieldChain,
RepositorySortOrder sortOrder
) {
public Repository addSortOrder(List<Schema.SObjectField> parentFieldChain, RepositorySortOrder sortOrder) {
this.fieldToSortOrder.put(Query.getBuiltUpParentFieldName(parentFieldChain), sortOrder);
return this;
}

public Repository addParentFields(
List<Schema.SObjectField> parentTypes,
List<Schema.SObjectField> parentFields
) {
public Repository addBaseFields(List<Schema.SObjectField> fields) {
Set<Schema.SObjectField> uniqueFields = new Set<Schema.SObjectField>(this.queryFields);
uniqueFields.addAll(fields);
this.queryFields.clear();
this.queryFields.addAll(uniqueFields);
return this;
}

public Repository addParentFields(List<Schema.SObjectField> parentTypes, List<Schema.SObjectField> parentFields) {
String parentBase = '';
for (SObjectField parentId : parentTypes) {
parentBase += parentId.getDescribe().getRelationshipName() + '.';
Expand Down Expand Up @@ -138,19 +136,16 @@ public virtual without sharing class Repository implements IRepository {
return this;
}

public Repository clearBindVars() {
this.bindVars.clear();
return this;
}

protected virtual Set<String> addSelectFields() {
this.baseSelectUsed = true;
return this.addSelectFields(this.queryFields);
}

private Set<String> addSelectFields(List<Schema.SObjectField> fields) {
Set<String> fieldStrings = new Set<String>{ 'Id' };
for (SObjectField field : fields) {
fieldStrings.add(field.getDescribe().getName());
}
return fieldStrings;
}

protected virtual String getFinalQuery(List<Query> queries) {
return this.getSelectAndFrom() +
this.addWheres(queries) +
Expand All @@ -159,7 +154,6 @@ public virtual without sharing class Repository implements IRepository {
}

protected virtual void clearState() {
this.bindVars.clear();
this.fieldToSortOrder.clear();
this.limitAmount = null;
}
Expand All @@ -181,11 +175,22 @@ public virtual without sharing class Repository implements IRepository {
return 'SELECT ' + String.join(localSelectFields, ', ') + '\nFROM ' + this.repoType;
}

private Set<String> addSelectFields(List<Schema.SObjectField> fields) {
Set<String> fieldStrings = new Set<String>{ 'Id' };
for (SObjectField field : fields) {
fieldStrings.add(field.getDescribe().getName());
}
return fieldStrings;
}

private String addWheres(List<Query> queries) {
List<String> wheres = new List<String>();
for (Query qry : queries) {
wheres.add(this.isSosl ? qry.toSoslString() : qry.toString());
this.bindVars.putAll(qry.getBindVars());
String possibleClauseToAdd = this.isSosl ? qry.toSoslString() : qry.toString();
if (qry.isSoslEmpty() == false) {
wheres.add(possibleClauseToAdd);
this.bindVars.putAll(qry.getBindVars());
}
}
return wheres.isEmpty() ? '' : '\nWHERE ' + String.join(wheres, '\nAND ');
}
Expand Down Expand Up @@ -225,7 +230,7 @@ public virtual without sharing class Repository implements IRepository {
return this.getSosl(searchTerm, queryFilters, new List<AdditionalSoslObject>());
}

public virtual List<List<SObject>> getSosl(
public virtual List<List<SObject>> getSosl(
String searchTerm,
List<Query> queryFilters,
List<AdditionalSoslObject> additionalSoslObjects
Expand Down Expand Up @@ -261,11 +266,11 @@ public virtual without sharing class Repository implements IRepository {
for (AdditionalSoslObject soslObject : soslObjects) {
objectsPreJoin.add(
soslObject.objectType +
'(' +
String.join(this.addSelectFields(soslObject.selectFields), ',') +
this.addWheres(soslObject.queryFilters) +
this.getLimitAmount(soslObject.queryLimit) +
')'
'(' +
String.join(this.addSelectFields(soslObject.selectFields), ',') +
this.addWheres(soslObject.queryFilters) +
this.getLimitAmount(soslObject.queryLimit) +
')'
);
}
return String.join(objectsPreJoin, ',');
Expand Down
50 changes: 34 additions & 16 deletions force-app/repository/RepositoryTests.cls
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,7 @@ private class RepositoryTests {

IRepository repo = new ContactPointAddressRepo();

Query notLike = Query.notLike(
ContactPointAddress.Name,
new List<String>{ cpa.Name, 'someOtherString' }
);
Query notLike = Query.notLike(ContactPointAddress.Name, new List<String>{ cpa.Name, 'someOtherString' });

List<ContactPointAddress> cpas = repo.get(notLike);

Expand Down Expand Up @@ -151,10 +148,7 @@ private class RepositoryTests {
.addSortOrder(Account.Name, RepositorySortOrder.ASCENDING)
.addSortOrder(
Account.AnnualRevenue,
new RepositorySortOrder(
RepositorySortOrder.SortOrder.DESCENDING,
RepositorySortOrder.NullSortOrder.LAST
)
new RepositorySortOrder(RepositorySortOrder.SortOrder.DESCENDING, RepositorySortOrder.NullSortOrder.LAST)
)
.setLimit(1)
.getAll();
Expand All @@ -177,17 +171,15 @@ private class RepositoryTests {
accounts[2].ParentId = accounts[3].Id;
update accounts;

List<Account> returnedAccounts = new AccountRepo()
IRepository accountRepo = new AccountRepo();
List<Account> returnedAccounts = accountRepo
.addParentFields(
new List<Schema.SObjectField>{ Account.ParentId },
new List<Schema.SObjectField>{ Account.Id, Account.Name }
)
.addSortOrder(
new List<Schema.SObjectField>{ Account.ParentId, Account.Name },
new RepositorySortOrder(
RepositorySortOrder.SortOrder.ASCENDING,
RepositorySortOrder.NullSortOrder.LAST
)
new RepositorySortOrder(RepositorySortOrder.SortOrder.ASCENDING, RepositorySortOrder.NullSortOrder.LAST)
)
.setLimit(1)
.getAll();
Expand All @@ -200,9 +192,7 @@ private class RepositoryTests {

@IsTest
static void it_should_decorate_dml_methods() {
IRepository repo = new RepoFactory()
.setFacade(new RepoFactoryMock.FacadeMock())
.getProfileRepo();
IRepository repo = new RepoFactory().setFacade(new RepoFactoryMock.FacadeMock()).getProfileRepo();
Account acc = new Account();
List<Account> accs = new List<Account>{ acc };

Expand Down Expand Up @@ -277,6 +267,34 @@ private class RepositoryTests {
System.assertEquals(record.Id, results.get(1).get(0).Id);
}

@IsTest
static void it_handles_empty_sosl_searches() {
ContactPointPhone record = new ContactPointPhone(TelephoneNumber = 'hello universe');
insert record;

Test.setFixedSearchResults(new List<Id>{ record.Id });

List<List<SObject>> results = new ContactPointAddressRepo()
.setSearchGroup(SearchGroup.NAME_FIELDS)
.getSosl(
'hel',
new List<Query>(),
new List<AdditionalSoslObject>{
new AdditionalSoslObject(
ContactPointPhone.SObjectType,
new List<Schema.SObjectField>(),
new List<Query>{
Query.notEquals(ContactPointPhone.Id, new List<Id>()),
Query.equals(ContactPointPhone.TelephoneNumber, 'hello universe')
},
1
)
}
);

System.assertEquals(record.Id, results.get(1).get(0).Id);
}

private class GroupMemberRepo extends Repository {
public GroupMemberRepo() {
super(GroupMember.SObjectType, new List<Schema.SObjectField>{ GroupMember.GroupId }, new RepoFactory());
Expand Down
Loading

0 comments on commit 20c18d3

Please sign in to comment.