Author: aadamchik
Date: Sat Aug 11 17:48:49 2007
New Revision: 564992
URL: http://svn.apache.org/viewvc?view=rev&rev=564992
Log:
CAY-846 EJBQL Collections condition support
Added:
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLConditionsPeopleTest.java
Modified:
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLIdentifierColumnsTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslationContext.java
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLConditionsTest.java
Modified:
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java?view=diff&rev=564992&r1=564991&r2=564992
==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLConditionTranslator.java
Sat Aug 11 17:48:49 2007
@@ -29,10 +29,20 @@
import org.apache.cayenne.ejbql.EJBQLBaseVisitor;
import org.apache.cayenne.ejbql.EJBQLException;
import org.apache.cayenne.ejbql.EJBQLExpression;
+import org.apache.cayenne.ejbql.parser.EJBQLEquals;
+import org.apache.cayenne.ejbql.parser.EJBQLIdentificationVariable;
+import org.apache.cayenne.ejbql.parser.EJBQLPath;
import org.apache.cayenne.ejbql.parser.EJBQLPositionalInputParameter;
import org.apache.cayenne.ejbql.parser.EJBQLSubselect;
import org.apache.cayenne.ejbql.parser.EJBQLTrimBoth;
import org.apache.cayenne.ejbql.parser.EJBQLTrimSpecification;
+import org.apache.cayenne.ejbql.parser.Node;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.map.DbJoin;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.map.ObjRelationship;
+import org.apache.cayenne.reflect.ClassDescriptor;
/**
* @since 3.0
@@ -107,28 +117,86 @@
}
public boolean visitMemberOf(EJBQLExpression expression) {
- // handle as "? =|<> path" (an alt. way would've been a correlated
subquery
- // on the target entity)...
- if (expression.isNegated()) {
- context.switchToMarker(EJBQLSelectTranslator.makeDistinctMarker(),
true);
- context.append(" DISTINCT");
- context.switchToMainBuffer();
+ // create a correlated subquery, using the following transformation:
- visitNotEquals(expression, -1);
- for (int i = 0; i < expression.getChildrenCount(); i++) {
- expression.getChild(i).visit(this);
- visitNotEquals(expression, i);
- }
- }
- else {
- visitEquals(expression, -1);
- for (int i = 0; i < expression.getChildrenCount(); i++) {
- expression.getChild(i).visit(this);
- visitEquals(expression, i);
- }
+ // * Subquery Root is always an entity that is a target of relationship
+ // * A subquery has a join based on reverse relationship, pointing to
the
+ // original ID.
+ // * Join must be transled as a part of the subquery WHERE clause
instead of
+ // FROM.
+ // * A condition is added: subquery_root_id = LHS_memberof
+
+ if (expression.getChildrenCount() != 2) {
+ throw new EJBQLException("MEMBER OF must have exactly two
children, got: "
+ + expression.getChildrenCount());
+ }
+
+ if (!(expression.getChild(1) instanceof EJBQLPath)) {
+ throw new EJBQLException(
+ "Second child of the MEMBER OF must be a collection path,
got: "
+ + expression.getChild(1));
+ }
+
+ EJBQLPath path = (EJBQLPath) expression.getChild(1);
+
+ // make sure the ID for the path does not overlap with other condition
+ // joins...
+ String id = path.getAbsolutePath();
+
+ String correlatedEntityId = path.getId();
+ ClassDescriptor correlatedEntityDescriptor = context
+ .getEntityDescriptor(correlatedEntityId);
+ String correlatedTableName = correlatedEntityDescriptor
+ .getEntity()
+ .getDbEntity()
+ .getFullyQualifiedName();
+ String correlatedTableAlias = context.getTableAlias(
+ correlatedEntityId,
+ correlatedTableName);
+
+ String subqueryId = context.createIdAlias(id);
+ ClassDescriptor targetDescriptor =
context.getEntityDescriptor(subqueryId);
+ String subqueryTableName = targetDescriptor
+ .getEntity()
+ .getDbEntity()
+ .getFullyQualifiedName();
+ String subqueryRootAlias = context.getTableAlias(subqueryId,
subqueryTableName);
+
+ if (expression.isNegated()) {
+ context.append(" NOT");
}
+ context.append(" EXISTS (SELECT 1 FROM ");
+ // not using "AS" to separate table name and alias name - OpenBase
doesn't
+ // support "AS", and the rest of the databases do not care
+ context.append(subqueryTableName).append('
').append(subqueryRootAlias);
+ context.append(" WHERE");
+
+ ObjRelationship relationship = context.getIncomingRelationship(id);
+ // TODO: andrus, 8/11/2007 flattened?
+ DbRelationship correlatedJoinRelationship = (DbRelationship)
relationship
+ .getDbRelationships()
+ .get(0);
+ Iterator it = correlatedJoinRelationship.getJoins().iterator();
+ while (it.hasNext()) {
+ DbJoin join = (DbJoin) it.next();
+ context.append(' ').append(subqueryRootAlias).append('.').append(
+ join.getTargetName()).append(" = ");
+
context.append(correlatedTableAlias).append('.').append(join.getSourceName());
+ context.append(" AND");
+ }
+
+ // translate subquery_root_id = LHS_of_memberof
+ EJBQLEquals equals = new EJBQLEquals(-1);
+ EJBQLIdentificationVariable identifier = new
EJBQLIdentificationVariable(-1);
+ identifier.setText(subqueryId);
+ equals.jjtAddChild(identifier, 0);
+ equals.jjtAddChild((Node) expression.getChild(0), 1);
+ equals.visit(this);
+
+ context.append(")");
+
return false;
}
@@ -323,6 +391,32 @@
context.append(text);
}
}
+ }
+
+ public boolean visitIdentificationVariable(EJBQLExpression expression) {
+ // this is a match on a variable, like "x = :x"
+
+ ClassDescriptor descriptor =
context.getEntityDescriptor(expression.getText());
+ if (descriptor == null) {
+ throw new EJBQLException("Invalid identification variable: "
+ + expression.getText());
+ }
+
+ DbEntity table = descriptor.getEntity().getDbEntity();
+ String alias = context.getTableAlias(expression.getText(), table
+ .getFullyQualifiedName());
+
+ List pks = table.getPrimaryKey();
+
+ if (pks.size() == 1) {
+ DbAttribute pk = (DbAttribute) pks.get(0);
+ context.append(' ').append(alias).append('.').append(pk.getName());
+ }
+ else {
+ throw new EJBQLException(
+ "Multi-column PK to-many matches are not yet supported.");
+ }
+ return false;
}
public boolean visitPath(EJBQLExpression expression, int
finishedChildIndex) {
Modified:
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java?view=diff&rev=564992&r1=564991&r2=564992
==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLFromTranslator.java
Sat Aug 11 17:48:49 2007
@@ -96,9 +96,7 @@
String rhsId = join.getRightHandSideId();
- ObjRelationship joinRelationship = context
- .getCompiledExpression()
- .getIncomingRelationship(rhsId);
+ ObjRelationship joinRelationship =
context.getIncomingRelationship(rhsId);
if (joinRelationship == null) {
throw new EJBQLException("No join configured for id " + rhsId);
}
@@ -147,8 +145,7 @@
}
private String appendTable(String id) {
- ClassDescriptor descriptor =
context.getCompiledExpression().getEntityDescriptor(
- id);
+ ClassDescriptor descriptor = context.getEntityDescriptor(id);
String tableName =
descriptor.getEntity().getDbEntity().getFullyQualifiedName();
String alias = context.getTableAlias(id, tableName);
Modified:
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLIdentifierColumnsTranslator.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLIdentifierColumnsTranslator.java?view=diff&rev=564992&r1=564991&r2=564992
==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLIdentifierColumnsTranslator.java
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLIdentifierColumnsTranslator.java
Sat Aug 11 17:48:49 2007
@@ -58,8 +58,7 @@
final String idVar = expression.getText();
// append all table columns
- ClassDescriptor descriptor =
context.getCompiledExpression().getEntityDescriptor(
- idVar);
+ ClassDescriptor descriptor = context.getEntityDescriptor(idVar);
PropertyVisitor visitor = new PropertyVisitor() {
Modified:
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java?view=diff&rev=564992&r1=564991&r2=564992
==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLPathTranslator.java
Sat Aug 11 17:48:49 2007
@@ -82,8 +82,7 @@
}
public boolean visitIdentifier(EJBQLExpression expression) {
- ClassDescriptor descriptor =
context.getCompiledExpression().getEntityDescriptor(
- expression.getText());
+ ClassDescriptor descriptor =
context.getEntityDescriptor(expression.getText());
if (descriptor == null) {
throw new EJBQLException("Invalid identification variable: "
+ expression.getText());
@@ -150,7 +149,7 @@
join.jjtAddChild(path, 0);
join.jjtAddChild(joinId, 1);
getJoinAppender().visitInnerJoin(join);
-
+
this.lastAlias = context.getTableAlias(fullPath, currentEntity
.getDbEntityName());
}
@@ -159,10 +158,11 @@
join.jjtAddChild(path, 0);
join.jjtAddChild(joinId, 1);
getJoinAppender().visitOuterJoin(join);
-
- Relationship lastRelationship =
currentEntity.getRelationship(lastPathComponent);
+
+ Relationship lastRelationship = currentEntity
+ .getRelationship(lastPathComponent);
ObjEntity targetEntity = (ObjEntity)
lastRelationship.getTargetEntity();
-
+
this.lastAlias = context.getTableAlias(fullPath, targetEntity
.getDbEntityName());
}
@@ -239,11 +239,7 @@
if (pks.size() == 1) {
DbAttribute pk = (DbAttribute) pks.get(0);
- context
- .append(' ')
- .append(alias)
- .append('.')
- .append(pk.getName());
+ context.append('
').append(alias).append('.').append(pk.getName());
}
else {
throw new EJBQLException(
Modified:
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslationContext.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslationContext.java?view=diff&rev=564992&r1=564991&r2=564992
==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslationContext.java
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/main/java/org/apache/cayenne/access/jdbc/EJBQLTranslationContext.java
Sat Aug 11 17:48:49 2007
@@ -23,8 +23,10 @@
import org.apache.cayenne.ejbql.EJBQLCompiledExpression;
import org.apache.cayenne.ejbql.EJBQLException;
+import org.apache.cayenne.map.ObjRelationship;
import org.apache.cayenne.query.SQLResultSetMapping;
import org.apache.cayenne.query.SQLTemplate;
+import org.apache.cayenne.reflect.ClassDescriptor;
/**
* A context used for translating of EJBQL to SQL.
@@ -42,6 +44,7 @@
private Map attributes;
private Map reusableJoins;
private Map parameters;
+ private Map idAliases;
private int columnAliasPosition;
// a flag indicating whether column expressions should be treated as
result columns or
@@ -62,6 +65,57 @@
.getObjectClass(), sql);
query.setParameters(boundParameters);
return query;
+ }
+
+ private String resolveId(String id) {
+ if (idAliases == null) {
+ return id;
+ }
+
+ String resolvedAlias = (String) idAliases.get(id);
+ if (resolvedAlias != null) {
+ return resolvedAlias;
+ }
+
+ return id;
+ }
+
+ /**
+ * Looks up entity descriptor for an identifier that can be a compiled
expression id
+ * or one of the aliases.
+ */
+ ClassDescriptor getEntityDescriptor(String id) {
+ return compiledExpression.getEntityDescriptor(resolveId(id));
+ }
+
+ ObjRelationship getIncomingRelationship(String id) {
+ return compiledExpression.getIncomingRelationship(resolveId(id));
+ }
+
+ /**
+ * Creates a previously unused id alias for an entity identified by an id.
+ */
+ String createIdAlias(String id) {
+
+ if (idAliases == null) {
+ idAliases = new HashMap();
+ }
+
+ for (int i = 0; i < 1000; i++) {
+ String alias = id + "_alias" + i;
+ if (idAliases.containsKey(alias)) {
+ continue;
+ }
+
+ if (compiledExpression.getEntityDescriptor(alias) != null) {
+ continue;
+ }
+
+ idAliases.put(alias, id);
+ return alias;
+ }
+
+ throw new EJBQLException("Failed to create id alias");
}
/**
Added:
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLConditionsPeopleTest.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLConditionsPeopleTest.java?view=auto&rev=564992
==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLConditionsPeopleTest.java
(added)
+++
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLConditionsPeopleTest.java
Sat Aug 11 17:48:49 2007
@@ -0,0 +1,140 @@
+/*****************************************************************
+ * 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.cayenne.access;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.query.EJBQLQuery;
+import org.apache.cayenne.testdo.inherit.Address;
+import org.apache.cayenne.testdo.inherit.Department;
+import org.apache.cayenne.testdo.inherit.Manager;
+import org.apache.cayenne.unit.PeopleCase;
+
+public class DataContextEJBQLConditionsPeopleTest extends PeopleCase {
+
+ protected void setUp() throws Exception {
+ deleteTestData();
+
+ ObjectContext context = createDataContext();
+ Department d1 = (Department) context.newObject(Department.class);
+ d1.setName("d1");
+
+ Department d2 = (Department) context.newObject(Department.class);
+ d2.setName("d2");
+
+ Department d3 = (Department) context.newObject(Department.class);
+ d3.setName("d3");
+
+ context.commitChanges();
+
+ Manager m1 = (Manager) context.newObject(Manager.class);
+ m1.setName("m1");
+ m1.setPersonType("EM");
+
+ Manager m2 = (Manager) context.newObject(Manager.class);
+ m2.setName("m2");
+ m2.setPersonType("EM");
+
+ Manager m3 = (Manager) context.newObject(Manager.class);
+ m3.setName("m3");
+ m3.setPersonType("EM");
+
+ Address a1 = (Address) context.newObject(Address.class);
+ m1.addToAddresses(a1);
+
+ Address a2 = (Address) context.newObject(Address.class);
+ m2.addToAddresses(a2);
+
+ Address a3 = (Address) context.newObject(Address.class);
+ m3.addToAddresses(a3);
+
+ d1.addToEmployees(m1);
+ d1.addToEmployees(m2);
+ d3.addToEmployees(m3);
+
+ context.commitChanges();
+
+ d1.setToManager(m1);
+ d2.setToManager(m2);
+ d3.setToManager(m3);
+
+ context.commitChanges();
+ }
+
+ public void testCollectionMemberOfId() throws Exception {
+
+ String ejbql = "SELECT DISTINCT m FROM Manager m JOIN
m.managedDepartments d"
+ + " WHERE m MEMBER d.employees";
+
+ ObjectContext context = createDataContext();
+
+ EJBQLQuery query = new EJBQLQuery(ejbql);
+ List objects = context.performQuery(query);
+ assertEquals(2, objects.size());
+
+ Set ids = new HashSet();
+ Iterator it = objects.iterator();
+ while (it.hasNext()) {
+ Manager m = (Manager) it.next();
+ ids.add(m.getName());
+ }
+
+ assertTrue(ids.contains("m1"));
+ assertTrue(ids.contains("m3"));
+ }
+
+ public void testCollectionNotMemberOfId() throws Exception {
+
+ String ejbql = "SELECT DISTINCT m FROM Manager m JOIN
m.managedDepartments d"
+ + " WHERE m NOT MEMBER d.employees";
+
+ ObjectContext context = createDataContext();
+
+ EJBQLQuery query = new EJBQLQuery(ejbql);
+ List objects = context.performQuery(query);
+ assertEquals(1, objects.size());
+
+ Set ids = new HashSet();
+ Iterator it = objects.iterator();
+ while (it.hasNext()) {
+ Manager m = (Manager) it.next();
+ ids.add(m.getName());
+ }
+
+ assertTrue(ids.contains("m2"));
+ }
+
+ public void testCollectionNotMemberOfToOne() throws Exception {
+
+ // need a better test ... this query returns zero rows by definition
+ String ejbql = "SELECT a"
+ + " FROM Address a JOIN a.toEmployee m JOIN m.toDepartment d"
+ + " WHERE m NOT MEMBER d.employees";
+
+ ObjectContext context = createDataContext();
+
+ EJBQLQuery query = new EJBQLQuery(ejbql);
+ List objects = context.performQuery(query);
+ assertEquals(0, objects.size());
+ }
+}
Modified:
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLConditionsTest.java
URL:
http://svn.apache.org/viewvc/cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLConditionsTest.java?view=diff&rev=564992&r1=564991&r2=564992
==============================================================================
---
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLConditionsTest.java
(original)
+++
cayenne/main/trunk/framework/cayenne-jdk1.4-unpublished/src/test/java/org/apache/cayenne/access/DataContextEJBQLConditionsTest.java
Sat Aug 11 17:48:49 2007
@@ -237,7 +237,7 @@
public void testCollectionMemberOfParameter() throws Exception {
createTestData("prepareCollection");
- String ejbql = "SELECT a FROM Artist a " + "WHERE :x MEMBER OF
a.paintingArray";
+ String ejbql = "SELECT a FROM Artist a WHERE :x MEMBER OF
a.paintingArray";
ObjectContext context = createDataContext();
@@ -259,50 +259,50 @@
assertTrue(ids.contains(new Integer(33001)));
}
-// public void testCollectionNotMemberOfParameter() throws Exception {
-// createTestData("prepareCollection");
-//
-// String ejbql = "SELECT a FROM Artist a " + "WHERE :x NOT MEMBER
a.paintingArray";
-//
-// ObjectContext context = createDataContext();
-//
-// EJBQLQuery query = new EJBQLQuery(ejbql);
-// query.setParameter("x", DataObjectUtils.objectForPK(
-// context,
-// Painting.class,
-// 33010));
-// List objects = context.performQuery(query);
-// assertEquals(2, objects.size());
-//
-// Set ids = new HashSet();
-// Iterator it = objects.iterator();
-// while (it.hasNext()) {
-// Object id = DataObjectUtils.pkForObject((Persistent) it.next());
-// ids.add(id);
-// }
-//
-// assertTrue(ids.contains(new Integer(33002)));
-// assertTrue(ids.contains(new Integer(33003)));
-// }
-
-// public void testCollectionMemberOfThetaJoin() throws Exception {
-// createTestData("prepareCollection");
-//
-// String ejbql = "SELECT p FROM Painting p, Artist a "
-// + "WHERE p MEMBER OF a.paintingArray AND a.artistName = 'B'";
-//
-// EJBQLQuery query = new EJBQLQuery(ejbql);
-// List objects = createDataContext().performQuery(query);
-// assertEquals(2, objects.size());
-//
-// Set ids = new HashSet();
-// Iterator it = objects.iterator();
-// while (it.hasNext()) {
-// Object id = DataObjectUtils.pkForObject((Persistent) it.next());
-// ids.add(id);
-// }
-//
-// assertTrue(ids.contains(new Integer(33009)));
-// assertTrue(ids.contains(new Integer(33010)));
-// }
+ public void testCollectionNotMemberOfParameter() throws Exception {
+ createTestData("prepareCollection");
+
+ String ejbql = "SELECT a FROM Artist a WHERE :x NOT MEMBER
a.paintingArray";
+
+ ObjectContext context = createDataContext();
+
+ EJBQLQuery query = new EJBQLQuery(ejbql);
+ query.setParameter("x", DataObjectUtils.objectForPK(
+ context,
+ Painting.class,
+ 33010));
+ List objects = context.performQuery(query);
+ assertEquals(2, objects.size());
+
+ Set ids = new HashSet();
+ Iterator it = objects.iterator();
+ while (it.hasNext()) {
+ Object id = DataObjectUtils.pkForObject((Persistent) it.next());
+ ids.add(id);
+ }
+
+ assertTrue(ids.contains(new Integer(33002)));
+ assertTrue(ids.contains(new Integer(33003)));
+ }
+
+ public void testCollectionMemberOfThetaJoin() throws Exception {
+ createTestData("prepareCollection");
+
+ String ejbql = "SELECT p FROM Painting p, Artist a "
+ + "WHERE p MEMBER OF a.paintingArray AND a.artistName = 'B'";
+
+ EJBQLQuery query = new EJBQLQuery(ejbql);
+ List objects = createDataContext().performQuery(query);
+ assertEquals(2, objects.size());
+
+ Set ids = new HashSet();
+ Iterator it = objects.iterator();
+ while (it.hasNext()) {
+ Object id = DataObjectUtils.pkForObject((Persistent) it.next());
+ ids.add(id);
+ }
+
+ assertTrue(ids.contains(new Integer(33009)));
+ assertTrue(ids.contains(new Integer(33010)));
+ }
}