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

prerna.sablecc2.GreedyTranslation Maven / Gradle / Ivy

The newest version!
package prerna.sablecc2;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import prerna.algorithm.api.ICodeExecution;
import prerna.algorithm.api.ITableDataFrame;
import prerna.om.Insight;
import prerna.om.InsightPanel;
import prerna.query.querystruct.selectors.QueryColumnSelector;
import prerna.reactor.AssignmentReactor;
import prerna.reactor.Assimilator;
import prerna.reactor.IReactor;
import prerna.reactor.IfReactor;
import prerna.reactor.expression.IfError;
import prerna.reactor.imports.FrameSizeRetrictions;
import prerna.reactor.qs.AbstractQueryStructReactor;
import prerna.reactor.qs.GroupReactor;
import prerna.reactor.qs.filter.FilterReactor;
import prerna.reactor.qs.selectors.QuerySelectorExpressionAssimilator;
import prerna.reactor.qs.selectors.SelectReactor;
import prerna.reactor.qs.source.FileReadReactor;
import prerna.reactor.qs.source.FrameReactor;
import prerna.reactor.utils.RemoveVariableReactor;
import prerna.sablecc2.node.AIdWordOrId;
import prerna.sablecc2.node.AOperation;
import prerna.sablecc2.node.POtherOpInput;
import prerna.sablecc2.om.PixelDataType;
import prerna.sablecc2.om.PixelOperationType;
import prerna.sablecc2.om.execptions.SemossPixelException;
import prerna.sablecc2.om.nounmeta.NounMetadata;
import prerna.sablecc2.om.task.ITask;
import prerna.sablecc2.om.task.options.TaskOptions;

public class GreedyTranslation extends LazyTranslation {

	protected PixelRunner runner;

	public GreedyTranslation(PixelRunner runner, Insight insight) {
		super(insight);
		this.runner = runner;
	}
	
    /**
     * This is greedy because we get the variable value (which means if its an embedded reactor we call execute)
     * instead of just passing the noun which points to a lambda
     */
    @Override
    public void inAIdWordOrId(AIdWordOrId node)
    {
    	defaultIn(node);
    	String idInput = (node.getId()+"").trim();
    	
    	if(this.planner.hasVariable(idInput)) {
    		NounMetadata varValue = this.planner.getVariableValue(idInput);
    		PixelDataType varType = varValue.getNounType();
    		if(curReactor != null) {
    			if(curReactor instanceof RemoveVariableReactor) {
    				curReactor.getCurRow().addLiteral(idInput);
    			}
    			// we will do just a little bit of value validation
    			// so that we only push in basic data types
    			else if(curReactor instanceof SelectReactor 
    					|| curReactor instanceof GroupReactor 
    					|| curReactor instanceof QuerySelectorExpressionAssimilator 
    					|| curReactor instanceof FilterReactor) {
    				if(varType == PixelDataType.CONST_STRING || varType == PixelDataType.CONST_INT || varType == PixelDataType.CONST_DECIMAL
    						|| varType == PixelDataType.CONST_DATE || varType == PixelDataType.CONST_TIMESTAMP 
    						// also account for complex expressions!
    						|| varType == PixelDataType.TASK
    						|| varType == PixelDataType.FORMATTED_DATA_SET) {
    					// this is a basic type
    					// or a task which needs to be flushed out
    					// so i can probably add it to the 
    					// query to work properly
    					curReactor.getCurRow().add(varValue);
    				} else {
    					// if this is not a basic type
    					// will probably break a query
    					// so pass in the original stuff
    					QueryColumnSelector s = new QueryColumnSelector(idInput);
    					curReactor.getCurRow().addColumn(s);
    				}
    			} else if(curReactor instanceof FrameReactor && varType == PixelDataType.FRAME) {
    				// add the frame based on the variable
    				curReactor.getCurRow().add(varValue);
    				// store the frame as an input
    				if(this.pixelObj != null) {
    					this.pixelObj.addFrameInput(((ITableDataFrame) varValue.getValue()).getOriginalName());
    				}
    			} else if(curReactor instanceof AbstractQueryStructReactor) {
    				// if it is a join or an as 
					curReactor.getCurRow().addColumn(idInput);
    			} else {
    				// let the assimilator handle the variables by defining it in the generated code
    				if(curReactor instanceof Assimilator) {
        				curReactor.getCurRow().addColumn(idInput);
    				} else {
        				curReactor.getCurRow().add(varValue);
        				if(varType == PixelDataType.FRAME) {
            				// store the frame as an input
        					if(this.pixelObj != null) {
        						this.pixelObj.addFrameInput(((ITableDataFrame) varValue.getValue()).getOriginalName());
        					}
            			}
    				}
    			}
    		} else {
    			if(varType == PixelDataType.FRAME) {
    				this.currentFrame = (ITableDataFrame) varValue.getValue();
    				// store the frame as an input
    				if(this.pixelObj != null) {
    					this.pixelObj.addFrameInput(this.currentFrame.getOriginalName());
    				}
    			}
    			this.planner.addVariable(this.resultKey, varValue);
    		}
    	} else {
    		if(curReactor != null) {
    			if(curReactor instanceof SelectReactor 
    					|| curReactor instanceof GroupReactor 
    					|| curReactor instanceof QuerySelectorExpressionAssimilator 
    					|| curReactor instanceof FilterReactor) {
    				// this is part of a query 
    				// add it as a proper query selector object
    				QueryColumnSelector s = new QueryColumnSelector(idInput);
					curReactor.getCurRow().addColumn(s);
    			} else {
    				curReactor.getCurRow().addColumn(idInput);
    				curReactor.setProp(node.toString().trim(), idInput);
    			}
    		} else {
    			// i guess we should return the actual column from the frame?
    			// TODO: build this out
    			// for now, will just return the column name again... 
    			NounMetadata noun = new NounMetadata(idInput, PixelDataType.CONST_STRING);
    			this.planner.addVariable(this.resultKey, noun);
    		}
    	}
    }
	
	@Override
	public void caseAOperation(AOperation node) {
        inAOperation(node);
        if(node.getId() != null)
        {
            node.getId().apply(this);
        }
        if(node.getLPar() != null)
        {
        	node.getLPar().apply(this);
        }
        if(curReactor instanceof IfError) {
        	try {
	        	if(node.getOpInput() != null)
	            {
	            	node.getOpInput().apply(this);
	            }
        	} catch(Exception ex) {
        		// hey, we got an error
        		// so i will do the other stuff
        		// but i also need to update the reference
        		// since the curReactor has changed
        		IReactor parentR = this.curReactor.getParentReactor();
        		while(!(parentR instanceof IfError)) {
        			parentR = parentR.getParentReactor();
        		}
        		curReactor = parentR;
        		List copy = new ArrayList(node.getOtherOpInput());
        		for(POtherOpInput e : copy)
        		{
        			e.apply(this);
        		}
        	}
    	} 
        // need to account for if error
        else {
	        if(node.getOpInput() != null)
	        {
	        	node.getOpInput().apply(this);
	        }
	        {
	        	if(curReactor instanceof IfReactor) {
	        		boolean caseBool = ((IfReactor) curReactor).getBooleanEvaluation();
	        		// case bool tells us if we should run the true case or the false case
	        		// index 0 is the true case, index 1 is the false case
	    			List copy = new ArrayList(node.getOtherOpInput());
	        		if(!caseBool) {
	    	            if(copy.size() >= 2) {
	    	            	POtherOpInput e = copy.get(1);
	    	            	e.apply(this);
	    	            } else {
	    	            	// wtf.. why would have you have more????
	    	            	// syntax must always be if(boolean, true case, [optional] false case)
	    	            }
	        		} else {
	        			POtherOpInput e = copy.get(0);
	        			e.apply(this);
	        		}
	        	} else {
	        		List copy = new ArrayList(node.getOtherOpInput());
	        		for(POtherOpInput e : copy)
	        		{
	        			e.apply(this);
	        		}
	        	}
	        }
    	}
        if(node.getRPar() != null)
        {
        	node.getRPar().apply(this);
        }
        if(node.getAsop() != null)
        {
        	node.getAsop().apply(this);
        }
        outAOperation(node);
	}

	@Override
    protected void deInitReactor()
    {
    	// couple of things I need to do here
    	// a. see if this is a reduce operation if so.. execute the reactor at once
    	// b. see if it can be done all through the native query
    	// c. If it can't be done as native query <--- This will be the last piece I will come to
    	// get the operation signature to be executed along with the genRowStruct
    	// all of this logic is sitting in the out method
    	
    	// time for the last piece or may be ?
    	// this is an all out codagen for now - mostly
    	// Couple of things we need
    	// we need some kind of a java class where I can continue to plug what I need to plug
    	// - Need a query method which returns a row iterator
    	// - You can pass in a query at any time and it would return that row iterator
    	// - Each of the pieces are divided into blocks
    	// - There needs to be something that gets you the blocks every single time
    	// - The top of the block is always a query
    	// - and the end of the block is either a query or it is some kind of a reduce value.. we should possibly keep this as an object as well
    	// - When the expression is typically added, it should add the components i.e. the projectors to the block and add the other portion of the code to the block to indicate
    	// this is what will be run at every block
    	// Question - What decides the separation of blocks
    	// a. Reduce operation - This should include the update and insert into the frame if you would like the to think of it that way.. 
    	// b. FlatMap operation - This means something else being added
    	// c. It also needs to follow George's logic in terms of breaking it into components
    	
    	if(curReactor != null)
    	{
	    	Object parent = curReactor.Out();
	    	
	    	//TODO : i hate these special case checks....how do we make this more elegant
	    	if(parent instanceof Assimilator) {
	    		// if our parent is an assimilator
	    		// we want to not execute but put the curReactor as a lamda
	    		((Assimilator) parent).getCurRow().add(new NounMetadata(curReactor, PixelDataType.LAMBDA));
	    		// when the assimilator executes
	    		// it will call super.execute
	    		// which will evaluate this reactor and do a string replace
	    		// on the signature
	    		curReactor = (Assimilator)parent;
	    		return;
	    	}
	    	
	    	NounMetadata output = null;
	    	// do we want to merge this into the parent QS reactor for lazy execution?
	    	if(curReactor.canMergeIntoQs() && parent instanceof AbstractQueryStructReactor) {
	    		output = new NounMetadata(curReactor, PixelDataType.LAMBDA);
	    	} else {
		    	output = curReactor.execute();
	    	}
	    	this.planner = curReactor.getPixelPlanner();

	    	// this now becomes the prev reactor
    		this.prevReactor = this.curReactor;
	    	//set the curReactor
	    	if(parent != null && parent instanceof IReactor) {
	    		this.curReactor = (IReactor) parent;
	    	} else {
	    		this.curReactor = null;
//	    		// store the noun map in the pixel
//    			this.pixelObj.addReactorInput(prevReactor.getStoreMap());
	    	}
	    	
	    	// we will merge up to the parent if one is present
	    	// otherwise, we will store the result in the planner for future use
	    	// the beginning of the pixel command the beginning of each pipe is an independent routine and doesn't have a parent
	    	// these will push their output to the result in the pixel planner
	    	// if a routine does have children, we will push the to the result directly to the parent
	    	// so the out of the parent can utilize it for its execution
	    	// ( ex. Select(Studio, Sum(Movie_Budget) where the Sum is a child of the Select reactor )
	    	
	    	if(output != null) {
	    		// size check
	    		if(output.getNounType() == PixelDataType.FRAME) {
	    			ITableDataFrame frame = (ITableDataFrame) output.getValue();
					if(!FrameSizeRetrictions.frameWithinLimits(frame)) {
	    				SemossPixelException exception = new SemossPixelException(
		    					new NounMetadata("Frame size is too large, please limit the data size before proceeding", 
		    							PixelDataType.CONST_STRING, 
		    							PixelOperationType.FRAME_SIZE_LIMIT_EXCEEDED, PixelOperationType.ERROR));
		    				exception.setContinueThreadOfExecution(false);
		    				throw exception;
	    			}
	    			// store the frame output in the pixel
	    			this.pixelObj.addFrameOutput(frame.getOriginalName());
	    		}
	    		
	    		if(curReactor != null && !(curReactor instanceof AssignmentReactor)) {
	    			// add the value to the parent's curnoun
	    			curReactor.getCurRow().add(output);
		    	} else {
		    		//otherwise if we have an assignment reactor or no reactor then add the result to the planner
		    		this.planner.addVariable(this.resultKey, output);
		    	}
	    		
	    		// WE WILL STORE SOME ADDITIONAL METADATA TO HELP WITH CACHING
	    		// ON THE PIXEL OBJECT ITSELF
	    		if(this.pixelObj != null) {
		    		if(output.getNounType() == PixelDataType.FORMATTED_DATA_SET) {
		    			Object oVal = output.getValue();
		    			if(oVal instanceof ITask) {
							ITask task = (ITask) oVal;
							if(task.getTaskOptions() != null) {
								pixelObj.addTaskOptions(task.getTaskOptions());
							}
		    			} else if(oVal instanceof Map) {
		    				Map taskMap = (Map) oVal;
		    				if(taskMap.get("taskOptions") != null) {
		    					Map tOptions = (Map) taskMap.get("taskOptions");
								pixelObj.addTaskOptions(new TaskOptions(tOptions));
		    				}
		    			}
		    		} else if(output.getNounType() == PixelDataType.TASK_LIST) {
		    			// we have multiple tasks that we are looping through
		    			Object oNoun = output.getValue();
		    			if(oNoun instanceof List) {
		    				List listVal = (List) oNoun;
		    				for(NounMetadata noun : listVal) {
		    					Object oVal = noun.getValue();
				    			if(oVal instanceof ITask) {
									ITask task = (ITask) oVal;
									if(task.getTaskOptions() != null) {
										pixelObj.addTaskOptions(task.getTaskOptions());
									}
				    			} else if(oVal instanceof Map) {
				    				Map taskMap = (Map) oVal;
				    				if(taskMap.get("taskOptions") != null) {
				    					Map tOptions = (Map) taskMap.get("taskOptions");
										pixelObj.addTaskOptions(new TaskOptions(tOptions));
				    				}
				    			}
		    				}
		    			}
		    		} else if(output.getNounType() == PixelDataType.REMOVE_LAYER) {
						pixelObj.addRemoveLayer((Map) output.getValue());
		    		} else if(output.getNounType() == PixelDataType.PANEL_CLONE_MAP) {
		    			Map cloneMap = (Map) output.getValue();
		    			Map simpleMap = new HashMap<>();
		    			simpleMap.put("original", cloneMap.get("original").getPanelId());
		    			simpleMap.put("clone", cloneMap.get("clone").getPanelId());
						pixelObj.addCloneMap(simpleMap);
		    		} 
		    		// replaced with below logic so we can store all the scripts 
		    		// that were run in an insight
//		    		else if(output.getNounType() == PixelDataType.CODE) {
//		    			String codeExecuted = ((ICodeExecution) prevReactor).getCode();
//		    			Variable.LANGUAGE language = ((ICodeExecution) prevReactor).getLanguage();
//		    			pixelObj.setCodeDetails(true, codeExecuted, language);
//		    		}
		    		
		    		// if we have a code execution reactor 
		    		// just set this as something to save
		    		if(prevReactor instanceof ICodeExecution) {
		    			String codeExecuted = ((ICodeExecution) prevReactor).getExecutedCode();
		    			if(codeExecuted != null && !codeExecuted.isEmpty()) {
			    			pixelObj.setCodeDetails(true, codeExecuted, 
			    					((ICodeExecution) prevReactor).getLanguage(),
			    					((ICodeExecution) prevReactor).isUserScript());
		    			}
		    		}
		    		
		    		List opTypes = output.getOpType();
		    		if(opTypes.contains(PixelOperationType.RESET_PANEL_TASKS)) {
		    			pixelObj.setRefreshPanel(true);
		    		}
		    		// TODO: i believe we are using this in a lot of places
		    		// where we run a script
		    		// but its not base code that can be executed
		    		if(opTypes.contains(PixelOperationType.CODE_EXECUTION)) {
		    			pixelObj.setSaveDataTransformation(true);
		    		}
		    		if(opTypes.contains(PixelOperationType.FRAME) 
		    				|| opTypes.contains(PixelOperationType.FRAME_DATA_CHANGE)
		    				|| opTypes.contains(PixelOperationType.FRAME_HEADERS_CHANGE)) {
		    			pixelObj.setFrameTransformation(true);
		    		}
		    		if(opTypes.remove(PixelOperationType.FORCE_SAVE_DATA_TRANSFORMATION)) {
		    			pixelObj.setSaveDataTransformation(true);
		    		}
		    		if(opTypes.remove(PixelOperationType.FORCE_SAVE_DATA_EXPORT)) {
		    			pixelObj.setSaveDataExport(true);
		    		}
		    		if(opTypes.remove(PixelOperationType.FORCE_SAVE_VISUALIZATION)) {
		    			pixelObj.setSaveVisualization(true);
		    		}
		    		
		    		// if we are an assignment, let us track that as well
		    		if(opTypes.contains(PixelOperationType.ADD_VARIABLE) 
		    				|| this.prevReactor instanceof AssignmentReactor) {
		    			pixelObj.setAssignment(true);
		    		}
		    		// store if we are doing a file read
		    		if(this.prevReactor instanceof FileReadReactor) {
		    			pixelObj.setFileRead(true);
		    		}
	    		}
	    		
	    	} else {
	    		this.planner.removeVariable(this.resultKey);
	    	}
    	}
    }
    
    @Override
	protected void postProcess(String pixelExpression) {
		super.postProcess(pixelExpression);
		// get the noun meta result
		// set that in the runner for later retrieval
		// if it is a frame
		// set it as the frame for the runner
		NounMetadata noun = planner.getVariableValue(this.resultKey);
		if(noun != null) {
			this.runner.addResult(pixelExpression, noun, this.pixelObj.isMeta());
			// if there was a previous result
			// remove it
			this.planner.removeVariable(this.resultKey);
		}
		else {
			this.runner.addResult(pixelExpression, new NounMetadata("no output", PixelDataType.CONST_STRING), this.pixelObj.isMeta());
		}
		this.curReactor = null;
		this.prevReactor = null;
	}
	
	protected void postRuntimeErrorProcess(String pixelExpression, NounMetadata errorNoun, List unexecutedPixels) {
		errorNoun.addAdditionalReturn(new NounMetadata(unexecutedPixels, PixelDataType.CONST_STRING, PixelOperationType.UNEXECUTED_PIXELS));
		this.runner.addResult(pixelExpression, errorNoun, this.pixelObj.isMeta());
		this.curReactor = null;
		this.prevReactor = null;
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy