Is it possible to get a list of key prefixes for all Metadata types in Salesforce org. Not the standard objects or custom objects, but Metadata types e.g. AccountSettings, ApexPage, CustomObject etc (listed here: https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_types_list.htm). Thank you!
1 Answer
You can't generally get the key prefixes of some objects (those that are not describe-able), but I've devised a workaround that actually (mosty) does just this. Here's the code:
Page
<apex:page controller="describe">
<style>
#output {
display: table;
}
#output div {
display: table-row;
}
#output div span {
display: table-cell;
padding: 2px;
}
</style>
<script>
var temp, parent;
function processResults(data) {
var index = 0, row, key, value;
if(data) {
while(index < data.validKeys.length) {
row = document.createElement("div");
key = document.createElement("span");
value = document.createElement("span");
key.appendChild(document.createTextNode(data.validKeys[index].key));
value.appendChild(document.createTextNode(data.validKeys[index].value));
row.appendChild(key);
row.appendChild(value);
temp.appendChild(row);
index++;
}
} else {
data = { nextValue: 0 };
}
if(data.nextValue!=null) {
{!$RemoteAction.describe.getList}(data.nextValue, processResults);
}
if(data.nextValue==null) {
data.nextValue = 262144;
parent.appendChild(temp);
}
document.getElementById("progress").value = data.nextValue;
row = document.getElementById("valuepercent");
if(row.firstChild) row.removeChild(row.firstChild);
key = parseInt(data.nextValue)/262144;
key = Math.floor(key*10000)/100;
row.appendChild(document.createTextNode(key+'%'));
}
window.addEventListener("load", function() { temp = document.getElementById("output"); parent = temp.parentNode; temp.parentNode.removeChild(temp); processResults(null); }, true);
</script>
<progress value="0" max="262143" id="progress"/>
<span id="valuepercent"></span>
<div id="output">
</div>
</apex:page>
Controller
global class describe {
global class KeyValuePair {
global String key, value;
global KeyValuePair(String k, String v) {
key = k;
value = v;
}
}
global class Result {
global Integer nextValue;
global KeyValuePair[] validKeys;
global Result() {
validKeys = new KeyValuePair[0];
}
}
@RemoteAction global static Result getList(Integer firstIndex) {
Result result = new Result();
String[] base62 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
base62.remove(0);
Integer a = (firstIndex & 258048) >> 12, b = (firstIndex & 4032) >> 6, c = (firstIndex & 63);
while(Limits.getCpuTime()<1000) {
try {
String key = base62[a]+base62[b]+base62[c];
Id value = Id.valueOf(key+'000000000000');
result.validKeys.add(new KeyValuePair(key, String.valueOf(value.getSObjectType())));
} catch(Exception e) { }
c++;
if(c>62) {
b++;
c = 0;
}
if(b>62) {
a++;
b = 0;
}
if(a>62) {
result.nextValue = null;
break;
}
result.nextValue = (a<<12)+(b<<6)+c;
}
return result;
}
}
This code basically brute-forces every key prefix by way of Id.getSObjectType()
to describe every single object in the system. It provides a very basic table that allows you to find any type of object that has a stable key prefix. It even includes some tables that I'm pretty sure we shouldn't be able to know about but have nevertheless been exposed to us.
Note: AccountSettings is a specific example of something that apparently doesn't have any key prefix at all. These are probably stored in some specific table that is a meta-table (contains a large number of settings that are all lumped into one). I would guess that the Organization table probably contains this information, but there's no documentation of how this data is organized. Other tables, like CustomObject, are actually aliased to a different type; for example, CustomObject is internally called CustomEntityDefinition.