Index: tck/src/java/org/apache/jdo/tck/query/api/SampleQueries.java =================================================================== --- tck/src/java/org/apache/jdo/tck/query/api/SampleQueries.java (revision 1800078) +++ tck/src/java/org/apache/jdo/tck/query/api/SampleQueries.java (working copy) @@ -210,6 +210,35 @@ } } } + + /** + * Parameter passing. + * + * This query selects all Employee instances from the candidate collection where the salary + * is greater than the value passed as a parameter and the name starts with the value passed + * as a second parameter. + * If the value for the salary field in a candidate instance is null, then it cannot be + * unwrapped for the comparison, and the candidate instance is rejected. + */ + public void testQuery03c() { + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + String singleStringQuery = "select where salary > :sal && firstname.startsWith(:begin)"; + Query q = + pm.newQuery(FullTimeEmployee.class,"salary > sal && firstname.startsWith(begin)"); + q.declareParameters("Double sal, String begin"); + q.setParameters(30000., "M"); + List emps = q.executeList(); + List expected = getTransientCompanyModelInstancesAsList(new String[] {"emp1"}); + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, emps, expected); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } /** * Navigation through single-valued field. @@ -269,6 +298,34 @@ } /** + * Navigation through single-valued field. + * + * This query selects all Employee instances from the candidate collection where the value + * of the name field in the Department instance associated with the Employee instance + * is equal to the value passed as a parameter. + * If the value for the dept field in a candidate instance is null, then it cannot be + * navigated for the comparison, and the candidate instance is rejected. + */ + public void testQuery04c() { + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + String singleStringQuery = "select where department.name == :dep"; + Query q = pm.newQuery (Employee.class, "department.name == dep"); + q.declareParameters ("String dep"); + q.setParameters("R&D"); + List emps = q.executeList(); + List expected = getTransientCompanyModelInstancesAsList(new String[] {"emp1", "emp2", "emp3"}); + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, emps, expected); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } + + /** * Navigation through multi-valued field. * * This query selects all Department instances from the candidate collection where @@ -326,6 +383,34 @@ } /** + * Navigation through multi-valued field. + * + * This query selects all Department instances from the candidate collection where + * the collection of Employee instances contains at least one Employee instance + * having a salary greater than the value passed as a parameter. + */ + public void testQuery05c() { + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + String singleStringQuery = "select where employees.contains(e) && e.weeklyhours > :hours"; + String filter = "employees.contains (emp) && emp.weeklyhours > hours"; + Query q = pm.newQuery(Department.class, filter); + q.declareVariables("Employee emp"); + q.declareParameters("double hours"); + q.setParameters(30.); + List deps = q.executeList(); + List expected = getTransientCompanyModelInstancesAsList(new String[] {"dept1"}); + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, deps, expected); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } + + /** * Membership in a collection. * * This query selects all Department instances where the name field is contained in @@ -339,11 +424,11 @@ String filter = "depts.contains(name)"; Query q = pm.newQuery(Department.class, filter); q.declareParameters("java.util.Collection depts"); - List depts = Arrays.asList("R&D", "Sales", "Marketing"); - List deps = (List)q.execute(depts); + List deptNames = Arrays.asList("R&D", "Sales", "Marketing"); + List result = (List)q.execute(deptNames); List expected = getTransientCompanyModelInstancesAsList(new String[] {"dept1", "dept2", "dept3"}); - checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, deps, expected); + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, result, expected); tx.commit(); } finally { if (tx.isActive()) { @@ -369,10 +454,10 @@ Map paramValues = new HashMap<>(); paramValues.put("depts", Arrays.asList("R&D", "Sales", "Marketing")); q.setNamedParameters(paramValues); - List deps = q.executeList(); + List result = q.executeList(); List expected = getTransientCompanyModelInstancesAsList(new String[] {"dept1", "dept2", "dept3"}); - checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, deps, expected); + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, result, expected); tx.commit(); } finally { if (tx.isActive()) { @@ -380,8 +465,35 @@ } } } - + /** + * Membership in a collection. + * + * This query selects all Department instances where the name field is contained in + * a parameter collection, which in this example consists of three department names. + */ + public void testQuery06c() { + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + String singleStringQuery = "select where :depts.contains(name)"; + String filter = "depts.contains(name)"; + Query q = pm.newQuery(Department.class, filter); + q.declareParameters("java.util.Collection depts"); + q.setParameters(Arrays.asList("R&D", "Sales", "Marketing")); + List result = q.executeList(); + List expected = + getTransientCompanyModelInstancesAsList(new String[] {"dept1", "dept2", "dept3"}); + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, result, expected); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } + + /** * Projection of a Single Field. * * This query selects names of all Employees who work in the parameter department. @@ -433,6 +545,31 @@ } /** + * Projection of a Single Field. + * + * This query selects names of all Employees who work in the parameter department. + */ + public void testQuery07c() { + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + String singleStringQuery = "select firstname where department.name == :deptName"; + Query q = pm.newQuery(Employee.class, "department.name == deptName"); + q.setResult("firstname"); + q.declareParameters("String deptName"); + q.setParameters("R&D"); + List names = q.executeResultList(String.class); + List expected = Arrays.asList("Joe", "Craig", "Michael"); + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, names, expected); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } + + /** * Projection of Multiple Fields and Expressions. * * This query selects names, salaries, and bosses of Employees who work in the parameter department. @@ -506,6 +643,43 @@ } } } + + /** + * Projection of Multiple Fields and Expressions. + * + * This query selects names, salaries, and bosses of Employees who work in the parameter department. + */ + public void testQuery08c() { + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + String singleStringQuery = + "select firstname, salary, manager as reportsTo " + + "into org.apache.jdo.tck.query.api.SampleQueries$Info where department.name == :deptName"; + Query q = pm.newQuery(FullTimeEmployee.class, "department.name == deptName"); + q.setResult("firstname, salary, manager as reportsTo"); + q.setResultClass(Info.class); + q.declareParameters("String deptName"); + q.setParameters("R&D"); + List infos = q.executeResultList(Info.class); + + Info info1 = new Info(); + info1.firstname = "Michael"; + info1.salary = 40000.; + info1.reportsTo = (Employee)getTransientCompanyModelInstance("emp2"); + Info info2 = new Info(); + info2.firstname = "Craig"; + info2.salary = 50000.; + info2.reportsTo = null; + List expected = Arrays.asList(info1, info2); + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, infos, expected); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } /** * Projection of Multiple Fields and Expressions into a Constructed instance. @@ -573,6 +747,38 @@ } /** + * Projection of Multiple Fields and Expressions into a Constructed instance. + * + * This query selects names, salaries, and bosses of Employees who work in the parameter department, + * and uses the constructor for the result class. + */ + public void testQuery09c() { + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + String singleStringQuery = + "select new org.apache.jdo.tck.query.api.SampleQueries$Info (firstname, salary, manager) " + + "where department.name == :deptName"; + Query q = pm.newQuery(FullTimeEmployee.class, "department.name == deptName"); + q.setResult("new org.apache.jdo.tck.query.api.SampleQueries$Info(firstname, salary, manager)"); + q.declareParameters("String deptName"); + q.setParameters("R&D"); + List infos = q.executeResultList(Info.class); + + List expected = Arrays.asList( + new Info("Michael", 40000., (Employee)getTransientCompanyModelInstance("emp2")), + new Info("Craig", 50000., null) + ); + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, infos, expected); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } + + /** * Aggregation of a single Field. * * This query averages the salaries of Employees who work in the parameter department @@ -628,6 +834,33 @@ } /** + * Aggregation of a single Field. + * + * This query averages the salaries of Employees who work in the parameter department + * and returns a single value. + */ + public void testQuery10c() { + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + String singleStringQuery = "select avg(salary) where department.name == :deptName"; + Query q = pm.newQuery(FullTimeEmployee.class, "department.name == deptName"); + q.setResult("avg(salary)"); + q.declareParameters("String deptName"); + q.setParameters("R&D"); + Double avgSalary = q.executeResultUnique(Double.class); + + Double expected = 45000.; + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, avgSalary, expected); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } + + /** * Aggregation of Multiple Fields and Expressions. * * This query averages and sums the salaries of Employees who work in the parameter department. @@ -681,6 +914,32 @@ } /** + * Aggregation of Multiple Fields and Expressions. + * + * This query averages and sums the salaries of Employees who work in the parameter department. + */ + public void testQuery11c() { + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + String singleStringQuery = "select avg(salary), sum(salary) where department.name == :deptName"; + Query q = pm.newQuery(FullTimeEmployee.class, "department.name == deptName"); + q.setResult("avg(salary), sum(salary)"); + q.declareParameters("String deptName"); + q.setParameters("R&D"); + Object[] avgSum = (Object[])q.executeResultUnique(); + + Double[] expected = new Double[] {45000., 90000.}; + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, avgSum, expected); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } + + /** * Aggregation of Multiple fields with Grouping. * * This query averages and sums the salaries of Employees who work in all departments having @@ -747,7 +1006,7 @@ } } } - + /** * Selection of a Single Instance. * @@ -800,6 +1059,31 @@ } /** + * Selection of a Single Instance. + * + * This query returns a single instance of Employee. + */ + public void testQuery13c() { + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + String singleStringQuery = "select unique this where firstname == :empName"; + Query q = pm.newQuery (Employee.class, "firstname == empName"); + q.setUnique(true); + q.declareParameters ("String empName"); + q.setParameters("Michael"); + Employee emp = q.executeUnique(); + Employee expectedEmp = (Employee)getTransientCompanyModelInstance("emp1"); + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, emp, expectedEmp); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } + + /** * Selection of a Single Field. * * This query returns a single field of a single Employee. @@ -852,8 +1136,34 @@ } } } - + /** + * Selection of a Single Field. + * + * This query returns a single field of a single Employee. + */ + public void testQuery14c() { + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + String singleStringQuery = "select unique new Double(salary) where firstname == :empName"; + Query q = pm.newQuery(FullTimeEmployee.class, "firstname == empName"); + q.setResult("salary"); + q.setResultClass(Double.class); + q.declareParameters("String empName"); + q.setParameters("Michael"); + Double salary = q.executeResultUnique(Double.class); + Double expectedSalary = 40000.; + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, salary, expectedSalary); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } + + /** * Projection of "this" to User-defined Result Class with Matching Field. * * This query selects instances of Employee who make more than the parameter salary and @@ -937,8 +1247,50 @@ } } } - + /** + * Projection of "this" to User-defined Result Class with Matching Field. + * + * This query selects instances of Employee who make more than the parameter salary and + * stores the result in a user-defined class. Since the default is "distinct this as FullTimeEmployee", + * the field must be named FullTimeEmployee and be of type FullTimeEmployee. + */ + public void testQuery15c() { + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + String singleStringQuery = + "select into org.apache.jdo.tck.query.api.SampleQueries$EmpWrapper where salary > sal"; + Query q = pm.newQuery(FullTimeEmployee.class, "salary > sal"); + // ToDo: the following line should no be necessary + // org.datanucleus.exceptions.NucleusUserException: + // Query needs to return objects of type "org.apache.jdo.tck.query.api.SampleQueries$EmpWrapper" + // but it was impossible to set the field "birthdate" type "java.util.Date". The field should + // have either a public set/put method, or be public. + //q.setResult("distinct this as FullTimeEmployee"); + q.setResultClass(EmpWrapper.class); + + q.declareParameters ("Double sal"); + q.setParameters(30000.); + List infos = q.executeResultList(EmpWrapper.class); + + EmpWrapper wrapper1 = new EmpWrapper(); + wrapper1.FullTimeEmployee = (FullTimeEmployee)getTransientCompanyModelInstance("emp1"); + EmpWrapper wrapper2 = new EmpWrapper(); + wrapper2.FullTimeEmployee = (FullTimeEmployee)getTransientCompanyModelInstance("emp2"); + EmpWrapper wrapper3 = new EmpWrapper(); + wrapper3.FullTimeEmployee = (FullTimeEmployee)getTransientCompanyModelInstance("emp5"); + List expected = Arrays.asList(wrapper1, wrapper2, wrapper3); + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, infos, expected); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } + + /** * Projection of "this" to User-defined Result Class with Matching Method * * This query selects instances of FullTimeEmployee who make more than the parameter salary and @@ -1022,6 +1374,47 @@ } /** + * Projection of "this" to User-defined Result Class with Matching Method + * + * This query selects instances of FullTimeEmployee who make more than the parameter salary and + * stores the result in a user-defined class. + */ + public void testQuery16c() { + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + String singleStringQuery = + "select into org.apache.jdo.tck.query.api.SampleQueries$EmpInfo where salary > sal"; + Query q = pm.newQuery(FullTimeEmployee.class, "salary > sal"); + // ToDo: the following line should no be necessary + // org.datanucleus.exceptions.NucleusUserException: + // Query needs to return objects of type "org.apache.jdo.tck.query.api.SampleQueries$EmpInfo" + // but it was impossible to set the field "birthdate" type "java.util.Date". The field should + // have either a public set/put method, or be public. + //q.setResult("distinct this as FullTimeEmployee"); + q.setResultClass(EmpInfo.class); + + q.declareParameters("Double sal"); + q.setParameters(30000.); + List infos = q.executeResultList(EmpInfo.class); + + EmpInfo info1 = new EmpInfo(); + info1.setFullTimeEmployee((FullTimeEmployee)getTransientCompanyModelInstance("emp1")); + EmpInfo info2 = new EmpInfo(); + info2.setFullTimeEmployee((FullTimeEmployee)getTransientCompanyModelInstance("emp2")); + EmpInfo info3 = new EmpInfo(); + info3.setFullTimeEmployee((FullTimeEmployee)getTransientCompanyModelInstance("emp5")); + List expected = Arrays.asList(info1, info2, info3); + checkQueryResultWithoutOrder(ASSERTION_FAILED, singleStringQuery, infos, expected); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + } + } + + /** * Projection of variables. * * This query returns the names of all Employees of all "Research" departments.