6

I have written a SOQL-tool which allows me stuff like SELECT * FROM ...

It is based on APEX Schema functions and works very good. It expands and compiles a full list of fields in a string, which I feed into Database.query() like this:

 Database.query( xs.soql('SELECT * FROM User') ); 

For Standard Objects I have this use case:

I like to keep the APEX class which contains the Database.query() lets say at v36.0 for some reasons or simply because I don't want to touch it. At the same time I want to upgrade library APEX class xs which contains xs.soql() to e.g. v40.0 or v42.0. Now obviously the schema is composing me fields introduced post v36 by the xs-class which I'm querying in a v36 context in which those fields do not exist and this will and up in an exception. Sure thing and well understood. I have already a down-compatibility filter in place, but the setup of this logic and maintainace of it requires some manual work and testing. I want to avoid or reduce it - but still do the crazy thing described above ;-)

I wonder if there is some documentation available, which states in which API version every standard field has been introduced or depreciated or removed from the schema? Same question for objects itself.

User is the most important affected SObject, but also others like Order, ContentDocument or the Fieldservice-Stuff introduced around v39/40.

At least these documentations are not stating the API Versions for fields:

Are the other documentations for that?

Has someone maybe created a script or tool which digs this out of the schema by comparing result of different API versions to each others and digest the diff? I ask because we have started to do that and I don't want to reinvent the wheel...

1
  • This is one reason why I recommended to keep all your API versions the same. I realize it's not always feasible to be at the latest version, but you should consider moving all classes at once when you do move up, instead of just accepting the defaults. – sfdcfox May 9 '18 at 21:55
5

Crazy idea... Create a collection of Apex classes. One for every API version you are interested in getting metadata for. The sole purpose of that class is to call Schema.sObjectType.getDescribe() and return the result.

Very rough prototype:

public interface DescribeApiVersioned {
    Schema.DescribeSObjectResult getDescribe(Schema.sObjectType sObjectType);   
}

public class DescribeApiVersioned42 implements DescribeApiVersioned {
    public Schema.DescribeSObjectResult getDescribe(Schema.sObjectType sObjectType) {
        Schema.DescribeSObjectResult v42 = sObjectType.getDescribe();
        System.debug('Number of fields v42 : ' + v42.fields.getMap().size());
        return v42;
    }
}

public class DescribeApiVersioned38 implements DescribeApiVersioned {
    public Schema.DescribeSObjectResult getDescribe(Schema.sObjectType sObjectType) {
        Schema.DescribeSObjectResult v38 = sObjectType.getDescribe();
        System.debug('Number of fields v38 : ' + v38.fields.getMap().size());
        return v38;
    }
}

Then testing it with anonymous Apex from v42.0:

Schema.sObjectType t = ContentDocument.sObjectType;
DescribeApiVersioned v42 = new DescribeApiVersioned42();
DescribeApiVersioned v38 = new DescribeApiVersioned38();

Schema.DescribeSObjectResult cd42 = v42.getDescribe(t);
Schema.DescribeSObjectResult cd38 = v38.getDescribe(t);

System.debug('v42: ' + cd42.fields.getMap().size());
System.debug('v38: ' + cd38.fields.getMap().size());

Result:

13:08:15.2 (11189280)|USER_DEBUG|[4]|DEBUG|Number of fields v42 : 25
13:08:15.2 (11935260)|USER_DEBUG|[4]|DEBUG|Number of fields v38 : 24
13:08:15.2 (12562021)|USER_DEBUG|[8]|DEBUG|v42: 25
13:08:15.2 (12749702)|USER_DEBUG|[9]|DEBUG|v38: 25

Well dang. The v38.0 bounced back to 25 in the anonymous Apex. It appears Schema.DescribeSObjectResult alters its results depending on the API version of the class interacting with it. Not the API version of the class where it was called. All is not lost though. You would just need to push the code that builds the field set up from the describe results into the versioned class.

Update

I was thinking some more about this. If the interface is changed so that the versioned classes return the Schema.DescribeSObjectResult.fields.getMap() directly then it should be possible to see the results specific to the API version.

public interface DescribeFieldsApiVersioned {
    Map<String, Schema.DescribeFieldResult> getFields(Schema.sObjectType sObjectType);
}

If you want to make a deluxe version you could pass in the class name where you want to make the call from. Then use that to lookup the ApexClass.ApiVersion. Have a factory class the creates the correct DescribeApiVersioned implementer for that API version.

2
  • I suppose you could also have Apex call out to the REST API with a variety of versions. At least that way you don't have to create dozens of per-version classes. Caveat is that if request/response shape changes per version you have to account for that too. – Charles T May 8 '18 at 21:05
  • @CharlesT Yes. That is another option. Would also need the Remote Site setting plus it could burn through a number of API callouts if you are dealing with lots of API versions. The data could be pushed into the platform cache to – Daniel Ballinger May 8 '18 at 21:12

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.