package org.opencb.opencga.storage.core.manager; import org.apache.commons.lang.StringUtils; import org.opencb.commons.datastore.core.Query; import org.opencb.commons.datastore.core.QueryParam; import org.opencb.opencga.catalog.exceptions.CatalogException; import org.opencb.opencga.catalog.managers.CatalogManager; import org.opencb.opencga.storage.core.variant.adaptors.VariantDBAdaptor.VariantQueryParams; import org.opencb.opencga.storage.core.variant.adaptors.VariantDBAdaptorUtils; import java.util.*; import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; import static org.opencb.opencga.storage.core.variant.adaptors.VariantDBAdaptorUtils.*; /** * Created by pfurio on 02/12/16. */ public class CatalogUtils { protected final CatalogManager catalogManager; public CatalogUtils(CatalogManager catalogManager) { this.catalogManager = catalogManager; } /** * @see {@link org.opencb.opencga.catalog.db.mongodb.MongoDBUtils#ANNOTATION_PATTERN} */ public static final Pattern ANNOTATION_PATTERN = Pattern.compile("^([a-zA-Z\\\\.]+)([\\^=<>~!$]+.*)$"); /** * Parse a generic string with comma separated key=values and obtain a query understandable by catalog. * * @param value String of the kind age>20;ontologies=hpo:123,hpo:456;name=smith * @param getParam Get param function that will return null if the key string is not one of the accepted keys in catalog. For those * cases, they will be treated as annotations. * @return A query object. */ protected static Query parseSampleAnnotationQuery(String value, Function<String, QueryParam> getParam) { Query query = new Query(); List<String> annotationList = new ArrayList<>(); List<String> params = Arrays.asList(value.replaceAll("\\s+", "").split(";")); for (String param : params) { Matcher matcher = ANNOTATION_PATTERN.matcher(param); String key; if (matcher.find()) { key = matcher.group(1); if (getParam.apply(key) != null && !key.startsWith("annotation")) { query.put(key, matcher.group(2)); } else { // Annotation String myKey = key; if (!key.startsWith("annotation.")) { myKey = "annotation." + key; } annotationList.add(myKey + matcher.group(2)); } } } query.put("annotation", annotationList); return query; } @FunctionalInterface protected interface CatalogIdResolver { Long get(String value) throws CatalogException; } /** * Splits the value from the query (if any) and translates the IDs to numerical Ids. * @param query Query with the data * @param param Param to modify * @param toId Method to translate from String to numerical ID * @throws CatalogException if there is any catalog error */ protected void transformFilter(Query query, VariantQueryParams param, CatalogIdResolver toId) throws CatalogException { if (VariantDBAdaptorUtils.isValidParam(query, param)) { String valuesStr = query.getString(param.key()); // Do not try to transform ALL or NONE values if (isNoneOrAll(valuesStr)) { return; } VariantDBAdaptorUtils.QueryOperation queryOperation = VariantDBAdaptorUtils.checkOperator(valuesStr); if (queryOperation == null) { queryOperation = VariantDBAdaptorUtils.QueryOperation.OR; } List<String> values = VariantDBAdaptorUtils.splitValue(valuesStr, queryOperation); StringBuilder sb = new StringBuilder(); for (String value : values) { if (sb.length() > 0) { sb.append(queryOperation.separator()); } if (value.startsWith("!")) { sb.append('!'); value = value.substring(1); } if (StringUtils.isNumeric(value)) { sb.append(value); } else { sb.append(toId.get(value)); } } query.put(param.key(), sb.toString()); } } /** * Get the list of studies. Discards negated studies (starting with '!'). * * @see VariantDBAdaptorUtils#getStudyIds(List, org.opencb.commons.datastore.core.QueryOptions) * @param query Query with the values * @param sessionId User's sessionId * @return List of positive studies. * @throws CatalogException if there is an error with catalog */ public Set<Long> getStudies(Query query, String sessionId) throws CatalogException { List<Long> studies = getStudies(query, VariantQueryParams.STUDIES, sessionId); studies.addAll(getStudies(query, VariantQueryParams.RETURNED_STUDIES, sessionId)); // Use a set to remove duplicated return new HashSet<>(studies); } /** * Get the list of studies. Discards negated studies (starting with '!'). * * @see VariantDBAdaptorUtils#getStudyIds(List, org.opencb.commons.datastore.core.QueryOptions) * @param query Query with the values * @param param Param to check. {@link VariantQueryParams#STUDIES} or {@link VariantQueryParams#RETURNED_STUDIES} * @param sessionId User's sessionId * @return List of positive studies. * @throws CatalogException if there is an error with catalog */ public List<Long> getStudies(Query query, VariantQueryParams param, String sessionId) throws CatalogException { List<Long> studies = new ArrayList<>(); if (isValidParam(query, param)) { String value = query.getString(param.key()); if (isNoneOrAll(value)) { return studies; } VariantDBAdaptorUtils.QueryOperation op = checkOperator(value); List<String> values = splitValue(value, op); for (String id : values) { if (!VariantDBAdaptorUtils.isNegated(id) && !id.isEmpty()) { studies.add(catalogManager.getStudyId(id, sessionId)); } } } return studies; } /** * Gets any studyId referred in the Query. If none, tries to get the default study. If more than one, thrown an exception. * @param query Variants query * @param sessionId User's sessionId * @return Any study id * @throws CatalogException if there is a catalog error or the study is missing */ public long getAnyStudyId(Query query, String sessionId) throws CatalogException { Long id = getAnyStudyId(query, VariantQueryParams.STUDIES, sessionId); if (id == null) { id = getAnyStudyId(query, VariantQueryParams.RETURNED_STUDIES, sessionId); if (id == null) { id = catalogManager.getStudyId(null, sessionId); if (id < 0) { throw new CatalogException("Missing StudyId. Unable to get any variant!"); } } } return id; } private Long getAnyStudyId(Query query, VariantQueryParams param, String sessionId) throws CatalogException { List<Long> studies = getStudies(query, param, sessionId); if (studies.isEmpty()) { return null; } else { return studies.get(0); } } }