PageRenderTime 127ms CodeModel.GetById 15ms app.highlight 98ms RepoModel.GetById 1ms app.codeStats 1ms

/tests/com/google/appengine/datanucleus/query/JPQLQueryTest.java

http://datanucleus-appengine.googlecode.com/
Java | 3434 lines | 2943 code | 393 blank | 98 comment | 47 complexity | 3aab801a7e71a928c5a79dcec9a57053 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/**********************************************************************
   2 Copyright (c) 2009 Google Inc.
   3
   4 Licensed under the Apache License, Version 2.0 (the "License");
   5 you may not use this file except in compliance with the License.
   6 You may obtain a copy of the License at
   7
   8 http://www.apache.org/licenses/LICENSE-2.0
   9
  10 Unless required by applicable law or agreed to in writing, software
  11 distributed under the License is distributed on an "AS IS" BASIS,
  12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 See the License for the specific language governing permissions and
  14 limitations under the License.
  15 **********************************************************************/
  16package com.google.appengine.datanucleus.query;
  17
  18import com.google.appengine.api.datastore.DatastoreFailureException;
  19import com.google.appengine.api.datastore.DatastoreTimeoutException;
  20import com.google.appengine.api.datastore.Entity;
  21import com.google.appengine.api.datastore.Key;
  22import com.google.appengine.api.datastore.KeyFactory;
  23import com.google.appengine.api.datastore.Query.FilterOperator;
  24import com.google.appengine.api.datastore.Query.FilterPredicate;
  25import com.google.appengine.api.datastore.Query.SortDirection;
  26import com.google.appengine.api.datastore.Query.SortPredicate;
  27import com.google.appengine.api.datastore.ShortBlob;
  28import com.google.appengine.api.datastore.dev.LocalDatastoreService;
  29import com.google.appengine.datanucleus.DatastoreManager;
  30import com.google.appengine.datanucleus.DatastoreServiceFactoryInternal;
  31import com.google.appengine.datanucleus.DatastoreServiceInterceptor;
  32import com.google.appengine.datanucleus.ExceptionThrowingDatastoreDelegate;
  33import com.google.appengine.datanucleus.PrimitiveArrays;
  34import com.google.appengine.datanucleus.TestUtils;
  35import com.google.appengine.datanucleus.Utils;
  36import com.google.appengine.datanucleus.WriteBlocker;
  37import com.google.appengine.datanucleus.jpa.JPATestCase;
  38import com.google.appengine.datanucleus.test.jdo.Flight;
  39import com.google.appengine.datanucleus.test.jdo.KitchenSink;
  40import com.google.appengine.datanucleus.test.jdo.Person;
  41import com.google.appengine.datanucleus.test.jpa.BidirectionalChildListJPA;
  42import com.google.appengine.datanucleus.test.jpa.BidirectionalChildLongPkListJPA;
  43import com.google.appengine.datanucleus.test.jpa.BidirectionalGrandchildListJPA;
  44import com.google.appengine.datanucleus.test.jpa.Book;
  45import com.google.appengine.datanucleus.test.jpa.DetachableJPA;
  46import com.google.appengine.datanucleus.test.jpa.HasBytesJPA;
  47import com.google.appengine.datanucleus.test.jpa.HasDoubleJPA;
  48import com.google.appengine.datanucleus.test.jpa.HasEncodedStringPkJPA;
  49import com.google.appengine.datanucleus.test.jpa.HasEncodedStringPkSeparateIdFieldJPA;
  50import com.google.appengine.datanucleus.test.jpa.HasEncodedStringPkSeparateNameFieldJPA;
  51import com.google.appengine.datanucleus.test.jpa.HasEnumJPA;
  52import com.google.appengine.datanucleus.test.jpa.HasFloatJPA;
  53import com.google.appengine.datanucleus.test.jpa.HasKeyAncestorStringPkJPA;
  54import com.google.appengine.datanucleus.test.jpa.HasKeyPkJPA;
  55import com.google.appengine.datanucleus.test.jpa.HasLongPkJPA;
  56import com.google.appengine.datanucleus.test.jpa.HasMultiValuePropsJPA;
  57import com.google.appengine.datanucleus.test.jpa.HasOneToManyKeyPkListJPA;
  58import com.google.appengine.datanucleus.test.jpa.HasOneToManyKeyPkSetJPA;
  59import com.google.appengine.datanucleus.test.jpa.HasOneToManyListJPA;
  60import com.google.appengine.datanucleus.test.jpa.HasOneToManyLongPkListJPA;
  61import com.google.appengine.datanucleus.test.jpa.HasOneToManyLongPkSetJPA;
  62import com.google.appengine.datanucleus.test.jpa.HasOneToManyUnencodedStringPkListJPA;
  63import com.google.appengine.datanucleus.test.jpa.HasOneToManyUnencodedStringPkSetJPA;
  64import com.google.appengine.datanucleus.test.jpa.HasOneToOneJPA;
  65import com.google.appengine.datanucleus.test.jpa.HasOneToOneParentJPA;
  66import com.google.appengine.datanucleus.test.jpa.HasStringAncestorStringPkJPA;
  67import com.google.appengine.datanucleus.test.jpa.HasUnencodedStringPkJPA;
  68import com.google.appengine.datanucleus.test.jpa.InTheHouseJPA;
  69import com.google.appengine.datanucleus.test.jpa.NullDataJPA;
  70import com.google.appengine.datanucleus.test.jpa.AbstractBaseClassesJPA.Base1;
  71import com.google.appengine.datanucleus.test.jpa.UnidirectionalSingeTableChildJPA.UnidirTop;
  72import com.google.apphosting.api.ApiProxy;
  73import com.google.apphosting.api.DatastorePb;
  74
  75import org.datanucleus.api.jpa.JPAQuery;
  76import org.datanucleus.exceptions.NucleusFatalUserException;
  77import org.datanucleus.exceptions.NucleusUserException;
  78import org.datanucleus.query.expression.Expression;
  79import org.easymock.EasyMock;
  80
  81import java.io.ByteArrayOutputStream;
  82import java.io.IOException;
  83import java.io.ObjectOutputStream;
  84import java.math.BigDecimal;
  85import java.util.Arrays;
  86import java.util.Collections;
  87import java.util.Date;
  88import java.util.HashMap;
  89import java.util.HashSet;
  90import java.util.Iterator;
  91import java.util.List;
  92import java.util.Map;
  93import java.util.Set;
  94import java.util.concurrent.ExecutionException;
  95import java.util.concurrent.Future;
  96
  97import javax.persistence.NoResultException;
  98import javax.persistence.NonUniqueResultException;
  99import javax.persistence.PersistenceException;
 100import javax.persistence.Query;
 101import javax.persistence.QueryTimeoutException;
 102import javax.persistence.TypedQuery;
 103
 104import static com.google.appengine.datanucleus.test.jdo.Flight.newFlightEntity;
 105
 106/**
 107 * @author Max Ross <maxr@google.com>
 108 */
 109public class JPQLQueryTest extends JPATestCase {
 110
 111  private static final List<SortPredicate> NO_SORTS = Collections.emptyList();
 112  private static final List<FilterPredicate> NO_FILTERS = Collections.emptyList();
 113
 114  private static final FilterPredicate TITLE_EQ_2 =
 115      new FilterPredicate("title", FilterOperator.EQUAL, 2L);
 116  private static final FilterPredicate TITLE_EQ_2STR =
 117      new FilterPredicate("title", FilterOperator.EQUAL, "2");
 118  private static final FilterPredicate ISBN_EQ_4 =
 119      new FilterPredicate("isbn", FilterOperator.EQUAL, 4L);
 120  private static final FilterPredicate TITLE_GT_2 =
 121      new FilterPredicate("title", FilterOperator.GREATER_THAN, 2L);
 122  private static final FilterPredicate TITLE_GTE_2 =
 123      new FilterPredicate("title", FilterOperator.GREATER_THAN_OR_EQUAL, 2L);
 124  private static final FilterPredicate ISBN_LT_4 =
 125      new FilterPredicate("isbn", FilterOperator.LESS_THAN, 4L);
 126  private static final FilterPredicate ISBN_LTE_4 =
 127      new FilterPredicate("isbn", FilterOperator.LESS_THAN_OR_EQUAL, 4L);
 128  private static final FilterPredicate TITLE_NEQ_NULL_LITERAL =
 129      new FilterPredicate("title", FilterOperator.NOT_EQUAL, null);
 130  private static final FilterPredicate TITLE_NEQ_2_LITERAL =
 131      new FilterPredicate("title", FilterOperator.NOT_EQUAL, 2L);
 132  private static final SortPredicate TITLE_ASC =
 133      new SortPredicate("title", SortDirection.ASCENDING);
 134  private static final SortPredicate ISBN_DESC =
 135      new SortPredicate("isbn", SortDirection.DESCENDING);
 136  private static final FilterPredicate TITLE_IN_2_ARGS =
 137      new FilterPredicate("title", FilterOperator.IN, Arrays.asList("2", 2L));
 138  private static final FilterPredicate TITLE_IN_3_ARGS =
 139      new FilterPredicate("title", FilterOperator.IN, Arrays.asList("2", 2L, false));
 140
 141  @Override
 142  protected void setUp() throws Exception {
 143    super.setUp();
 144    DatastoreServiceInterceptor.install(getStoreManager(), new WriteBlocker());
 145  }
 146
 147  @Override
 148  protected void tearDown() throws Exception {
 149    try {
 150      super.tearDown();
 151    } finally {
 152      DatastoreServiceInterceptor.uninstall();
 153    }
 154  }
 155
 156  @Override
 157  protected EntityManagerFactoryName getEntityManagerFactoryName() {
 158    return EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_allowed;
 159  }
 160
 161  public void testUnsupportedFilters_NoResultExpr() {
 162    String baseQuery = "SELECT FROM " + Book.class.getName() + " b ";
 163    testUnsupportedFilters(baseQuery);
 164  }
 165
 166  public void testUnsupportedFilters_PrimaryResultExpr() {
 167    String baseQuery = "SELECT b FROM " + Book.class.getName() + " b ";
 168    testUnsupportedFilters(baseQuery);
 169  }
 170
 171  private void testUnsupportedFilters(String baseQuery) {
 172    Set<Expression.Operator> unsupportedOps =
 173        new HashSet<Expression.Operator>(DatastoreQuery.UNSUPPORTED_OPERATORS);
 174    baseQuery += "WHERE ";
 175    assertQueryUnsupportedByOrm(baseQuery + "NOT title = 'foo'", Expression.OP_NOT, unsupportedOps);
 176    assertQueryUnsupportedByOrm(baseQuery + "(title + author) = 'foo'", Expression.OP_ADD,
 177                                unsupportedOps);
 178    assertQueryUnsupportedByOrm(baseQuery + "title + author = 'foo'", Expression.OP_ADD,
 179                                unsupportedOps);
 180    assertQueryUnsupportedByOrm(baseQuery + "(title - author) = 'foo'", Expression.OP_SUB,
 181                                unsupportedOps);
 182    assertQueryUnsupportedByOrm(baseQuery + "title - author = 'foo'", Expression.OP_SUB,
 183                                unsupportedOps);
 184    assertQueryUnsupportedByOrm(baseQuery + "(title / author) = 'foo'", Expression.OP_DIV,
 185                                unsupportedOps);
 186    assertQueryUnsupportedByOrm(baseQuery + "title / author = 'foo'", Expression.OP_DIV,
 187                                unsupportedOps);
 188    assertQueryUnsupportedByOrm(baseQuery + "(title * author) = 'foo'", Expression.OP_MUL,
 189                                unsupportedOps);
 190    assertQueryUnsupportedByOrm(baseQuery + "title * author = 'foo'", Expression.OP_MUL,
 191                                unsupportedOps);
 192    assertQueryUnsupportedByOrm(baseQuery + "(title % author) = 'foo'", Expression.OP_MOD,
 193                                unsupportedOps);
 194    assertQueryUnsupportedByOrm(baseQuery + "title % author = 'foo'", Expression.OP_MOD,
 195                                unsupportedOps);
 196    assertQueryRequiresUnsupportedDatastoreFeature(baseQuery + "title LIKE '%foo'");
 197    // can't have 'or' on multiple properties
 198    assertQueryRequiresUnsupportedDatastoreFeature(baseQuery + "title = 'yar' or author = null");
 199    assertQueryRequiresUnsupportedDatastoreFeature(baseQuery + "isbn = 4 and (title = 'yar' or author = 'yam')");
 200    assertQueryRequiresUnsupportedDatastoreFeature(baseQuery + "title IN('yar') or author = 'yam'");
 201    // can only check equality
 202    assertQueryRequiresUnsupportedDatastoreFeature(baseQuery + "title > 5 or title < 2");
 203
 204    // multiple inequality filters
 205    // TODO(maxr) Make this pass against the real datastore.
 206    // We need to have it return BadRequest instead of NeedIndex for that to happen.
 207    assertQueryUnsupportedByDatastore(baseQuery + "(title > 2 AND isbn < 4)", IllegalArgumentException.class);
 208    // inequality filter prop is not the same as the first order by prop
 209    assertQueryUnsupportedByDatastore(baseQuery + "(title > 2) order by isbn", IllegalArgumentException.class);
 210    // gets split into multiple inequality props
 211    assertQueryUnsupportedByDatastore(baseQuery + "title <> 2 AND isbn <> 4", IllegalArgumentException.class);
 212    assertEquals(
 213        new HashSet<Expression.Operator>(Arrays.asList(Expression.OP_CONCAT, Expression.OP_COM,
 214                                                       Expression.OP_NEG, Expression.OP_IS,
 215                                                       Expression.OP_LIKE,
 216                                                       Expression.OP_ISNOT)), unsupportedOps);
 217  }
 218
 219  public void testEvaluateInMemory() {
 220    ds.put(null, newFlightEntity("1", "yar", "bam", 1, 2));
 221    ds.put(null, newFlightEntity("1", "yam", null, 1, 2));
 222
 223    // This is impossible in the datastore, so run totally in-memory
 224    String query = "SELECT f FROM " + Flight.class.getName() + " f WHERE origin = 'yar' OR dest IS null";
 225    Query q = em.createQuery(query);
 226    q.setHint("datanucleus.query.evaluateInMemory", "true");
 227    try {
 228       List<Flight> results = (List<Flight>) q.getResultList();
 229       assertEquals("Number of results was wrong", 2, results.size());
 230    } catch (RuntimeException e) {
 231      fail("Threw exception when evaluating query in-memory, but should have run");
 232    }
 233  }
 234
 235  public void testSupportedFilters_NoResultExpr() {
 236    String baseQuery = "SELECT FROM " + Book.class.getName() + " b ";
 237    testSupportedFilters(baseQuery);
 238  }
 239
 240  public void testSupportedFilters_PrimaryResultExpr() {
 241    String baseQuery = "SELECT b FROM " + Book.class.getName() + " b ";
 242    testSupportedFilters(baseQuery);
 243  }
 244
 245  private void testSupportedFilters(String baseQuery) {
 246
 247    assertQuerySupported(baseQuery, NO_FILTERS, NO_SORTS);
 248
 249    baseQuery += "WHERE ";
 250    assertQuerySupported(baseQuery + "title = 2", Utils.newArrayList(TITLE_EQ_2), NO_SORTS);
 251    assertQuerySupported(baseQuery + "title = \"2\"", Utils.newArrayList(TITLE_EQ_2STR), NO_SORTS);
 252    assertQuerySupported(baseQuery + "(title = 2)", Utils.newArrayList(TITLE_EQ_2), NO_SORTS);
 253    assertQuerySupported(baseQuery + "title = 2 AND isbn = 4",
 254                         Utils.newArrayList(TITLE_EQ_2,ISBN_EQ_4),
 255                         NO_SORTS);
 256    assertQuerySupported(baseQuery + "(title = 2 AND isbn = 4)",
 257                         Utils.newArrayList(TITLE_EQ_2, ISBN_EQ_4),
 258                         NO_SORTS);
 259    assertQuerySupported(baseQuery + "(title = 2) AND (isbn = 4)", Utils.newArrayList(
 260        TITLE_EQ_2, ISBN_EQ_4), NO_SORTS);
 261    assertQuerySupported(baseQuery + "title > 2", Utils.newArrayList(TITLE_GT_2), NO_SORTS);
 262    assertQuerySupported(baseQuery + "title >= 2", Utils.newArrayList(TITLE_GTE_2), NO_SORTS);
 263    assertQuerySupported(baseQuery + "isbn < 4", Utils.newArrayList(ISBN_LT_4), NO_SORTS);
 264    assertQuerySupported(baseQuery + "isbn <= 4", Utils.newArrayList(ISBN_LTE_4), NO_SORTS);
 265
 266    baseQuery = "SELECT FROM " + Book.class.getName() + " b ";
 267    assertQuerySupported(baseQuery + "ORDER BY title ASC", NO_FILTERS,
 268                         Utils.newArrayList(TITLE_ASC));
 269    assertQuerySupported(baseQuery + "ORDER BY isbn DESC", NO_FILTERS,
 270                         Utils.newArrayList(ISBN_DESC));
 271    assertQuerySupported(baseQuery + "ORDER BY title ASC, isbn DESC", NO_FILTERS,
 272                         Utils.newArrayList(TITLE_ASC, ISBN_DESC));
 273
 274    assertQuerySupported(baseQuery + "WHERE title = 2 AND isbn = 4 ORDER BY title ASC, isbn DESC",
 275                         Utils.newArrayList(TITLE_EQ_2, ISBN_EQ_4),
 276                         Utils.newArrayList(TITLE_ASC, ISBN_DESC));
 277    assertQuerySupported(baseQuery + "WHERE title <> null",
 278                         Utils.newArrayList(TITLE_NEQ_NULL_LITERAL), NO_SORTS);
 279    assertQuerySupported(baseQuery + "WHERE title <> 2",
 280                         Utils.newArrayList(TITLE_NEQ_2_LITERAL), NO_SORTS);
 281    assertQuerySupported(baseQuery + "WHERE title = '2' OR title = 2",
 282                         Utils.newArrayList(TITLE_IN_2_ARGS), NO_SORTS);
 283    assertQuerySupported(baseQuery + "WHERE title = '2' OR title = 2 OR title = false",
 284                         Utils.newArrayList(TITLE_IN_3_ARGS), NO_SORTS);
 285    assertQuerySupported(baseQuery + "WHERE title IN ('2', 2)",
 286                         Utils.newArrayList(TITLE_IN_2_ARGS), NO_SORTS);
 287    assertQuerySupported(baseQuery + "WHERE title IN ('2', 2, false)",
 288                         Utils.newArrayList(TITLE_IN_3_ARGS), NO_SORTS);
 289    assertQuerySupported(baseQuery + "WHERE (title = '2' OR title = 2) AND isbn = 4",
 290                         Utils.newArrayList(ISBN_EQ_4, TITLE_IN_2_ARGS), NO_SORTS);
 291    assertQuerySupported(baseQuery + "WHERE title IN ('2', 2) AND isbn = 4",
 292                         Utils.newArrayList(ISBN_EQ_4, TITLE_IN_2_ARGS), NO_SORTS);
 293    assertQuerySupported(baseQuery + "WHERE (title = '2' OR title = 2 OR title = false) AND isbn = 4",
 294                         Utils.newArrayList(ISBN_EQ_4, TITLE_IN_3_ARGS), NO_SORTS);
 295    assertQuerySupported(baseQuery + "WHERE title IN ('2', 2, false) AND isbn = 4",
 296                         Utils.newArrayList(ISBN_EQ_4, TITLE_IN_3_ARGS), NO_SORTS);
 297  }
 298
 299  public void test2Equals2OrderBy() {
 300    ds.put(Book.newBookEntity("Joe Blow", "67890", "Bar Book"));
 301    ds.put(Book.newBookEntity("Joe Blow", "11111", "Bar Book"));
 302    ds.put(Book.newBookEntity("Joe Blow", "12345", "Foo Book"));
 303    ds.put(Book.newBookEntity("Joe Blow", "54321", "A Book"));
 304    ds.put(Book.newBookEntity("Jane Blow", "13579", "Baz Book"));
 305
 306    Query q = em.createQuery("SELECT FROM " +
 307                             Book.class.getName() + " b" +
 308                             " WHERE author = 'Joe Blow'" +
 309                             " ORDER BY title DESC, isbn ASC");
 310
 311    @SuppressWarnings("unchecked")
 312    List<Book> result = (List<Book>) q.getResultList();
 313
 314    assertEquals(4, result.size());
 315    assertEquals("12345", result.get(0).getIsbn());
 316    assertEquals("11111", result.get(1).getIsbn());
 317    assertEquals("67890", result.get(2).getIsbn());
 318    assertEquals("54321", result.get(3).getIsbn());
 319  }
 320
 321  public void testDefaultOrderingIsAsc() {
 322    ds.put(Book.newBookEntity("Joe Blow", "67890", "Bar Book"));
 323    ds.put(Book.newBookEntity("Joe Blow", "11111", "Bar Book"));
 324    ds.put(Book.newBookEntity("Joe Blow", "12345", "Foo Book"));
 325    ds.put(Book.newBookEntity("Joe Blow", "54321", "A Book"));
 326    ds.put(Book.newBookEntity("Jane Blow", "13579", "Baz Book"));
 327
 328    Query q = em.createQuery("SELECT FROM " +
 329                             Book.class.getName() + " b" +
 330                             " WHERE author = 'Joe Blow'" +
 331                             " ORDER BY title");
 332
 333    @SuppressWarnings("unchecked")
 334    List<Book> result = (List<Book>) q.getResultList();
 335
 336    assertEquals(4, result.size());
 337    assertEquals("54321", result.get(0).getIsbn());
 338    assertEquals("67890", result.get(1).getIsbn());
 339    assertEquals("11111", result.get(2).getIsbn());
 340    assertEquals("12345", result.get(3).getIsbn());
 341  }
 342
 343  public void testLimitQuery() {
 344    ds.put(Book.newBookEntity("Joe Blow", "67890", "Bar Book"));
 345    ds.put(Book.newBookEntity("Joe Blow", "11111", "Bar Book"));
 346    ds.put(Book.newBookEntity("Joe Blow", "12345", "Foo Book"));
 347    ds.put(Book.newBookEntity("Joe Blow", "54321", "A Book"));
 348    ds.put(Book.newBookEntity("Jane Blow", "13579", "Baz Book"));
 349
 350    Query q = em.createQuery("SELECT FROM " +
 351                             Book.class.getName() + " b" + 
 352                             " WHERE author = 'Joe Blow'" +
 353                             " ORDER BY title DESC, isbn ASC");
 354
 355    q.setMaxResults(1);
 356    @SuppressWarnings("unchecked")
 357    List<Book> result1 = (List<Book>) q.getResultList();
 358    assertEquals(1, result1.size());
 359    assertEquals("12345", result1.get(0).getIsbn());
 360
 361    q.setMaxResults(0);
 362    @SuppressWarnings("unchecked")
 363    List<Book> result2 = (List<Book>) q.getResultList();
 364    assertEquals(0, result2.size());
 365
 366    try {
 367      q.setMaxResults(-1);
 368      fail("expected iae");
 369    } catch (IllegalArgumentException iae) {
 370      // good
 371    }
 372  }
 373
 374  public void testOffsetQuery() {
 375    ds.put(Book.newBookEntity("Joe Blow", "67890", "Bar Book"));
 376    ds.put(Book.newBookEntity("Joe Blow", "11111", "Bar Book"));
 377    ds.put(Book.newBookEntity("Joe Blow", "12345", "Foo Book"));
 378    ds.put(Book.newBookEntity("Joe Blow", "54321", "A Book"));
 379    ds.put(Book.newBookEntity("Jane Blow", "13579", "Baz Book"));
 380    Query q = em.createQuery("SELECT FROM " +
 381                             Book.class.getName() + " b" + 
 382                             " WHERE author = 'Joe Blow'" +
 383                             " ORDER BY title DESC, isbn ASC");
 384
 385    q.setFirstResult(0);
 386    @SuppressWarnings("unchecked")
 387    List<Book> result1 = (List<Book>) q.getResultList();
 388    assertEquals(4, result1.size());
 389    assertEquals("12345", result1.get(0).getIsbn());
 390
 391    q.setFirstResult(1);
 392    @SuppressWarnings("unchecked")
 393    List<Book> result2 = (List<Book>) q.getResultList();
 394    assertEquals(3, result2.size());
 395    assertEquals("11111", result2.get(0).getIsbn());
 396
 397    try {
 398      q.setFirstResult(-1);
 399      fail("expected iae");
 400    } catch (IllegalArgumentException iae) {
 401      // good
 402    }
 403  }
 404
 405  public void testOffsetLimitQuery() {
 406    ds.put(Book.newBookEntity("Joe Blow", "67890", "Bar Book"));
 407    ds.put(Book.newBookEntity("Joe Blow", "11111", "Bar Book"));
 408    ds.put(Book.newBookEntity("Joe Blow", "12345", "Foo Book"));
 409    ds.put(Book.newBookEntity("Joe Blow", "54321", "A Book"));
 410    ds.put(Book.newBookEntity("Jane Blow", "13579", "Baz Book"));
 411    Query q = em.createQuery("SELECT FROM " +
 412                             Book.class.getName() + " b" + 
 413                             " WHERE author = 'Joe Blow'" +
 414                             " ORDER BY title DESC, isbn ASC");
 415
 416    q.setFirstResult(0);
 417    q.setMaxResults(0);
 418    @SuppressWarnings("unchecked")
 419    List<Book> result1 = (List<Book>) q.getResultList();
 420    assertEquals(0, result1.size());
 421
 422    q.setFirstResult(1);
 423    q.setMaxResults(0);
 424    @SuppressWarnings("unchecked")
 425    List<Book> result2 = (List<Book>) q.getResultList();
 426    assertEquals(0, result2.size());
 427
 428    q.setFirstResult(0);
 429    q.setMaxResults(1);
 430    @SuppressWarnings("unchecked")
 431    List<Book> result3 = (List<Book>) q.getResultList();
 432    assertEquals(1, result3.size());
 433
 434    q.setFirstResult(0);
 435    q.setMaxResults(2);
 436    @SuppressWarnings("unchecked")
 437    List<Book> result4 = (List<Book>) q.getResultList();
 438    assertEquals(2, result4.size());
 439    assertEquals("12345", result4.get(0).getIsbn());
 440
 441    q.setFirstResult(1);
 442    q.setMaxResults(1);
 443    @SuppressWarnings("unchecked")
 444    List<Book> result5 = (List<Book>) q.getResultList();
 445    assertEquals(1, result5.size());
 446    assertEquals("11111", result5.get(0).getIsbn());
 447
 448    q.setFirstResult(2);
 449    q.setMaxResults(5);
 450    @SuppressWarnings("unchecked")
 451    List<Book> result6 = (List<Book>) q.getResultList();
 452    assertEquals(2, result6.size());
 453    assertEquals("67890", result6.get(0).getIsbn());
 454  }
 455
 456  public void testSerialization() throws IOException {
 457    Query q = em.createQuery("select from " + Book.class.getName() + " b ");
 458    q.getResultList();
 459
 460    JPQLQuery innerQuery = (JPQLQuery) ((JPAQuery) q).getInternalQuery();
 461    ByteArrayOutputStream baos = new ByteArrayOutputStream();
 462    ObjectOutputStream oos = new ObjectOutputStream(baos);
 463    // the fact that this doesn't blow up is the test
 464    oos.writeObject(innerQuery);
 465  }
 466
 467  public void testBindVariables() {
 468
 469    assertQuerySupported("select from " + Book.class.getName() + " b where title = :titleParam",
 470                         Utils.newArrayList(TITLE_EQ_2), NO_SORTS, "titleParam", 2L);
 471
 472    assertQuerySupported("select from " + Book.class.getName() + " b" + 
 473                         " where title = :titleParam AND isbn = :isbnParam",
 474                         Utils.newArrayList(TITLE_EQ_2, ISBN_EQ_4), NO_SORTS, "titleParam", 2L, "isbnParam", 4L);
 475
 476    assertQuerySupported("select from " + Book.class.getName() + " b" + 
 477                         " where title = :titleParam AND isbn = :isbnParam order by title asc, isbn desc",
 478                         Utils.newArrayList(TITLE_EQ_2, ISBN_EQ_4),
 479                         Utils.newArrayList(TITLE_ASC, ISBN_DESC), "titleParam", 2L, "isbnParam", 4L);
 480  }
 481
 482  public void testKeyQuery() {
 483    Entity bookEntity = Book.newBookEntity("Joe Blow", "67890", "Bar Book");
 484    ds.put(bookEntity);
 485
 486    javax.persistence.Query q = em.createQuery(
 487        "select from " + Book.class.getName() + " b where id = :key");
 488    q.setParameter("key", KeyFactory.keyToString(bookEntity.getKey()));
 489    @SuppressWarnings("unchecked")
 490    List<Book> books = (List<Book>) q.getResultList();
 491    assertEquals(1, books.size());
 492    assertEquals(bookEntity.getKey(), KeyFactory.stringToKey(books.get(0).getId()));
 493
 494    // now issue the same query, but instead of providing a String version of
 495    // the key, provide the Key itself.
 496    q.setParameter("key", bookEntity.getKey());
 497    @SuppressWarnings("unchecked")
 498    List<Book> books2 = (List<Book>) q.getResultList();
 499    assertEquals(1, books2.size());
 500    assertEquals(bookEntity.getKey(), KeyFactory.stringToKey(books2.get(0).getId()));
 501  }
 502
 503  public void testKeyQuery_KeyPk() {
 504    Entity entityWithName = new Entity(HasKeyPkJPA.class.getSimpleName(), "blarg");
 505    Entity entityWithId = new Entity(HasKeyPkJPA.class.getSimpleName());
 506    ds.put(entityWithName);
 507    ds.put(entityWithId);
 508
 509    Query q = em.createQuery(
 510        "select from " + HasKeyPkJPA.class.getName() + " b where id = :key");
 511    q.setParameter("key", entityWithName.getKey());
 512    HasKeyPkJPA result = (HasKeyPkJPA) q.getSingleResult();
 513    assertEquals(entityWithName.getKey(), result.getId());
 514
 515    q = em.createQuery("select from " + HasKeyPkJPA.class.getName() + " b where id = :mykey");
 516    q.setParameter("mykey", entityWithId.getKey());
 517    result = (HasKeyPkJPA) q.getSingleResult();
 518    assertEquals(entityWithId.getKey(), result.getId());
 519
 520    q = em.createQuery("select from " + HasKeyPkJPA.class.getName() + " b where id = :mykeyname");
 521    q.setParameter("mykeyname", entityWithName.getKey().getName());
 522    result = (HasKeyPkJPA) q.getSingleResult();
 523    assertEquals(entityWithName.getKey(), result.getId());
 524
 525    q = em.createQuery("select from " + HasKeyPkJPA.class.getName() + " b where id = :mykeyid");
 526    q.setParameter("mykeyid", entityWithId.getKey().getId());
 527    result = (HasKeyPkJPA) q.getSingleResult();
 528    assertEquals(entityWithId.getKey(), result.getId());
 529  }
 530
 531  public void testKeyQueryWithSorts() {
 532    Entity bookEntity = Book.newBookEntity("Joe Blow", "67890", "Bar Book");
 533    ds.put(bookEntity);
 534
 535    javax.persistence.Query q = em.createQuery(
 536        "select from " + Book.class.getName() + " c where id = :key order by isbn ASC");
 537    q.setParameter("key", KeyFactory.keyToString(bookEntity.getKey()));
 538    @SuppressWarnings("unchecked")
 539    List<Book> books = (List<Book>) q.getResultList();
 540    assertEquals(1, books.size());
 541    assertEquals(bookEntity.getKey(), KeyFactory.stringToKey(books.get(0).getId()));
 542  }
 543
 544  public void testKeyQuery_MultipleFilters() {
 545    Entity bookEntity = Book.newBookEntity("Joe Blow", "67890", "Bar Book");
 546    ds.put(bookEntity);
 547
 548    javax.persistence.Query q = em.createQuery(
 549        "select from " + Book.class.getName() + " c where id = :key and isbn = \"67890\"");
 550    q.setParameter("key", KeyFactory.keyToString(bookEntity.getKey()));
 551    @SuppressWarnings("unchecked")
 552    List<Book> books = (List<Book>) q.getResultList();
 553    assertEquals(1, books.size());
 554    assertEquals(bookEntity.getKey(), KeyFactory.stringToKey(books.get(0).getId()));
 555  }
 556
 557  public void testKeyQuery_NonEqualityFilter() {
 558    Entity bookEntity1 = Book.newBookEntity("Joe Blow", "67890", "Bar Book");
 559    ds.put(bookEntity1);
 560
 561    Entity bookEntity2 = Book.newBookEntity("Joe Blow", "67890", "Bar Book");
 562    ds.put(bookEntity2);
 563
 564    javax.persistence.Query q = em.createQuery(
 565        "select from " + Book.class.getName()
 566        + " b where id > :key");
 567    q.setParameter("key", KeyFactory.keyToString(bookEntity1.getKey()));
 568    @SuppressWarnings("unchecked")
 569    List<Book> books = (List<Book>) q.getResultList();
 570    assertEquals(1, books.size());
 571    assertEquals(bookEntity2.getKey(), KeyFactory.stringToKey(books.get(0).getId()));
 572  }
 573
 574  public void testKeyQuery_SortByKey() {
 575    Entity bookEntity1 = Book.newBookEntity("Joe Blow", "67890", "Bar Book");
 576    ds.put(bookEntity1);
 577
 578    Entity bookEntity2 = Book.newBookEntity("Joe Blow", "67890", "Bar Book");
 579    ds.put(bookEntity2);
 580
 581    javax.persistence.Query q = em.createQuery(
 582        "select from " + Book.class.getName()
 583        + " b order by id DESC");
 584    @SuppressWarnings("unchecked")
 585    List<Book> books = (List<Book>) q.getResultList();
 586    assertEquals(2, books.size());
 587    assertEquals(bookEntity2.getKey(), KeyFactory.stringToKey(books.get(0).getId()));
 588  }
 589
 590  public void testKeyQuery_FilterAndSortByKeyComponent() {
 591    // filter by pk-id
 592    assertQueryUnsupportedByDatastore(
 593        "select from " + HasEncodedStringPkSeparateIdFieldJPA.class.getName() + " b where id = 4",
 594        NucleusFatalUserException.class);
 595    // sort by pk-id
 596    assertQueryUnsupportedByDatastore(
 597        "select from " + HasEncodedStringPkSeparateIdFieldJPA.class.getName() + " b order by id",
 598        NucleusFatalUserException.class);
 599    // filter by pk-id
 600    assertQueryUnsupportedByDatastore(
 601        "select from " + HasEncodedStringPkSeparateNameFieldJPA.class.getName() + " b where name = 4",
 602        NucleusFatalUserException.class);
 603    // sort by pk-id
 604    assertQueryUnsupportedByDatastore(
 605        "select from " + HasEncodedStringPkSeparateNameFieldJPA.class.getName() + " b order by name",
 606        NucleusFatalUserException.class);
 607  }
 608
 609  public void testAncestorQuery() {
 610    Entity bookEntity = Book.newBookEntity("Joe Blow", "67890", "Bar Book");
 611    ds.put(bookEntity);
 612    Entity
 613        hasAncestorEntity =
 614        new Entity(HasStringAncestorStringPkJPA.class.getSimpleName(), bookEntity.getKey());
 615    ds.put(hasAncestorEntity);
 616
 617    javax.persistence.Query q = em.createQuery(
 618        "select from " + HasStringAncestorStringPkJPA.class.getName()
 619        + " b where ancestorId = :ancId");
 620    q.setParameter("ancId", KeyFactory.keyToString(bookEntity.getKey()));
 621
 622    @SuppressWarnings("unchecked")
 623    List<HasStringAncestorStringPkJPA>
 624        haList =
 625        (List<HasStringAncestorStringPkJPA>) q.getResultList();
 626    assertEquals(1, haList.size());
 627    assertEquals(bookEntity.getKey(), KeyFactory.stringToKey(haList.get(0).getAncestorId()));
 628
 629    assertEquals(
 630        bookEntity.getKey(), getDatastoreQuery(q).getLatestDatastoreQuery().getAncestor());
 631    assertEquals(NO_FILTERS, getFilterPredicates(q));
 632    assertEquals(NO_SORTS, getSortPredicates(q));
 633  }
 634
 635  public void testIllegalAncestorQuery() {
 636    Entity bookEntity = Book.newBookEntity("Joe Blow", "67890", "Bar Book");
 637    ds.put(bookEntity);
 638    Entity
 639        hasAncestorEntity =
 640        new Entity(HasStringAncestorStringPkJPA.class.getName(), bookEntity.getKey());
 641    ds.put(hasAncestorEntity);
 642
 643    javax.persistence.Query q = em.createQuery(
 644        "select from " + HasStringAncestorStringPkJPA.class.getName() + " b"
 645        + " where ancestorId > :ancId");
 646    q.setParameter("ancId", KeyFactory.keyToString(bookEntity.getKey()));
 647    q.setHint(DatastoreManager.QUERYEXT_INMEMORY_WHEN_UNSUPPORTED, "false");
 648    try {
 649      q.getResultList();
 650      fail("expected udfe");
 651    } catch (PersistenceException pe) {
 652        if (pe.getCause() instanceof DatastoreQuery.UnsupportedDatastoreFeatureException) {
 653            // good
 654        }
 655        else {
 656          throw pe;
 657        }
 658    }
 659  }
 660
 661  public void testSortByFieldWithCustomColumn() {
 662    ds.put(Book.newBookEntity("Joe Blow", "67890", "Bar Book", 2003));
 663    ds.put(Book.newBookEntity("Joe Blow", "11111", "Bar Book", 2002));
 664    ds.put(Book.newBookEntity("Joe Blow", "12345", "Foo Book", 2001));
 665
 666    Query q = em.createQuery("SELECT FROM " +
 667                             Book.class.getName() + " b" +
 668                             " WHERE b.author = 'Joe Blow'" +
 669                             " ORDER BY firstPublished ASC");
 670
 671    @SuppressWarnings("unchecked")
 672    List<Book> result = (List<Book>) q.getResultList();
 673
 674    assertEquals(3, result.size());
 675    assertEquals("12345", result.get(0).getIsbn());
 676    assertEquals("11111", result.get(1).getIsbn());
 677    assertEquals("67890", result.get(2).getIsbn());
 678  }
 679
 680  private interface BookProvider {
 681
 682    Book getBook(Key key);
 683  }
 684
 685  private class AttachedBookProvider implements BookProvider {
 686
 687    public Book getBook(Key key) {
 688      return em.find(Book.class, key);
 689    }
 690  }
 691
 692  private class TransientBookProvider implements BookProvider {
 693
 694    public Book getBook(Key key) {
 695      Book b = new Book();
 696      b.setId(KeyFactory.keyToString(key));
 697      return b;
 698    }
 699  }
 700
 701  private void testFilterByChildObject(BookProvider bp) {
 702    Entity parentEntity = new Entity(HasOneToOneJPA.class.getSimpleName());
 703    ds.put(parentEntity);
 704    Entity bookEntity = Book.newBookEntity(parentEntity.getKey(), "Joe Blow", "11111", "Bar Book", 1929);
 705    ds.put(bookEntity);
 706
 707    Book book = bp.getBook(bookEntity.getKey());
 708    Query q = em.createQuery(
 709        "select from " + HasOneToOneJPA.class.getName() + " c where book = :b");
 710    q.setParameter("b", book);
 711    List<HasOneToOneJPA> result = (List<HasOneToOneJPA>) q.getResultList();
 712    assertEquals(1, result.size());
 713    assertEquals(parentEntity.getKey(), KeyFactory.stringToKey(result.get(0).getId()));
 714  }
 715
 716  public void testFilterByChildObject() {
 717    testFilterByChildObject(new AttachedBookProvider());
 718    testFilterByChildObject(new TransientBookProvider());
 719  }
 720
 721  private void testFilterByChildObject_AdditionalFilterOnParent(BookProvider bp) {
 722    Entity parentEntity = new Entity(HasOneToOneJPA.class.getSimpleName());
 723    ds.put(parentEntity);
 724    Entity bookEntity = Book.newBookEntity(parentEntity.getKey(), "Joe Blow", "11111", "Bar Book", 1929);
 725    ds.put(bookEntity);
 726
 727    Book book = bp.getBook(bookEntity.getKey());
 728    Query q = em.createQuery(
 729        "select from " + HasOneToOneJPA.class.getName() + " c where id = :parentId and book = :b");
 730    q.setParameter("parentId", KeyFactory.keyToString(bookEntity.getKey()));
 731    q.setParameter("b", book);
 732    List<HasOneToOneJPA> result = (List<HasOneToOneJPA>) q.getResultList();
 733    assertTrue(result.isEmpty());
 734
 735    q.setParameter("parentId", KeyFactory.keyToString(parentEntity.getKey()));
 736    q.setParameter("b", book);
 737    result = (List<HasOneToOneJPA>) q.getResultList();
 738    assertEquals(1, result.size());
 739    assertEquals(parentEntity.getKey(), KeyFactory.stringToKey(result.get(0).getId()));
 740  }
 741
 742  public void testFilterByChildObject_AdditionalFilterOnParent() {
 743    testFilterByChildObject_AdditionalFilterOnParent(new AttachedBookProvider());
 744    testFilterByChildObject_AdditionalFilterOnParent(new TransientBookProvider());
 745  }
 746
 747
 748  private void testFilterByChildObject_UnsupportedOperator(BookProvider bp) {
 749    Entity parentEntity = new Entity(HasOneToOneJPA.class.getSimpleName());
 750    ds.put(parentEntity);
 751    Entity bookEntity = Book.newBookEntity(parentEntity.getKey(), "Joe Blow", "11111", "Bar Book", 1929);
 752    ds.put(bookEntity);
 753
 754    Book book = bp.getBook(bookEntity.getKey());
 755    Query q = em.createQuery(
 756        "select from " + HasOneToOneJPA.class.getName() + " c where book > :b");
 757    q.setHint(DatastoreManager.QUERYEXT_INMEMORY_WHEN_UNSUPPORTED, "false");
 758    q.setParameter("b", book);
 759    try {
 760      q.getResultList();
 761      fail("expected udfe");
 762    } catch (PersistenceException pe) {
 763        if (pe.getCause() instanceof DatastoreQuery.UnsupportedDatastoreFeatureException) {
 764            // good
 765        }
 766        else {
 767          throw pe;
 768        }
 769    }
 770  }
 771
 772  public void testFilterByChildObject_UnsupportedOperator() {
 773    testFilterByChildObject_UnsupportedOperator(new AttachedBookProvider());
 774    testFilterByChildObject_UnsupportedOperator(new TransientBookProvider());
 775  }
 776
 777  private void testFilterByChildObject_ValueWithoutAncestor(BookProvider bp) {
 778    Entity parentEntity = new Entity(HasOneToOneJPA.class.getSimpleName());
 779    ds.put(parentEntity);
 780    Entity bookEntity = Book.newBookEntity("Joe Blow", "11111", "Bar Book", 1929);
 781    ds.put(bookEntity);
 782
 783    Book book = bp.getBook(bookEntity.getKey());
 784    Query q = em.createQuery(
 785        "select from " + HasOneToOneJPA.class.getName() + " c where book = :b");
 786    q.setParameter("b", book);
 787    q.setHint(DatastoreManager.QUERYEXT_INMEMORY_WHEN_UNSUPPORTED, "false");
 788    try {
 789      q.getResultList();
 790      fail("expected JPAException");
 791    } catch (PersistenceException e) {
 792      // good
 793    }
 794  }
 795
 796  public void testFilterByChildObject_ValueWithoutAncestor() {
 797    testFilterByChildObject_ValueWithoutAncestor(new AttachedBookProvider());
 798    testFilterByChildObject_ValueWithoutAncestor(new TransientBookProvider());
 799  }
 800
 801  public void testFilterByChildObject_KeyIsWrongType() {
 802    Entity parentEntity = new Entity(HasOneToOneJPA.class.getSimpleName());
 803    ds.put(parentEntity);
 804
 805    Query q = em.createQuery(
 806        "select from " + HasOneToOneJPA.class.getName() + " c where book = :b");
 807    q.setParameter("b", parentEntity.getKey());
 808    q.setHint(DatastoreManager.QUERYEXT_INMEMORY_WHEN_UNSUPPORTED, "false");
 809    try {
 810      q.getResultList();
 811      fail("expected JPAException");
 812    } catch (PersistenceException e) {
 813      // good
 814    }
 815  }
 816
 817  public void testFilterByChildObject_KeyParentIsWrongType() {
 818    Key parent = KeyFactory.createKey("yar", 44);
 819    Entity bookEntity = new Entity(Book.class.getSimpleName(), parent);
 820
 821    Query q = em.createQuery(
 822        "select from " + HasOneToOneJPA.class.getName() + " c where book = :b");
 823    q.setParameter("b", bookEntity.getKey());
 824
 825    assertTrue(q.getResultList().isEmpty());
 826  }
 827
 828  public void testFilterByChildObject_ValueWithoutId() {
 829    Entity parentEntity = new Entity(HasOneToOneJPA.class.getSimpleName());
 830    ds.put(parentEntity);
 831    Entity bookEntity = Book.newBookEntity("Joe Blow", "11111", "Bar Book", 1929);
 832    ds.put(bookEntity);
 833
 834    Book book = new Book();
 835    Query q = em.createQuery(
 836        "select from " + HasOneToOneJPA.class.getName() + " c where book = :b");
 837    q.setParameter("b", book);
 838    q.setHint(DatastoreManager.QUERYEXT_INMEMORY_WHEN_UNSUPPORTED, "false");
 839    try {
 840      q.getResultList();
 841      fail("expected JPAException");
 842    } catch (PersistenceException e) {
 843      // good
 844    }
 845  }
 846
 847  public void testFilterByParentObject() {
 848    Entity parentEntity = new Entity(HasOneToManyListJPA.class.getSimpleName());
 849    ds.put(parentEntity);
 850    Entity bidirEntity =
 851        new Entity(BidirectionalChildListJPA.class.getSimpleName(), parentEntity.getKey());
 852    ds.put(bidirEntity);
 853    Entity bidirEntity2 =
 854        new Entity(BidirectionalChildListJPA.class.getSimpleName(), parentEntity.getKey());
 855    ds.put(bidirEntity2);
 856
 857    HasOneToManyListJPA parent =
 858        em.find(HasOneToManyListJPA.class, KeyFactory.keyToString(parentEntity.getKey()));
 859    Query q = em.createQuery("SELECT FROM " +
 860                             BidirectionalChildListJPA.class.getName() +
 861                             " c WHERE parent = :p");
 862
 863    q.setParameter("p", parent);
 864    @SuppressWarnings("unchecked")
 865    List<BidirectionalChildListJPA> result = (List<BidirectionalChildListJPA>) q.getResultList();
 866    assertEquals(2, result.size());
 867    assertEquals(bidirEntity.getKey(), KeyFactory.stringToKey(result.get(0).getId()));
 868    assertEquals(bidirEntity2.getKey(), KeyFactory.stringToKey(result.get(1).getId()));
 869  }
 870
 871  public void testFilterByParentLongObjectId() {
 872    Entity parentEntity = new Entity(HasOneToManyLongPkListJPA.class.getSimpleName());
 873    ds.put(parentEntity);
 874    Entity bidirEntity =
 875        new Entity(BidirectionalChildLongPkListJPA.class.getSimpleName(), parentEntity.getKey());
 876    ds.put(bidirEntity);
 877    Entity bidirEntity2 =
 878        new Entity(BidirectionalChildLongPkListJPA.class.getSimpleName(), parentEntity.getKey());
 879    ds.put(bidirEntity2);
 880
 881    HasOneToManyLongPkListJPA parent =
 882        em.find(HasOneToManyLongPkListJPA.class, KeyFactory.keyToString(parentEntity.getKey()));
 883    Query q = em.createQuery("SELECT FROM " +
 884                             BidirectionalChildLongPkListJPA.class.getName() + " c WHERE parent = :p");
 885
 886    q.setParameter("p", parent.getId());
 887    @SuppressWarnings("unchecked")
 888    List<BidirectionalChildLongPkListJPA> result = (List<BidirectionalChildLongPkListJPA>) q.getResultList();
 889    assertEquals(2, result.size());
 890    assertEquals(bidirEntity.getKey(), KeyFactory.stringToKey(result.get(0).getId()));
 891    assertEquals(bidirEntity2.getKey(), KeyFactory.stringToKey(result.get(1).getId()));
 892  }
 893
 894  public void testFilterByParentIntObjectId() {
 895    Entity parentEntity = new Entity(HasOneToManyLongPkListJPA.class.getSimpleName());
 896    ds.put(parentEntity);
 897    Entity bidirEntity =
 898        new Entity(BidirectionalChildLongPkListJPA.class.getSimpleName(), parentEntity.getKey());
 899    ds.put(bidirEntity);
 900    Entity bidirEntity2 =
 901        new Entity(BidirectionalChildLongPkListJPA.class.getSimpleName(), parentEntity.getKey());
 902    ds.put(bidirEntity2);
 903
 904    HasOneToManyLongPkListJPA parent =
 905        em.find(HasOneToManyLongPkListJPA.class, KeyFactory.keyToString(parentEntity.getKey()));
 906    Query q = em.createQuery("SELECT FROM " +
 907                             BidirectionalChildLongPkListJPA.class.getName() + " c WHERE parent = :p");
 908
 909    q.setParameter("p", parent.getId().intValue());
 910    @SuppressWarnings("unchecked")
 911    List<BidirectionalChildLongPkListJPA> result = (List<BidirectionalChildLongPkListJPA>) q.getResultList();
 912    assertEquals(2, result.size());
 913    assertEquals(bidirEntity.getKey(), KeyFactory.stringToKey(result.get(0).getId()));
 914    assertEquals(bidirEntity2.getKey(), KeyFactory.stringToKey(result.get(1).getId()));
 915  }
 916
 917  public void testFilterByParentObjectWhereParentIsAChild() {
 918    Entity parentEntity = new Entity(HasOneToManyListJPA.class.getSimpleName());
 919    ds.put(parentEntity);
 920    Entity childEntity = new Entity(BidirectionalChildListJPA.class.getSimpleName(), parentEntity.getKey());
 921    ds.put(childEntity);
 922    Entity grandChildEntity1 =
 923        new Entity(BidirectionalGrandchildListJPA.class.getSimpleName(), childEntity.getKey());
 924    ds.put(grandChildEntity1);
 925    Entity grandChildEntity2 =
 926        new Entity(BidirectionalGrandchildListJPA.class.getSimpleName(), childEntity.getKey());
 927    ds.put(grandChildEntity2);
 928
 929    BidirectionalChildListJPA child =
 930        em.find(BidirectionalChildListJPA.class, KeyFactory.keyToString(childEntity.getKey()));
 931    Query q = em.createQuery(
 932        "select from " + BidirectionalGrandchildListJPA.class.getName() + " c where parent = :p");
 933    q.setParameter("p", child);
 934    @SuppressWarnings("unchecked")
 935    List<BidirectionalGrandchildListJPA> result = (List<BidirectionalGrandchildListJPA>) q.getResultList();
 936    assertEquals(2, result.size());
 937    assertEquals(grandChildEntity1.getKey(), KeyFactory.stringToKey(result.get(0).getId()));
 938    assertEquals(grandChildEntity2.getKey(), KeyFactory.stringToKey(result.get(1).getId()));
 939  }
 940  public void testFilterByParentId() {
 941    Entity parentEntity = new Entity(HasOneToManyListJPA.class.getSimpleName());
 942    ds.put(parentEntity);
 943    Entity
 944        bidirEntity =
 945        new Entity(BidirectionalChildListJPA.class.getSimpleName(), parentEntity.getKey());
 946    ds.put(bidirEntity);
 947    Entity
 948        bidirEntity2 =
 949        new Entity(BidirectionalChildListJPA.class.getSimpleName(), parentEntity.getKey());
 950    ds.put(bidirEntity2);
 951
 952    HasOneToManyListJPA parent =
 953        em.find(HasOneToManyListJPA.class, KeyFactory.keyToString(parentEntity.getKey()));
 954    Query q = em.createQuery("SELECT FROM " +
 955                             BidirectionalChildListJPA.class.getName() +
 956                             " c WHERE parent = :p");
 957
 958    q.setParameter("p", parent.getId());
 959    @SuppressWarnings("unchecked")
 960    List<BidirectionalChildListJPA> result = (List<BidirectionalChildListJPA>) q.getResultList();
 961    assertEquals(2, result.size());
 962    assertEquals(bidirEntity.getKey(), KeyFactory.stringToKey(result.get(0).getId()));
 963    assertEquals(bidirEntity2.getKey(), KeyFactory.stringToKey(result.get(1).getId()));
 964  }
 965
 966  public void testFilterByParentKey() {
 967    Entity parentEntity = new Entity(HasOneToManyListJPA.class.getSimpleName());
 968    ds.put(parentEntity);
 969    Entity
 970        bidirEntity =
 971        new Entity(BidirectionalChildListJPA.class.getSimpleName(), parentEntity.getKey());
 972    ds.put(bidirEntity);
 973    Entity
 974        bidirEntity2 =
 975        new Entity(BidirectionalChildListJPA.class.getSimpleName(), parentEntity.getKey());
 976    ds.put(bidirEntity2);
 977
 978    Query q = em.createQuery("SELECT FROM " +
 979                             BidirectionalChildListJPA.class.getName() +
 980                             " c WHERE parent = :p");
 981
 982    q.setParameter("p", parentEntity.getKey());
 983    @SuppressWarnings("unchecked")
 984    List<BidirectionalChildListJPA> result = (List<BidirectionalChildListJPA>) q.getResultList();
 985    assertEquals(2, result.size());
 986    assertEquals(bidirEntity.getKey(), KeyFactory.stringToKey(result.get(0).getId()));
 987    assertEquals(bidirEntity2.getKey(), KeyFactory.stringToKey(result.get(1).getId()));
 988  }
 989
 990  public void testFilterByMultiValueProperty() {
 991    Entity entity = new Entity(HasMultiValuePropsJPA.class.getSimpleName());
 992    entity.setProperty("strList", Utils.newArrayList("1", "2", "3"));
 993    entity.setProperty("keyList",
 994                       Utils.newArrayList(KeyFactory.createKey("be", "bo"),
 995                                          KeyFactory.createKey("bo", "be")));
 996    ds.put(entity);
 997
 998    Query q = em.createQuery(
 999        "select from " + HasMultiValuePropsJPA.class.getName()
1000        + " c where strList = :p1 AND strList = :p2");
1001    q.setParameter("p1", "1");
1002    q.setParameter("p2", "3");
1003    @SuppressWarnings("unchecked")
1004    List<HasMultiValuePropsJPA> result = (List<HasMultiValuePropsJPA>) q.getResultList();
1005    assertEquals(1, result.size());
1006    q.setParameter("p1", "1");
1007    q.setParameter("p2", "4");
1008    @SuppressWarnings("unchecked")
1009    List<HasMultiValuePropsJPA> result2 = (List<HasMultiValuePropsJPA>) q.getResultList();
1010    assertEquals(0, result2.size());
1011
1012    q = em.createQuery(
1013        "select from " + HasMultiValuePropsJPA.class.getName() + " c where keyList = :p1 AND keyList = :p2");
1014    q.setParameter("p1", KeyFactory.createKey("be", "bo"));
1015    q.setParameter("p2", KeyFactory.createKey("bo", "be"));
1016    assertEquals(1, result.size());
1017    q.setParameter("p1", KeyFactory.createKey("be", "bo"));
1018    q.setParameter("p2", KeyFactory.createKey("bo", "be2"));
1019    @SuppressWarnings("unchecked")
1020    List<HasMultiValuePropsJPA> result3 = (List<HasMultiValuePropsJPA>) q.getResultList();
1021    assertEquals(0, result3.size());
1022  }
1023
1024  public void testNoPutsAfterLoadingMultiValueProperty() throws NoSuchMethodException {
1025    switchDatasource(EntityManagerFactoryName.nontransactional_ds_non_transactional_ops_allowed);
1026    testFilterByMultiValueProperty();
1027    em.close();
1028  }
1029
1030  public void testFilterByMultiValueProperty_MemberOf_ArgsWrongOrder() {
1031    Entity entity = new Entity(HasMultiValuePropsJPA.class.getSimpleName());
1032    entity.setProperty("strList", Utils.newArrayList("1", "2", "3"));
1033    entity.setProperty("keyList",
1034                       Utils.newArrayList(KeyFactory.createKey("be", "bo"),
1035                                          KeyFactory.createKey("bo", "be")));
1036    ds.put(entity);
1037
1038    Query q = em.createQuery(
1039        "select from " + HasMultiValuePropsJPA.class.getName()
1040        + " c where strList MEMBER OF :p1 AND strList MEMBER OF :p2");
1041    q.setParameter("p1", "1");
1042    q.setParameter("p2", "3");
1043    @SuppressWarnings("unchecked")
1044    List<HasMultiValuePropsJPA> result = (List<HasMultiValuePropsJPA>) q.getResultList();
1045    assertEquals(1, result.size());
1046    q.setParameter("p1", "1");
1047    q.setParameter("p2", "4");
1048    @SuppressWarnings("unchecked")
1049    List<HasMultiValuePropsJPA> result2 = (List<HasMultiValuePropsJPA>) q.getResultList();
1050    assertEquals(0, result2.size());
1051
1052    q = em.createQuery(
1053        "select from " + HasMultiValuePropsJPA.class.getName()
1054        + " c where keyList MEMBER OF :p1 AND keyList MEMBER OF :p2");
1055    q.setParameter("p1", KeyFactory.createKey("be", "bo"));
1056    q.setParameter("p2", KeyFactory.createKey("bo", "be"));
1057    result = q.getResultList();
1058    assertEquals(1, result.size());
1059    q.setParameter("p1", KeyFactory.createKey("be", "bo"));
1060    q.setParameter("p2", KeyFactory.createKey("bo", "be2"));
1061    @SuppressWarnings("unchecked")
1062    List<HasMultiValuePropsJPA> result3 = (List<HasMultiValuePropsJPA>) q.getResultList();
1063    assertEquals(0, result3.size());
1064  }
1065
1066  public void testFilterByMultiValueProperty_MemberOf_ArgsCorrectOrder() {
1067    Entity entity = new Entity(HasMultiValuePropsJPA.class.getSimpleName());
1068    entity.setProperty("strList", Utils.newArrayList("1", "2", "3"));
1069    entity.setProperty("keyList",
1070                       Utils.newArrayList(KeyFactory.createKey("be", "bo"),
1071                                          KeyFactory.createKey("bo", "be")));
1072    ds.put(entity);
1073
1074    Query q = em.createQuery(
1075        "select from " + HasMultiValuePropsJPA.class.getName()
1076        + " c where :p1 MEMBER OF strList AND :p2 MEMBER OF strList");
1077    q.setParameter("p1", "1");
1078    q.setParameter("p2", "3");
1079    @SuppressWarnings("unchecked")
1080    List<HasMultiValuePropsJPA> result = (List<HasMultiValuePropsJPA>) q.getResultList();
1081    assertEquals(1, result.size());
1082    q.setParameter("p1", "1");
1083    q.setParameter("p2", "4");
1084    @SuppressWarnings("unchecked")
1085    List<HasMultiValuePropsJPA> result2 = (List<HasMultiValuePropsJPA>) q.getResultList();
1086    assertEquals(0, result2.size());
1087
1088    q = em.createQuery(
1089        "select from " + HasMultiValuePropsJPA.class.getName()
1090        + " c where :p1 MEMBER OF keyList AND :p2 MEMBER OF keyList");
1091    q.setParameter("p1", KeyFactory.createKey("be", "bo"));
1092    q.setParameter("p2", KeyFactory.createKey("bo", "be"));
1093    result = q.getResultList();
1094    assertEquals(1, result.size());
1095    q.setParameter("p1", KeyFactory.createKey("be", "bo"));
1096    q.setParameter("p2", KeyFactory.createKey("bo", "be2"));
1097    @SuppressWarnings("unchecked")
1098    List<HasMultiValuePropsJPA> result3 = (List<HasMultiValuePropsJPA>) q.getResultList();
1099    assertEquals(0, result3.size());
1100
1101    // try one with a literal value
1102    q = em.createQuery(
1103        "select from " + HasMultiValuePropsJPA.class.getName()
1104        + " c where '1' MEMBER OF strList");
1105    result = q.getResultList();
1106    assertEquals(1, result.size());
1107  }
1108
1109  public void testFilterByEmbeddedField() {
1110    Entity entity = new Entity(Person.class.getSimpleName());
1111    e

Large files files are truncated, but you can click here to view the full file