package org.molgenis.data.rest.v2;
import org.molgenis.data.Fetch;
import org.molgenis.data.UnknownAttributeException;
import org.molgenis.data.meta.AttributeType;
import org.molgenis.data.meta.model.Attribute;
import org.molgenis.data.meta.model.EntityType;
import org.molgenis.file.model.FileMetaMetaData;
import static java.lang.String.format;
import static org.molgenis.data.meta.AttributeType.FILE;
import static org.molgenis.data.support.EntityTypeUtils.isReferenceType;
/**
* Converts {@link AttributeFilter} to {@link Fetch}.
*/
public class AttributeFilterToFetchConverter
{
/**
* Converts {@link AttributeFilter} to {@link Fetch} based on {@link EntityType}.
*
* @param attrFilter the {@link AttributeFilter} to convert
* @param entityType {@link EntityType} for the entity
* @return {@link Fetch}, or null for 'all attributes' {@link AttributeFilter} there are no refEntities
* @throws UnknownAttributeException if the entity does not have one of the attributes mentioned in the filter
*/
public static Fetch convert(AttributeFilter attrFilter, EntityType entityType, String languageCode)
{
if (attrFilter == null || attrFilter.isStar())
{
return createDefaultEntityFetch(entityType, languageCode);
}
Fetch fetch = new Fetch();
createFetchContentRec(attrFilter, entityType, fetch, languageCode);
return fetch;
}
private static void createFetchContentRec(AttributeFilter attrFilter, EntityType entityType, Fetch fetch,
String languageCode)
{
if (attrFilter.isIncludeAllAttrs())
{
entityType.getAtomicAttributes()
.forEach(attr -> fetch.field(attr.getName(), createDefaultAttributeFetch(attr, languageCode)));
}
if (attrFilter.isIncludeIdAttr())
{
fetch.field(entityType.getIdAttribute().getName());
}
if (attrFilter.isIncludeLabelAttr())
{
fetch.field(entityType.getLabelAttribute(languageCode).getName());
}
attrFilter.forEach(entry ->
{
String attrName = entry.getKey();
Attribute attr = getAttribute(entityType, attrName);
createFetchContentRec(attrFilter, entityType, attr, fetch, languageCode);
});
}
private static void createFetchContentRec(AttributeFilter attrFilter, EntityType entityType, Attribute attr,
Fetch fetch, String languageCode)
{
AttributeType attrType = attr.getDataType();
switch (attrType)
{
case COMPOUND:
{
AttributeFilter subAttrFilter =
attrFilter != null ? attrFilter.getAttributeFilter(entityType, attr) : null;
if (subAttrFilter != null && !subAttrFilter.isIncludeAllAttrs())
{
// include compound attribute parts defined by filter
if (subAttrFilter.isIncludeIdAttr())
{
createFetchContentRec(subAttrFilter, entityType, entityType.getIdAttribute(), fetch,
languageCode);
}
if (subAttrFilter.isIncludeLabelAttr())
{
createFetchContentRec(subAttrFilter, entityType, entityType.getLabelAttribute(languageCode),
fetch, languageCode);
}
subAttrFilter.forEach(entry ->
{
String attrPartName = entry.getKey();
Attribute attrPart = attr.getChild(attrPartName);
createFetchContentRec(subAttrFilter, entityType, attrPart, fetch, languageCode);
});
}
else
{
// include all compound attribute parts
attr.getChildren().forEach(attrPart ->
{
createFetchContentRec(subAttrFilter, entityType, attrPart, fetch, languageCode);
});
}
break;
}
case CATEGORICAL:
case CATEGORICAL_MREF:
case FILE:
case MREF:
case XREF:
case ONE_TO_MANY:
{
AttributeFilter subAttrFilter =
attrFilter != null ? attrFilter.getAttributeFilter(entityType, attr) : null;
Fetch subFetch;
if (subAttrFilter != null)
{
subFetch = convert(subAttrFilter, attr.getRefEntity(), languageCode);
}
else
{
subFetch = createDefaultAttributeFetch(attr, languageCode);
}
fetch.field(attr.getName(), subFetch);
break;
}
// $CASES-OMITTED$
default:
fetch.field(attr.getName());
break;
}
}
private static Attribute getAttribute(EntityType entityType, String attrName)
{
Attribute attr = entityType.getAttribute(attrName);
if (attr == null)
{
throw new UnknownAttributeException(
format("Unknown attribute [%s] of entity [%s]", attrName, entityType.getName()));
}
return attr;
}
/**
* Create default entity fetch that fetches all attributes.
*
* @param entityType
* @return default entity fetch or null
*/
public static Fetch createDefaultEntityFetch(EntityType entityType, String languageCode)
{
boolean hasRefAttr = false;
Fetch fetch = new Fetch();
for (Attribute attr : entityType.getAtomicAttributes())
{
Fetch subFetch = createDefaultAttributeFetch(attr, languageCode);
if (subFetch != null)
{
hasRefAttr = true;
}
fetch.field(attr.getName(), subFetch);
}
return hasRefAttr ? fetch : null;
}
/**
* Create default fetch for the given attribute. For attributes referencing entities the id and label value are
* fetched. Additionally for file entities the URL is fetched. For other attributes the default fetch is null;
*
* @param attr
* @return default attribute fetch or null
*/
public static Fetch createDefaultAttributeFetch(Attribute attr, String languageCode)
{
Fetch fetch;
if (isReferenceType(attr))
{
fetch = new Fetch();
EntityType refEntityType = attr.getRefEntity();
String idAttrName = refEntityType.getIdAttribute().getName();
fetch.field(idAttrName);
String labelAttrName = refEntityType.getLabelAttribute(languageCode).getName();
if (!labelAttrName.equals(idAttrName))
{
fetch.field(labelAttrName);
}
if (attr.getDataType() == FILE)
{
fetch.field(FileMetaMetaData.URL);
}
}
else
{
fetch = null;
}
return fetch;
}
}