Sparqlify-master/sparqlify-trash/trash/SqlOpSelectBlockCollector.java
package org.aksw.sparqlify.core.algorithms;

import java.util.ArrayList;
import java.util.List;

import org.aksw.commons.util.reflect.MultiMethod;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOp;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOpDistinct;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOpEmpty;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOpFilter;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOpJoin;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOpProject;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOpQuery;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOpRename;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOpSelectBlock;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOpSlice;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOpTable;
import org.aksw.sparqlify.algebra.sql.nodes.SqlOpUnionN;

import org.apache.jena.sdb.core.Generator;
import org.apache.jena.sdb.core.Gensym;
import org.apache.jena.sparql.expr.ExprVar;


/**
 * Pitfalls:
 *     (distinct (project ...)) -> First project then make distinct
 *         -> Select Distinct [project]
 *     But
 *     (project (distinct ...)) -> First make distinct (with potentially some different projection),
 *     then project:
 *     Select [projection] FROM (Select Distinct * From ...)    
 * 
 * 
 * @author Claus Stadler <cstadler@informatik.uni-leipzig.de>
 *
 */
public class SqlOpSelectBlockCollector {

	private static Generator aliasGenerator = Gensym.create("a");
	
	
	/*
	public static boolean isModifier(SqlOp sqlOp) {
		
		
	}
	*/
	
	public static SqlOpSelectBlock _makeSelect(SqlOp sqlOp) {
		SqlOpSelectBlock result = MultiMethod.invokeStatic(SqlOpSelectBlockCollector.class, "makeSelect", sqlOp, null);
		
		return result;
	}

	public static SqlOpSelectBlock _makeSelect(SqlOp sqlOp, SqlOpSelectBlock context) {
		SqlOpSelectBlock result = MultiMethod.invokeStatic(SqlOpSelectBlockCollector.class, "makeSelect", sqlOp, null);
		
		return result;
	}

	/*
	public static SqlOpSelectBlock makeSelect(SqlGroup node) {
		SqlOpSelectBlock result;
		
		if(node.getSubOp() instanceof SqlOpSlice) {
			
			SqlOpSelectBlock tmp = _makeSelect(node.getSubOp());

			result = new SqlOpSelectBlock(tmp.getAliasName(), tmp);
			copyProjection(result, result);

			
		}
		else {
			result = _makeSelect(node.getSubOp());
		}

		System.err.println("TODO Handle group by vars if present");
		
		return result;
	}
	*/
	
	public static SqlOpSelectBlock makeSelect(SqlOpTable node) {

		SqlOpTable opTable = makeSelectOrTable(node);
		
		SqlOpSelectBlock result = SqlOpSelectBlock.create(opTable);

		for(String columnName : opTable.getSchema().getColumnNames())  {
			result.getProjection().put(columnName, new ExprVar(opTable.getAliasName() + "." + columnName));
		}

		
		return result;
	}
	
	public static SqlOpSelectBlock makeSelect(SqlOpQuery node) {

		SqlOpQuery opQuery = makeSelectOrTable(node);

		
		SqlOpSelectBlock result = SqlOpSelectBlock.create(opQuery);

		
		for(String columnName : opQuery.getSchema().getColumnNames())  {
			result.getProjection().put(columnName, new ExprVar(opQuery.getAliasName() + "." + columnName));
		}
				
		return result;
	}
	
	public static SqlOpSelectBlock requireContext(SqlOp node, SqlOpSelectBlock context) {
		if(context != null) {
			return context;
		}
		
		SqlOpSelectBlock result = SqlOpSelectBlock.create(node);
		return result;
	}
	
	public static SqlOpSelectBlock makeSelect(SqlOpFilter op) {
		
		SqlOp effectiveOp = _makeSelect(op.getSubOp());
		
//		SqlOpSelectBlock result = null; requireSelectBlock(effectiveOp, op);
				
		result.getConditions().addAll(op.getExprs());
		
		return result;
	}
	
	public static SqlOpSelectBlock makeSelect(SqlOpSlice node) {
		SqlOpSelectBlock result = _makeSelect(node.getSubOp());
    	SqlOpSelectBlock.slice(null, result, node.getOffset(), node.getLimit());
		
		return result;
	}
	
	public static SqlOpSelectBlock makeSelect(SqlOpDistinct node) {
		SqlOpSelectBlock result = _makeSelect(node.getSubOp());
		result.setDistinct(true);
		
		return result;
	}
	
