I am trying to create a dynamic query to csv class that will take any query and convert it to a csv and send it back to the caller. I would like to use keith-c's format logic because it's way cool and needed. BUT sobject.get('fieldname') returns back an Object.

I either need to cast it to the correct datatype or deal with it some how.

Any thoughts would be great, I don't want to create classes for every sobject type.


public class ConvertToCsv {

public static Blob convert(CustomQuery.CustomQueryResult pResult) {

String csvFile;
List<String> tmpFieldList = new List<String>();
List<String> tmpRow = new List<String>();

for (String field :pResult.getFields()) {

csvFile = ConvertToCsv.line(tmpFieldList);

for (sObject row :pResult.getResults) {
  for (String fieldKey :pResult.getFields()) {
  csvFile += ConvertToCsv.line(tmpRow);
  tmpRow = new List<String>();

return Blob.valueOf(csvFile);

private static String line(String[] cells) {
return String.join(cells, ',') + '\n';
private static String format(Date d)    {
return d != null ? '"' + d.format().escapeCsv() + '"' : '""';
private static String format(String s) {
return s != null ? '"' + s.escapeCsv() + '"' : '""';
private static String format(Decimal d, Integer scale) {
return d != null ? String.valueOf(d.setScale(scale)) : '';
private static String format(Decimal d) {
 return format(d, 2);
  • doesn't instanceOf help you here? As in if (row.get(fieldKey) instanceOf Date) tmpRow.add(ConvertToCsv((Date)row.get(fieldKey)) else if(row.get(fieldKey instanceOf Decimal) ... – cropredy Nov 6 '15 at 1:43
  • I've done this before, but ended up using field describes to get the datatype, and then running an if/else tree on the field/data type to return the string representation in the desired format. I couldn't figure a better way than to convert them the way I wanted the file to be created. I can dig up my solution if you want me to post it as an answer? – Ben Naylor Nov 6 '15 at 2:57

Decided I should just post my transformation tree. This could be better as a function, doing early returning, all that sort of stuff, but I was coding lazily at the time:

for (String field : this.fields) {

    //we only add it if there is a value, and we need to augment the output value based on the data type
    String fieldType = this.fieldTypes.get(field);
    if (s.get(field) != null) {
        if (fieldType == 'STRING' || fieldType == 'EMAIL' || fieldType == 'PICKLIST' || fieldType == 'REFERENCE' || fieldType == 'BASE64' || fieldType == 'TEXTAREA' || fieldType == 'ID' || fieldType == 'PHONE' || fieldType == 'URL') line += '"' + (String)s.get(field) + '"';
        if (fieldType == 'BOOLEAN') line += (((Boolean)s.get(field))?'true':'false');
        if (fieldType == 'DATE') line += Datetime.newInstance((Date)s.get(field), Time.newInstance(0,0,0,0)).format('yyyy-MM-dd');
        if (fieldType == 'DATETIME') line += ((Datetime)s.get(field)).format('yyyy-MM-dd hh:mm:ss');
        if (fieldType == 'INTEGER') line += (Integer)s.get(field);
        if (fieldType == 'DECIMAL' || fieldType == 'PERCENT' || fieldType == 'CURRENCY' || fieldType == 'DOUBLE') line += (Decimal)s.get(field);
    line += ',';

this.fields is a List of all the fields in the object (Account.getDescribe().fields.getMap().keyset() should do it I think).

this.fieldTypes is a Map of fieldname to datatype. This was created by looping through the fields.getMap() result, and calling .getType() on each field (returns a string used in the IF above).

As a utility class it could work, but theres a bunch of logic in there that might take a bit of processing time that could be optimised out.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.