io.odysz.transact.sql.parts.condition.Condit Maven / Gradle / Ivy
package io.odysz.transact.sql.parts.condition;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import io.odysz.semantics.ISemantext;
import io.odysz.transact.sql.Query;
import io.odysz.transact.sql.parts.Logic;
import io.odysz.transact.sql.parts.Logic.op;
import io.odysz.transact.sql.parts.Logic.type;
import io.odysz.transact.sql.parts.antlr.ConditVisitor;
import io.odysz.transact.x.TransException;
/**Logical Conditioning, a {@link Predicate} tree.
* For grammar definition, see {@link ConditVisitor}.
* @author ody
*
*/
public class Condit extends Predicate {
protected type logitype;
protected List condts;
/**When this is not null, this object is representing search_condition_not:
search_condition_not
: NOT? predicate
;
protected Predicate predict;
*/
public Condit(op op, String lop, String rop) {
super(op, lop, rop); // FIXME op = eq, lop = e.pid, rop = ch.entfk, line 1:8 mismatched input '' expecting '.'
this.logitype = Logic.type.empty;
}
public Condit(op op, String lop, ExprPart rop) {
super(op, lop, rop);
this.logitype = Logic.type.empty;
}
public Condit(op op, ExprPart lop, ExprPart rop) {
super(op, lop, rop);
this.logitype = Logic.type.empty;
}
public Condit(Logic.type type, List condts) {
super();
this.logitype = type;
this.condts = condts;
}
public Condit(Predicate predicate) {
super(predicate);
this.logitype = Logic.type.empty;
}
public Condit(op op, String lop, Query rop) throws TransException {
super(op, lop, rop);
this.logitype = Logic.type.empty;
}
/**
* Generate a "in" condition for: lop in ('constr[0]', 'constr[1]', ...)
* @param lop
* @param constvs
* @return Condit instance
* @since 1.4.36
public static Condit in(String lop, String[] constr) {
if (constr != null) {
ArrayList rops = new ArrayList(constr.length);
for (String c : constr)
rops.add(Funcall.constr(c));
return new Condit(op.in, lop, rops);
}
return null;
}
*/
public boolean isEmpty() {
return (condts == null || condts.size() == 0) && super.empty;
}
public Condit and(Condit and) {
if (logitype == type.or) {
// and is prior to the other ors
condts.get(condts.size() - 1).and(and);
return this;
}
else if (logitype == type.and) {
condts.add(and);
return this;
}else if (logitype == type.not) {
Condit left = new Condit(type.not, condts);
condts = new ArrayList();
condts.add(left);
logitype = type.and;
condts.add(and);
return this;
}
else { // empty logic, AND with it
ArrayList ands = new ArrayList();
ands.add(this);
ands.add(and);
return new Condit(Logic.type.and, ands);
}
}
public Condit or(Condit or) {
if (logitype == type.or) {
condts.add(or);
return this;
}
else if (logitype == type.and) {
condts.get(condts.size() - 1).or(or);
return this;
}else if (logitype == type.not) {
// shouldn't reach here
Condit left = new Condit(type.not, condts);
condts = new ArrayList();
condts.add(left);
logitype = type.or;
condts.add(or);
return this;
}
else { // empty logic, OR with it
ArrayList ands = new ArrayList();
ands.add(this);
ands.add(or);
return new Condit(Logic.type.or, ands);
}
}
/** Additional information of left alias for generating sql. */
String lAlias;
/** Additional information of right alias for generating sql. */
String rAlias;
private int priority = 0;
/**Set the priority 1 more higher than parent
* - call this only when composing sql(conditions won't changing)
* @param parentLogic
* @return
*/
private Condit prio(Logic.type parentLogic) {
if (parentLogic == Logic.type.and && logitype == Logic.type.or
// call this only when composing sql(conditions won't changing)
&& condts != null && condts.size() > 1)
this.priority = 1;
return this;
}
private String lbrace() {
String l = "";
if (condts != null && condts.size() > 0)
for (int b = 0; b < priority; b++)
l += "(";
return l;
}
private String rbrace() {
String r = "";
if (condts != null && condts.size() > 0)
for (int b = 0; b < priority; b++)
r += ")";
return r;
}
/**Sometimes conditions's table name or alias are ignored by client.
* This method can be called by {@link io.odysz.transact.sql.parts.JoinTabl}
* to supply additional information when generating sql.
*
TODO DESIGN MEMO
* {@link Condit}s are parsed from sometimes from where clause, sometimes from join-on clause,
* so it's not have enough information to parse ignored alias.
* Should we implement this fault tolerance?
*
@Deprecated
* @param lt left operand's alias (table name)
* @param rt right operand's alias (table name)
* @return this
*/
public Condit sqlTbl(String lt, String rt) {
this.lAlias = lt;
this.rAlias = lt;
return this;
}
@Override
public String sql(ISemantext sctx) throws TransException {
// handling with 3 grammar rule: search_condition, search_condition_and, search_condition_not
// 1. search_condition_not
// 2. search_condition_and
if (logitype == type.empty) {
return super.sql(sctx);
}
else if (logitype == type.and) {
if (condts != null && condts.size() > 0) {
String sql = condts.stream()
.map(cdt -> {
try {
cdt.prio(logitype);
return cdt.sql(sctx);
} catch (TransException e) {
e.printStackTrace();
return e.getMessage();
}
})
.collect(Collectors.joining(" AND ", lbrace(), rbrace()));
return sql;
}
}
// 3. search_conditon_not
else if (logitype == type.or) {
if (condts != null && condts.size() > 0) {
String sql = condts.stream()
.map(cdt -> {
try {
return cdt.sql(sctx);
} catch (TransException e) {
e.printStackTrace();
return e.getMessage();
}
})
.collect(Collectors.joining(" OR ", lbrace(), rbrace()));
return sql;
}
}
return null;
}
}