package org.yaac.server.egql;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.newLinkedList;
import static com.google.common.collect.Sets.newHashSet;
import java.util.List;
import java.util.Set;
import org.yaac.server.egql.exception.EGQLE050Exception;
import org.yaac.server.egql.exception.EGQLE051Exception;
import org.yaac.server.egql.exception.EGQLE052Exception;
import org.yaac.server.egql.exception.EGQLException;
import org.yaac.server.egql.processor.ChannelMsgSender;
import org.yaac.server.egql.processor.InsertProcessor;
import org.yaac.server.egql.processor.Processor;
import org.yaac.shared.SharedConstants;
import org.yaac.shared.egql.EGQLConstant;
import com.google.common.base.Objects;
/**
* @author Max Zhu (thebbsky@gmail.com)
*
*/
public class InsertStatement extends Statement {
/**
*
*/
private static final long serialVersionUID = 1L;
private String kind;
private List<InsertItem> items;
private SelectStatement selectStmt;
public InsertStatement() {
super();
this.items = newLinkedList();
}
public String getKind() {
return kind;
}
public InsertStatement withKind(String kind) {
this.kind = kind;
return this;
}
public InsertStatement withItem(InsertItem item) {
this.items.add(item);
return this;
}
public InsertStatement withSelectStatement(SelectStatement stmt) {
this.selectStmt = stmt;
return this;
}
/**
* @return keyItem, if any
*/
public InsertItem keyItem() {
for (InsertItem item : items) {
if (SharedConstants.Datastore.KEY_RESERVED_NAME.equals(item.getIdentity())) {
return item;
}
}
return null;
}
/**
* @return
*/
public Iterable<InsertItem> propertyItems() {
List<InsertItem> properties = newArrayList(items);
properties.remove(keyItem());
return properties;
}
@Override
public void validate() throws EGQLException {
Set<String> itemNames = newHashSet();
for (InsertItem item : items) {
// duplicate insert item is not allowed
if (itemNames.contains(item.getIdentity())) {
throw new EGQLE050Exception();
} else {
itemNames.add(item.getIdentity());
}
// aggregation function is not allowed in insert statement without select clause
if (!item.getE().aggregationChildren().isEmpty() && this.selectStmt == null) {
throw new EGQLE051Exception();
}
// field is not allowed in insert statement without select clause
if (!item.getE().nonAggregationProperties().isEmpty() && this.selectStmt == null) {
throw new EGQLE052Exception();
}
}
}
@Override
public boolean equals(Object obj) {
if (obj instanceof InsertStatement) {
return Objects.equal(this.kind, ((InsertStatement) obj).kind)
&& Objects.equal(this.items, ((InsertStatement) obj).items)
&& Objects.equal(this.selectStmt, ((InsertStatement) obj).selectStmt);
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(kind, selectStmt);
}
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("kind", kind)
.add("items", items)
.add("selectStmt", selectStmt)
.toString();
}
@Override
public List<Processor> generateProcessors() {
Processor datastoreLoader = this.selectStmt.datastoreLoader();
Processor selector = this.selectStmt.selector();
Processor inserter = new InsertProcessor(this);
Processor msgSender = new ChannelMsgSender(EGQLConstant.DEFAULT_MAX_RESULT);
return newArrayList(datastoreLoader, selector, inserter, msgSender);
}
@Override
public boolean isSimpleStatement() {
// if there is a select statement, then execute as processors, otherwise simply insert
return this.selectStmt == null;
}
}