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

prompto.expression.FetchManyExpression Maven / Gradle / Ivy

The newest version!
package prompto.expression;

import java.util.stream.Collectors;

import prompto.compiler.CompilerUtils;
import prompto.compiler.Flags;
import prompto.compiler.InterfaceConstant;
import prompto.compiler.MethodConstant;
import prompto.compiler.MethodInfo;
import prompto.compiler.Opcode;
import prompto.compiler.ResultInfo;
import prompto.declaration.CategoryDeclaration;
import prompto.error.PromptoError;
import prompto.error.SyntaxError;
import prompto.grammar.OrderByClauseList;
import prompto.intrinsic.IterableWithCounts;
import prompto.intrinsic.PromptoRoot;
import prompto.parser.Dialect;
import prompto.runtime.Context;
import prompto.store.AttributeInfo;
import prompto.store.IQuery;
import prompto.store.IQueryBuilder;
import prompto.store.IQueryBuilder.MatchOp;
import prompto.store.IStore;
import prompto.store.IStoredIterable;
import prompto.store.InvalidValueError;
import prompto.transpiler.Transpiler;
import prompto.type.AnyType;
import prompto.type.CategoryType;
import prompto.type.CursorType;
import prompto.type.IType;
import prompto.utils.CodeWriter;
import prompto.utils.IdentifierList;
import prompto.value.CursorValue;
import prompto.value.IValue;


public class FetchManyExpression extends FetchOneExpression {

	protected IExpression first;
	protected IExpression last;
	protected OrderByClauseList orderBy;
	
	public FetchManyExpression(CategoryType type, IExpression first, IExpression last, IExpression predicate, IdentifierList include, OrderByClauseList orderBy) {
		super(type, predicate, include);
		this.first = first;
		this.last = last;
		this.orderBy = orderBy;
	}
	
	
	@Override
	public String toString() {
		CodeWriter writer = new CodeWriter(Dialect.E, Context.newGlobalsContext());
		toDialect(writer);
		return writer.toString();
	}
	
	public void setFirst(IExpression first) {
		this.first = first;
	}
	
	public IExpression getFirst() {
		return first;
	}
	
	
	public void setLast(IExpression last) {
		this.last = last;
	}
	
	public IExpression getLast() {
		return last;
	}
	

	@Override
	public void toDialect(CodeWriter writer) {
		switch(writer.getDialect()) {
		case E:
			toEDialect(writer);
			break;
		case O:
			toODialect(writer);
			break;
		case M:
			toMDialect(writer);
			break;
		}
	}
	
	private void toMDialect(CodeWriter writer) {
		writer.append("fetch ");
		if(first!=null) {
			writer.append("rows ");
			first.toDialect(writer);
			writer.append(" to ");
			last.toDialect(writer);
			writer.append(" ");
		} else
			writer.append("all ");
		writer.append("( ");
		if(type!=null) {
			type.toDialect(writer);
			writer.append(" ");
		}
		writer.append(") ");
		if(predicate!=null) {
			writer.append("where ");
			predicate.toDialect(writer);
			writer.append(" ");
		}
		if(include != null) {
			writer.append(" include ");
			include.toDialect(writer, false);
		}
		if(orderBy!=null)
			orderBy.toDialect(writer);
	}


	private void toODialect(CodeWriter writer) {
		writer.append("fetch ");
		if(first==null)
			writer.append("all ");
		if(type!=null) {
			writer.append("( ");
			type.toDialect(writer);
			writer.append(" ) ");
		}
		if(first!=null) {
			writer.append("rows ( ");
			first.toDialect(writer);
			writer.append(" to ");
			last.toDialect(writer);
			writer.append(") ");
		}
		if(predicate!=null) {
			writer.append(" where ( ");
			predicate.toDialect(writer);
			writer.append(") ");
		}
		if(include != null) {
			writer.append(" include (");
			include.toDialect(writer, true);
			writer.append(") ");
		}
		if(orderBy!=null)
			orderBy.toDialect(writer);
	}


