// Path: olastic-core/src/test/java/com/hevelian/olastic/core/TestUtils.java
// public static void checkFilterGrandChildEqualsQuery(String query, String field, String value,
//         String child, String grandChild) {
//     JSONObject childObj = new JSONObject(query).getJSONObject("has_child");
//     String childType = (String) childObj.get("type");
//     assertEquals(child, childType);
//     JSONObject subChildObj = childObj.getJSONObject("query").getJSONObject("has_child");
//     String subChildType = (String) subChildObj.get("type");
//     assertEquals(grandChild, subChildType);
//     JSONObject rootObj;
//     rootObj = subChildObj.getJSONObject("query").getJSONObject("term");
// 
//     String fieldName = field + ".keyword";
//     JSONObject valueObject = rootObj.getJSONObject(fieldName);
//     String actualValue = (String) valueObject.get("value");
//     assertEquals(value.substring(1, value.length() - 1), actualValue);
// }
// 
// Path: olastic-core/src/test/java/com/hevelian/olastic/core/TestUtils.java
// public static void checkFilterGrandParentEqualsQuery(String query, String field, String value,
//         String parent, String grandParent, String queryKey, String valueKey) {
//     JSONObject childObj = new JSONObject(query).getJSONObject("has_parent");
//     String childType = (String) childObj.get("parent_type");
//     assertEquals(parent, childType);
//     JSONObject subChildObj = childObj.getJSONObject("query").getJSONObject("has_parent");
//     String subChildType = (String) subChildObj.get("parent_type");
//     assertEquals(grandParent, subChildType);
//     JSONObject rootObj;
//     rootObj = subChildObj.getJSONObject("query").getJSONObject(queryKey);
// 
//     String fieldName = field + ".keyword";
//     JSONObject valueObject = rootObj.getJSONObject(fieldName);
//     String actualValue = (String) valueObject.get(valueKey);
//     assertEquals(value.substring(1, value.length() - 1), actualValue);
// }
// 
// Path: olastic-core/src/test/java/com/hevelian/olastic/core/TestUtils.java
// public static void checkFilterParentEqualsQuery(String query, String parent, String field,
//         String value) {
//     checkFilterParentEqualsQueryInternal(query, parent, field, value, false);
// }
// 
// Path: olastic-core/src/main/java/com/hevelian/olastic/core/api/uri/queryoption/expression/member/ExpressionMember.java
// public interface ExpressionMember extends LogicalExpression, LambdaExpression, MethodExpression {
// 
// }
// 
// Path: olastic-core/src/main/java/com/hevelian/olastic/core/api/uri/queryoption/expression/member/impl/ExpressionResult.java
// @AllArgsConstructor
// @Getter
// public class ExpressionResult extends BaseMember {
// 
//     private final QueryBuilder queryBuilder;
// 
//     @Override
//     public ExpressionResult and(ExpressionMember expressionMember)
//             throws ODataApplicationException {
//         return new ExpressionResult(boolQuery().must(queryBuilder)
//                 .must(((ExpressionResult) expressionMember).getQueryBuilder()));
//     }
// 
//     @Override
//     public ExpressionResult or(ExpressionMember expressionMember) throws ODataApplicationException {
//         return new ExpressionResult(boolQuery().should(queryBuilder)
//                 .should(((ExpressionResult) expressionMember).getQueryBuilder()));
//     }
// 
//     @Override
//     public ExpressionResult not() throws ODataApplicationException {
//         return new ExpressionResult(boolQuery().mustNot(queryBuilder));
//     }
// }


