Skip to content

Commit 74d5fd6

Browse files
authored
Merge pull request #23 from jongpie/feature/potential-refactor
Feature/potential refactor - slimming down SObjectRepo
2 parents 6cb2362 + f30b1d2 commit 74d5fd6

File tree

7 files changed

+334
-116
lines changed

7 files changed

+334
-116
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
3+
<apiVersion>38.0</apiVersion>
4+
<status>Active</status>
5+
</ApexClass>
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
@isTest
2+
public class AccountRepository_Tests {
3+
@testSetup
4+
static void setupData() {
5+
List<Account> accounts = new List<Account>();
6+
for(Integer i =0; i <3; i++) {
7+
Account account = new Account();
8+
account.FirstName = 'George' + i;
9+
account.LastName = 'Washington';
10+
11+
accounts.add(account);
12+
}
13+
14+
insert accounts;
15+
}
16+
17+
@isTest
18+
static void it_should_return_an_account_by_id() {
19+
//Given I have a known account Id
20+
//When I query for that record in particular
21+
//Then it should be returned
22+
Account account = [SELECT Id FROM Account LIMIT 1];
23+
24+
Test.startTest();
25+
Account returnedAccount = new AccountRepository().getById(account.Id);
26+
Test.stopTest();
27+
28+
System.assertEquals(account.Id,returnedAccount.Id);
29+
}
30+
31+
@isTest
32+
static void it_should_return_accounts_by_id_list() {
33+
//Given that I have known accounts
34+
//When I query for them by Id
35+
//Then the accounts should be returned
36+
37+
List<Account> expectedAccounts = [SELECT Id FROM Account];
38+
List<Id> expectedAccountIds = new List<Id>(new Map<Id, Account>(expectedAccounts).keySet());
39+
40+
Test.startTest();
41+
Map<Id,Account> returnedAccountsMap = new Map<Id,Account>(new AccountRepository().getById(expectedAccountIds));
42+
Test.stopTest();
43+
44+
System.assertEquals(expectedAccounts.size(),returnedAccountsMap.size());
45+
}
46+
47+
@isTest
48+
static void it_should_return_accounts_for_a_given_time_period() {
49+
//Given that I have accounts
50+
//When I query for them with a given field and time range
51+
//Then only accounts that match both those criteria should be returned
52+
List<Account> expectedAccounts = [SELECT Id FROM Account];
53+
54+
//Now create an account that should not be returned.
55+
Account account = TestDataGenerator.createPersonAccount();
56+
account.CreatedDate = System.today().addDays(-1);
57+
insert account;
58+
59+
Test.startTest();
60+
Schema.SObjectField source = Schema.Account.AccountSource;
61+
Map<Id,Account> returnedAccountsMap = new Map<Id,Account>(new AccountRepository().getByFieldAndTypeForGivenTimePeriod(source, 'Web', new DateLiterals().TODAY));
62+
Test.stopTest();
63+
64+
System.assertEquals(expectedAccounts.size(),returnedAccountsMap.size());
65+
for(Account acc : returnedAccountsMap.values()) {
66+
System.assertNotEquals(account.Id,acc.Id);
67+
}
68+
}
69+
70+
@isTest
71+
static void it_should_return_accounts_by_field_for_a_set_of_ids() {
72+
//Given I have a set of account Ids
73+
//When I query for those accounts and a specific field
74+
//Then the matching accounts should be returned
75+
List<Account> expectedAccounts = [SELECT Id FROM Account];
76+
Set<Id> accountIds = new Set<Id>(new List<Id>(new Map<Id,Account>(expectedAccounts).keySet()));
77+
78+
Test.startTest();
79+
Schema.SObjectField source = Schema.Account.AccountSource;
80+
List<Account> returnedAccounts = new AccountRepository().getByFieldForIds(source,'Web',accountIds);
81+
Test.stopTest();
82+
83+
System.assertEquals(expectedAccounts.size(),returnedAccounts.size());
84+
}
85+
86+
@isTest
87+
static void it_should_return_accounts_by_field_for_a_list_of_ids() {
88+
//Given I have a list of account Ids
89+
//When I query for those accounts and a specific field
90+
//Then the matching accounts should be returned
91+
List<Account> expectedAccounts = [SELECT Id FROM Account];
92+
List<Id> accountIds = new List<Id>(new Map<Id,Account>(expectedAccounts).keySet());
93+
94+
Test.startTest();
95+
Schema.SObjectField source = Schema.Account.AccountSource;
96+
List<Account> returnedAccounts = new AccountRepository().getByFieldForIds(source,'Web',accountIds);
97+
Test.stopTest();
98+
99+
System.assertEquals(expectedAccounts.size(),returnedAccounts.size());
100+
}
101+
102+
@isTest
103+
static void it_should_return_accounts_that_match_sosl_search_term() {
104+
//Given that I have a string
105+
//When I search accounts for that string
106+
//Then the accounts with a matching string should be returned
107+
108+
List<Account> expectedAccounts = (List<Account>)[FIND 'Web' IN ALL FIELDS RETURNING Account][0];
109+
110+
Test.startTest();
111+
Map<Id,Account> returnedAccountsMap = new Map<Id,Account>(new AccountRepository().searchInAllFields('Web'));
112+
Test.stopTest();
113+
114+
for(Account account : expectedAccounts) {
115+
System.assert(returnedAccountsMap.containsKey(account.Id));
116+
}
117+
}
118+
}

