/*****************************************************************
* 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 org.apache.cayenne.Cayenne;
import org.apache.cayenne.PersistenceState;
import org.apache.cayenne.di.Inject;
import org.apache.cayenne.exp.ExpressionFactory;
import org.apache.cayenne.query.EJBQLQuery;
import org.apache.cayenne.query.SelectQuery;
import org.apache.cayenne.reflect.PersistentDescriptor;
import org.apache.cayenne.test.jdbc.DBHelper;
import org.apache.cayenne.test.jdbc.TableHelper;
import org.apache.cayenne.testdo.testmap.Artist;
import org.apache.cayenne.testdo.testmap.CompoundPainting;
import org.apache.cayenne.testdo.testmap.CompoundPaintingLongNames;
import org.apache.cayenne.testdo.testmap.Gallery;
import org.apache.cayenne.unit.di.server.CayenneProjects;
import org.apache.cayenne.unit.di.server.ServerCase;
import org.apache.cayenne.unit.di.server.UseServerRuntime;
import org.junit.Test;
import java.math.BigDecimal;
import java.sql.Types;
import java.util.Iterator;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
public class DataContextFlattenedAttributesIT extends ServerCase {
@Inject
private DataContext context;
@Inject
private DBHelper dbHelper;
private void createTestDataSet() throws Exception {
TableHelper tArtist = new TableHelper(dbHelper, "ARTIST");
tArtist.setColumns("ARTIST_ID", "ARTIST_NAME", "DATE_OF_BIRTH");
TableHelper tPainting = new TableHelper(dbHelper, "PAINTING");
tPainting.setColumns(
"PAINTING_ID",
"PAINTING_TITLE",
"ARTIST_ID",
"ESTIMATED_PRICE",
"GALLERY_ID").setColumnTypes(
Types.INTEGER,
Types.VARCHAR,
Types.BIGINT,
Types.DECIMAL,
Types.INTEGER);
TableHelper tPaintingInfo = new TableHelper(dbHelper, "PAINTING_INFO");
tPaintingInfo.setColumns("PAINTING_ID", "TEXT_REVIEW");
TableHelper tGallery = new TableHelper(dbHelper, "GALLERY");
tGallery.setColumns("GALLERY_ID", "GALLERY_NAME");
long dateBase = System.currentTimeMillis();
for (int i = 1; i <= 4; i++) {
tArtist.insert(i + 1, "artist" + i, new java.sql.Date(dateBase
+ 1000
* 60
* 60
* 24
* i));
}
for (int i = 1; i <= 2; i++) {
tGallery.insert(i + 2, "gallery" + i);
}
for (int i = 1; i <= 8; i++) {
Integer galleryId = (i == 3) ? null : (i - 1) % 2 + 3;
tPainting.insert(
i,
"painting" + i,
(i - 1) % 4 + 2,
new BigDecimal(1000d),
galleryId);
tPaintingInfo.insert(i, "painting review" + i);
}
}
@Test
public void testSelectCompound1() throws Exception {
createTestDataSet();
SelectQuery query = new SelectQuery(CompoundPainting.class);
List<?> objects = context.performQuery(query);
assertNotNull(objects);
assertEquals(8, objects.size());
assertTrue(
"CompoundPainting expected, got " + objects.get(0).getClass(),
objects.get(0) instanceof CompoundPainting);
for (Iterator<?> i = objects.iterator(); i.hasNext();) {
CompoundPainting painting = (CompoundPainting) i.next();
Number id = (Number) painting
.getObjectId()
.getIdSnapshot()
.get("PAINTING_ID");
assertEquals(
"CompoundPainting.getPaintingTitle(): " + painting.getPaintingTitle(),
"painting" + id,
painting.getPaintingTitle());
if (painting.getToPaintingInfo() == null) {
assertNull(painting.getTextReview());
}
else {
assertEquals(
"CompoundPainting.getTextReview(): " + painting.getTextReview(),
"painting review" + id,
painting.getTextReview());
}
assertEquals(
"CompoundPainting.getArtistName(): " + painting.getArtistName(),
painting.getToArtist().getArtistName(),
painting.getArtistName());
if (painting.getToGallery() == null) {
assertNull(painting.getGalleryName());
}
else {
assertEquals(
"CompoundPainting.getGalleryName(): " + painting.getGalleryName(),
painting.getToGallery().getGalleryName(),
painting.getGalleryName());
}
}
}
// TODO: andrus 1/5/2007 - CAY-952: SelectQuery uses INNER JOIN for flattened
// attributes, while
// EJBQLQuery does an OUTER JOIN... which seems like a better idea...
// 14/01/2010 now it uses LEFT JOIN
@Test
public void testSelectCompound2() throws Exception {
createTestDataSet();
SelectQuery query = new SelectQuery(
CompoundPainting.class,
ExpressionFactory.matchExp("artistName", "artist2"));
List<?> objects = context.performQuery(query);
assertNotNull(objects);
assertEquals(2, objects.size());
assertTrue(
"CompoundPainting expected, got " + objects.get(0).getClass(),
objects.get(0) instanceof CompoundPainting);
for (Iterator<?> i = objects.iterator(); i.hasNext();) {
CompoundPainting painting = (CompoundPainting) i.next();
assertEquals(PersistenceState.COMMITTED, painting.getPersistenceState());
assertEquals(
"CompoundPainting.getArtistName(): " + painting.getArtistName(),
"artist2",
painting.getArtistName());
assertEquals(
"CompoundPainting.getArtistName(): " + painting.getGalleryName(),
painting.getToGallery().getGalleryName(),
painting.getGalleryName());
}
}
/**
* Emulates the situation when flattened attribute has unusual(long) name, that puts
* this attribute property to the top of PersistentDescriptor.declaredProperties map,
* {@link PersistentDescriptor}[105] That forced an error during the building of the
* SelectQuery statement, CAY-1484
*/
@Test
public void testSelectCompoundLongNames() throws Exception {
createTestDataSet();
SelectQuery query = new SelectQuery(CompoundPaintingLongNames.class);
// the error was thrown on query execution
List<?> objects = context.performQuery(query);
assertNotNull(objects);
}
@Test
public void testSelectEJQBQL() throws Exception {
createTestDataSet();
EJBQLQuery query = new EJBQLQuery(
"SELECT a FROM CompoundPainting a WHERE a.artistName = 'artist2'");
List<?> objects = context.performQuery(query);
assertNotNull(objects);
assertEquals(2, objects.size());
assertTrue(
"CompoundPainting expected, got " + objects.get(0).getClass(),
objects.get(0) instanceof CompoundPainting);
Iterator<?> i = objects.iterator();
while (i.hasNext()) {
CompoundPainting painting = (CompoundPainting) i.next();
assertEquals(PersistenceState.COMMITTED, painting.getPersistenceState());
}
}
@Test
public void testSelectEJQBQLCollectionTheta() throws Exception {
createTestDataSet();
EJBQLQuery query = new EJBQLQuery(
"SELECT DISTINCT a FROM CompoundPainting cp, Artist a "
+ "WHERE a.artistName=cp.artistName ORDER BY a.artistName");
List<?> objects = context.performQuery(query);
assertNotNull(objects);
assertEquals(4, objects.size());
Iterator<?> i = objects.iterator();
int index = 1;
while (i.hasNext()) {
Artist artist = (Artist) i.next();
assertEquals("artist" + index, artist.getArtistName());
index++;
}
}
@Test
public void testSelectEJQBQLLike() throws Exception {
createTestDataSet();
EJBQLQuery query = new EJBQLQuery(
"SELECT a FROM CompoundPainting a WHERE a.artistName LIKE 'artist%' "
+ "ORDER BY a.paintingTitle");
List<?> objects = context.performQuery(query);
assertNotNull(objects);
assertEquals(8, objects.size());
Iterator<?> i = objects.iterator();
int index = 1;
while (i.hasNext()) {
CompoundPainting painting = (CompoundPainting) i.next();
assertEquals("painting" + index, painting.getPaintingTitle());
index++;
}
}
@Test
public void testSelectEJQBQLBetween() throws Exception {
createTestDataSet();
EJBQLQuery query = new EJBQLQuery("SELECT a FROM CompoundPainting a "
+ "WHERE a.artistName BETWEEN 'artist1' AND 'artist4' "
+ "ORDER BY a.paintingTitle");
List<?> objects = context.performQuery(query);
assertNotNull(objects);
assertEquals(8, objects.size());
Iterator<?> i = objects.iterator();
int index = 1;
while (i.hasNext()) {
CompoundPainting painting = (CompoundPainting) i.next();
assertEquals("painting" + index, painting.getPaintingTitle());
index++;
}
}
@Test
public void testSelectEJQBQLSubquery() throws Exception {
createTestDataSet();
EJBQLQuery query = new EJBQLQuery(
"SELECT g FROM Gallery g WHERE "
+ "(SELECT COUNT(cp) FROM CompoundPainting cp WHERE g.galleryName=cp.galleryName) = 4");
List<?> objects = context.performQuery(query);
assertNotNull(objects);
assertEquals(1, objects.size());
Gallery gallery = (Gallery) objects.get(0);
assertEquals("gallery2", gallery.getGalleryName());
}
@Test
public void testSelectEJQBQLHaving() throws Exception {
createTestDataSet();
EJBQLQuery query = new EJBQLQuery(
"SELECT cp.galleryName, COUNT(a) from Artist a, CompoundPainting cp "
+ "WHERE cp.artistName = a.artistName "
+ "GROUP BY cp.galleryName "
+ "HAVING cp.galleryName LIKE 'gallery1'");
List<Object[]> objects = context.performQuery(query);
assertNotNull(objects);
assertEquals(1, objects.size());
Object[] galleryItem = objects.get(0);
assertEquals("gallery1", galleryItem[0]);
assertEquals(3L, galleryItem[1]);
}
@Test
public void testInsert() {
CompoundPainting o1 = context.newObject(CompoundPainting.class);
o1.setArtistName("A1");
o1.setEstimatedPrice(new BigDecimal(1.0d));
o1.setGalleryName("G1");
o1.setPaintingTitle("P1");
o1.setTextReview("T1");
context.commitChanges();
Number artistCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
"select count(a) from Artist a"));
assertEquals(1, artistCount.intValue());
Number paintingCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
"select count(a) from Painting a"));
assertEquals(1, paintingCount.intValue());
Number galleryCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
"select count(a) from Gallery a"));
assertEquals(1, galleryCount.intValue());
}
@Test
public void testDelete() throws Exception {
// throw in a bit of random overlapping data, to make sure FK/PK correspondence is
// not purely coincidental
Artist a = context.newObject(Artist.class);
a.setArtistName("AX");
context.commitChanges();
CompoundPainting o1 = context.newObject(CompoundPainting.class);
o1.setArtistName("A1");
o1.setEstimatedPrice(new BigDecimal(1.0d));
o1.setGalleryName("G1");
o1.setPaintingTitle("P1");
o1.setTextReview("T1");
context.commitChanges();
context.deleteObjects(o1);
context.commitChanges();
Number artistCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
"select count(a) from Artist a"));
assertEquals(1, artistCount.intValue());
Number paintingCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
"select count(a) from Painting a"));
assertEquals(0, paintingCount.intValue());
Number galleryCount = (Number) Cayenne.objectForQuery(context, new EJBQLQuery(
"select count(a) from Gallery a"));
assertEquals(0, galleryCount.intValue());
}
@Test
public void testUpdate() {
CompoundPainting o1 = context.newObject(CompoundPainting.class);
o1.setArtistName("A1");
o1.setEstimatedPrice(new BigDecimal(1d));
o1.setGalleryName("G1");
o1.setPaintingTitle("P1");
o1.setTextReview("T1");
context.commitChanges();
o1.setArtistName("X1");
o1.setEstimatedPrice(new BigDecimal(2d));
o1.setGalleryName("X1");
o1.setPaintingTitle("X1");
o1.setTextReview("X1");
context.commitChanges();
}
}