fflib-apex-common icon indicating copy to clipboard operation
fflib-apex-common copied to clipboard

fflib_QueryFactory.InvalidFieldException when running user is not system admin

Open cropredyHelix opened this issue 4 years ago • 0 comments

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 have View 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

cropredyHelix avatar Dec 11 '20 22:12 cropredyHelix