	private void toEDialect(CodeWriter writer) {
		writer.append("fetch ");
		if(first==null)
			writer.append("all ");
		if(type!=null) {
			type.toDialect(writer);
			writer.append(" ");
		}
		if(first!=null) {
			first.toDialect(writer);
			writer.append(" to ");
			last.toDialect(writer);
			writer.append(" ");
		} 
		if(predicate!=null) {
			writer.append("where ");
			predicate.toDialect(writer);
		}
		if(include != null) {
			writer.append(" include ");
			include.toDialect(writer, true);
		}
		if(orderBy!=null) {
			writer.append(" ");
			orderBy.toDialect(writer);
		}
	}


	@Override
	public IType check(Context context) {
		IType type = checkType(context);
		checkPredicate(context);
		checkInclude(context);
		checkOrderBy(context);
		checkSlice(context);
		return type;
	}
	
	protected IType checkType(Context context) {
		IType type = this.type;
		if(type==null)
			type = AnyType.instance();
		else {
			CategoryDeclaration decl = context.getRegisteredDeclaration(CategoryDeclaration.class, type.getTypeNameId());
			if(decl==null)
				throw new SyntaxError("Expecting a type type !");
			if(!decl.isStorable(context))
				context.getProblemListener().reportNotStorable(this, type.getTypeName());
			context = context.newInstanceContext(decl.getType(context), true);
		}
		return new CursorType(type);
	}
	
	protected void checkPredicate(Context context) {
		if(predicate==null)
			return;
		if(predicate instanceof IPredicate)
			((IPredicate)predicate).checkQuery(context);
		else
			context.getProblemListener().reportIllegalPredicate(this, predicate);
	}

	private void checkSlice(Context context) {
		// TODO Auto-generated method stub
		
	}


	private void checkOrderBy(Context context) {
		// TODO Auto-generated method stub
		
	}


	@Override
	public Object fetchRaw(IStore store) {
		IQuery query = buildFetchManyQuery(Context.newGlobalsContext(), store);
		return store.fetchMany(query);
	}

	@Override
	public IValue fetch(Context context, IStore store) throws PromptoError {
		IQuery query = buildFetchManyQuery(context, store);
		IStoredIterable docs = store.fetchMany(query);
		IType type = this.type==null ? AnyType.instance() : this.type;
		return new CursorValue(context, type, docs);
	}
	
	private IQuery buildFetchManyQuery(Context context, IStore store) {
		IQueryBuilder builder = store.newQueryBuilder();
		if(type!=null) {
			AttributeInfo info = AttributeInfo.CATEGORY;
			builder.verify(info, MatchOp.HAS, type.getTypeName());
		}
		if(predicate!=null) {
			if(predicate instanceof IPredicate)
				((IPredicate)predicate).interpretQuery(context, builder, store);
			else
				context.getProblemListener().reportIllegalPredicate(this, predicate);
		}
		if(type!=null && predicate!=null)
			builder.and();
		builder.first(interpretLimit(context, first));
		builder.last(interpretLimit(context, last));
		if(include!=null)
			builder.project(include.stream().map(Object::toString).collect(Collectors.toList()));
		if(orderBy!=null)
			orderBy.interpretQuery(context, builder);
		return builder.build();
	}

	private Long interpretLimit(Context context, IExpression exp) throws PromptoError {
		if(exp==null)
			return null;
		IValue value = exp.interpret(context);
		if(!(value instanceof prompto.value.IntegerValue))
			throw new InvalidValueError("Expecting an Integer, got:" + value.getType().toString());
		return ((prompto.value.IntegerValue)value).longValue();
	}	

	@Override
	public ResultInfo compile(Context context, MethodInfo method, Flags flags) {
		compileNewQueryBuilder(context, method, flags); // -> IStore, IQueryBuilder
		compilePredicates(context, method, flags); // -> IStore, IQueryBuilder
		compileLimits(context, method, flags); // -> IStore, IQueryBuilder
		compileProject(context, method, flags); // -> IStore, IQueryBuilder
		compileOrderBy(context, method, flags); // -> IStore, IQueryBuilder
		compileBuildQuery(context, method, flags); // -> IStore, IQuery
		compileFetchMany(context, method, flags); // -> IStored
		return compileInstantiation(context, method, flags);
	}
	
