Skip to content

Commit

Permalink
Merge pull request #1 from afawcett/master
Browse files Browse the repository at this point in the history
sync up from main repo
  • Loading branch information
douglascayers authored Nov 18, 2016
2 parents fb39469 + d42fbb8 commit f7aec55
Show file tree
Hide file tree
Showing 203 changed files with 27,123 additions and 5,723 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

rolluptool/.project

rolluptool/.settings/com.salesforce.ide.core.prefs

rolluptool/salesforce.schema

rolluptool/Referenced Packages/

12 changes: 12 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
language: java
sudo: false
branches:
only:
- master
env:
global:
- secure: "OmrJ9gTiMzTIWzO2X3vGIx1Yp7HnDY1SBsKChBcYhtb0G6XVlpit0GnkbSozEwnInATwC2XjrIwpliUJNizWuYhpwoH9r/iCVU7qG4MCYEVtFaDQmnPXeTvSOs5peC5tor0r6UkjiHIUF4WorFNidGXqXrCxGciF8RyV76ouuew="
- secure: "B6Uu3RCXUcXmQEedqGoYDVhmw5x8glATC7aquVSg/zbVOqc2W118Rhu0a0NK3DHLmtwlx8lyj3bGCph3LAJ1raQ0wyb7X5nsC/v1T1Z4gRo8nLjD1aYZiot2l7iwOSK6YN0mYwvIxjGo29AUL+wQXPxw2lj/MhO+LuIGh6bBliQ="
script:
- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && ant -lib lib/ant-salesforce.jar -Dsf.username=${SFUSER} -Dsf.password=${SFPWD} deployRunAllTests || [ "${TRAVIS_PULL_REQUEST}" != "false" ]'
- '[ "${TRAVIS_PULL_REQUEST}" != "false" ] && ant -lib lib/ant-salesforce.jar -Dsf.username=${SFUSER} -Dsf.password=${SFPWD} validateAllTests || [ "${TRAVIS_PULL_REQUEST}" = "false" ]'
246 changes: 235 additions & 11 deletions README.markdown

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions build.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
sf.serverurl = https://login.salesforce.com

sf.maxPoll = 100
37 changes: 37 additions & 0 deletions build.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<project name="dlrs" default="test" basedir="." xmlns:sf="antlib:com.salesforce">

<property file="build.properties"/>
<property environment="env"/>

<target name="deployRunAllTests">
<sf:deploy username="${sf.username}"
password="${sf.password}"
serverurl="${sf.serverurl}"
runAllTests="true"
logType="Detail"
deployRoot="rolluptool/src"
maxPoll="${sf.maxPoll}" />
</target>

<target name="deployRunNoTests">
<sf:deploy username="${sf.username}"
password="${sf.password}"
serverurl="${sf.serverurl}"
runAllTests="false"
logType="Detail"
deployRoot="rolluptool/src"
maxPoll="${sf.maxPoll}" />
</target>

<target name="validateAllTests">
<sf:deploy username="${sf.username}"
password="${sf.password}"
serverurl="${sf.serverurl}"
runAllTests="true"
logType="Detail"
deployRoot="src"
maxPoll="${sf.maxPoll}"
checkOnly="true" />
</target>

