/** * 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.metamodel.query.builder; import java.util.Arrays; import java.util.List; import org.apache.metamodel.DataContext; import org.apache.metamodel.data.DataSet; import org.apache.metamodel.query.CompiledQuery; import org.apache.metamodel.query.FilterItem; import org.apache.metamodel.query.FromItem; import org.apache.metamodel.query.FunctionType; import org.apache.metamodel.query.Query; import org.apache.metamodel.query.ScalarFunction; import org.apache.metamodel.query.SelectItem; import org.apache.metamodel.query.parser.SelectItemParser; import org.apache.metamodel.schema.Column; import org.apache.metamodel.schema.Table; import org.apache.metamodel.util.BaseObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Main implementation of the {@link GroupedQueryBuilder} interface. */ final class GroupedQueryBuilderImpl extends BaseObject implements GroupedQueryBuilder { private static final Logger logger = LoggerFactory.getLogger(GroupedQueryBuilderImpl.class); private final Query _query; private final DataContext _dataContext; public GroupedQueryBuilderImpl(DataContext dataContext, Query query) { if (query == null) { throw new IllegalArgumentException("query cannot be null"); } _dataContext = dataContext; _query = query; } @Override public ColumnSelectBuilder<GroupedQueryBuilder> select(Column column) { if (column == null) { throw new IllegalArgumentException("column cannot be null"); } return new ColumnSelectBuilderImpl(column, _query, this); } @Override public SatisfiedQueryBuilder<?> select(FunctionType function, String columnName) { if (function == null) { throw new IllegalArgumentException("function cannot be null"); } final Column column = findColumn(columnName); return new FunctionSelectBuilderImpl(function, column, null, _query, this); } @Override public FunctionSelectBuilder<GroupedQueryBuilder> select(FunctionType function, Column column) { if (function == null) { throw new IllegalArgumentException("function cannot be null"); } if (column == null) { throw new IllegalArgumentException("column cannot be null"); } return new FunctionSelectBuilderImpl(function, column, null, _query, this); } @Override public SatisfiedQueryBuilder<GroupedQueryBuilder> where(FilterItem... filters) { _query.where(filters); return this; } @Override public SatisfiedQueryBuilder<GroupedQueryBuilder> where(Iterable<FilterItem> filters) { _query.where(filters); return this; } @Override public ColumnSelectBuilder<GroupedQueryBuilder> select(String columnName) { final Column column = findColumn(columnName); return select(column); } @Override public CountSelectBuilder<GroupedQueryBuilder> selectCount() { return new CountSelectBuilderImpl(_query, this); } @Override public SatisfiedSelectBuilder<GroupedQueryBuilder> select(Column... columns) { if (columns == null) { throw new IllegalArgumentException("column cannot be null"); } _query.select(columns); return new SatisfiedSelectBuilderImpl(this); } @Override public WhereBuilder<GroupedQueryBuilder> where(Column column) { if (column == null) { throw new IllegalArgumentException("column cannot be null"); } return new WhereBuilderImpl(column, _query, this); } @Override public WhereBuilder<GroupedQueryBuilder> where(String columnName) { final Column column = findColumn(columnName); return where(column); } @Override public WhereBuilder<GroupedQueryBuilder> where(ScalarFunction function, Column column) { final SelectItem selectItem = new SelectItem(function, column); return new WhereBuilderImpl(selectItem, _query, this); } @Override public WhereBuilder<GroupedQueryBuilder> where(ScalarFunction function, String columnName) { final Column column = findColumn(columnName); return where(function, column); } @Override public Column findColumn(final String columnName) throws IllegalArgumentException { if (columnName == null) { throw new IllegalArgumentException("columnName cannot be null"); } final List<FromItem> fromItems = _query.getFromClause().getItems(); final List<SelectItem> selectItems = _query.getSelectClause().getItems(); int dotIndex = columnName.indexOf('.'); if (dotIndex != -1) { // check aliases of from items final String aliasPart = columnName.substring(0, dotIndex); final String columnPart = columnName.substring(dotIndex + 1); for (FromItem fromItem : fromItems) { Column column = null; column = findColumnInAliasedTable(column, fromItem, aliasPart, columnPart); if (column != null) { return column; } } } // check columns already in select clause for (SelectItem item : selectItems) { Column column = item.getColumn(); if (column != null) { if (columnName.equals(column.getName())) { return column; } } } for (FromItem fromItem : fromItems) { Table table = fromItem.getTable(); if (table != null) { Column column = table.getColumnByName(columnName); if (column != null) { return column; } } } Column column = _dataContext.getColumnByQualifiedLabel(columnName); if (column != null) { return column; } final IllegalArgumentException exception = new IllegalArgumentException("Could not find column: " + columnName); if (logger.isDebugEnabled()) { logger.debug("findColumn('" + columnName + "') could not resolve a column", exception); for (FromItem fromItem : fromItems) { final Table table = fromItem.getTable(); if (table != null) { logger.debug("Table available in FROM item: {}. Column names: {}", table, Arrays.toString(table .getColumnNames())); } } } throw exception; } private Column findColumnInAliasedTable(Column column, FromItem fromItem, String aliasPart, String columnPart) { if (column != null) { // ensure that if the column has already been found, return it return column; } Table table = fromItem.getTable(); if (table != null) { String alias = fromItem.getAlias(); if (alias != null && alias.equals(aliasPart)) { column = table.getColumnByName(columnPart); } } else { FromItem leftSide = fromItem.getLeftSide(); column = findColumnInAliasedTable(column, leftSide, aliasPart, columnPart); FromItem rightSide = fromItem.getRightSide(); column = findColumnInAliasedTable(column, rightSide, aliasPart, columnPart); if (column != null) { Query subQuery = fromItem.getSubQuery(); if (subQuery != null) { List<FromItem> items = subQuery.getFromClause().getItems(); for (FromItem subQueryFromItem : items) { column = findColumnInAliasedTable(column, subQueryFromItem, aliasPart, columnPart); } } } } return column; } @Override public SatisfiedOrderByBuilder<GroupedQueryBuilder> orderBy(String columnName) { return orderBy(findColumn(columnName)); } @Override public SatisfiedOrderByBuilder<GroupedQueryBuilder> orderBy(Column column) { if (column == null) { throw new IllegalArgumentException("column cannot be null"); } return new SatisfiedOrderByBuilderImpl(column, _query, this); } @Override public SatisfiedOrderByBuilder<GroupedQueryBuilder> orderBy(FunctionType function, Column column) { if (function == null) { throw new IllegalArgumentException("function cannot be null"); } if (column == null) { throw new IllegalArgumentException("column cannot be null"); } return new SatisfiedOrderByBuilderImpl(function, column, _query, this); } @Override public GroupedQueryBuilder groupBy(Column column) { if (column == null) { throw new IllegalArgumentException("column cannot be null"); } _query.groupBy(column); return this; } @Override public GroupedQueryBuilder groupBy(String columnName) { final Column column = findColumn(columnName); return groupBy(column); } @Override public GroupedQueryBuilder groupBy(String... columnNames) { _query.groupBy(columnNames); return this; } @Override public GroupedQueryBuilder groupBy(Column... columns) { if (columns == null) { throw new IllegalArgumentException("columns cannot be null"); } _query.groupBy(columns); return this; } @Override public HavingBuilder having(String columnExpression) { final SelectItemParser parser = new SelectItemParser(_query, false); final SelectItem selectItem = parser.findSelectItem(columnExpression); return having(selectItem); } @Override public HavingBuilder having(SelectItem selectItem) { if (selectItem == null) { throw new IllegalArgumentException("selectItem cannot be null"); } return new HavingBuilderImpl(selectItem, _query, this); } @Override public HavingBuilder having(FunctionType function, Column column) { if (function == null) { throw new IllegalArgumentException("function cannot be null"); } if (column == null) { throw new IllegalArgumentException("column cannot be null"); } return new HavingBuilderImpl(function, column, _query, this); } @Override public SatisfiedQueryBuilder<GroupedQueryBuilder> limit(int maxRows) { _query.setMaxRows(maxRows); return this; } @Override public SatisfiedQueryBuilder<GroupedQueryBuilder> maxRows(int maxRows) { _query.setMaxRows(maxRows); return this; } @Override public SatisfiedQueryBuilder<GroupedQueryBuilder> firstRow(int firstRow) { if (firstRow >= 0) { _query.setFirstRow(firstRow); } else { _query.setFirstRow(null); } return this; } @Override public SatisfiedQueryBuilder<GroupedQueryBuilder> offset(int offset) { if (offset >= 0) { _query.setFirstRow(offset + 1); } else { _query.setFirstRow(null); } return this; } @Override public String toString() { return _query.toSql(); } @Override public Query toQuery() { return _query.clone(); } @Override public CompiledQuery compile() { return _dataContext.compileQuery(_query); } @Override public DataSet execute() { return _dataContext.executeQuery(_query); } @Override protected void decorateIdentity(List<Object> identifiers) { identifiers.add(_query); } }