You are currently browsing the monthly archive for January 2011.
This week I :
(1) Wrote and deployed a Sinatra App to Heroku to test Jeff Douglas’s code. It works! Link.
(2) Leveraged the Cinch framework to write an IRC Bot for the #salesforce IRC channel on Freenode. Please say hello to “Saasy” in the #salesforce channel and see what it can do.
(3) Wrote and deployed a simple Rails app (v. 3) to Heroku which displays the log from the IRC Bot (link edited 2/28/11).
Here are some takeaways:
(1) Getting started with Ruby can be a bit tough. There are often versioning issues and incompatibilities which can take a long time to solve. I was switching back between different versions of Ruby, Rails, and various gems — often finding that documentation was out of date. You also need to spend a fair amount of time on the command line, which can be difficult for folks used to a super IDE.
(2) Writing with Ruby is fun. Of course, there is a learning curve with anything, but there is a lot of syntactical sugar that makes writing Ruby one of my favorite things to do (once I get the hang of it).
(3) Heroku is awesome. I’ve written a couple Rails apps before but deployment was kind of pain. No longer! Heroku is super fun and super easy.
(4) The Ruby community is great. Even if sorting through blogs to find up-to-date instructions is not the most fun activity, there is tons of information out there and also lots of helpful people on various IRC channels (#heroku #ruby #cinch #rubyonrails).
So why not get started? For resources I highly highly recommend Peepcode, as well as the “Pickaxe”. For a (if you are doing Rails stuff, also the Agile Guide). For a quirkier, quicker, and in many ways more delightful (if not as comprehensive) approach, check out Why’s Guide to Ruby and learn the meaning of chunky bacon.
Special thanks to Domink Honnef, who provided helpful advice and put up with my safe harbor statement testing on the #cinch-bots channel, as well as aliasweird, apothecary, and others who made helpful suggestions re: the irc bot in #salesforce.
Problem:
You use the 10000 record limit on your queries but they still could fail since you might return 5000 in one and 6000 in the next leading to greater than 10000 records returned. Or potentially more annoying… running into the different limits at play when you are in a test method.
Solution:
Use my rapidly growing Limit Utilities class:
public class LimitsUtility
{
static final Integer PERCENT_PER_QUERY = 65;
public Integer rowsAvailable()
{
Integer rowLimit = Math.round( ( Limits.getLimitQueryRows() - Limits.getQueryRows() ) * ( PERCENT_PER_QUERY / 100.00 ) );
if (rowLimit < 15)
rowLimit = 1;
return rowLimit;
}
}
This function simply takes the total limit and subtracts the available rows, then only queries a certain percentage of the available rows (in this case, 65%).
Use as follows:
List<SObject> sos = [select id from MySObject__c limit = :LimitsUtility.rowsAvailable() ];
I’ve also created a little spreadsheet to show how fast you will burn down the queries at various percentages (assuming you are hitting a full record set).
Note that things won’t be quite this bad if you use my method, since it will drop the limit to 1 if you go below 15 available rows, giving you a little bit of an extra lifeline before you hit the limit. This code is now also available on Snipplr.
With the sponsorship of the phenomenal company Hoopla Software, I’ve put together a number of enhancements to the SOQLBuilder as included in Apex-lang, a community project headed by developer hero Richard Vanhook. For those who don’t know, SOQL Builder allows you to simply and reliably create queries like this:
new al.SoqlBuilder()
.selectx('name')
.fromx('Opportunity')
.wherex(new al.FieldCondition('employees').lessThan(10))
.toSoql();
I’ve added support for aggregate queries:
Count:
new al.SoqlBuilder()
.selectCount('Id')
.fromx('Opportunity')
.toSoql();
Sum:
new al.SoqlBuilder()
.selectSumx('Amount')
.fromx('Opportunity')
.toSoql();
Average:
new al.SoqlBuilder()
.selectAveragex('Amount')
.fromx('Opportunity')
.toSoql();
Max:
new al.SoqlBuilder()
.selectMaxx('Amount')
.fromx('Opportunity')
.toSoql();
Min:
new al.SoqlBuilder()
.selectMinx('Amount')
.fromx('Opportunity')
.toSoql();
I’ve also added support for Group by:
new al.SoqlBuilder()
.selectx('OwnerId')
.fromx('Opportunity')
.groupBy('OwnerId')
.toSoql();
Get Apex-lang here.
Here’s a video showing the sort of things that are possible with this library:
Although this technique has been around forever I’ve never seen it documented anywhere so I thought I’d share for all those looking to power up their Salesforce skilz.
Problem: You’ve got a record, potentially a junction object, and you want to create a new object if both of the other objects you are referencing exist but and update if there is an existing record with references to both of the other objects.
Solution:
(1) Create an external id field called “Composite_Key__c”
Make sure you set it to be Unique, Required, and the External id:
(2) Populate it with a composite id (id of object 1 + id of object 2)
If you are doing this via Apex (as I always do since I’m a code monkey)
myObject.Composite_Key__c = '' + object1.id + object2.id;
You can also set this via a workflow rule.
(3) Upsert on the composite key
upsert myObject Composite_Key__c;
Now you will get a new record if it is not there, and update the existing record if there is one already with that key.
As an added bonus, here’s what Force.com guru Simon Fell has to say about how awesome this is:
Upsert + External ID, there’s so many uses for this its hard to know where to start. The External Id is a flag on custom fields, when you turn it on, we index that field (improved query performance for filtering on that field), in addition it now allows you to use the upsert call which uses that external Id as the key instead of the Salesforce Id. If you’re syncing additional data sources with Salesforce, it makes that process much easier to handle. On additional use is to an external Id field as an operation identifier, SOAP over HTTP is not 100% reliable, if you make a create call and the response never makes it back to the client, its hard to work out if the data got created or not, by adding an operation Id custom field, you can make all your creates calls via the upsert call, simply assign a unique id (say a GUID) to the create you’re trying to do and call upsert. If something goes wrong and the response is lost in transit, you can simply make the upsert call again, if the original insert never happened, then there won’t be a row for that GUID and we’ll do the insert, or if we did the original insert, the row will now be there, and we’ll just update it. This can drastically simplify handling failure conditions.
Additional Acknowledgement: This technique shamelessly swiped from the ever percolating mind of Alex “Idea Exchange” Sutherland.