src/classes/ISObjectRepository.cls

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
public interface ISObjectRepository {
2-
32
// SOQL
4-
SObject getRecord(Id recordId);
5-
List<SObject> getList(List<Id> recordIdList);
3+
SObject getById(Id recordId);
4+
List<SObject> getById(List<Id> recordIdList);
5+
List<SObject> getByFieldAndTypeForGivenTimePeriod(Schema.SObjectField field, String operator, Object value);
66
// SOSL
77
List<SObject> searchInAllFields(String searchTerm);
8-
98
}

src/classes/SOQLUtils.cls

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public without sharing class SOQLUtils {
99
public static String toSOQLString(Object value) {
1010
if(value == null) return null;
1111
else if(value instanceof DateLiterals) {
12-
DateLiterals dateLiteral = (DateLiterals) value;
12+
DateLiterals dateLiteral = (DateLiterals)value;
1313
return dateLiteral.value;
1414
}
1515
else if(value instanceof Boolean) return String.valueOf((Boolean)value);
@@ -31,6 +31,8 @@ public without sharing class SOQLUtils {
3131
}
3232

3333
public static String wrapInSingleQuotes(String input) {
34+
if(input.toLowerCase() == 'null') return input;
35+
3436
if(input.left(1) != '\'') input = '\'' + input;
3537
if(input.right(1) != '\'') input = input + '\'';
3638
return input;

src/classes/SObjectRepository.cls

Lines changed: 35 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public abstract class SObjectRepository implements ISObjectRepository {
99
private Map<String, Schema.SObjectField> sobjectTypeFieldMap;
1010
private Set<String> queryFields;
1111
private String query;
12-
private Boolean addCommonQueryFields;
12+
private Boolean shouldAddCommonFields;
1313
private Schema.FieldSet fieldSet;
1414
private List<String> whereClauseList;
1515
private List<String> orderByList;
@@ -20,87 +20,35 @@ public abstract class SObjectRepository implements ISObjectRepository {
2020
this(fieldSet, true);
2121
}
2222

23-
protected SObjectRepository(Schema.FieldSet fieldSet, Boolean addCommonQueryFields) {
24-
this.fieldSet = fieldSet;
25-
this.addCommonQueryFields = addCommonQueryFields;
23+
protected SObjectRepository(Schema.FieldSet fieldSet, Boolean shouldAddCommonFields) {
24+
this.fieldSet = fieldSet;
25+
this.shouldAddCommonFields = shouldAddCommonFields;
2626

27-
this.sobjectType = fieldSet.getSObjectType();
28-
this.sobjectTypeFieldMap = this.sobjectType.getDescribe().fields.getMap();
29-
this.queryFields = new Set<String>();
30-
this.whereClauseList = new List<String>();
31-
this.orderByList = new List<String>();
32-
this.forUpdate = false;
27+
this.sobjectType = fieldSet.getSObjectType();
28+
this.sobjectTypeFieldMap = this.sobjectType.getDescribe().fields.getMap();
29+
this.queryFields = new Set<String>();
30+
this.whereClauseList = new List<String>();
31+
this.orderByList = new List<String>();
32+
this.forUpdate = false;
3333

3434
this.addCommonQueryFields();
3535
this.addFieldSetMembers();
3636
}
3737

38-
protected SObjectRepository whereIdEquals(Id recordId) {
39-
return this.whereFieldEquals(sobjectTypeFieldMap.get('Id'), SOQLUtils.toSOQLString(recordId));
38+
protected SObjectRepository whereFieldOperatorEqualsValue(Schema.SObjectField field, String operator, Object value) {
39+
return this.addCondition(field, operator, SOQLUtils.toSOQLString(value));
4040
}
4141

42-
protected SObjectRepository whereIdIn(Set<Id> recordIdSet) {
43-
return this.whereFieldIn(sobjectTypeFieldMap.get('Id'), new List<Id>(recordIdSet));
44-
}
45-
46-
protected SObjectRepository whereIdIn(List<Id> recordList) {
47-
return this.whereFieldIn(sobjectTypeFieldMap.get('Id'), recordList);
48-
}
49-
50-
protected SObjectRepository whereFieldEquals(Schema.SObjectField field, Object value) {
51-
return this.addCondition(field, '=', SOQLUtils.toSOQLString(value));
52-
}
53-
54-
protected SObjectRepository whereFieldDoesNotEqual(Schema.SObjectField field, Object value) {
55-
return this.addCondition(field, '!=', SOQLUtils.toSOQLString(value));
56-
}
57-
58-
protected SObjectRepository whereFieldGreaterThan(Schema.SObjectField field, Object value) {
59-
return this.addCondition(field, '>', SOQLUtils.toSOQLString(value));
60-
}
61-
62-
protected SObjectRepository whereFieldGreaterThanOrEqualTo(Schema.SObjectField field, Object value) {
63-
return this.addCondition(field, '>=', SOQLUtils.toSOQLString(value));
64-
}
65-
66-
protected SObjectRepository whereFieldLessThan(Schema.SObjectField field, Object value) {
67-
return this.addCondition(field, '<', SOQLUtils.toSOQLString(value));
68-
}
69-
70-
protected SObjectRepository whereFieldLessThanOrEqualTo(Schema.SObjectField field, Object value) {
71-
return this.addCondition(field, '<=', SOQLUtils.toSOQLString(value));
72-
}
73-
74-
protected SObjectRepository whereFieldIn(Schema.SObjectField field, List<Object> valueList) {
75-
return this.addCondition(field, 'IN', SOQLUtils.toSOQLString(valueList));
76-
}
77-
78-
protected SObjectRepository whereFieldNotIn(Schema.SObjectField field, List<Object> valueList) {
79-
return this.addCondition(field, 'NOT IN', SOQLUtils.toSOQLString(valueList));
80-
}
81-
82-
protected SObjectRepository whereFieldIncludes(Schema.SObjectField field, List<Object> valueList) {
83-
return this.addCondition(field, 'INCLUDES', SOQLUtils.toSOQLString(valueList));
84-
}
85-
86-
protected SObjectRepository whereFieldExcludes(Schema.SObjectField field, List<Object> valueList) {
87-
return this.addCondition(field, 'EXCLUDES', SOQLUtils.toSOQLString(valueList));
88-
}
89-
90-
protected SObjectRepository whereFieldLike(Schema.SObjectField field, String comparisonValue) {
91-
return this.addCondition(field, 'LIKE', comparisonValue);
92-
}
93-
94-
protected SObjectRepository whereFieldNotLike(Schema.SObjectField field, String comparisonValue) {
95-
return this.addCondition(field, 'NOT LIKE', comparisonValue);
42+
protected SObjectRepository whereFieldOperatorEqualsListValues(Schema.SObjectField field, String operator, List<Object> values) {
43+
return this.addCondition(field, operator, SOQLUtils.toSOQLString(values));
9644
}
9745

9846
protected SObjectRepository orderBy(Schema.SObjectField orderByField) {
9947
return this.orderBy(orderByField, null, null);
10048
}
10149

10250
protected SObjectRepository orderBy(Schema.SObjectField orderByField, SObjectRepository.SortOrder sortOrder) {
103-
return orderBy(orderByField, sortOrder, null);
51+
return this.orderBy(orderByField, sortOrder, null);
10452
}
10553

10654
protected SObjectRepository orderBy(Schema.SObjectField orderByField, SObjectRepository.SortOrder sortOrder, SObjectRepository.NullsSortOrder nullsSortOrder) {
@@ -137,29 +85,44 @@ public abstract class SObjectRepository implements ISObjectRepository {
13785
return Search.query(this.getSearchQuery(searchTerm, searchGroup))[0];
13886
}
13987

88+
89+
//CRUD
90+
protected void doInsert(SObject record) {doInsert(new List<SObject>{record});}
91+
protected void doInsert(List<SObject> records) {Database.insert(records);}
92+
protected void doUpsert(List<SObject> records) {Database.upsert(records);}
93+
protected void doUpdate(List<SObject> records) {Database.update(records);}
94+
protected void doDelete(List<SObject> records) {Database.delete(records);}
95+
14096
private void addCommonQueryFields() {
141-
if(!this.addCommonQueryFields) return;
97+
if(!this.shouldAddCommonFields) return;
14298

14399
// Auto-add the common fields that are available for the SObject Type
144-
List<String> commonFieldNameList = new List<String>{
100+
Set<String> commonFieldNameList = new Set<String>{
145101
'Id', 'CaseNumber', 'CreatedById', 'CreatedDate', 'IsClosed', 'LastModifiedById', 'LastModifiedDate',
146102
'Name', 'OwnerId', 'Subject', 'RecordTypeId', 'SystemModStamp'
147103
};
104+
148105
for(String commonFieldName : commonFieldNameList) {
106+
//Verify that the field is available on the object being used
149107
if(!this.sobjectTypeFieldMap.containsKey(commonFieldName)) continue;
150108

151-
this.queryFields.add(commonFieldName);
109+
//Salesforce has some inconsistencies in casing for standard field names. We'll go lowercase
110+
//here and in addFieldSetMembers() to ensure the set is unique
111+
this.queryFields.add(commonFieldName.toLowerCase());
152112
}
153113
}
154114

155115
private void addFieldSetMembers() {
156116
if(this.fieldSet == null) return;
157117

158-
for(Schema.FieldSetMember field : this.fieldSet.getFields()) this.queryFields.add(field.getFieldPath());
118+
for(Schema.FieldSetMember field : this.fieldSet.getFields()) {
119+
//Lowercase here as well to ensure strings added to the set are unique
120+
this.queryFields.add(field.getFieldPath().toLowerCase());
121+
}
159122
}
160123

161124
private SObjectRepository addCondition(Schema.SObjectField field, String operator, String value) {
162-
this.whereClauseList.add('(' + field + ' ' + operator.trim() + ' ' + value + ')');
125+
this.whereClauseList.add(field + ' ' + operator.trim() + ' ' + value);
163126
return this;
164127
}
165128

0 commit comments

Comments
 (0)