	private void compileOrderBy(Context context, MethodInfo method, Flags flags) {
		if(orderBy!=null)
			orderBy.compileQuery(context, method, flags);
	}


	private void compileLimits(Context context, MethodInfo method, Flags flags) {
		if(first!=null) {
			ResultInfo info = first.compile(context, method, flags.withPrimitive(false));
			if(long.class==info.getType())
				CompilerUtils.longToLong(method);
			InterfaceConstant i = new InterfaceConstant(IQueryBuilder.class, "first", Long.class, IQueryBuilder.class);
			method.addInstruction(Opcode.INVOKEINTERFACE, i);
		}
		if(last!=null) {
			ResultInfo info = last.compile(context, method, flags.withPrimitive(false));
			if(long.class==info.getType())
				CompilerUtils.longToLong(method);
			InterfaceConstant i = new InterfaceConstant(IQueryBuilder.class, "last", Long.class, IQueryBuilder.class);
			method.addInstruction(Opcode.INVOKEINTERFACE, i);
		}
	}


	private void compileFetchMany(Context context, MethodInfo method, Flags flags) {
		InterfaceConstant i = new InterfaceConstant(IStore.class, "fetchMany", IQuery.class, IStoredIterable.class);
		method.addInstruction(Opcode.INVOKEINTERFACE, i);
	}

	private ResultInfo compileInstantiation(Context context, MethodInfo method, Flags flags) {
		MethodConstant m = new MethodConstant(PromptoRoot.class, "newIterable", IStoredIterable.class, IterableWithCounts.class);
		method.addInstruction(Opcode.INVOKESTATIC, m);
		return new ResultInfo(IterableWithCounts.class);
	}
	
	@Override
	public void declare(Transpiler transpiler) {
	    transpiler.require("Cursor");
	    transpiler.require("MatchOp");
	    transpiler.require("DataStore");
	    transpiler.require("AttributeInfo");
	    transpiler.require("TypeFamily");
	    if (this.type != null)
	        this.type.declare(transpiler);
	    if (this.predicate != null)
	        this.predicate.declare(transpiler);
	    if (this.first != null)
	        this.first.declare(transpiler);
	    if (this.last != null)
	        this.last.declare(transpiler);
	    if (this.orderBy != null)
	        this.orderBy.declare(transpiler);
	}
	
	@Override
	public boolean transpile(Transpiler transpiler) {
	    transpiler.append("(function() {").indent();
	    this.transpileQuery(transpiler);
	    boolean mutable = this.type!=null ? this.type.isMutable() : false;
	    transpiler.append("return $DataStore.instance.fetchMany(builder.build(),").append(mutable).append(");").newLine().dedent();
	    transpiler.append("})()");
	    return false;
	}
	
	@Override
	protected void transpileQuery(Transpiler transpiler) {
	    transpiler.append("var builder = $DataStore.instance.newQueryBuilder();").newLine();
	    if (type != null)
	        transpiler.append("builder.verify(new AttributeInfo('category', TypeFamily.TEXT, true, null), MatchOp.HAS, '").append(this.type.getTypeName()).append("');").newLine();
	    if (predicate instanceof IPredicate)
	        ((IPredicate)predicate).transpileQuery(transpiler, "builder");
	    if (type != null && predicate instanceof IPredicate)
	        transpiler.append("builder.and();").newLine();
	    if (this.first  != null) {
	        transpiler.append("builder.setFirst(");
	        this.first.transpile(transpiler);
	        transpiler.append(");").newLine();
	    }
	    if (this.last  != null) {
	        transpiler.append("builder.setLast(");
	        this.last.transpile(transpiler);
	        transpiler.append(");").newLine();
	    }
	    if (this.include != null) {
	    	transpiler.append("builder.project([");
	    	this.include.forEach(id->transpiler.append('"').append(id.toString()).append('"').append(", "));
	    	transpiler.trimLast(", ".length());
	    	transpiler.append("]);").newLine();
	    }
	    if (this.orderBy  != null)
	        this.orderBy.transpileQuery(transpiler, "builder");
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy