use of org.apache.cayenne.access.jdbc.ColumnDescriptor in project cayenne by apache.
the class DefaultSelectTranslatorIT method testBuildResultColumns2.
/**
* Tests columns generated for an object query with joint prefetch.
*/
@Test
public void testBuildResultColumns2() throws Exception {
SelectQuery q = new SelectQuery(Painting.class);
q.addPrefetch(Painting.TO_ARTIST.joint());
DefaultSelectTranslator tr = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver());
List<?> columns = tr.buildResultColumns();
// assert root entity columns
DbEntity entity = context.getEntityResolver().getDbEntity("PAINTING");
for (final DbAttribute a : entity.getAttributes()) {
ColumnDescriptor c = new ColumnDescriptor(a, "t0");
assertTrue("No descriptor for " + a + ", columns: " + columns, columns.contains(c));
}
// assert joined columns
DbEntity joined = context.getEntityResolver().getDbEntity("ARTIST");
for (final DbAttribute a : joined.getAttributes()) {
// skip ARTIST PK, it is joined from painting
if (Artist.ARTIST_ID_PK_COLUMN.equals(a.getName())) {
continue;
}
ColumnDescriptor c = new ColumnDescriptor(a, "t1");
c.setDataRowKey("toArtist." + a.getName());
assertTrue("No descriptor for " + a + ", columns: " + columns, columns.contains(c));
}
}
use of org.apache.cayenne.access.jdbc.ColumnDescriptor in project cayenne by apache.
the class DefaultSelectTranslatorIT method testBuildResultColumns1.
/**
* Tests columns generated for a simple object query.
*/
@Test
public void testBuildResultColumns1() throws Exception {
SelectQuery q = new SelectQuery(Painting.class);
DefaultSelectTranslator tr = new DefaultSelectTranslator(q, dataNode.getAdapter(), dataNode.getEntityResolver());
List<?> columns = tr.buildResultColumns();
// all DbAttributes must be included
DbEntity entity = context.getEntityResolver().getDbEntity("PAINTING");
for (final DbAttribute a : entity.getAttributes()) {
ColumnDescriptor c = new ColumnDescriptor(a, "t0");
assertTrue("No descriptor for " + a + ", columns: " + columns, columns.contains(c));
}
}
use of org.apache.cayenne.access.jdbc.ColumnDescriptor in project cayenne by apache.
the class DefaultSelectTranslator method appendColumn.
private void appendColumn(List<ColumnDescriptor> columns, ObjAttribute objAttribute, DbAttribute attribute, Set<ColumnTracker> skipSet, String label, String alias) {
if (alias == null) {
alias = getCurrentAlias();
}
if (skipSet.add(new ColumnTracker(alias, attribute))) {
ColumnDescriptor column = (objAttribute != null) ? new ColumnDescriptor(objAttribute, attribute, alias) : new ColumnDescriptor(attribute, alias);
if (label != null) {
column.setDataRowKey(label);
}
columns.add(column);
// TODO: andrus, 5/7/2006 - replace 'columns' collection with this map, as it is redundant
defaultAttributesByColumn.put(column, objAttribute);
} else if (objAttribute != null) {
// record ObjAttribute override
for (ColumnDescriptor column : columns) {
if (attribute.getName().equals(column.getName())) {
if (attributeOverrides == null) {
attributeOverrides = new HashMap<>();
}
// kick out the original attribute
ObjAttribute original = defaultAttributesByColumn.remove(column);
if (original != null) {
attributeOverrides.put(original, column);
}
attributeOverrides.put(objAttribute, column);
column.setJavaClass(Void.TYPE.getName());
break;
}
}
}
}
use of org.apache.cayenne.access.jdbc.ColumnDescriptor in project cayenne by apache.
the class DefaultSelectTranslator method appendOverriddenColumns.
/**
* If query contains explicit column list, use only them
*/
<T> List<ColumnDescriptor> appendOverriddenColumns(List<ColumnDescriptor> columns, SelectQuery<T> query) {
groupByColumns = new HashMap<>();
QualifierTranslator qualifierTranslator = adapter.getQualifierTranslator(this);
AccumulatingBindingListener bindingListener = new AccumulatingBindingListener();
final String[] joinTableAliasForProperty = { null };
// capture last alias for joined table, will use it to resolve object columns
joinListener = () -> joinTableAliasForProperty[0] = getCurrentAlias();
setAddBindingListener(bindingListener);
for (Property<?> property : query.getColumns()) {
joinTableAliasForProperty[0] = null;
int expressionType = property.getExpression().getType();
// forbid direct selection of toMany relationships columns
if (property.getType() != null && (expressionType == Expression.OBJ_PATH || expressionType == Expression.DB_PATH) && (Collection.class.isAssignableFrom(property.getType()) || Map.class.isAssignableFrom(property.getType()))) {
throw new CayenneRuntimeException("Can't directly select toMany relationship columns. " + "Either select it with aggregate functions like count() or with flat() function to select full related objects.");
}
// evaluate ObjPath with Persistent type as toOne relations and use it as full object
boolean objectProperty = expressionType == Expression.FULL_OBJECT || (property.getType() != null && expressionType == Expression.OBJ_PATH && Persistent.class.isAssignableFrom(property.getType()));
// Qualifier Translator in case of Object Columns have side effect -
// it will create required joins, that we catch with listener above.
// And we force created join alias for all columns of Object we select.
qualifierTranslator.setQualifier(property.getExpression());
qualifierTranslator.setForceJoinForRelations(objectProperty);
StringBuilder builder = qualifierTranslator.appendPart(new StringBuilder());
if (objectProperty) {
// If we want full object, use appendQueryColumns method, to fully process class descriptor
List<ColumnDescriptor> classColumns = new ArrayList<>();
ObjEntity entity = entityResolver.getObjEntity(property.getType());
if (getQueryMetadata().getPageSize() > 0) {
appendIdColumns(classColumns, entity);
} else {
ClassDescriptor classDescriptor = entityResolver.getClassDescriptor(entity.getName());
appendQueryColumns(classColumns, query, classDescriptor, joinTableAliasForProperty[0]);
}
for (ColumnDescriptor descriptor : classColumns) {
columns.add(descriptor);
groupByColumns.put(descriptor, Collections.<DbAttributeBinding>emptyList());
}
} else {
// This property will go as scalar value
String alias = property.getAlias();
if (alias != null) {
builder.append(" AS ").append(alias);
}
int type = getJdbcTypeForProperty(property);
ColumnDescriptor descriptor;
if (property.getType() != null) {
descriptor = new ColumnDescriptor(builder.toString(), type, property.getType().getCanonicalName());
} else {
descriptor = new ColumnDescriptor(builder.toString(), type);
}
descriptor.setDataRowKey(alias);
descriptor.setIsExpression(true);
columns.add(descriptor);
if (isAggregate(property)) {
haveAggregate = true;
} else {
groupByColumns.put(descriptor, bindingListener.getBindings());
}
bindingListener.reset();
}
}
setAddBindingListener(null);
qualifierTranslator.setForceJoinForRelations(false);
joinListener = null;
return columns;
}
use of org.apache.cayenne.access.jdbc.ColumnDescriptor in project cayenne by apache.
the class DefaultSelectTranslator method doTranslate.
@Override
protected void doTranslate() {
checkLimitAndJointPrefetch();
DataMap dataMap = queryMetadata.getDataMap();
JoinStack joins = getJoinStack();
QuotingStrategy strategy = getAdapter().getQuotingStrategy();
forcingDistinct = false;
// build column list
this.resultColumns = buildResultColumns();
// build qualifier
QualifierTranslator qualifierTranslator = adapter.getQualifierTranslator(this);
StringBuilder whereQualifierBuffer = qualifierTranslator.appendPart(new StringBuilder());
// build having qualifier
Expression havingQualifier = getSelectQuery().getHavingQualifier();
StringBuilder havingQualifierBuffer = null;
if (havingQualifier != null) {
haveAggregate = true;
QualifierTranslator havingQualifierTranslator = adapter.getQualifierTranslator(this);
havingQualifierTranslator.setQualifier(havingQualifier);
havingQualifierBuffer = havingQualifierTranslator.appendPart(new StringBuilder());
}
if (!haveAggregate && groupByColumns != null) {
// if no expression with aggregation function found
// in select columns and there is no having clause
groupByColumns.clear();
}
// build ORDER BY
OrderingTranslator orderingTranslator = new OrderingTranslator(this);
StringBuilder orderingBuffer = orderingTranslator.appendPart(new StringBuilder());
// assemble
StringBuilder queryBuf = new StringBuilder();
queryBuf.append("SELECT ");
// side effect: "suppressingDistinct" flag may end up being flipped here
if (forcingDistinct || getSelectQuery().isDistinct()) {
suppressingDistinct = queryMetadata.isSuppressingDistinct();
if (!suppressingDistinct) {
for (ColumnDescriptor column : resultColumns) {
if (isUnsupportedForDistinct(column.getJdbcType())) {
suppressingDistinct = true;
break;
}
}
}
if (!suppressingDistinct) {
queryBuf.append(buildDistinctStatement()).append(" ");
}
}
// convert ColumnDescriptors to column names
List<String> selectColumnExpList = new ArrayList<>();
for (ColumnDescriptor column : resultColumns) {
String fullName;
if (column.isExpression()) {
fullName = column.getName();
} else {
fullName = strategy.quotedIdentifier(dataMap, column.getNamePrefix(), column.getName());
}
selectColumnExpList.add(fullName);
}
// uses the DISTINCT modifier
if (forcingDistinct || getSelectQuery().isDistinct()) {
List<String> orderByColumnList = orderingTranslator.getOrderByColumnList();
for (String orderByColumnExp : orderByColumnList) {
// Convert to ColumnDescriptors??
if (!selectColumnExpList.contains(orderByColumnExp)) {
selectColumnExpList.add(orderByColumnExp);
}
}
}
appendSelectColumns(queryBuf, selectColumnExpList);
// append from clause
queryBuf.append(" FROM ");
// append tables and joins
joins.appendRootWithQuoteSqlIdentifiers(queryBuf, getQueryMetadata().getDbEntity());
joins.appendJoins(queryBuf);
joins.appendQualifier(whereQualifierBuffer, whereQualifierBuffer.length() == 0);
// append qualifier
if (whereQualifierBuffer.length() > 0) {
queryBuf.append(" WHERE ");
queryBuf.append(whereQualifierBuffer);
}
if (groupByColumns != null && !groupByColumns.isEmpty()) {
queryBuf.append(" GROUP BY ");
appendGroupByColumns(queryBuf, groupByColumns);
}
// append HAVING qualifier
if (havingQualifierBuffer != null && havingQualifierBuffer.length() > 0) {
queryBuf.append(" HAVING ");
queryBuf.append(havingQualifierBuffer);
}
// append prebuilt ordering
if (orderingBuffer.length() > 0) {
queryBuf.append(" ORDER BY ").append(orderingBuffer);
}
if (!isSuppressingDistinct()) {
appendLimitAndOffsetClauses(queryBuf);
}
this.sql = queryBuf.toString();
}
Aggregations