</project>
Binary file added images/newscheduledcalc.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/newscheduledcalcbutton.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added lib/ant-salesforce.jar
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<CustomApplication xmlns="http://soap.sforce.com/2006/04/metadata">
<defaultLandingTab>LookupRollupSummary__c</defaultLandingTab>
<defaultLandingTab>Welcome</defaultLandingTab>
<label>Declarative Lookup Rollup Summaries</label>
<tab>LookupRollupSummary__c</tab>
<tab>Welcome</tab>
<tab>ManageLookupRollupSummaries</tab>
<tab>LookupRollupSummaryLog__c</tab>
</CustomApplication>
13 changes: 6 additions & 7 deletions rolluptool/src/classes/ApexClassesSelector.cls
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
/**
* Performs various queries on the ApexClass object
**/
public with sharing class ApexClassesSelector extends SObjectSelector
public class ApexClassesSelector extends fflib_SObjectSelector
{
public List<Schema.SObjectField> getSObjectFieldList()
{
Expand Down Expand Up @@ -59,12 +59,11 @@ public with sharing class ApexClassesSelector extends SObjectSelector
**/
public Map<String, ApexClass> selectByName(Set<String> names)
{
assertIsAccessible();
List<ApexClass> apexClasses = Database.query(String.format(
'select {0} from {1} where Name in :names order by {2}',
new List<String>{getFieldListString(),
getSObjectName(),
getOrderBy()}));
List<ApexClass> apexClasses =
Database.query(
newQueryFactory().
setCondition('Name in :names').
toSOQL());
Map<String, ApexClass> mapByName = new Map<String, ApexClass>();
for(ApexClass apexClass : apexClasses)
mapByName.put(apexClass.Name, apexClass);
Expand Down
2 changes: 1 addition & 1 deletion rolluptool/src/classes/ApexClassesSelector.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>28.0</apiVersion>
<apiVersion>37.0</apiVersion>
<status>Active</status>
</ApexClass>
13 changes: 6 additions & 7 deletions rolluptool/src/classes/ApexTriggersSelector.cls
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
/**
* Performs various queries on the ApexTrigger object
**/
public with sharing class ApexTriggersSelector extends SObjectSelector
public class ApexTriggersSelector extends fflib_SObjectSelector
{
public List<Schema.SObjectField> getSObjectFieldList()
{
Expand Down Expand Up @@ -68,12 +68,11 @@ public with sharing class ApexTriggersSelector extends SObjectSelector
**/
public Map<String, ApexTrigger> selectByName(Set<String> names)
{
assertIsAccessible();
List<ApexTrigger> apexTriggers = Database.query(String.format(
'select {0} from {1} where Name in :names order by {2}',
new List<String>{getFieldListString(),
getSObjectName(),
getOrderBy()}));
List<ApexTrigger> apexTriggers =
Database.query(
newQueryFactory().
setCondition('Name in :names').
toSOQL());
Map<String, ApexTrigger> mapByName = new Map<String, ApexTrigger>();
for(ApexTrigger apexTrigger : apexTriggers)
mapByName.put(apexTrigger.Name, apexTrigger);
Expand Down
2 changes: 1 addition & 1 deletion rolluptool/src/classes/ApexTriggersSelector.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>28.0</apiVersion>
<apiVersion>37.0</apiVersion>
<status>Active</status>
</ApexClass>
23 changes: 11 additions & 12 deletions rolluptool/src/classes/AsyncApexJobsSelector.cls
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,8 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/

public with sharing class AsyncApexJobsSelector extends SObjectSelector
{
public override String getOrderBy()
{
return 'CreatedDate';
}

public class AsyncApexJobsSelector extends fflib_SObjectSelector
{
List<Schema.SObjectField> getSObjectFieldList()
{
return new List<Schema.SObjectField> {
Expand All @@ -49,6 +44,11 @@ public with sharing class AsyncApexJobsSelector extends SObjectSelector
{
return AsyncApexJob.sObjectType;
}

public override String getOrderBy()
{
return 'CreatedDate';
}

public List<AsyncApexJob> selectById(Set<ID> idSet)
{
Expand All @@ -63,12 +63,11 @@ public with sharing class AsyncApexJobsSelector extends SObjectSelector
Set<String> statuses = new Set<String> { 'Queued', 'Processing', 'Preparing' };
String jobType = 'BatchApex';
String query =
String.format(
'select {0} from {1} ' +
'where JobType = :jobType And ' +
newQueryFactory().
setCondition(
'JobType = :jobType And ' +
'ApexClass.Name in :classNames And ' +
'Status in :statuses',
new List<String>{getFieldListString(),getSObjectName()});
'Status in :statuses').toSOQL();
List<AsyncApexJob> jobs = (List<AsyncApexJob>)
Database.query(query);
return jobs.size()>0;
Expand Down
2 changes: 1 addition & 1 deletion rolluptool/src/classes/AsyncApexJobsSelector.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>24.0</apiVersion>
<apiVersion>37.0</apiVersion>
<status>Active</status>
</ApexClass>
175 changes: 175 additions & 0 deletions rolluptool/src/classes/CustomMetadataService.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/**
* Copyright (c) 2013, Andrew Fawcett
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the Andrew Fawcett, nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**/

/**
* Wraps the Apex Metadata API to provide create, update and delete operations around Custom Metadata SObject's
*
* NOTE: Upsert is currently not supported by the Metadata API
*
* TODO: Support bulk requests
* TODO: Support All Or Nothing (new for Metadata API v34.0)
**/
public class CustomMetadataService {

public static void createMetadata(SObjectType mdtType, List<Map<SObjectField, Object>> records) {

}

/**
* Insert the given Custom Metadata records into the orgs config
**/
public static void createMetadata(List<SObject> records) {
// Call Metadata API and handle response
MetadataService.MetadataPort service = createService();
List<MetadataService.SaveResult> results =
service.createMetadata(new List<MetadataService.Metadata> { toCustomMetadata(records[0]) });
handleSaveResults(results[0]);
}

/**
* Update the given Custom Metadata records in the orgs config
**/
public static void updateMetadata(List<SObject> records) {
// Call Metadata API and handle response
MetadataService.MetadataPort service = createService();
List<MetadataService.SaveResult> results =
service.updateMetadata(new List<MetadataService.Metadata> { toCustomMetadata(records[0]) });
handleSaveResults(results[0]);
}

/**
* Delete the given Custom Metadata records from the orgs config
**/
public static void deleteMetadata(SObjectType qualifiedMetadataType, List<String> customMetadataFullNames) {
MetadataService.MetadataPort service = createService();
List<String> qualifiedFullNames = new List<String>();
for(String customMetadataFullName : customMetadataFullNames)
qualifiedFullNames.add(qualifiedMetadataType.getDescribe().getName() + '.' + customMetadataFullName);
List<MetadataService.DeleteResult> results =
service.deleteMetadata('CustomMetadata', qualifiedFullNames);
handleDeleteResults(results[0]);
}

public class CustomMetadataServiceException extends Exception {}

/**
* Takes the SObject instance of the Custom Metadata Type and translates to a Metadata API Custmo Metadata Type
**/
private static MetadataService.CustomMetadata toCustomMetadata(SObject customMetadataRecord) {
MetadataService.CustomMetadata cm = new MetadataService.CustomMetadata();
cm.values = new List<MetadataService.CustomMetadataValue>();
SObjectType recordType = customMetadataRecord.getSObjectType();
cm.fullName = recordType.getDescribe().getName().replace('__mdt', '') + '.' + customMetadataRecord.get('DeveloperName');
cm.label = (String) customMetadataRecord.get('Label');
for(SObjectField sObjectField : recordType.getDescribe().fields.getMap().values()) {
DescribeFieldResult dsr = sObjectField.getDescribe();
if(!dsr.isCustom())
continue;
Object fieldValue = customMetadataRecord.get(sObjectField);
MetadataService.CustomMetadataValue cmdv = new MetadataService.CustomMetadataValue();
cmdv.field = dsr.getName();
if(dsr.getType() == Schema.DisplayType.Double) {
if(fieldValue!=null) {
Decimal fieldValueNumber = (Decimal) fieldValue;
// TODO: Bit of a hack, MDT Number fields seem to be populated with zeros when the VF bound field is emptied by the user?!?
if(fieldValueNumber != 0) {
fieldValueNumber = fieldValueNumber.setScale(dsr.getScale());
cmdv.value = fieldValueNumber.format();
}
}
} else {
cmdv.value = fieldValue + ''; // TODO: More work here, type conversion
}
cm.values.add(cmdv);
}
return cm;
}

/**
* Connect to the Metadata API
**/
private static MetadataService.MetadataPort createService()
{
MetadataService.MetadataPort service = new MetadataService.MetadataPort();
service.SessionHeader = new MetadataService.SessionHeader_element();
service.SessionHeader.sessionId = UserInfo.getSessionId();
return service;
}

/**
* Example helper method to interpret a SaveResult, throws an exception if errors are found
**/
private static void handleSaveResults(MetadataService.SaveResult saveResult)
{
// Nothing to see?
if(saveResult==null || saveResult.success)
return;
// Construct error message and throw an exception
if(saveResult.errors!=null)
{
List<String> messages = new List<String>();
messages.add(
(saveResult.errors.size()==1 ? 'Error ' : 'Errors ') +
'occured processing component ' + saveResult.fullName + '.');
for(MetadataService.Error error : saveResult.errors)
messages.add(
error.message + ' (' + error.statusCode + ').' +
( error.fields!=null && error.fields.size()>0 ?
' Fields ' + String.join(error.fields, ',') + '.' : '' ) );
if(messages.size()>0)
throw new CustomMetadataServiceException(String.join(messages, ' '));
}
if(!saveResult.success)
throw new CustomMetadataServiceException('Request failed with no specified error.');
}

/**
* Example helper method to interpret a SaveResult, throws an exception if errors are found
**/
private static void handleDeleteResults(MetadataService.DeleteResult deleteResult)
{
// Nothing to see?
if(deleteResult==null || deleteResult.success)
return;
// Construct error message and throw an exception
if(deleteResult.errors!=null)
{
List<String> messages = new List<String>();
messages.add(
(deleteResult.errors.size()==1 ? 'Error ' : 'Errors ') +
'occured processing component ' + deleteResult.fullName + '.');
for(MetadataService.Error error : deleteResult.errors)
messages.add(
error.message + ' (' + error.statusCode + ').' +
( error.fields!=null && error.fields.size()>0 ?
' Fields ' + String.join(error.fields, ',') + '.' : '' ) );
if(messages.size()>0)
throw new CustomMetadataServiceException(String.join(messages, ' '));
}
if(!deleteResult.success)
throw new CustomMetadataServiceException('Request failed with no specified error.');
}
}
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>28.0</apiVersion>
<apiVersion>37.0</apiVersion>
<status>Active</status>
</ApexClass>
Loading

0 comments on commit f7aec55

Please sign in to comment.