/*
 * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.testing.tests.queries;

import java.util.Vector;
import org.eclipse.persistence.sessions.UnitOfWork;
import org.eclipse.persistence.testing.framework.*;
import org.eclipse.persistence.queries.*;
import org.eclipse.persistence.expressions.*;
import org.eclipse.persistence.testing.models.employee.domain.*;

/**
 * Test for bug 3568141: CONFORMING QUERY DOESN'T RETURN CORRECT ROWS WHEN INDIRECTION IS USED
 * <p>
 * We decoupled the in-memory query indirection policy from conforming, making
 * it impossible for a user to set shouldTriggerIndirection() on a conforming
 * query.
 * <p>
 * This broke a lot of customers, so we had to undo what we did.
 *
 *  @author  smcritch
 */
public class ConformingShouldTriggerIndirectionTest extends AutoVerifyTestCase {
    public ConformingShouldTriggerIndirectionTest() {
    }

    @Override
    public void test() throws Exception {
        UnitOfWork uow = getSession().acquireUnitOfWork();

        ExpressionBuilder proj = new ExpressionBuilder();
        Expression outOfOttawaProjectsExp = proj.get("teamLeader").get("address").get("city").notEqual("Ottawa");

        ReadAllQuery originalQuery = new ReadAllQuery(Project.class);
        originalQuery.setSelectionCriteria(outOfOttawaProjectsExp);

        Vector outOfOttawaProjects = (Vector)uow.executeQuery(originalQuery);

        ExpressionBuilder emp = new ExpressionBuilder();
        Expression ottawaEmpsExp = emp.get("address").get("city").equal("Ottawa");

        ReadAllQuery employeeQuery = new ReadAllQuery(Employee.class);
        employeeQuery.setSelectionCriteria(ottawaEmpsExp);

        Vector ottawaEmps = (Vector)uow.executeQuery(employeeQuery);

        Project conformingProject = (Project)outOfOttawaProjects.elementAt(0);
        Employee conformingEmp = (Employee)ottawaEmps.elementAt(0);

        // Now this project will no longer conform.
        // The crux is that this project's teamleader's address was changed
        // without triggering all valueholders.  Hence the default heuristic
        // conforming would assume that project has not changed relative to the
        // query.
        // The 2 levels of indirection were needed because setting an attribute
        // (changing an object) automatically triggers one level of indirection.
        conformingProject.setTeamLeader(conformingEmp);

        // Now execute the original query again as a conforming query.  This
        // time the project that was changed should get dropped from the result.
        ReadAllQuery conformingQuery = originalQuery;
        conformingQuery.setInMemoryQueryIndirectionPolicy(new InMemoryQueryIndirectionPolicy(InMemoryQueryIndirectionPolicy.SHOULD_TRIGGER_INDIRECTION));
        conformingQuery.conformResultsInUnitOfWork();

        Vector conformingProjects = (Vector)uow.executeQuery(conformingQuery);

        if ((conformingProjects.size() + 1) != outOfOttawaProjects.size()) {
            throw new TestErrorException("The result was not conformed.  Original: " + outOfOttawaProjects + " Conforming: " + conformingProjects);
        }
    }
}