	/*
	public static SqlOpSelectBlock makeSelect(SqlAlias node) {
		
		if(true) {
			SqlOpSelectBlock result = _makeSelect(node.getSubOp());
			//result.setAliasName(node.getAliasName());
			
			SqlOpSelectBlock wrap = new SqlOpSelectBlock(node.getAliasName(), result);
			copyProjection(wrap, result);
			
			return wrap;

			/*
			copyProjection(result, node);
			result.setAliasName(node.getAliasName());
			return result;
			* /
		}
		//throw new RuntimeException("Should not come here");
		

    	SqlOp result = _makeSelectOrTable(node.getSubOp());    	
    	

		SqlOpSelectBlock wrap = new SqlOpSelectBlock(node.getAliasName(), result);
		copyProjection(wrap, result);
		
		return wrap;
		
		
		/*
		wrap.getSparqlVarToExprs().putAll(node.getSparqlVarToExprs());
		wrap.getAliasToColumn().putAll(node.getAliasToColumn());

    	result.setAliasName(node.getAliasName());
    	
    	return result;
    	* /
	}
	*/

	
	/*
	public static SqlOpSelectBlock makeSelect(SqlOpOrder node) {
    	SqlOpSelectBlock result = _makeSelect(node.getSubOp());    	
    	result.getSortConditions().addAll(node.getConditions());
    	
    	copyProjection(result, node);
    	
    	return result;
	}
	*/
	
	public static SqlOpSelectBlock makeSelect(SqlOpProject node) {
		SqlOpSelectBlock result = _makeSelect(node.getSubOp());

		// If the node is distinct, or if it already has a projection set,
		// we must create a subselect
		if(result.isDistinct()) { // || result.isResultStar()
			//SqlOpSelectBlock wrapped = new 
			
		}
				
		
		return result;
	}

//	public static priority
	
	
	public static SqlOpSelectBlock makeSelect(SqlOpRename op) {
	
		SqlOp tmp = _makeSelectOrTable(op.getSubOp());

		SqlOpSelectBlock result = requireSelectBlock(tmp, op);
		
		result.getProjection().renameAll(op.getRename());
		
		return result;		
	}

	
	public static SqlOpSelectBlock makeSelect(SqlOpJoin node, SqlOpSelectBlock context) {
		
		SqlOpSelectBlock result = requireContext(node, context);
		
		
		//SqlOp join = makeSelectOrTable(node, result);
		
		return new SqlOpSelectBlock(null);
	}
	
	public static SqlOpSelectBlock makeSelect(SqlOpUnionN node) {
    	// Wrap all elements of the union
    	List<SqlOp> wrapped = new ArrayList<SqlOp>();
    	for(SqlOp arg : node.getSubOps()) {
    		SqlOpSelectBlock argSelect = _makeSelect(arg);
    		
    		/*
    		argSelect.getSparqlVarToExprs().clear();
    		argSelect.getAliasToColumn().clear();
    		
    		
    		argSelect.getSparqlVarToExprs().putAll(arg.getSparqlVarToExprs());
    		argSelect.getAliasToColumn().putAll(arg.getAliasToColumn());
    		*/
    		
    		
    		wrapped.add(argSelect);
    	}
    	    	
    	SqlOpUnionN union = SqlOpUnionN.create(wrapped); //, SqlOpSelectBlock.getAliasName(node));


    	SqlOpSelectBlock result = SqlOpSelectBlock.create(union);
    	
    	return result;
	}
		
	public static SqlOp _makeSelectOrTable(SqlOp node) {
		return MultiMethod.invokeStatic(SqlOpSelectBlockCollector.class, "makeSelectOrTable", node);		
	}

	public static SqlOp makeSelectOrTable(SqlOpEmpty node) {
		throw new RuntimeException("Empty SQL node");
		// Should never come here
		return node;
	}

	public static SqlOp makeSelectOrTable(SqlOpProject node) {
		return _makeSelect(node);
	}

	public static SqlOpTable makeSelectOrTable(SqlOpTable node) {
		
		String alias = aliasGenerator.next();
		SqlOpTable result = new SqlOpTable(node.getSchema(), node.getTableName(), alias);
		
		return result;
	}
	
	public static SqlOpQuery makeSelectOrTable(SqlOpQuery node) {
		String alias = aliasGenerator.next();
		
		SqlOpQuery result = new SqlOpQuery(node.getSchema(), node.getQueryString(), alias);

		return result;
	}

	/*
	public static SqlOp makeSelectOrTable(SqlAlias node) {
    	SqlOp tmp = _makeSelectOrTable(node.getSubOp());    	
		
    	SqlAlias result = new SqlAlias(node.getAliasName(), tmp);
    	copyProjection(result, node);
    	
    	return result;
	}
	*/
	
	public static SqlOp makeSelectOrTable(SqlOpFilter node) {
		return _makeSelect(node);		
	}

	public static SqlOp makeSelectOrTable(SqlOpSlice node) {		
		return _makeSelect(node);
	}

	public static SqlOp makeSelectOrTable(SqlOpDistinct node) {		
		return _makeSelect(node);
	}

	public static SqlOp makeSelectOrTable(SqlOpRename op) {		
		return _makeSelect(op);
	}

	
	public static SqlOp makeSelectOrTable(SqlOpJoin node) {
		SqlOp left = _makeSelectOrTable(node.getLeft());
		SqlOp right = _makeSelectOrTable(node.getRight());
		
		SqlOpJoin join = SqlOpJoin.create(node.getJoinType(), left, right);
		join.getConditions().addAll(node.getConditions());
		//copyProjection(join, node);

		return join;
	}
	
	public static SqlOp makeSelectOrTable(SqlOpUnionN node) {
		return makeSelect(node);
	}
	
}

