/*
$Header: /cvsroot/xorm/xorm/src/org/xorm/query/Selector.java,v 1.18 2003/11/12 23:39:06 wbiggs Exp $
This file is part of XORM.
XORM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
XORM 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with XORM; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.xorm.query;
import org.xorm.datastore.Column;
import org.xorm.datastore.DataFetchGroup;
import org.xorm.datastore.Table;
import java.util.Set;
import java.util.Iterator;
public class Selector implements Cloneable {
/** Immutable class to capture ordering information. */
public static class Ordering {
public static final int ASCENDING = 0;
public static final int DESCENDING = 1;
private Column column;
private int order;
public Ordering(Column column, int order) {
this.column = column;
this.order = order;
}
public Column getColumn() { return column; }
public int getOrder() { return order; }
}
private Table table;
private Condition condition;
private Set fetchColumns;
private boolean outerJoin;
private Ordering[] ordering;
private Column joinColumn;
public Selector(Table table, Condition condition) {
this.table = table;
this.condition = condition;
this.joinColumn = table.getPrimaryKey();
}
public Object clone() {
Selector clone = null;
try {
clone = (Selector) super.clone();
if (condition != null) {
clone.condition = (Condition) condition.clone();
}
} catch (CloneNotSupportedException ignore) {
}
return clone;
}
public boolean isOuterJoin() {
return outerJoin;
}
public void setOuterJoin(boolean value) {
outerJoin = value;
}
public Table getTable() { return table; }
public Condition getCondition() { return condition; }
public void setCondition(Condition condition) {
this.condition = condition;
}
public Set getFetchColumns() { return fetchColumns; }
public void setOrdering(Ordering[] ordering) {
this.ordering = ordering;
}
public Ordering[] getOrdering() { return ordering; }
public Column getJoinColumn() {
return joinColumn;
}
public void setJoinColumn(Column joinColumn) {
this.joinColumn = joinColumn;
}
public String toString() {
return (table == null? null : table.getName()) + "." + (joinColumn == null ? null: joinColumn.getName()) + " where " + condition;
}
public void require(DataFetchGroup fetchGroup) {
fetchColumns = fetchGroup.getColumns();
Column column;
Iterator i = fetchGroup.getSubgroupColumns().iterator();
while (i.hasNext()) {
column = (Column) i.next();
DataFetchGroup subgroup = fetchGroup.getSubgroup(column);
// Find or create the Selector for the subgroup
Selector selector = findSelector(condition, subgroup.getTable());
if (selector == null) {
selector = new Selector(subgroup.getTable(), null);
selector.outerJoin = !column.isNonNull();
Condition join = new SimpleCondition
(column, Operator.EQUAL, selector);
if (condition != null) {
condition = new AndCondition(join, condition);
} else {
condition = join;
}
}
selector.require(subgroup);
}
}
public Selector findSelector(Table table) {
if (this.table == table) return this;
return findSelector(condition, table);
}
private static Selector findSelector(Condition condition, Table table) {
Selector result = null;
if (condition instanceof SimpleCondition) {
Object v = ((SimpleCondition) condition).getValue();
if (v instanceof Selector) {
Selector s = (Selector) v;
if (s.getTable().equals(table)) {
result = s;
} else {
return findSelector(s.getCondition(), table);
}
}
} else if (condition instanceof CompoundCondition) {
CompoundCondition cc = (CompoundCondition) condition;
// Try LHS
result = findSelector(cc.getLHS(), table);
if (result == null) {
// Try RHS
result = findSelector(cc.getRHS(), table);
}
}
return result;
}
/**
* Optimizes two Selectors by creating an AndCondition or
* OrCondition at the proper level.
*
* @return true if the selectors were merged
*/
public boolean merge(Selector other, Operator operator) {
if (other.getTable().equals(table)) {
Condition otherCond = other.condition;
if (otherCond == null) return true;
Condition thisCond = condition;
if ((thisCond instanceof SimpleCondition) && (otherCond instanceof SimpleCondition)) {
SimpleCondition thisSC = (SimpleCondition) thisCond;
SimpleCondition otherSC = (SimpleCondition) otherCond;
if (thisSC.getColumn().equals(otherSC.getColumn()) &&
thisSC.getOperator().equals(otherSC.getOperator())) {
Object thisVal = thisSC.getValue();
Object otherVal = otherSC.getValue();
if ((thisVal instanceof Selector) && (otherVal instanceof Selector)) {
Selector thisSel = (Selector) thisVal;
Selector otherSel = (Selector) otherVal;
if (thisSel.getTable().equals(otherSel.getTable())) {
return thisSel.merge(otherSel, operator);
}
}
}
}
// Merge at this point
if (operator.equals(Operator.ANDC)) {
condition = new AndCondition(thisCond, otherCond);
} else {
condition = new OrCondition(thisCond, otherCond);
}
return true;
} else {
// Don't merge
return false;
}
}
}