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

io.deephaven.engine.table.impl.select.codegen.FormulaAnalyzer Maven / Gradle / Ivy

There is a newer version: 0.37.1
Show newest version
/**
 * Copyright (c) 2016-2022 Deephaven Data Labs and Patent Pending
 */
package io.deephaven.engine.table.impl.select.codegen;

import io.deephaven.datastructures.util.CollectionUtil;
import io.deephaven.engine.context.ExecutionContext;
import io.deephaven.engine.table.ColumnDefinition;
import io.deephaven.engine.table.impl.lang.QueryLanguageParser;
import io.deephaven.engine.table.impl.select.QueryScopeParamTypeUtil;
import io.deephaven.engine.context.QueryScopeParam;
import io.deephaven.time.TimeLiteralReplacedExpression;
import io.deephaven.vector.ObjectVector;
import io.deephaven.engine.context.QueryScope;
import io.deephaven.engine.table.impl.select.DhFormulaColumn;
import io.deephaven.engine.table.impl.select.formula.FormulaSourceDescriptor;
import io.deephaven.engine.table.WritableColumnSource;
import io.deephaven.engine.rowset.TrackingWritableRowSet;
import io.deephaven.internal.log.LoggerFactory;
import io.deephaven.io.logger.Logger;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

public class FormulaAnalyzer {
    private static final Logger log = LoggerFactory.getLogger(FormulaAnalyzer.class);

    public static Result analyze(final String rawFormulaString,
            final Map> columnDefinitionMap,
            final TimeLiteralReplacedExpression timeConversionResult,
            final QueryLanguageParser.Result queryLanguageResult) throws Exception {
        final Map> possibleParams = new HashMap<>();
        final QueryScope queryScope = ExecutionContext.getContext().getQueryScope();
        for (QueryScopeParam param : queryScope.getParams(queryScope.getParamNames())) {
            possibleParams.put(param.getName(), param);
        }

        log.debug().append("Expression (after language conversion) : ")
                .append(queryLanguageResult.getConvertedExpression())
                .append(" isConstantValueExpression=").append(queryLanguageResult.isConstantValueExpression())
                .endl();

        final List usedColumns = new ArrayList<>();
        final List userParams = new ArrayList<>();
        final List usedColumnArrays = new ArrayList<>();
        for (String variable : queryLanguageResult.getVariablesUsed()) {
            final String colSuffix = DhFormulaColumn.COLUMN_SUFFIX;
            final String bareName;
            if (variable.equals("i") || variable.equals("ii") || variable.equals("k")) {
                usedColumns.add(variable);
            } else if (columnDefinitionMap.get(variable) != null) {
                usedColumns.add(variable);
            } else if (variable.endsWith(colSuffix) &&
                    null != columnDefinitionMap
                            .get(bareName = variable.substring(0, variable.length() - colSuffix.length()))) {
                usedColumnArrays.add(bareName);
            } else if (possibleParams.containsKey(variable)) {
                userParams.add(variable);
            }
        }
        Class returnedType = queryLanguageResult.getType();
        if (returnedType == boolean.class) {
            returnedType = Boolean.class;
        }
        final String cookedFormulaString = queryLanguageResult.getConvertedExpression();
        final String timeInstanceVariables = timeConversionResult.getInstanceVariablesString();
        return new Result(returnedType,
                usedColumns.toArray(CollectionUtil.ZERO_LENGTH_STRING_ARRAY),
                usedColumnArrays.toArray(CollectionUtil.ZERO_LENGTH_STRING_ARRAY),
                userParams.toArray(CollectionUtil.ZERO_LENGTH_STRING_ARRAY),
                rawFormulaString, cookedFormulaString, timeInstanceVariables,
                queryLanguageResult.isConstantValueExpression());
    }

    public static QueryLanguageParser.Result getCompiledFormula(Map> availableColumns,
            TimeLiteralReplacedExpression timeConversionResult) throws Exception {
        final Map> possibleVariables = new HashMap<>();
        possibleVariables.put("i", int.class);
        possibleVariables.put("ii", long.class);
        possibleVariables.put("k", long.class);

        final Map[]> possibleVariableParameterizedTypes = new HashMap<>();

        for (ColumnDefinition columnDefinition : availableColumns.values()) {
            final String columnSuffix = DhFormulaColumn.COLUMN_SUFFIX;
            final Class vectorType = DhFormulaColumn.getVectorType(columnDefinition.getDataType());

            possibleVariables.put(columnDefinition.getName() + columnSuffix, vectorType);

            if (vectorType == ObjectVector.class) {
                possibleVariableParameterizedTypes.put(columnDefinition.getName() + columnSuffix,
                        new Class[] {columnDefinition.getDataType()});
            }
        }

        final ExecutionContext context = ExecutionContext.getContext();
        final QueryScope queryScope = context.getQueryScope();
        for (QueryScopeParam param : queryScope.getParams(queryScope.getParamNames())) {
            possibleVariables.put(param.getName(), QueryScopeParamTypeUtil.getDeclaredClass(param.getValue()));

            Type declaredType = QueryScopeParamTypeUtil.getDeclaredType(param.getValue());
            if (declaredType instanceof ParameterizedType) {
                ParameterizedType pt = (ParameterizedType) declaredType;
                Class[] paramTypes = Arrays.stream(pt.getActualTypeArguments())
                        .map(QueryScopeParamTypeUtil::classFromType)
                        .toArray(Class[]::new);
                possibleVariableParameterizedTypes.put(param.getName(), paramTypes);
            }
        }

        for (ColumnDefinition columnDefinition : availableColumns.values()) {
            possibleVariables.put(columnDefinition.getName(), columnDefinition.getDataType());
            final Class compType = columnDefinition.getComponentType();
            if (compType != null && !compType.isPrimitive()) {
                possibleVariableParameterizedTypes.put(columnDefinition.getName(), new Class[] {compType});
            }
        }

        // log.debug().append("Expression (before) : ").append(formulaString).endl();

        log.debug().append("Expression (after time conversion) : ").append(timeConversionResult.getConvertedFormula())
                .endl();

        possibleVariables.putAll(timeConversionResult.getNewVariables());

        final Set> classImports =
                new HashSet<>(context.getQueryLibrary().getClassImports());
        classImports.add(TrackingWritableRowSet.class);
        classImports.add(WritableColumnSource.class);
        return new QueryLanguageParser(timeConversionResult.getConvertedFormula(),
                context.getQueryLibrary().getPackageImports(),
                classImports, context.getQueryLibrary().getStaticImports(), possibleVariables,
                possibleVariableParameterizedTypes)
                .getResult();
    }

    public static class Result {
        public final FormulaSourceDescriptor sourceDescriptor;
        public final String rawFormulaString;
        public final String cookedFormulaString;
        public final String timeInstanceVariables;
        public final boolean isConstantValueFormula;

        public Result(Class returnedType, String[] usedColumns, String[] usedArrays, String[] usedParams,
                String rawFormulaString, String cookedFormulaString, String timeInstanceVariables,
                boolean isConstantValueFormula) {
            this.sourceDescriptor = new FormulaSourceDescriptor(returnedType, usedColumns, usedArrays, usedParams);
            this.rawFormulaString = rawFormulaString;
            this.cookedFormulaString = cookedFormulaString;
            this.timeInstanceVariables = timeInstanceVariables;
            this.isConstantValueFormula = isConstantValueFormula;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy