/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.openjpa.persistence.criteria;

import java.util.List;
import java.util.Map;
import java.util.Set;

import jakarta.persistence.Parameter;
import jakarta.persistence.Query;
import jakarta.persistence.Tuple;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Join;
import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.criteria.ListJoin;
import jakarta.persistence.criteria.MapJoin;
import jakarta.persistence.criteria.ParameterExpression;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;

import org.apache.openjpa.persistence.embed.Company1;
import org.apache.openjpa.persistence.embed.Company1_;
import org.apache.openjpa.persistence.embed.Company2;
import org.apache.openjpa.persistence.embed.Company2_;
import org.apache.openjpa.persistence.embed.Department1;
import org.apache.openjpa.persistence.embed.Department1_;
import org.apache.openjpa.persistence.embed.Department2;
import org.apache.openjpa.persistence.embed.Department3;
import org.apache.openjpa.persistence.embed.Division;
import org.apache.openjpa.persistence.embed.Embed;
import org.apache.openjpa.persistence.embed.Embed_;
import org.apache.openjpa.persistence.embed.Embed_Coll_Embed;
import org.apache.openjpa.persistence.embed.Embed_Coll_Embed_;
import org.apache.openjpa.persistence.embed.Embed_Coll_Integer;
import org.apache.openjpa.persistence.embed.Embed_Coll_Integer_;
import org.apache.openjpa.persistence.embed.Embed_Embed;
import org.apache.openjpa.persistence.embed.Embed_Embed_;
import org.apache.openjpa.persistence.embed.Embed_Embed_ToMany;
import org.apache.openjpa.persistence.embed.Embed_Embed_ToMany_;
import org.apache.openjpa.persistence.embed.Embed_MappedToOne;
import org.apache.openjpa.persistence.embed.Embed_MappedToOne_;
import org.apache.openjpa.persistence.embed.Embed_ToMany;
import org.apache.openjpa.persistence.embed.Embed_ToMany_;
import org.apache.openjpa.persistence.embed.Embed_ToOne;
import org.apache.openjpa.persistence.embed.Embed_ToOne_;
import org.apache.openjpa.persistence.embed.Employee1;
import org.apache.openjpa.persistence.embed.Employee2;
import org.apache.openjpa.persistence.embed.Employee3;
import org.apache.openjpa.persistence.embed.EntityA_Coll_Embed_Embed;
import org.apache.openjpa.persistence.embed.EntityA_Coll_Embed_Embed_;
import org.apache.openjpa.persistence.embed.EntityA_Coll_Embed_ToOne;
import org.apache.openjpa.persistence.embed.EntityA_Coll_Embed_ToOne_;
import org.apache.openjpa.persistence.embed.EntityA_Coll_String;
import org.apache.openjpa.persistence.embed.EntityA_Coll_String_;
import org.apache.openjpa.persistence.embed.EntityA_Embed_Coll_Embed;
import org.apache.openjpa.persistence.embed.EntityA_Embed_Coll_Embed_;
import org.apache.openjpa.persistence.embed.EntityA_Embed_Coll_Integer;
import org.apache.openjpa.persistence.embed.EntityA_Embed_Coll_Integer_;
import org.apache.openjpa.persistence.embed.EntityA_Embed_Embed;
import org.apache.openjpa.persistence.embed.EntityA_Embed_Embed_;
import org.apache.openjpa.persistence.embed.EntityA_Embed_Embed_ToMany;
import org.apache.openjpa.persistence.embed.EntityA_Embed_Embed_ToMany_;
import org.apache.openjpa.persistence.embed.EntityA_Embed_MappedToOne;
import org.apache.openjpa.persistence.embed.EntityA_Embed_MappedToOne_;
import org.apache.openjpa.persistence.embed.EntityA_Embed_ToMany;
import org.apache.openjpa.persistence.embed.EntityA_Embed_ToMany_;
import org.apache.openjpa.persistence.embed.EntityA_Embed_ToOne;
import org.apache.openjpa.persistence.embed.EntityA_Embed_ToOne_;
import org.apache.openjpa.persistence.embed.EntityB1;
import org.apache.openjpa.persistence.embed.EntityB1_;
import org.apache.openjpa.persistence.embed.Item1;
import org.apache.openjpa.persistence.embed.Item1_;
import org.apache.openjpa.persistence.embed.Item2;
import org.apache.openjpa.persistence.embed.Item2_;
import org.apache.openjpa.persistence.embed.Item3;
import org.apache.openjpa.persistence.embed.Item3_;
import org.apache.openjpa.persistence.embed.VicePresident;
import org.apache.openjpa.persistence.embed.VicePresident_;
import org.apache.openjpa.persistence.test.AllowFailure;


public class TestEmbeddableCriteria extends EmbeddableDomainTestCase {

    private static int TEST_COUNT = 0;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        TEST_COUNT++;
    }

    @Override
    public void tearDown() throws Exception {
        // Hack to cleanup EM and EMF when we're done
        if (TEST_COUNT >= 123)
            super.tearDown();
    }

    public void testEmbeddableQuery1() {
        String jpql = "select e from EntityA_Coll_String a, in (a.nickNames) e order by a.id";
        CriteriaQuery<String> q = cb.createQuery(String.class);
        Root<EntityA_Coll_String> a = q.from(EntityA_Coll_String.class);
        Join<EntityA_Coll_String, String> e = a.join(EntityA_Coll_String_.nickNames);
        q.select(e);
        q.orderBy(cb.asc(a.get(EntityA_Coll_String_.id)));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery3() {
        String jpql = "select e from EntityA_Coll_String a, in (a.nickNames) e order by e";
        CriteriaQuery<String> q = cb.createQuery(String.class);
        Root<EntityA_Coll_String> a = q.from(EntityA_Coll_String.class);
        Join<EntityA_Coll_String, String> e = a.join(EntityA_Coll_String_.nickNames);
        q.select(e);
        q.orderBy(cb.asc(e));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery4() {
        String jpql = "select a from EntityA_Coll_String a WHERE a.nickNames IS EMPTY order by a";
        CriteriaQuery<EntityA_Coll_String> q = cb.createQuery(EntityA_Coll_String.class);
        Root<EntityA_Coll_String> a = q.from(EntityA_Coll_String.class);
        q.select(a);
        q.where(cb.isEmpty(a.get(EntityA_Coll_String_.nickNames)));
        q.orderBy(cb.asc(a));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery5() {
        String jpql = "select a from EntityA_Coll_String a WHERE exists (select n from EntityA_Coll_String a, " +
                " in (a.nickNames) n where n like '%1') order by a";
        CriteriaQuery<EntityA_Coll_String> q = cb.createQuery(EntityA_Coll_String.class);
        Root<EntityA_Coll_String> a = q.from(EntityA_Coll_String.class);
        q.select(a);
        Subquery<Set> sq = q.subquery(Set.class);
        Root<EntityA_Coll_String> a1 = sq.from(EntityA_Coll_String.class);
        Expression n = a1.get(EntityA_Coll_String_.nickNames);
        n.alias("n");
        sq.where(cb.like(n, "%1"));
        sq.select(n);
        q.where(cb.exists(sq));
        q.orderBy(cb.asc(a));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery6() {
        String jpql = "select a from EntityA_Coll_String a";
        CriteriaQuery<EntityA_Coll_String> q = cb.createQuery(EntityA_Coll_String.class);
        Root<EntityA_Coll_String> a = q.from(EntityA_Coll_String.class);
        q.select(a);

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery7() {
        String jpql = "select a.embed from EntityA_Embed_ToOne a ";
        CriteriaQuery<Embed_ToOne> q = cb.createQuery(Embed_ToOne.class);
        Root<EntityA_Embed_ToOne> a = q.from(EntityA_Embed_ToOne.class);
        q.select(a.get(EntityA_Embed_ToOne_.embed));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery9() {
        String jpql = "select e from EntityA_Embed_ToOne a " +
                " join a.embed e join e.b b where e.b.id > 0 order by a.id";
        CriteriaQuery<Embed_ToOne> q = cb.createQuery(Embed_ToOne.class);
        Root<EntityA_Embed_ToOne> a = q.from(EntityA_Embed_ToOne.class);
        Join<EntityA_Embed_ToOne, Embed_ToOne> e = a.join(EntityA_Embed_ToOne_.embed);
        Join<Embed_ToOne, EntityB1> b = e.join(Embed_ToOne_.b);
        q.where(cb.gt(b.get(EntityB1_.id), 0));
        q.select(e);
        q.orderBy(cb.asc(a.get(EntityA_Embed_ToOne_.id)));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery11() {
        String jpql = "select a.embed from EntityA_Embed_ToOne a ORDER BY a.embed";
        CriteriaQuery<Embed_ToOne> q = cb.createQuery(Embed_ToOne.class);
        Root<EntityA_Embed_ToOne> a = q.from(EntityA_Embed_ToOne.class);
        q.select(a.get(EntityA_Embed_ToOne_.embed));
        q.orderBy(cb.asc(a.get(EntityA_Embed_ToOne_.embed)));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery12() {
        String jpql = "select a.embed from EntityA_Embed_ToOne a WHERE a.embed.b IS NOT NULL " +
                " ORDER BY a.embed";
        CriteriaQuery<Embed_ToOne> q = cb.createQuery(Embed_ToOne.class);
        Root<EntityA_Embed_ToOne> a = q.from(EntityA_Embed_ToOne.class);
        q.select(a.get(EntityA_Embed_ToOne_.embed));
        q.where(cb.isNotNull(a.get(EntityA_Embed_ToOne_.embed).get(Embed_ToOne_.b)));
        q.orderBy(cb.asc(a.get(EntityA_Embed_ToOne_.embed)));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery13() {
        String jpql = "select a.embed from EntityA_Embed_ToOne a WHERE exists " +
                " (select a from EntityA_Embed_ToOne a where a.embed.b IS NOT NULL) " +
                " ORDER BY a.embed";
        CriteriaQuery<Embed_ToOne> q = cb.createQuery(Embed_ToOne.class);
        Root<EntityA_Embed_ToOne> a = q.from(EntityA_Embed_ToOne.class);
        q.select(a.get(EntityA_Embed_ToOne_.embed));
        Subquery<EntityA_Embed_ToOne> sq = q.subquery(EntityA_Embed_ToOne.class);
        Root<EntityA_Embed_ToOne> a1 = sq.from(EntityA_Embed_ToOne.class);
        Expression n = a1.get(EntityA_Embed_ToOne_.embed).get(Embed_ToOne_.b);
        sq.where(cb.isNotNull(n));
        sq.select(a1);
        q.where(cb.exists(sq));
        q.orderBy(cb.asc(a.get(EntityA_Embed_ToOne_.embed)));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery14() {
        String jpql = "select a.embed from EntityA_Embed_MappedToOne a ";
        CriteriaQuery<Embed_MappedToOne> q = cb.createQuery(Embed_MappedToOne.class);
        Root<EntityA_Embed_MappedToOne> a = q.from(EntityA_Embed_MappedToOne.class);
        q.select(a.get(EntityA_Embed_MappedToOne_.embed));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery15() {
        String jpql = "select e from EntityA_Embed_MappedToOne a " +
                " join a.embed e join e.bm bm where e.bm.id > 0 order by a.id";
        CriteriaQuery<Embed_MappedToOne> q = cb.createQuery(Embed_MappedToOne.class);
        Root<EntityA_Embed_MappedToOne> a = q.from(EntityA_Embed_MappedToOne.class);
        Join<EntityA_Embed_MappedToOne,Embed_MappedToOne> e = a.join(EntityA_Embed_MappedToOne_.embed);
        Join<Embed_MappedToOne,EntityB1> bm = e.join(Embed_MappedToOne_.bm);
        q.where(cb.gt(e.get(Embed_MappedToOne_.bm).get(EntityB1_.id), 0));
        q.orderBy(cb.asc(a.get(EntityA_Embed_MappedToOne_.id)));
        q.select(e);

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery16() {
        String jpql = "select a.embed as e from EntityA_Embed_MappedToOne a ORDER BY e";
        CriteriaQuery<Embed_MappedToOne> q = cb.createQuery(Embed_MappedToOne.class);
        Root<EntityA_Embed_MappedToOne> a = q.from(EntityA_Embed_MappedToOne.class);
        Expression<Embed_MappedToOne> e = a.get(EntityA_Embed_MappedToOne_.embed);
        e.alias("e");
        q.select(e);
        q.orderBy(cb.asc(e));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery17() {
        String jpql = "select a.embed from EntityA_Embed_MappedToOne a WHERE a.embed.bm IS NOT NULL";
        CriteriaQuery<Embed_MappedToOne> q = cb.createQuery(Embed_MappedToOne.class);
        Root<EntityA_Embed_MappedToOne> a = q.from(EntityA_Embed_MappedToOne.class);
        q.where(cb.isNotNull(a.get(EntityA_Embed_MappedToOne_.embed).get(Embed_MappedToOne_.bm)));
        q.select(a.get(EntityA_Embed_MappedToOne_.embed));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery18() {
        String jpql = "select a.embed from EntityA_Embed_MappedToOne a " +
                " WHERE exists (select a from EntityA_Embed_MappedToOne a " +
                " where a.embed.bm IS NOT NULL)";
        CriteriaQuery<Embed_MappedToOne> q = cb.createQuery(Embed_MappedToOne.class);
        Root<EntityA_Embed_MappedToOne> a = q.from(EntityA_Embed_MappedToOne.class);
        Subquery<EntityA_Embed_MappedToOne> sq = q.subquery(EntityA_Embed_MappedToOne.class);
        Root<EntityA_Embed_MappedToOne> a1 = sq.from(EntityA_Embed_MappedToOne.class);
        sq.select(a1);
        sq.where(cb.isNotNull(a1.get(EntityA_Embed_MappedToOne_.embed).get(Embed_MappedToOne_.bm)));
        q.where(cb.exists(sq));
        q.select(a.get(EntityA_Embed_MappedToOne_.embed));

        assertEquivalence(q, jpql);
    }

    //jpql does not support comparison of embeddable
    public void testEmbeddableQuery19() {
        String jpql = "select a.embed from EntityA_Embed_MappedToOne a " +
                " WHERE exists (select e from EntityA_Embed_MappedToOne a" +
                " join a.embed e where e.bm IS NOT NULL)";
        CriteriaQuery<Embed_MappedToOne> q = cb.createQuery(Embed_MappedToOne.class);
        Root<EntityA_Embed_MappedToOne> a = q.from(EntityA_Embed_MappedToOne.class);
        Subquery<Embed_MappedToOne> sq = q.subquery(Embed_MappedToOne.class);
        Root<EntityA_Embed_MappedToOne> a1 = sq.from(EntityA_Embed_MappedToOne.class);
        Join<EntityA_Embed_MappedToOne, Embed_MappedToOne> e = a1.join(EntityA_Embed_MappedToOne_.embed);
        sq.select(e);
        sq.where(cb.isNotNull(e.get(Embed_MappedToOne_.bm)));
        q.where(cb.exists(sq));
        q.select(a.get(EntityA_Embed_MappedToOne_.embed));

        executeExpectFail(jpql);
        executeExpectFail(q, jpql);
    }

    //no support for comparison of embeddable
    public void testEmbeddableQuery20() {
        String jpql = "select a.embed from EntityA_Embed_MappedToOne a " +
                " WHERE exists (select a.embed from EntityA_Embed_MappedToOne a " +
                " where a.embed.bm IS NOT NULL)";
        CriteriaQuery<Embed_MappedToOne> q = cb.createQuery(Embed_MappedToOne.class);
        Root<EntityA_Embed_MappedToOne> a = q.from(EntityA_Embed_MappedToOne.class);
        Subquery<Embed_MappedToOne> sq = q.subquery(Embed_MappedToOne.class);
        Root<EntityA_Embed_MappedToOne> a1 = sq.from(EntityA_Embed_MappedToOne.class);
        sq.select(a1.get(EntityA_Embed_MappedToOne_.embed));
        sq.where(cb.isNotNull(a1.get(EntityA_Embed_MappedToOne_.embed).get(Embed_MappedToOne_.bm)));
        q.where(cb.exists(sq));
        q.select(a.get(EntityA_Embed_MappedToOne_.embed));

        executeExpectFail(q, jpql);
        executeExpectFail(jpql);
    }

    public void testEmbeddableQuery21() {
        String jpql = "select a from EntityA_Embed_MappedToOne a";
        CriteriaQuery<EntityA_Embed_MappedToOne> q = cb.createQuery(EntityA_Embed_MappedToOne.class);
        Root<EntityA_Embed_MappedToOne> a = q.from(EntityA_Embed_MappedToOne.class);
        q.select(a);

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery22() {
        String jpql = "select e, e.b from EntityA_Coll_Embed_ToOne a, in (a.embed1s) e order by e.name1";
        CriteriaQuery<?> q = cb.createQuery();
        Root<EntityA_Coll_Embed_ToOne> a = q.from(EntityA_Coll_Embed_ToOne.class);
        Join<EntityA_Coll_Embed_ToOne, Embed_ToOne> e = a.join(EntityA_Coll_Embed_ToOne_.embed1s);
        q.orderBy(cb.asc(e.get(Embed_ToOne_.name1)));
        q.multiselect(e, e.get(Embed_ToOne_.b));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery23() {
        String jpql = "select e, a.id from EntityA_Coll_Embed_ToOne a, in (a.embed1s) e where e.b.id > 0 " +
            "order by a.id";
        CriteriaQuery<?> q = cb.createQuery();
        Root<EntityA_Coll_Embed_ToOne> a = q.from(EntityA_Coll_Embed_ToOne.class);
        Join<EntityA_Coll_Embed_ToOne, Embed_ToOne> e = a.join(EntityA_Coll_Embed_ToOne_.embed1s);
        q.where(cb.gt(e.get(Embed_ToOne_.b).get(EntityB1_.id), 0));
        q.orderBy(cb.asc(a.get(EntityA_Coll_Embed_ToOne_.id)));
        q.multiselect(e, a.get(EntityA_Coll_Embed_ToOne_.id));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery24() {
        String jpql = "select e, e.b.id from EntityA_Coll_Embed_ToOne a " +
                " , in (a.embed1s) e where e.name1 like '%1' order by e.name3";
        CriteriaQuery<?> q = cb.createQuery();
        Root<EntityA_Coll_Embed_ToOne> a = q.from(EntityA_Coll_Embed_ToOne.class);
        Join<EntityA_Coll_Embed_ToOne, Embed_ToOne> e = a.join(EntityA_Coll_Embed_ToOne_.embed1s);
        q.where(cb.like(e.get(Embed_ToOne_.name1), "%1"));
        q.orderBy(cb.asc(e.get(Embed_ToOne_.name3)));
        q.multiselect(e, e.get(Embed_ToOne_.b).get(EntityB1_.id));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery25() {
        String jpql = "select e, e.b.id  from EntityA_Coll_Embed_ToOne a " +
                " , in (a.embed1s) e where e.name1 like '%1' order by e";
        CriteriaQuery<?> q = cb.createQuery();
        Root<EntityA_Coll_Embed_ToOne> a = q.from(EntityA_Coll_Embed_ToOne.class);
        Join<EntityA_Coll_Embed_ToOne, Embed_ToOne> e = a.join(EntityA_Coll_Embed_ToOne_.embed1s);
        q.where(cb.like(e.get(Embed_ToOne_.name1), "%1"));
        q.orderBy(cb.asc(e));
        q.multiselect(e, e.get(Embed_ToOne_.b).get(EntityB1_.id));

        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery26() {
        String jpql = "select e, e.b.id  from EntityA_Coll_Embed_ToOne a, " +
                "in (a.embed1s) e where e.name1 like '%1' and a.embed1s IS NOT EMPTY and " +
                " e.b IS NOT NULL order by e";
        CriteriaQuery<?> q = cb.createQuery();
        Root<EntityA_Coll_Embed_ToOne> a = q.from(EntityA_Coll_Embed_ToOne.class);
        Join<EntityA_Coll_Embed_ToOne, Embed_ToOne> e = a.join(EntityA_Coll_Embed_ToOne_.embed1s);
        Predicate p1 = cb.like(e.get(Embed_ToOne_.name1), "%1");
        Predicate p2 = cb.isEmpty(a.get(EntityA_Coll_Embed_ToOne_.embed1s)).not();
        Predicate p3 = cb.isNotNull(e.get(Embed_ToOne_.b));
        q.where(cb.and(cb.and(p1, p2), p3));
        q.orderBy(cb.asc(e));
        q.multiselect(e, e.get(Embed_ToOne_.b).get(EntityB1_.id));

        assertEquivalence(q, jpql);
    }

    // can not compare embeddable. Expect to fail
    public void testEmbeddableQuery27() {
        String jpql = "select e, e.b.id from EntityA_Coll_Embed_ToOne a " +
                " , in (a.embed1s) e where exists (select a.embed1s from " +
                " EntityA_Coll_Embed_ToOne a) and exists (select e.b from a.embed1s e) " +
                " order by e";
        CriteriaQuery<Integer> q = cb.createQuery(Integer.class);
        Root<EntityA_Coll_Embed_ToOne> a = q.from(EntityA_Coll_Embed_ToOne.class);
        Join<EntityA_Coll_Embed_ToOne, Embed_ToOne> e = a.join(EntityA_Coll_Embed_ToOne_.embed1s);
        Subquery<Set> sq1 = q.subquery(Set.class);
        Root<EntityA_Coll_Embed_ToOne> a1 = sq1.from(EntityA_Coll_Embed_ToOne.class);
        Expression e1 = a1.get(EntityA_Coll_Embed_ToOne_.embed1s);
        sq1.select(e1);

        Subquery<EntityB1> sq2 = q.subquery(EntityB1.class);
        Root<EntityA_Coll_Embed_ToOne> a2 = sq2.correlate(a);
        Join<EntityA_Coll_Embed_ToOne, Embed_ToOne> e2 = a2.join(EntityA_Coll_Embed_ToOne_.embed1s);
        sq2.select(e2.get(Embed_ToOne_.b));

        Predicate p1 = cb.exists(sq1);
        Predicate p2 = cb.exists(sq2);
        q.where(cb.and(p1, p2));
        q.orderBy(cb.asc(e));
        q.multiselect(e, e.get(Embed_ToOne_.b).get(EntityB1_.id));

        executeExpectFail(q, jpql);
        executeExpectFail(jpql);
    }

    public void testEmbeddableQuery28() {
        String jpql = "select a.embed from EntityA_Embed_ToMany a";
        CriteriaQuery<Embed_ToMany> q = cb.createQuery(Embed_ToMany.class);
        Root<EntityA_Embed_ToMany> a = q.from(EntityA_Embed_ToMany.class);
        q.select(a.get(EntityA_Embed_ToMany_.embed));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery29() {
        String jpql = "select e from EntityA_Embed_ToMany a join a.embed e";
        CriteriaQuery<Embed_ToMany> q = cb.createQuery(Embed_ToMany.class);
        Root<EntityA_Embed_ToMany> a = q.from(EntityA_Embed_ToMany.class);
        Join<EntityA_Embed_ToMany,Embed_ToMany> e = a.join(EntityA_Embed_ToMany_.embed);
        q.select(e);
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery30() {
        String jpql = "select b from EntityA_Embed_ToMany a join a.embed.bs b";
        CriteriaQuery<EntityB1> q = cb.createQuery(EntityB1.class);
        Root<EntityA_Embed_ToMany> a = q.from(EntityA_Embed_ToMany.class);
        Join<Embed_ToMany, EntityB1> b = a.join(EntityA_Embed_ToMany_.embed).join(Embed_ToMany_.bs);
        q.select(b);
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery31() {
        String jpql = "select e from EntityA_Embed_ToMany a join a.embed e where e.name1 like '%1'";
        CriteriaQuery<Embed_ToMany> q = cb.createQuery(Embed_ToMany.class);
        Root<EntityA_Embed_ToMany> a = q.from(EntityA_Embed_ToMany.class);
        Join<EntityA_Embed_ToMany,Embed_ToMany> e = a.join(EntityA_Embed_ToMany_.embed);
        q.select(e);
        q.where(cb.like(e.get(Embed_ToMany_.name1), "%1"));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery32() {
        String jpql = "select a.embed from EntityA_Embed_ToMany a ORDER BY a.embed";
        CriteriaQuery<Embed_ToMany> q = cb.createQuery(Embed_ToMany.class);
        Root<EntityA_Embed_ToMany> a = q.from(EntityA_Embed_ToMany.class);
        q.select(a.get(EntityA_Embed_ToMany_.embed));
        q.orderBy(cb.asc(a.get(EntityA_Embed_ToMany_.embed)));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery33() {
        String jpql = "select e from EntityA_Embed_ToMany a join a.embed e ORDER BY e";
        CriteriaQuery<Embed_ToMany> q = cb.createQuery(Embed_ToMany.class);
        Root<EntityA_Embed_ToMany> a = q.from(EntityA_Embed_ToMany.class);
        Join<EntityA_Embed_ToMany,Embed_ToMany> e = a.join(EntityA_Embed_ToMany_.embed);
        e.alias("e");
        q.select(e);
        q.orderBy(cb.asc(e));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery34() {
        String jpql = "select b from EntityA_Embed_ToMany a join a.embed.bs b ORDER BY b";
        CriteriaQuery<EntityB1> q = cb.createQuery(EntityB1.class);
        Root<EntityA_Embed_ToMany> a = q.from(EntityA_Embed_ToMany.class);
        ListJoin<Embed_ToMany, EntityB1> b = a.join(EntityA_Embed_ToMany_.embed).join(Embed_ToMany_.bs);
        b.alias("b");
        q.select(b);
        q.orderBy(cb.asc(b));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery35() {
        String jpql = "select e from EntityA_Embed_ToMany a join a.embed e WHERE e.bs IS NOT EMPTY ORDER BY e";
        CriteriaQuery<Embed_ToMany> q = cb.createQuery(Embed_ToMany.class);
        Root<EntityA_Embed_ToMany> a = q.from(EntityA_Embed_ToMany.class);
        Join<EntityA_Embed_ToMany, Embed_ToMany> e = a.join(EntityA_Embed_ToMany_.embed);
        e.alias("e");
        q.select(e);
        q.where(cb.isEmpty(e.get(Embed_ToMany_.bs)).not());
        q.orderBy(cb.asc(e));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery36() {
        String jpql = "select a from EntityA_Embed_ToMany a WHERE exists (select a from EntityA_Embed_ToMany a" +
                " where a.embed.bs IS NOT EMPTY) ORDER BY a";
        CriteriaQuery<EntityA_Embed_ToMany> q = cb.createQuery(EntityA_Embed_ToMany.class);
        Root<EntityA_Embed_ToMany> a = q.from(EntityA_Embed_ToMany.class);
        q.select(a);

        Subquery<EntityA_Embed_ToMany> sq = q.subquery(EntityA_Embed_ToMany.class);
        Root<EntityA_Embed_ToMany> a1 = sq.from(EntityA_Embed_ToMany.class);
        sq.select(a1);
        sq.where(cb.isEmpty(a1.get(EntityA_Embed_ToMany_.embed).get(Embed_ToMany_.bs)).not());
        q.where(cb.exists(sq));
        q.orderBy(cb.asc(a));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery38() {
        String jpql = "select a from EntityA_Embed_ToMany a";
        CriteriaQuery<EntityA_Embed_ToMany> q = cb.createQuery(EntityA_Embed_ToMany.class);
        Root<EntityA_Embed_ToMany> a = q.from(EntityA_Embed_ToMany.class);
        q.select(a);
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery39() {
        String jpql = "select a.embed from EntityA_Embed_Embed_ToMany a";
        CriteriaQuery<Embed_Embed_ToMany> q = cb.createQuery(Embed_Embed_ToMany.class);
        Root<EntityA_Embed_Embed_ToMany> a = q.from(EntityA_Embed_Embed_ToMany.class);
        q.select(a.get(EntityA_Embed_Embed_ToMany_.embed));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery40() {
        String jpql = "select a.embed from EntityA_Embed_Embed_ToMany a where a.embed.embed.name1 like '%1' ";
        CriteriaQuery<Embed_Embed_ToMany> q = cb.createQuery(Embed_Embed_ToMany.class);
        Root<EntityA_Embed_Embed_ToMany> a = q.from(EntityA_Embed_Embed_ToMany.class);
        q.select(a.get(EntityA_Embed_Embed_ToMany_.embed));
        q.where(cb.like(a.get(EntityA_Embed_Embed_ToMany_.embed).get(Embed_Embed_ToMany_.embed).
            get(Embed_ToMany_.name1), "%1"));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery41() {
        String jpql = "select a.embed.embed from EntityA_Embed_Embed_ToMany a";
        CriteriaQuery<Embed_ToMany> q = cb.createQuery(Embed_ToMany.class);
        Root<EntityA_Embed_Embed_ToMany> a = q.from(EntityA_Embed_Embed_ToMany.class);
        q.select(a.get(EntityA_Embed_Embed_ToMany_.embed).get(Embed_Embed_ToMany_.embed));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery42() {
        String jpql = "select b from EntityA_Embed_Embed_ToMany a join a.embed.embed.bs b";
        CriteriaQuery<EntityB1> q = cb.createQuery(EntityB1.class);
        Root<EntityA_Embed_Embed_ToMany> a = q.from(EntityA_Embed_Embed_ToMany.class);
        Join<Embed_ToMany, EntityB1> b = a.join(EntityA_Embed_Embed_ToMany_.embed).join(Embed_Embed_ToMany_.embed).
            join(Embed_ToMany_.bs);
        b.alias("b");
        q.select(b);
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery43() {
        String jpql = "select a.embed.embed from EntityA_Embed_Embed_ToMany a where a.embed.embed.name1 like '%1'";
        CriteriaQuery<Embed_ToMany> q = cb.createQuery(Embed_ToMany.class);
        Root<EntityA_Embed_Embed_ToMany> a = q.from(EntityA_Embed_Embed_ToMany.class);
        q.select(a.get(EntityA_Embed_Embed_ToMany_.embed).get(Embed_Embed_ToMany_.embed));
        q.where(cb.like(a.get(EntityA_Embed_Embed_ToMany_.embed).get(Embed_Embed_ToMany_.embed).
            get(Embed_ToMany_.name1), "%1"));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery44() {
        String jpql = "select e2 from EntityA_Embed_Embed_ToMany a left join a.embed e1 left join e1.embed e2";
        CriteriaQuery<Embed_ToMany> q = cb.createQuery(Embed_ToMany.class);
        Root<EntityA_Embed_Embed_ToMany> a = q.from(EntityA_Embed_Embed_ToMany.class);
        Join<EntityA_Embed_Embed_ToMany, Embed_Embed_ToMany> e1 = a.join(EntityA_Embed_Embed_ToMany_.embed,
            JoinType.LEFT);
        Join<Embed_Embed_ToMany, Embed_ToMany> e2 = e1.join(Embed_Embed_ToMany_.embed, JoinType.LEFT);
        q.select(e2);
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery45() {
        String jpql = "select e2 from EntityA_Embed_Embed_ToMany a join a.embed e1 join e1.embed e2";
        CriteriaQuery<Embed_ToMany> q = cb.createQuery(Embed_ToMany.class);
        Root<EntityA_Embed_Embed_ToMany> a = q.from(EntityA_Embed_Embed_ToMany.class);
        Join<EntityA_Embed_Embed_ToMany, Embed_Embed_ToMany> e1 = a.join(EntityA_Embed_Embed_ToMany_.embed);
        Join<Embed_Embed_ToMany, Embed_ToMany> e2 = e1.join(Embed_Embed_ToMany_.embed);
        q.select(e2);
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery46() {
        String jpql = "select a.embed as e from EntityA_Embed_Embed_ToMany a ORDER BY e";
        CriteriaQuery<Embed_Embed_ToMany> q = cb.createQuery(Embed_Embed_ToMany.class);
        Root<EntityA_Embed_Embed_ToMany> a = q.from(EntityA_Embed_Embed_ToMany.class);
        Expression<Embed_Embed_ToMany> e = a.get(EntityA_Embed_Embed_ToMany_.embed);
        e.alias("e");
        q.select(e);
        q.orderBy(cb.asc(e));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery47() {
        String jpql = "select a.embed.embed as e from EntityA_Embed_Embed_ToMany a " +
            "where a.embed.embed.name1 like '%1' ORDER BY e";
        CriteriaQuery<Embed_ToMany> q = cb.createQuery(Embed_ToMany.class);
        Root<EntityA_Embed_Embed_ToMany> a = q.from(EntityA_Embed_Embed_ToMany.class);
        Expression<Embed_ToMany> e = a.get(EntityA_Embed_Embed_ToMany_.embed).get(Embed_Embed_ToMany_.embed);
        e.alias("e");
        q.select(e);
        q.where(cb.like(a.get(EntityA_Embed_Embed_ToMany_.embed).get(Embed_Embed_ToMany_.embed).
            get(Embed_ToMany_.name1), "%1"));
        q.orderBy(cb.asc(e));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery48() {
        String jpql = "select a.embed from EntityA_Embed_Embed_ToMany a " +
                " where a.embed.embed.bs IS NOT EMPTY";
        CriteriaQuery<Embed_Embed_ToMany> q = cb.createQuery(Embed_Embed_ToMany.class);
        Root<EntityA_Embed_Embed_ToMany> a = q.from(EntityA_Embed_Embed_ToMany.class);
        Expression<Embed_Embed_ToMany> e = a.get(EntityA_Embed_Embed_ToMany_.embed);
        q.select(e);
        q.where(cb.isEmpty(a.get(EntityA_Embed_Embed_ToMany_.embed).get(Embed_Embed_ToMany_.embed).
            get(Embed_ToMany_.bs)).not());
        q.orderBy(cb.asc(e));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery49() {
        String jpql = "select a.embed from EntityA_Embed_Embed_ToMany a " +
                " where exists (select a.embed.embed.bs from EntityA_Embed_Embed_ToMany a)";
        CriteriaQuery<Embed_Embed_ToMany> q = cb.createQuery(Embed_Embed_ToMany.class);
        Root<EntityA_Embed_Embed_ToMany> a = q.from(EntityA_Embed_Embed_ToMany.class);
        Expression<Embed_Embed_ToMany> e = a.get(EntityA_Embed_Embed_ToMany_.embed);
        q.select(e);
        Subquery<List> sq = q.subquery(List.class);
        Root<EntityA_Embed_Embed_ToMany> a1 = sq.from(EntityA_Embed_Embed_ToMany.class);
        Expression bs = a1.get(EntityA_Embed_Embed_ToMany_.embed).get(Embed_Embed_ToMany_.embed).
            get(Embed_ToMany_.bs);
        sq.select(bs);
        q.where(cb.exists(sq));
        assertEquivalence(q, jpql);
    }

    public void testEmbeddableQuery50() {
        String jpql = "select b from EntityA_Embed_Embed_ToMany a join a.embed.embed.bs b";
        CriteriaQuery<EntityB1> q = cb.createQuery(EntityB1.class);
        Root<EntityA_Embed_Embed_ToMany> a = q.from(EntityA_Embed_Embed_ToMany.class);
        Join<Embed_ToMany, EntityB1> b = a.join(EntityA_Embed_Embed_ToMany_.embed).
            join(Embed_Embed_ToMany_.embed).join(Embed_ToMany_.bs);
        b.alias("b");
        q.select(b);
