fflib-apex-common
fflib-apex-common copied to clipboard
fflib_QueryFactory.InvalidFieldException when running user is not system admin
This error
fflib_QueryFactory.InvalidFieldException: Invalid field 'FieldHistoryType' for object 'FieldHistoryArchive'
is thrown in method getFieldPath()
- Error does not occur when running user has
Admin
profile - Error does occur when running user is not
Admin
and does not haveView All Data
permission
when used in code as:
FieldHistoryArchive[] fhas =
FieldHistoryArchivesSelector.newInstance().selectByFieldHistoryTypeAndParentId(Account.SObjectType,parentIds);
Relevant fflib_QueryFactory code is here:
private String getFieldPath(String fieldName){
if(!fieldName.contains('.')){ //single field
Schema.SObjectField token = fflib_SObjectDescribe.getDescribe(table).getField(fieldName.toLowerCase());
if(token == null)
throw new InvalidFieldException(fieldName,this.table);
if (enforceFLS)
fflib_SecurityUtils.checkFieldIsReadable(this.table, token);
return token.getDescribe().getName();
}
Relevant selector is here:
for a Selector on FieldHistoryArchive, an OOTB object that comes with Shield Field Audit Trail that looks like this:
public inherited sharing class FieldHistoryArchivesSelector extends ApplicationSelector implements IFieldHistoryArchivesSelector {
public override String getOrderBy() {return 'FieldHistoryType ASC,ParentId ASC, CreatedDate DESC';} // required per doc
private static final Boolean INCLUDE_FIELDSETS= false; // false is default, if true, class must include getSobjectFieldSetList
private static final Boolean ENFORCE_CRUD= false; // true is default
private static final Boolean ENFORCE_FLS= false; // false is default
private static final Boolean SORT_SELECT_FIELDS= true; // true is default
public List<Schema.SObjectField> getSObjectFieldList() {
return new List<Schema.SObjectField> {
FieldHistoryArchive.CreatedDate,
FieldHistoryArchive.FieldHistoryType,
FieldHistoryArchive.HistoryId,
FieldHistoryArchive.ParentId
};
}
public FieldHistoryArchivesSelector() {
super(INCLUDE_FIELDSETS,ENFORCE_CRUD,ENFORCE_FLS,SORT_SELECT_FIELDS);
}
public static IFieldHistoryArchivesSelector newInstance() {
return (IFieldHistoryArchivesSelector) Application.Selector.newInstance(new FieldHistoryArchive().getSObjectType());
}
public Schema.SObjectType getSobjectType() {return new FieldHistoryArchive().getSObjectType();}
public virtual FieldHistoryArchive[] selectById(set<ID> ids) {
if (ids.isEmpty()) return new List<FieldHistoryArchive> ();
fflib_QueryFactory qF = newQueryFactory()
.setCondition('Id IN :ids');
return Database.query(qF.toSOQL());
}
public FieldHistoryArchive[] selectByFieldHistoryTypeAndParentId(SObjectType sobjType, Set<Id> parentIds) {
if (parentIds.isEmpty() || sobjType== null) {return new List<FieldHistoryArchive>();}
String fhType = String.valueOf(sobjType);
fflib_QueryFactory qF = newQueryFactory()
.setCondition('FieldHistoryType = :fhType AND ParentId IN :parentIds');
FieldHistoryArchive[] results = Database.query(qF.toSOQL());
return results;
}
Notes:
- fflib_SobjectDescribe class in my org is V50 (to gain access to objects and fields added in last few releases)
- fflib_QueryFactory class is also at V50
- If I change the selector to not use
fflib_QueryFactory
and instead just construct the SOQL as static or dynamic SOQL, when executed by the running, non-Admin user, the query finds the records as expected.
Analysis
I think this has something to do with certain objects that are otherwise inaccessible to the running user per Describe but are available to the running user where CRUD is not enforced or otherwise not specifiable. FieldHistoryArchive
appears to be one of these. So, fflib_QueryFactory
can't construct the query from the provided fieldnames. If I'm right, then perhaps the exception could provide more hints as to the range of possible causes:
- typo (eg.
StrgeName
) - standard field added after the fflib_SObjectDescribe.cls version
- running user doesn't have access to Describe for this object or field