package com.itemanalysis.squiggle.criteria; import java.util.List; import java.util.Set; import com.itemanalysis.squiggle.base.Criteria; import com.itemanalysis.squiggle.base.Table; import com.itemanalysis.squiggle.output.Output; /** * Class CriteriaExpression is Criteria class extension that generates the SQL * syntax for a compound logic expression in an SQL Where clause. The logic * expression that the class generates is a list of criteria terms each * separated by an {@link Operator#AND AND} or {@link Operator#OR OR} operator. * Formally, we may express a logic expression in Backus-Naur Form (BNF) as * <p> * <code> * <expression> ::= <term> | <term> <operator <expression> * <br/><term> ::= <criteria> * <br/><operator> ::= AND | OR * </code> * </p> * * @author <a href="mailto:derek@derekmahar.ca">Derek Mahar</a> */ public class CriteriaExpression extends Criteria { /** * Operator identifiers */ public static interface Operator { /** * Identifier for the AND operator. */ static final int AND = 0; /** * Identifier for the OR operator. */ static final int OR = 1; } // Recursive reference to another expression. private CriteriaExpression expression; // Operator that joins the initial criteria term with the trailing criteria // expression. private int operator; // Initial criteria term in the expression. private Criteria term; /** * Initializes a CriteriaExpression with a single criteria term, leaving the * trailing criteria expression set to null. This constructor definition * represents the rule * * <expression> ::= <term> * * in the formal criteria expression syntax. * * @param term * single criteria to assign to this criteria expression. */ public CriteriaExpression(final Criteria term) { this.term = term; } /** * Initializes a CriteriaExpression with an initial criteria term, an * operator, and a another trailing criteria expression. Note that this * constructor definition is recursive and represents the rule * * <expression> ::= <term> <operator <expression> * * in the formal criteria expression syntax. * * @param term * the starting criteria to assign to the new criteria * expression. * * @param operator * the infix operator, either {@link Operator#AND AND} or * {@link Operator#OR OR}, that joins the initial criteria with * the trailing criteria expression. * * @param expression * the trailing expression to assign to the new criteria * expression. */ public CriteriaExpression(final Criteria term, int operator, CriteriaExpression expression) { this(term); this.operator = operator; this.expression = expression; } /** * Recursively generates a CriteriaExpression from a given list of criteria * and an infix operator to join each criteria with the next in the list. * * @param terms * the list of criteria terms from which the constructor * generates the new criteria expression. * * @param operator * the infix operator, either {@link Operator#AND AND} or * {@link Operator#OR OR} that joins each criteria term with the * next in the list. */ public CriteriaExpression(final List<Criteria> terms, int operator) { this.operator = operator; if (terms.size() == 0) ; else { this.term = terms.get(0); if (terms.size() > 1) this.expression = new CriteriaExpression(terms.subList(1, terms .size()), operator); } } /** * Returns the trailing expression in this criteria expression. * * @return the trailing expression in this criteria expression. */ public CriteriaExpression getExpression() { return expression; } /** * Returns the operator, either {@link Operator#AND AND} or * {@link Operator#OR OR}, in this criteria expression that joins the * initial criteria with the trailing criteria expression. * * @return the operator, either {@link Operator#AND AND} or * {@link Operator#OR OR}, in this criteria expression. */ public int getOperator() { return operator; } /** * Returns the initial criteria in this criteria expression. * * @return the initial criteria in this criteria expression. */ public Criteria getTerm() { return term; } /** * Writes this criteria expression to the given output destination. If both * term and expression are null, this method generates no output. If * expression is null, but term is defined, the method writes the term * criteria to the output. If both expression and term are defined, however, * the method creates a new logic operator object, either * {@link Operator#AND AND} or {@link Operator#OR OR}, assigns it the term * and expression, and writes this new operator to the output. * * @param out * the output destination to which to write this criteria * expression. * * @see com.truemesh.squiggle.Criteria#write(com.truemesh.squiggle.output.Output) */ public void write(Output out) { if (term == null && expression == null) { ; } else if (expression == null) { term.write(out); } else if (operator == Operator.AND) { new AND(term, expression).write(out); } else if (operator == Operator.OR) { new OR(term, expression).write(out); } } public void addReferencedTablesTo(Set<Table> tables) { term.addReferencedTablesTo(tables); if (expression != null) expression.addReferencedTablesTo(tables); } }