/*
* Geotoolkit.org - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2007-2012, Open Source Geospatial Foundation (OSGeo)
* (C) 2007-2012, Geomatys
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotoolkit.internal.sql.table;
import java.util.Map;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Objects;
import org.geotoolkit.internal.sql.Ordering;
/**
* A column in a SQL {@linkplain Query query}. A collection of {@code Column} instances
* allows the creation of SQL fragment like below (this example assumes 3 {@code Column}
* instances named {@code c1}, {@code c2} and {@code c3}):
*
* {@preformat sql
* SELECT c1, c2, c3 FROM table;
* }
*
* @author Martin Desruisseaux (IRD, Geomatys)
* @version 3.10
*
* @since 3.09 (derived from Seagis)
* @module
*/
public final class Column extends ColumnOrParameter {
/**
* The name of the table in which this column is declared. This is usually the same
* than {@link Query#table}, except if we are building a more complex query with
* {@code JOIN} clauses.
*/
public final String table;
/**
* The name of the column, as declared in the database.
*/
public final String name;
/**
* The default value, or {@link #MANDATORY} if the value is mandatory.
* Default value can be a {@link Number}, a {@link String} or {@code null}.
*/
final Object defaultValue;
/**
* The ordering for each column. This field is the same reference than {@link Query#ordering}
* and must be shared by every columns in the same query. We retain the map instead of the
* whole {@link Query} object in order to avoid the retention of more objects than needed by
* the garbage collector.
*/
private final Map<Column,Ordering> ordering;
/**
* The types for which the ordering is applicable. Will be created only when first needed.
* In the majority of cases, this set is never created.
*/
private EnumSet<QueryType> orderUsage;
/**
* Creates a new column without query. This is used only for temporary columns to be
* referenced by {@link CrossReference}. It should not be used for any other usage.
*
* @param table The name of the table in which this column is declared.
* @param name The name of the column, as declared in the database.
*/
Column(final String table, final String name) {
this.ordering = null;
this.table = table;
this.name = name;
this.defaultValue = null;
}
/**
* Creates a column from the specified table with the specified name.
* The new column is automatically added to the specified query.
* <p>
* Instances of this class can be created only one of the {@code Query.addColumn(...)}
* method. This class is not designed for subclassing.
*
* @param query The query for which the column is created.
* @param table The name of the table in which this column is declared.
* @param name The name of the column, as declared in the database.
* @param defaultValue The default value if the column is not present in the database.
* It can be a {@link Number}, a {@link String} or {@code null}.
* @param types The query types for which the column applies.
*/
Column(final Query query, final String table, final String name,
final Object defaultValue, final QueryType[] types)
{
super(query, types);
this.ordering = query.ordering;
this.table = table.trim();
this.name = name .trim();
this.defaultValue = defaultValue;
}
/**
* Sets the function for this column when used in a query of the given type. The function is
* used in the {@code SELECT} part of the SQL statement. This function is <strong>not</strong>
* used in the {@code WHERE} part of the SQL statement.
*
* @param function The function to use with this column for the given types.
* @param types The type of the queries for which to use the given function.
*/
public void setFunction(final String function, final QueryType... types) {
setFunction(0, function, types);
}
/**
* Sets the ordering of this column to the specified value.
*
* @param order The ordering to set for this column.
* @param types The query types for which the given ordering apply.
*/
public void setOrdering(final Ordering order, final QueryType... types) {
if (orderUsage == null) {
orderUsage = EnumSet.noneOf(QueryType.class);
}
orderUsage.clear();
orderUsage.addAll(Arrays.asList(types));
ordering.put(this, order);
}
/**
* Returns the ordering of this column for the given query type.
* The returned ordering can be {@code "ASC"}, {@code "DESC"} or {@code null} if none.
*
* @param type The type of the query for which to get the ordering.
* @return The ordering for this column in a query of the given type, or {@code null} if none.
*/
public Ordering getOrdering(final QueryType type) {
return (orderUsage != null && orderUsage.contains(type)) ? ordering.get(this) : null;
}
/**
* Formats the name of this column.
*
* @param buffer The buffer in which to write the name.
* @param quote The database-dependent identifier quote.
*/
final void appendName(final StringBuilder buffer, final String quote) {
buffer.append(quote).append(name).append(quote);
}
/**
* Formats this column as a fully qualified name.
*
* @param buffer The buffer in which to write the name.
* @param quote The database-dependent identifier quote.
*/
final void appendFullName(final StringBuilder buffer, final String quote) {
buffer.append(quote).append(table).append(quote).append('.')
.append(quote).append(name).append(quote);
}
/**
* Returns a hash code value for this column.
*/
@Override
public int hashCode() {
return name.hashCode() + super.hashCode();
}
/**
* Compares this column with the specified object for equality.
*/
@Override
public boolean equals(final Object object) {
if (super.equals(object)) {
final Column that = (Column) object;
return Objects.equals(this.table, that.table) &&
Objects.equals(this.name, that.name ) &&
Objects.equals(this.defaultValue, that.defaultValue) &&
Objects.equals(this.ordering, that.ordering);
}
return false;
}
/**
* Returns a string representation of this column.
*/
@Override
public String toString() {
return "Column[" + table + '.' + name + ']';
}
}