All Downloads are FREE. Search and download functionalities are using the official Maven repository.

prerna.reactor.qs.AbstractQueryStructReactor Maven / Gradle / Ivy

The newest version!
package prerna.reactor.qs;

import java.util.List;
import java.util.Vector;

import prerna.algorithm.api.ITableDataFrame;
import prerna.query.querystruct.AbstractQueryStruct;
import prerna.query.querystruct.SelectQueryStruct;
import prerna.query.querystruct.selectors.IQuerySelector;
import prerna.query.querystruct.update.UpdateQueryStruct;
import prerna.reactor.AbstractReactor;
import prerna.sablecc2.om.GenRowStruct;
import prerna.sablecc2.om.PixelDataType;
import prerna.sablecc2.om.nounmeta.NounMetadata;

/**
 * This is the base class for any reactor responsible for building a querystruct
 * 
 * The design of this class is as such:
 * 		This class holds a query struct, responsible for grabbing input and passing output
 * 		any subclass is only responsible for building the query struct through method createQueryStruct()
 * 		Ex:
 * 			SelectReactor overrides createQueryStruct() build on top of the existing query struct with only Selectors
 * 			JoinReactor overrides createQueryStruct() builds on top of the existing query struct with only joins
 * 
 * 			QueryStructReactor is responsible for grabbing any input querystructs and passing the output
 */
public abstract class AbstractQueryStructReactor extends AbstractReactor {

	protected AbstractQueryStruct qs;
	protected String[] selectorAlias;
	
	// method to override in the specific qs classes
	protected abstract AbstractQueryStruct createQueryStruct();

	// store the number of previously defined selectors
	// this is so we can have multiple as statements 
	// for each portion of the select
	protected int existingSelectors = 0;
	
	@Override
	public NounMetadata execute() {
		init();
		//build the query struct
		AbstractQueryStruct qs = createQueryStruct();
		setAlias(qs.getSelectors(), selectorAlias, existingSelectors);
		//create the output and return
		NounMetadata noun = new NounMetadata(qs, PixelDataType.QUERY_STRUCT);
		return noun;
	}
	
	public void setAs(String[] asName) {
		this.selectorAlias = asName;
	}
	
	//initialize the reactor with its necessary inputs
	protected void init() {
		// this will happen when we have an explicit querystruct
		// or one result piped a query struct to the current reactor
		GenRowStruct qsInputParams = getNounStore().getNoun(PixelDataType.QUERY_STRUCT.getKey());
		if(qsInputParams != null) {
			int numInputs = qsInputParams.size();
			for(int inputIdx = 0; inputIdx < numInputs; inputIdx++) {
				NounMetadata qsNoun = (NounMetadata)qsInputParams.getNoun(inputIdx);
				AbstractQueryStruct qs = (AbstractQueryStruct) qsNoun.getValue();
				mergeQueryStruct(qs);
			}
		}
		
		// if it is not piped
		// but there is a query struct within a query struct
		// the specific instance of the reactor will handle those types of merges
		// example
		// selector ( studio , sum(mb) ) 
		// the selector reactor will handle putting the studio and the sum(mb)
		
		if(this.qs == null) {
			this.qs = new SelectQueryStruct();
			if(this.insight != null) {
				this.qs.setFrame((ITableDataFrame) this.insight.getDataMaker());
			}
		}
	}
	
	//method to merge an outside query struct with this query struct
	protected void mergeQueryStruct(AbstractQueryStruct queryStruct) {
		this.existingSelectors = queryStruct.getSelectors().size();
		if(this.qs == null) {
			this.qs = queryStruct;
		} else {
			// if we have an update QS
			// use that so we keep the correct qs type
			if(queryStruct instanceof UpdateQueryStruct) {
				queryStruct.merge(this.qs);
				this.qs = queryStruct;
			} else {
				this.qs.merge(queryStruct);
			}
		}
	}
	
	protected static void setAlias(List selectors, String[] selectorAlias, int startingPoint) {
		/*
		 * Since multiple select reactors can each have an alias
		 * we need to go back and add alias to the last selectors that were added
		 * based on the index of the alias we are adding
		 */
		if(selectorAlias != null) {
			int numSelectors = selectors.size();
			int numAlias = selectorAlias.length;
			if(numAlias != numSelectors) {
				// assume user is defining alias from left to right
				// but got lazy half way through
				// we we will set the numSelectors to be the number of aliases provided
				if(numSelectors > numAlias) {
					numSelectors = numAlias;
				} else {
					// this is awkward
					// you have more aliases than selectors
					// not sure why
				}
			}
			int counter = 0;
			for(int i = startingPoint; i < numSelectors; i++) {
				selectors.get(i).setAlias(selectorAlias[counter]);
				counter++;
			}
		}
	}
	
	@Override
	public List getOutputs() {
		// all of the classes return the same thing
		// which is a QS
		// this works because even if execute hasn't occurred yet
		// because the same preference exists for the qs
		// and since out is called prior to update the planner
		// the qs cannot be null
		List outputs = new Vector();
		if(this.qs != null) {
			NounMetadata output = new NounMetadata(this.qs, PixelDataType.QUERY_STRUCT);
			outputs.add(output);
		}
		return outputs;
	}
	
	@Override
	public void mergeUp() {
		// merge this reactor into the parent reactor
		init();
		createQueryStruct();
		setAlias(qs.getSelectors(), selectorAlias, existingSelectors);
		if(parentReactor != null) {
			// this is only called lazy
			// have to init to set the qs
			// to them add to the parent
			NounMetadata data = new NounMetadata(this.qs, PixelDataType.QUERY_STRUCT);
			// add to the parent reactors curRow
			parentReactor.getCurRow().add(data);
		}
	}
	
	/**
	 * Return the QS
	 * @return
	 */
	public AbstractQueryStruct getQs() {
		return qs;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy