private static Attribute getQueryRuleAttribute(QueryRule queryRule, EntityType entityType) {
    String queryRuleField = queryRule.getField();
    if (queryRuleField == null) {
      throw new MolgenisValidationException(
          new ConstraintViolation(
              format(
                  "Query rule with operator [%s] is missing required field",
                  queryRule.getOperator().toString())));
    }

    Attribute attr = entityType.getAttribute(queryRuleField);
    if (attr == null) {
      throw new MolgenisValidationException(
          new ConstraintViolation(
              format(
                  "Query rule field [%s] refers to unknown attribute in entity type [%s]",
                  queryRuleField, entityType.getName())));
    }
    return attr;
  }
  private void validateQueryRule(QueryRule queryRule, EntityType entityType) {
    QueryRule.Operator operator = queryRule.getOperator();
    switch (operator) {
      case AND:
      case NOT:
      case OR:
        break;
      case EQUALS:
      case FUZZY_MATCH:
      case FUZZY_MATCH_NGRAM:
      case GREATER:
      case GREATER_EQUAL:
      case LESS:
      case LESS_EQUAL:
      case LIKE:
        {
          Attribute attr = getQueryRuleAttribute(queryRule, entityType);
          Object value = toQueryRuleValue(queryRule.getValue(), attr);
          queryRule.setValue(value);
          break;
        }
      case SEARCH:
        {
          Object queryRuleValue = queryRule.getValue();
          if (queryRuleValue != null && !(queryRuleValue instanceof String)) {
            // fix value type
            queryRule.setValue(queryRuleValue.toString());
          }
          break;
        }
      case IN:
      case RANGE:
        {
          Attribute attr = getQueryRuleAttribute(queryRule, entityType);
          Object queryRuleValue = queryRule.getValue();
          if (queryRuleValue != null) {
            if (!(queryRuleValue instanceof Iterable<?>)) {
              throw new MolgenisValidationException(
                  new ConstraintViolation(
                      format(
                          "Query rule with operator [%s] value is of type [%s] instead of [Iterable]",
                          operator, queryRuleValue.getClass().getSimpleName())));
            }

            // fix value types
            Iterable<?> queryRuleValues = (Iterable<?>) queryRuleValue;
            List<Object> values =
                stream(queryRuleValues.spliterator(), false)
                    .map(value -> toQueryRuleValue(value, attr))
                    .collect(toList());
            queryRule.setValue(values);
          }
          break;
        }
      case DIS_MAX:
      case NESTED:
      case SHOULD:
        queryRule
            .getNestedRules()
            .forEach(nestedQueryRule -> validateQueryRule(nestedQueryRule, entityType));
        break;
      default:
        throw new RuntimeException(format("Unknown query operator [%s]", operator.toString()));
    }
  }