/*
* Copyright (c) 2013-2015 Josef Hardi <josef.hardi@gmail.com>
*
* Licensed 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 com.obidea.semantika.database.sql.parser;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import com.obidea.semantika.database.base.IColumn;
import com.obidea.semantika.database.base.ITable;
import com.obidea.semantika.mapping.base.sql.SqlColumn;
import com.obidea.semantika.mapping.base.sql.SqlTable;
import com.obidea.semantika.util.StringUtils;
/**
* A utility class to keep a list of tables in the FROM clause.
*/
/* package */
class FromTablesList implements Iterator<SqlTable>, Iterable<SqlTable>
{
private List<ITable> mSelectionList = new ArrayList<ITable>();
private int mSize = 0;
private int mCurrent = 0;
public void add(ITable table)
{
mSelectionList.add(table);
mSize++; // increment the size each time new table is added
}
/**
* Gets the column given its name and the table where it is located. If the
* table name is <code>null</code> or empty, the method will search the
* column in all tables listed in this list. It will throw an exception if
* there are more than one column found.
*
* @param anyTableName
* table name; can be local name or full name
* @param columnName
* column name
* @return a column object.
* @throws UnknownColumnNameException
* if the column name does not exist in any selected tables.
* @throws AmbiguousColumnNameException
* if there are more than one column using the same name.
*/
public SqlColumn getColumn(String anyTableName, String columnName) throws SqlParserException
{
IColumn c = (StringUtils.isEmpty(anyTableName)) ?
findColumnByNameOnly(columnName) :
findColumnByTableReference(anyTableName, columnName);
return new SqlColumn(c);
}
/**
* Gets all the column from a table. The table name must come from table
* selection.
*
* @param anyTableName
* table name; can be local name or full name
* @return a list of columns.
*/
public List<SqlColumn> getColumns(String anyTableName) throws SqlParserException
{
List<SqlColumn> toReturn = new ArrayList<SqlColumn>();
ITable sourceTable = findTableInSelectionList(anyTableName);
for (IColumn c : sourceTable.getColumns()) {
toReturn.add(new SqlColumn(c));
}
return toReturn;
}
/**
* Gets all columns from all selected table in the FROM clause.
*
* @return a list of columns.
*/
public List<SqlColumn> getAllColumns()
{
List<SqlColumn> toReturn = new ArrayList<SqlColumn>();
for (ITable sourceTable : mSelectionList) {
for (IColumn c : sourceTable.getColumns()) {
toReturn.add(new SqlColumn(c));
}
}
return toReturn;
}
/*
* Method implementation for the Iterator and Iterable interfaces.
*/
@Override
public boolean hasNext()
{
return mCurrent < mSize;
}
@Override
public SqlTable next()
{
if (hasNext()) {
final ITable nextTable = mSelectionList.get(mCurrent++);
return new SqlTable(nextTable);
}
throw new NoSuchElementException();
}
@Override
public void remove()
{
throw new UnsupportedOperationException();
}
@Override
public Iterator<SqlTable> iterator()
{
mCurrent = 0; // clear the current count every time client code asks for an iterator
return this;
}
/*
* Private helper methods
*/
private ITable findTableInSelectionList(String tableName) throws SqlParserException
{
for (ITable table : mSelectionList) {
// Check based its local name first
if (tableName.equals(table.getLocalName())) {
return table;
}
// If failed, check based on its full name
if (tableName.equals(table.getFullName())) {
return table;
}
}
// Give up
throw new UnknownTableNameException(tableName);
}
private IColumn findColumnByTableReference(String tableName, String columnName) throws SqlParserException
{
final ITable table = findTableInSelectionList(tableName);
IColumn column = table.getColumn(columnName);
if (column != null) {
return column;
}
throw new UnknownColumnNameException(columnName);
}
private IColumn findColumnByNameOnly(String columnName) throws SqlParserException
{
List<IColumn> possibleColumns = new ArrayList<IColumn>();
for (ITable table : mSelectionList) {
IColumn column = table.getColumn(columnName);
if (column != null) {
possibleColumns.add(column);
}
}
if (possibleColumns.size() == 0) {
throw new UnknownColumnNameException(columnName);
}
if (possibleColumns.size() > 1) {
throw new AmbiguousColumnNameException(columnName, possibleColumns);
}
return possibleColumns.get(0);
}
}