Pretty sure you need two queries and a Comparable
implementation. Luckily for you DISTANCE
is supported in SELECT clauses.
The sorting wrapper can be fairly simple:
public class DistanceSorter implements Comparable
{
final SObject record;
final Decimal distance;
public DistanceSorter(SObject record, Decimal distance)
{
this.record = record;
this.distance = distance;
}
public Integer evaluate(Object instance)
{
DistanceSorter that = (DistanceSorter)instance;
return (this.distance - that.distance).round(RoundingMode.UP);
// the above implementation implementation sorts closest first
// to reverse, just swap this and that
}
}
Then you can do the requisite two queries:
List<DistanceSorter> wrappers = new List<DistanceSorter>();
for (Project__c record : [SELECT DISTANCE(...) distance FROM Project__c WHERE ...])
{
wrappers.add(new DistanceSorter(record, (Decimal)record.get('distance'));
}
for (OtherObject__c record : [SELECT DISTANCE(...) distance FROM OtherObject__c WHERE ...])
{
wrappers.add(new DistanceSorter(record, (Decimal)record.get('distance'));
}
wrappers.sort();
List<SObject> combinedRecords = new List<SObject>();
for (DistanceSorter wrapper : wrappers)
{
combinedRecords.add(wrapper.record);
}
A parent-child subquery (also called a left outer join) that you're performing ends up returning a List<Assignment>
, not JSON. It only looks like JSON when you print it with a debug statement.
for(PermissionSet permSet :[<your query here>]){
// each permission set record has an embedded List<PermissionSetAssignment> with
// your query.
// Because that's true, the following line will compile
List<PermissionSetAssignment> children = permSet.Assignments;
}
You'd see the same thing if you tried to debug any other List
.
The nice thing about having the subquery return a List
is that you can simply call .size()
on it to get a count of the records.
// number of child records is simply the size of the list
permSet.Assignments.size();
The one gotcha to look out for is that after a certain, ill-defined, threshold (in number of child records), you may run into the following error
Aggregate Query has too many rows for direct assignment, use FOR loop
In that case, like the error says, you'd need to use a loop to iterate over all the child records for a given parent record. To get the number of child records in this case, you'd need to either increment some variable inside the loop, or store the child records in a collection (List
, Map
, or Set
), and you wouldn't be able to get the count until after that loop finishes.
Some example code of how to handle that situation would be
for(PermissionSet permSet :[<your query here>]){
// Pretend that we'd get an error if we try to access permSet.Assignments directly
// Declare a list to hold the children
// This list is re-created on every loop iteration (so Assignments for one
// PermissionSet won't be counted towards the number of Assignments for the next
// PermissionSet)
// If you need to keep the PermissionSetAssignment records for all PermissionSets,
// then you'd want to use a Map<Id, List<PermissionSetAssignment>> (keyed
// on the Id of the PermissionSet), and you'd want to declare it outside of all loops.
List<PermissionSetAssignment> children = new List<PermissionSetAssignment>();
for(PermissionSetAssignment permSetAssign : permSet.Assignments){
// Add the children to the list, one at a time
children.add(permSetAssign);
}
// Now that the (inner) loop is done, we can see how many children there are
system.debug('number of assignments: ' + children.size());
}
Best Answer
There's no such thing as UNION ALL, as you have probably found. I think the best thing to do is do a global describe, then loop through each object (table) and issue a COUNT() type SOQL query.
UPDATE: example code. Note that this fails for tables with >50K rows