Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polymorphic fields #39

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions force-app/main/default/classes/Q.cls
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public class Q {
private Integer numberOfRowsToSkip;

private Set<String> fieldList = new Set<String>();
private List<QTypeOf.QTypeOfBuilder> typeOfList = new List<QTypeOf.QTypeOfBuilder>();
private List<QOrder> orders = new List<QOrder>();
private List<QICondition> conditions = new List<QICondition>();
private List<Q> subQueries = new List<Q>();
Expand Down Expand Up @@ -67,6 +68,14 @@ public class Q {
return this;
}

/**
* Instantiate a QTypeOf object for polymorphic relationship query support
*/
public static QTypeOf.QTypeOfBuilder typeOf(String fieldName) {
QTypeOf.QTypeOfBuilder typeOf = new QTypeOf.QTypeOfBuilder(fieldName);
return typeOf;
}

/**
* Add fields to the SELECT statement from Set of Strings
*/
Expand All @@ -77,6 +86,14 @@ public class Q {
return this;
}

/**
* Add fields to the SELECT statement with TYPEOF logic
*/
public Q selectFields(QTypeOf.QTypeOfBuilder typeOf) {
this.typeOfList.add(typeOf);
return this;
}

/**
* Add a LIMIT statement
*/
Expand Down Expand Up @@ -117,6 +134,10 @@ public class Q {
this.fieldList.add('(' + qb.build() + ')');
}

for (QTypeOf.QTypeOfBuilder typeOfVal : this.typeOfList) {
this.fieldList.add(typeOfVal.build());
}

if (!this.fieldList.isEmpty()) {
return 'SELECT ' + String.join(new List<String>(this.fieldList), ', ');
} else {
Expand Down
2 changes: 1 addition & 1 deletion force-app/main/default/classes/QAndGroup.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>47.0</apiVersion>
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
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>47.0</apiVersion>
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
2 changes: 1 addition & 1 deletion force-app/main/default/classes/QICondition.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>47.0</apiVersion>
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
2 changes: 1 addition & 1 deletion force-app/main/default/classes/QOrGroup.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>47.0</apiVersion>
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>
23 changes: 23 additions & 0 deletions force-app/main/default/classes/QTest.cls
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,29 @@ private class QTest {
Database.query(query);
}

@isTest
static void testTypeOf() {
String query =
new Q(Event.SObjectType)
.selectFields(Q.typeOf('What')
.when('Account').then(new Set<String> {'Phone', 'NumberOfEmployees'})
.when('Opportunity').then(new Set<String> {'Amount', 'CloseDate'})
.otherwise(new Set<String> {'Name', 'Email'})
)
.build();

String expected = 'SELECT ' +
'TYPEOF What ' +
'WHEN Account THEN Phone,NumberOfEmployees ' +
'WHEN Opportunity THEN Amount,CloseDate ' +
'ELSE Name,Email ' +
'END ' +
'FROM Event';

System.assertEquals(expected, query, 'It should output a query with a TYPEOF');
Database.query(query);
}

@isTest
static void testOrGroup() {
String query =
Expand Down
57 changes: 57 additions & 0 deletions force-app/main/default/classes/QTypeOf.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* QTypeOf is a class used to build TYPEOF statement in the SELECT statement
* @author Fred Hays
* @since 2020-04-29
*/

public class QTypeOf {

// interfaces used to enforce valid method chaining order
public interface IWhen {
IThen when(String objectName);
QTypeOfBuilder otherwise(Set<String> fieldNames);
}

public interface IThen {
IWhen then(Set<String> fieldSet);
}

public class QTypeOfBuilder implements IWhen, IThen {

private String whenFieldName;
private Set<String> elseFieldNames = new Set<String>();
private Map<String, Set<String>> whenItems = new Map<String, Set<String>>();
private String currentObjectName;

public QTypeOfBuilder(String whenFieldName) {
this.whenFieldName = whenFieldName;
}

public IThen when(String objectName) {
this.currentObjectName = objectName;
return this;
}

public IWhen then(Set<String> fieldSet) {
this.whenItems.put(this.currentObjectName, fieldSet);
return this;
}

public QTypeOfBuilder otherwise(Set<String> elseFieldNames) {
this.elseFieldNames = elseFieldNames;
return this;
}

public String build() {
String val = 'TYPEOF ' + this.whenFieldName + ' ';
for (String objectName : this.whenItems.keySet()) {
val += 'WHEN ' + objectName + ' THEN ' + String.join(new List<String>(this.whenItems.get(objectName)), ',') + ' ';
}
if (!this.elseFieldNames.isEmpty()) {
val += 'ELSE ' + String.join(new List<String>(this.elseFieldNames), ',') + ' ';
}
val += 'END';
return val;
}
}
}
5 changes: 5 additions & 0 deletions force-app/main/default/classes/QTypeOf.cls-meta.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<status>Active</status>
</ApexClass>