package squill.query.select;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import squill.alias.Alias;
import squill.query.QueryContext;
import squill.query.from.FromExpression;
import squill.util.BeanUtil;
import squill.util.FieldHandler;
import squill.util.ReflectUtils;
import squill.util.StringUtil;
import squill.util.ToString;
/**
* This needs to be extended by tables which user can only select data from.
* WritableTable must be extended for tables where data needs to be updated,
* inserted or deleted.
*/
public abstract class ReadableTable<OBJ> extends BaseSelectExpression<OBJ> implements FromExpression {
private final Alias alias;
private List<Column<?, OBJ>> columns;
public static final ToString<ReadableTable<?>> GET_NAME = new ToString<ReadableTable<?>>() {
public String toString(final ReadableTable<?> table) {
return table.getTableName();
}
};
public ReadableTable() {
this.alias=Alias.newTableAlias();
}
public ReadableTable(final String alias) {
this.alias = Alias.newAlias(alias);
}
private List<Column<?, OBJ>> extractColumns() {
final List<Column<?, OBJ>> columns = new ArrayList<Column<?, OBJ>>();
ReflectUtils.processFields(getClass(), new FieldHandler() {
@SuppressWarnings({"unchecked"})
public boolean handleField(final Field field) throws Exception {
if (!Column.class.isAssignableFrom(field.getType())) return true;
final Column<?, OBJ> column = (Column<?, OBJ>) field.get(ReadableTable.this); // get the value of field
columns.add(column);
return true;
}
});
return Collections.unmodifiableList(columns);
}
/** default name database table (== getType()) in all lowercase **/
public String getTableName() {
return getTableType().getSimpleName().toLowerCase();
}
public abstract Class<OBJ> getTableType();
public String getAlias() {
return alias.resolve(getContext());
}
public String getTableWithAliasSql() {
return getTableName() + " " + getAlias();
}
/**
* Return field names together with aliases. Create alias names if not generated already
*/
public String getColumnsAsAliasSql() {
final StringBuilder sb = new StringBuilder();
for (final Column column : getColumns()) {
sb.append(",").append(column.getColumnAsAliasSql());
}
return sb.length() == 0 ? "" : sb.substring(1);
}
/**
* Return field names without aliases.
*/
@Override
public String getDefaultSql() {
return StringUtil.join(getColumns(), Column.GET_SQL_STRING, "," );
}
public String getFromSql() {
return getTableWithAliasSql();
}
public boolean isJoin() {
return false;
}
/**
* Convert model object into a map of fields.
* Key is sql of field and value is corresponding value from model object.
* If includeNullValues is false, only non-null values are present in list.
*/
public Map<Column, Object> getColumnValueMap(final OBJ modelObj, final boolean includeNullvalues) {
final Map<Column, Object> columnValueMap = new LinkedHashMap<Column, Object>();
final Map<String, Method> getterMap = BeanUtil.getGetters(getTableType());
for (final Column field : getColumns()) {
final Method getter = getterMap.get(field.getModelGetterName());
final Object value = ReflectUtils.getValue(modelObj, getter);
if (includeNullvalues || value != null) {
columnValueMap.put(field, value);
}
}
return columnValueMap;
}
public Column<?, OBJ> getColumn(final String propertyName) {
if (propertyName==null) throw new NullPointerException("propertyName");
if (columns == null) columns = extractColumns();
for (final Column<?, OBJ> column : columns) {
if (column.getPropertyName().equals(propertyName)) return column;
}
throw new RuntimeException("Unknown column: "+propertyName);
}
public List<Column<?, OBJ>> getColumns() {
if (columns == null) columns = extractColumns();
return columns;
}
@Override
public void setQueryContext(final QueryContext ctx) {
super.setQueryContext(ctx);
for (final Column field : getColumns()) {
field.setQueryContext(ctx);
}
}
}