import static com.hevelian.olastic.core.TestUtils.checkFilterGrandChildEqualsQuery;
import static com.hevelian.olastic.core.TestUtils.checkFilterGrandParentEqualsQuery;
import static com.hevelian.olastic.core.TestUtils.checkFilterParentEqualsQuery;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfo;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Test;
import com.hevelian.olastic.core.api.uri.queryoption.expression.member.ExpressionMember;
import com.hevelian.olastic.core.api.uri.queryoption.expression.member.impl.ExpressionResult;
        JSONObject queryObject = rootObj.getJSONObject("query");
        JSONArray must = queryObject.getJSONObject("bool").getJSONArray("must");
        JSONObject firstTermValue = must.getJSONObject(0).getJSONObject("term")
                .getJSONObject("_dimension.name");
        assertEquals("Validity", firstTermValue.get("value"));
        JSONObject secondTermValue = must.getJSONObject(1).getJSONObject("term")
                .getJSONObject("_dimension.state");
        assertEquals("true", secondTermValue.get("value"));
    }

    @Test
    public void visitMember_ChildLambdaAnyByComplexType_correctESQuery() throws Exception {
        String rawODataPath = "/author";
        String rawQueryPath = "$filter=book/any(b:b/_dimension/any(d:(d/name eq 'Validity' and d/state eq 'true')))";
        UriInfo uriInfo = buildUriInfo(defaultMetadata, defaultOData, rawODataPath, rawQueryPath);
        ExpressionMember result = uriInfo.getFilterOption().getExpression()
                .accept(new ElasticSearchExpressionVisitor());
        String query = ((ExpressionResult) result).getQueryBuilder().toString();

        JSONObject childObj = new JSONObject(query).getJSONObject("has_child");
        String actualType = (String) childObj.get("type");
        assertEquals("book", actualType);

        JSONObject rootObj = childObj.getJSONObject("query").getJSONObject("nested");
        String actualNestedType = (String) rootObj.get("path");
        assertEquals("_dimension", actualNestedType);
        JSONObject queryObject = rootObj.getJSONObject("query");
        JSONArray must = queryObject.getJSONObject("bool").getJSONArray("must");
        JSONObject firstTermValue = must.getJSONObject(0).getJSONObject("term")
                .getJSONObject("_dimension.name");
// Path: olastic-core/src/test/java/com/hevelian/olastic/core/TestUtils.java
// public static void checkFilterGrandChildEqualsQuery(String query, String field, String value,
//         String child, String grandChild) {
//     JSONObject childObj = new JSONObject(query).getJSONObject("has_child");
//     String childType = (String) childObj.get("type");
//     assertEquals(child, childType);
//     JSONObject subChildObj = childObj.getJSONObject("query").getJSONObject("has_child");
//     String subChildType = (String) subChildObj.get("type");
//     assertEquals(grandChild, subChildType);
//     JSONObject rootObj;
//     rootObj = subChildObj.getJSONObject("query").getJSONObject("term");
// 
//     String fieldName = field + ".keyword";
//     JSONObject valueObject = rootObj.getJSONObject(fieldName);
//     String actualValue = (String) valueObject.get("value");
//     assertEquals(value.substring(1, value.length() - 1), actualValue);
// }
// 
// Path: olastic-core/src/test/java/com/hevelian/olastic/core/TestUtils.java
// public static void checkFilterGrandParentEqualsQuery(String query, String field, String value,
//         String parent, String grandParent, String queryKey, String valueKey) {
//     JSONObject childObj = new JSONObject(query).getJSONObject("has_parent");
//     String childType = (String) childObj.get("parent_type");
//     assertEquals(parent, childType);
//     JSONObject subChildObj = childObj.getJSONObject("query").getJSONObject("has_parent");
//     String subChildType = (String) subChildObj.get("parent_type");
//     assertEquals(grandParent, subChildType);
//     JSONObject rootObj;
//     rootObj = subChildObj.getJSONObject("query").getJSONObject(queryKey);
// 
//     String fieldName = field + ".keyword";
//     JSONObject valueObject = rootObj.getJSONObject(fieldName);
//     String actualValue = (String) valueObject.get(valueKey);
//     assertEquals(value.substring(1, value.length() - 1), actualValue);
// }
// 
// Path: olastic-core/src/test/java/com/hevelian/olastic/core/TestUtils.java
// public static void checkFilterParentEqualsQuery(String query, String parent, String field,
//         String value) {
//     checkFilterParentEqualsQueryInternal(query, parent, field, value, false);
// }
// 
// Path: olastic-core/src/main/java/com/hevelian/olastic/core/api/uri/queryoption/expression/member/ExpressionMember.java
// public interface ExpressionMember extends LogicalExpression, LambdaExpression, MethodExpression {
// 
// }
// 
// Path: olastic-core/src/main/java/com/hevelian/olastic/core/api/uri/queryoption/expression/member/impl/ExpressionResult.java
// @AllArgsConstructor
// @Getter
// public class ExpressionResult extends BaseMember {
// 
//     private final QueryBuilder queryBuilder;
// 
//     @Override
//     public ExpressionResult and(ExpressionMember expressionMember)
//             throws ODataApplicationException {
//         return new ExpressionResult(boolQuery().must(queryBuilder)
//                 .must(((ExpressionResult) expressionMember).getQueryBuilder()));
//     }
// 
//     @Override
//     public ExpressionResult or(ExpressionMember expressionMember) throws ODataApplicationException {
//         return new ExpressionResult(boolQuery().should(queryBuilder)
//                 .should(((ExpressionResult) expressionMember).getQueryBuilder()));
//     }
// 
//     @Override
//     public ExpressionResult not() throws ODataApplicationException {
//         return new ExpressionResult(boolQuery().mustNot(queryBuilder));
//     }
// }


// Path: olastic-core/src/test/java/com/hevelian/olastic/core/api/uri/queryoption/expression/ElasticSearchExpressionRelationsTest.java
import static com.hevelian.olastic.core.TestUtils.checkFilterGrandChildEqualsQuery;
import static com.hevelian.olastic.core.TestUtils.checkFilterGrandParentEqualsQuery;
import static com.hevelian.olastic.core.TestUtils.checkFilterParentEqualsQuery;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfo;
import org.json.JSONArray;
import org.json.JSONObject;
import org.junit.Test;
import com.hevelian.olastic.core.api.uri.queryoption.expression.member.ExpressionMember;
import com.hevelian.olastic.core.api.uri.queryoption.expression.member.impl.ExpressionResult;

        JSONObject queryObject = rootObj.getJSONObject("query");
        JSONArray must = queryObject.getJSONObject("bool").getJSONArray("must");
        JSONObject firstTermValue = must.getJSONObject(0).getJSONObject("term")
                .getJSONObject("_dimension.name");
        assertEquals("Validity", firstTermValue.get("value"));
        JSONObject secondTermValue = must.getJSONObject(1).getJSONObject("term")
                .getJSONObject("_dimension.state");
        assertEquals("true", secondTermValue.get("value"));
    }

    @Test
    public void visitMember_ChildLambdaAnyByComplexType_correctESQuery() throws Exception {
        String rawODataPath = "/author";
        String rawQueryPath = "$filter=book/any(b:b/_dimension/any(d:(d/name eq 'Validity' and d/state eq 'true')))";
        UriInfo uriInfo = buildUriInfo(defaultMetadata, defaultOData, rawODataPath, rawQueryPath);
        ExpressionMember result = uriInfo.getFilterOption().getExpression()
                .accept(new ElasticSearchExpressionVisitor());
        String query = ((ExpressionResult) result).getQueryBuilder().toString();

        JSONObject childObj = new JSONObject(query).getJSONObject("has_child");
        String actualType = (String) childObj.get("type");
        assertEquals("book", actualType);

        JSONObject rootObj = childObj.getJSONObject("query").getJSONObject("nested");
        String actualNestedType = (String) rootObj.get("path");
        assertEquals("_dimension", actualNestedType);
        JSONObject queryObject = rootObj.getJSONObject("query");
        JSONArray must = queryObject.getJSONObject("bool").getJSONArray("must");
        JSONObject firstTermValue = must.getJSONObject(0).getJSONObject("term")
                .getJSONObject("_dimension.name");
        assertEquals("Validity", firstTermValue.get("value"));