<commit_before>package it.unibz.inf.ontop.model.term.functionsymbol.db.impl;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Maps;
import it.unibz.inf.ontop.model.term.ImmutableTerm;
import it.unibz.inf.ontop.model.term.TermFactory;
import it.unibz.inf.ontop.model.term.functionsymbol.InequalityLabel;
import it.unibz.inf.ontop.model.term.functionsymbol.db.*;
import it.unibz.inf.ontop.model.type.*;

import java.util.Map;
import java.util.UUID;
import java.util.function.Function;

public abstract class AbstractSQLDBFunctionSymbolFactory extends AbstractDBFunctionSymbolFactory {

    protected static final String UPPER_STR = "UPPER";
    protected static final String UCASE_STR = "UCASE";
    protected static final String LOWER_STR = "LOWER";
    protected static final String LCASE_STR = "LCASE";
    protected static final String CONCAT_STR = "CONCAT";
    protected static final String REPLACE_STR = "REPLACE";
    protected static final String REGEXP_REPLACE_STR = "REGEXP_REPLACE";
    protected static final String REGEXP_LIKE_STR = "REGEXP_LIKE";
    protected static final String AND_STR = "AND";
    protected static final String OR_STR = "OR";
    protected static final String NOT_STR = "NOT";
    protected static final String SUBSTR_STR = "SUBSTR";
    protected static final String SUBSTRING_STR = "SUBSTRING";
    protected static final String CHAR_LENGTH_STR = "CHAR_LENGTH";
    protected static final String LENGTH_STR = "LENGTH";
    protected static final String RIGHT_STR = "RIGHT";
    protected static final String MULTIPLY_STR = "*";
    protected static final String DIVIDE_STR = "/";
    protected static final String ADD_STR = "+";
    protected static final String SUBSTRACT_STR = "-";
    protected static final String ABS_STR = "ABS";
    protected static final String CEIL_STR = "CEIL";
    protected static final String ROUND_STR = "ROUND";
    protected static final String FLOOR_STR = "FLOOR";
    protected static final String RAND_STR = "RAND";
    protected static final String CURRENT_TIMESTAMP_STR = "CURRENT_TIMESTAMP";
    protected static final String COALESCE_STR = "COALESCE";
    protected static final String CONCAT_OP_STR = "||";


    protected DBTypeFactory dbTypeFactory;
    protected final TypeFactory typeFactory;
    protected final DBTermType dbStringType;
    protected final DBTermType dbBooleanType;
    protected final DBTermType dbDoubleType;
    protected final DBTermType abstractRootDBType;
    protected final TermType abstractRootType;
    private final Map<Integer, DBConcatFunctionSymbol> nullRejectingConcatMap;
    private final Map<Integer, DBConcatFunctionSymbol> concatOperatorMap;

    // Created in init()
    private DBFunctionSymbol ifThenElse;
    // Created in init()
    private DBBooleanFunctionSymbol isStringEmpty;
    // Created in init()
    private DBIsNullOrNotFunctionSymbol isNull;
    // Created in init()
    private DBIsNullOrNotFunctionSymbol isNotNull;
    // Created in init()
    private DBIsTrueFunctionSymbol isTrue;
    protected AbstractSQLDBFunctionSymbolFactory(ImmutableTable<String, Integer, DBFunctionSymbol> regularFunctionTable,
                                                 TypeFactory typeFactory) {
        super(regularFunctionTable, typeFactory);
        this.dbTypeFactory = typeFactory.getDBTypeFactory();
        this.typeFactory = typeFactory;
        this.dbStringType = dbTypeFactory.getDBStringType();
        this.dbBooleanType = dbTypeFactory.getDBBooleanType();
        this.dbDoubleType = dbTypeFactory.getDBDoubleType();
        this.abstractRootDBType = dbTypeFactory.getAbstractRootDBType();
        this.abstractRootType = typeFactory.getAbstractAtomicTermType();
        this.nullRejectingConcatMap = Maps.newConcurrentMap();
        this.concatOperatorMap = Maps.newConcurrentMap();
    }

    @Override
    protected void init() {
        // Always call it first
        super.init();
        ifThenElse = createDBIfThenElse(dbBooleanType, abstractRootDBType);
        isStringEmpty = createIsStringEmpty(dbBooleanType, abstractRootDBType);
        isNull = createDBIsNull(dbBooleanType, abstractRootDBType);
        isNotNull = createDBIsNotNull(dbBooleanType, abstractRootDBType);
        isTrue = createDBIsTrue(dbBooleanType);
    }

    protected static ImmutableTable<String, Integer, DBFunctionSymbol> createDefaultRegularFunctionTable(TypeFactory typeFactory) {
        DBTypeFactory dbTypeFactory = typeFactory.getDBTypeFactory();
        DBTermType dbStringType = dbTypeFactory.getDBStringType();
        DBTermType dbIntType = dbTypeFactory.getDBLargeIntegerType();
        DBTermType dbDateTimestamp = dbTypeFactory.getDBDateTimestampType();
        DBTermType abstractRootDBType = dbTypeFactory.getAbstractRootDBType();
        DBTermType dbBooleanType = dbTypeFactory.getDBBooleanType();

        ImmutableTable.Builder<String, Integer, DBFunctionSymbol> builder = ImmutableTable.builder();

        // TODO: provide the base input types
        DBFunctionSymbol upperFunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(UPPER_STR, 1, dbStringType,
                false, abstractRootDBType);
        builder.put(UPPER_STR, 1, upperFunctionSymbol);
        builder.put(UCASE_STR, 1, upperFunctionSymbol);

        DBFunctionSymbol lowerFunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(LOWER_STR, 1, dbStringType,
                false, abstractRootDBType);
        builder.put(LOWER_STR, 1, lowerFunctionSymbol);
        builder.put(LCASE_STR, 1, lowerFunctionSymbol);


        DBFunctionSymbol replace3FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(REPLACE_STR, 3, dbStringType,
                false, abstractRootDBType);
        builder.put(REPLACE_STR, 3, replace3FunctionSymbol);

        DBFunctionSymbol regexpReplace3FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(REGEXP_REPLACE_STR, 3, dbStringType,
                false, abstractRootDBType);
        builder.put(REGEXP_REPLACE_STR, 3, regexpReplace3FunctionSymbol);

        DBFunctionSymbol regexpReplace4FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(REGEXP_REPLACE_STR, 4, dbStringType,
                false, abstractRootDBType);
        builder.put(REGEXP_REPLACE_STR, 4, regexpReplace4FunctionSymbol);

        DBFunctionSymbol subString2FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(SUBSTRING_STR, 2, dbStringType,
                false, abstractRootDBType);
        builder.put(SUBSTRING_STR, 2, subString2FunctionSymbol);
        DBFunctionSymbol subStr2FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(SUBSTR_STR, 2, dbStringType,
                false, abstractRootDBType);
        builder.put(SUBSTR_STR, 2, subStr2FunctionSymbol);

        DBFunctionSymbol subString3FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(SUBSTRING_STR, 3, dbStringType,
                false, abstractRootDBType);
        builder.put(SUBSTRING_STR, 3, subString3FunctionSymbol);
        DBFunctionSymbol subStr3FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(SUBSTR_STR, 3, dbStringType,
                false, abstractRootDBType);
        builder.put(SUBSTR_STR, 3, subStr3FunctionSymbol);

        DBFunctionSymbol rightFunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(RIGHT_STR, 2, dbStringType,
                false, abstractRootDBType);
        builder.put(RIGHT_STR, 2, rightFunctionSymbol);

        // TODO: check precise output type
        DBFunctionSymbol strlenFunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(CHAR_LENGTH_STR, 1, dbIntType,
                false, abstractRootDBType);
        builder.put(CHAR_LENGTH_STR, 1, strlenFunctionSymbol);
        //TODO: move away this synonym as it is non-standard
        DBFunctionSymbol lengthFunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(LENGTH_STR, 1, dbIntType,
                false, abstractRootDBType);
        builder.put(LENGTH_STR, 1, lengthFunctionSymbol);

        DBFunctionSymbol nowFunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(CURRENT_TIMESTAMP_STR, 0,
                dbDateTimestamp, true, abstractRootDBType);
        builder.put(CURRENT_TIMESTAMP_STR, 0, nowFunctionSymbol);

        // Common for many dialects
        DBBooleanFunctionSymbol regexpLike2 = new DefaultSQLSimpleDBBooleanFunctionSymbol(REGEXP_LIKE_STR, 2, dbBooleanType,
                abstractRootDBType);
        builder.put(REGEXP_LIKE_STR, 2, regexpLike2);

        DBBooleanFunctionSymbol regexpLike3 = new RegexpLike3FunctionSymbol(dbBooleanType, abstractRootDBType);
        builder.put(REGEXP_LIKE_STR, 3, regexpLike3);


        return builder.build();
    }

    @Override
    public DBConcatFunctionSymbol getNullRejectingDBConcat(int arity) {
        if (arity < 2)
            throw new IllegalArgumentException("Arity of CONCAT must be >= 2");
        return nullRejectingConcatMap
                .computeIfAbsent(arity, a -> createNullRejectingDBConcat(arity));
    }

    @Override
    public DBConcatFunctionSymbol getDBConcatOperator(int arity) {
        if (arity < 2)
            throw new IllegalArgumentException("Arity of CONCAT must be >= 2");
        return concatOperatorMap
                .computeIfAbsent(arity, a -> createDBConcatOperator(arity));
    }

    protected abstract DBConcatFunctionSymbol createNullRejectingDBConcat(int arity);
    protected abstract DBConcatFunctionSymbol createDBConcatOperator(int arity);

    @Override
    protected DBFunctionSymbol createRegularUntypedFunctionSymbol(String nameInDialect, int arity) {
        // TODO: avoid if-then-else
        if (isAnd(nameInDialect))
            return createDBAnd(arity);
        else if (isOr(nameInDialect))
            return createDBOr(arity);
        else if (isConcat(nameInDialect))
            return createRegularDBConcat(arity);
        else if (isCoalesce(nameInDialect))
            return getDBCoalesce(arity);
        return new DefaultUntypedDBFunctionSymbol(nameInDialect, arity, dbTypeFactory.getAbstractRootDBType());
    }

    @Override
    protected DBBooleanFunctionSymbol createRegularBooleanFunctionSymbol(String nameInDialect, int arity) {
        return new DefaultSQLSimpleDBBooleanFunctionSymbol(nameInDialect, arity, dbBooleanType, abstractRootDBType);<commit_msg>COALESCE recognition disabled in the mapping (to be supported later).<commit_after>package it.unibz.inf.ontop.model.term.functionsymbol.db.impl;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Maps;
import it.unibz.inf.ontop.model.term.ImmutableTerm;
import it.unibz.inf.ontop.model.term.TermFactory;
import it.unibz.inf.ontop.model.term.functionsymbol.InequalityLabel;
import it.unibz.inf.ontop.model.term.functionsymbol.db.*;
import it.unibz.inf.ontop.model.type.*;

import java.util.Map;
import java.util.UUID;
import java.util.function.Function;

public abstract class AbstractSQLDBFunctionSymbolFactory extends AbstractDBFunctionSymbolFactory {

    protected static final String UPPER_STR = "UPPER";
    protected static final String UCASE_STR = "UCASE";
    protected static final String LOWER_STR = "LOWER";
    protected static final String LCASE_STR = "LCASE";
    protected static final String CONCAT_STR = "CONCAT";
    protected static final String REPLACE_STR = "REPLACE";
    protected static final String REGEXP_REPLACE_STR = "REGEXP_REPLACE";
    protected static final String REGEXP_LIKE_STR = "REGEXP_LIKE";
    protected static final String AND_STR = "AND";
    protected static final String OR_STR = "OR";
    protected static final String NOT_STR = "NOT";
    protected static final String SUBSTR_STR = "SUBSTR";
    protected static final String SUBSTRING_STR = "SUBSTRING";
    protected static final String CHAR_LENGTH_STR = "CHAR_LENGTH";
    protected static final String LENGTH_STR = "LENGTH";
    protected static final String RIGHT_STR = "RIGHT";
    protected static final String MULTIPLY_STR = "*";
    protected static final String DIVIDE_STR = "/";
    protected static final String ADD_STR = "+";
    protected static final String SUBSTRACT_STR = "-";
    protected static final String ABS_STR = "ABS";
    protected static final String CEIL_STR = "CEIL";
    protected static final String ROUND_STR = "ROUND";
    protected static final String FLOOR_STR = "FLOOR";
    protected static final String RAND_STR = "RAND";
    protected static final String CURRENT_TIMESTAMP_STR = "CURRENT_TIMESTAMP";
    protected static final String COALESCE_STR = "COALESCE";
    protected static final String CONCAT_OP_STR = "||";


    protected DBTypeFactory dbTypeFactory;
    protected final TypeFactory typeFactory;
    protected final DBTermType dbStringType;
    protected final DBTermType dbBooleanType;
    protected final DBTermType dbDoubleType;
    protected final DBTermType abstractRootDBType;
    protected final TermType abstractRootType;
    private final Map<Integer, DBConcatFunctionSymbol> nullRejectingConcatMap;
    private final Map<Integer, DBConcatFunctionSymbol> concatOperatorMap;

    // Created in init()
    private DBFunctionSymbol ifThenElse;
    // Created in init()
    private DBBooleanFunctionSymbol isStringEmpty;
    // Created in init()
    private DBIsNullOrNotFunctionSymbol isNull;
    // Created in init()
    private DBIsNullOrNotFunctionSymbol isNotNull;
    // Created in init()
    private DBIsTrueFunctionSymbol isTrue;
    protected AbstractSQLDBFunctionSymbolFactory(ImmutableTable<String, Integer, DBFunctionSymbol> regularFunctionTable,
                                                 TypeFactory typeFactory) {
        super(regularFunctionTable, typeFactory);
        this.dbTypeFactory = typeFactory.getDBTypeFactory();
        this.typeFactory = typeFactory;
        this.dbStringType = dbTypeFactory.getDBStringType();
        this.dbBooleanType = dbTypeFactory.getDBBooleanType();
        this.dbDoubleType = dbTypeFactory.getDBDoubleType();
        this.abstractRootDBType = dbTypeFactory.getAbstractRootDBType();
        this.abstractRootType = typeFactory.getAbstractAtomicTermType();
        this.nullRejectingConcatMap = Maps.newConcurrentMap();
        this.concatOperatorMap = Maps.newConcurrentMap();
    }

    @Override
    protected void init() {
        // Always call it first
        super.init();
        ifThenElse = createDBIfThenElse(dbBooleanType, abstractRootDBType);
        isStringEmpty = createIsStringEmpty(dbBooleanType, abstractRootDBType);
        isNull = createDBIsNull(dbBooleanType, abstractRootDBType);
        isNotNull = createDBIsNotNull(dbBooleanType, abstractRootDBType);
        isTrue = createDBIsTrue(dbBooleanType);
    }

    protected static ImmutableTable<String, Integer, DBFunctionSymbol> createDefaultRegularFunctionTable(TypeFactory typeFactory) {
        DBTypeFactory dbTypeFactory = typeFactory.getDBTypeFactory();
        DBTermType dbStringType = dbTypeFactory.getDBStringType();
        DBTermType dbIntType = dbTypeFactory.getDBLargeIntegerType();
        DBTermType dbDateTimestamp = dbTypeFactory.getDBDateTimestampType();
        DBTermType abstractRootDBType = dbTypeFactory.getAbstractRootDBType();
        DBTermType dbBooleanType = dbTypeFactory.getDBBooleanType();

        ImmutableTable.Builder<String, Integer, DBFunctionSymbol> builder = ImmutableTable.builder();

        // TODO: provide the base input types
        DBFunctionSymbol upperFunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(UPPER_STR, 1, dbStringType,
                false, abstractRootDBType);
        builder.put(UPPER_STR, 1, upperFunctionSymbol);
        builder.put(UCASE_STR, 1, upperFunctionSymbol);

        DBFunctionSymbol lowerFunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(LOWER_STR, 1, dbStringType,
                false, abstractRootDBType);
        builder.put(LOWER_STR, 1, lowerFunctionSymbol);
        builder.put(LCASE_STR, 1, lowerFunctionSymbol);


        DBFunctionSymbol replace3FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(REPLACE_STR, 3, dbStringType,
                false, abstractRootDBType);
        builder.put(REPLACE_STR, 3, replace3FunctionSymbol);

        DBFunctionSymbol regexpReplace3FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(REGEXP_REPLACE_STR, 3, dbStringType,
                false, abstractRootDBType);
        builder.put(REGEXP_REPLACE_STR, 3, regexpReplace3FunctionSymbol);

        DBFunctionSymbol regexpReplace4FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(REGEXP_REPLACE_STR, 4, dbStringType,
                false, abstractRootDBType);
        builder.put(REGEXP_REPLACE_STR, 4, regexpReplace4FunctionSymbol);

        DBFunctionSymbol subString2FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(SUBSTRING_STR, 2, dbStringType,
                false, abstractRootDBType);
        builder.put(SUBSTRING_STR, 2, subString2FunctionSymbol);
        DBFunctionSymbol subStr2FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(SUBSTR_STR, 2, dbStringType,
                false, abstractRootDBType);
        builder.put(SUBSTR_STR, 2, subStr2FunctionSymbol);

        DBFunctionSymbol subString3FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(SUBSTRING_STR, 3, dbStringType,
                false, abstractRootDBType);
        builder.put(SUBSTRING_STR, 3, subString3FunctionSymbol);
        DBFunctionSymbol subStr3FunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(SUBSTR_STR, 3, dbStringType,
                false, abstractRootDBType);
        builder.put(SUBSTR_STR, 3, subStr3FunctionSymbol);

        DBFunctionSymbol rightFunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(RIGHT_STR, 2, dbStringType,
                false, abstractRootDBType);
        builder.put(RIGHT_STR, 2, rightFunctionSymbol);

        // TODO: check precise output type
        DBFunctionSymbol strlenFunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(CHAR_LENGTH_STR, 1, dbIntType,
                false, abstractRootDBType);
        builder.put(CHAR_LENGTH_STR, 1, strlenFunctionSymbol);
        //TODO: move away this synonym as it is non-standard
        DBFunctionSymbol lengthFunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(LENGTH_STR, 1, dbIntType,
                false, abstractRootDBType);
        builder.put(LENGTH_STR, 1, lengthFunctionSymbol);

        DBFunctionSymbol nowFunctionSymbol = new DefaultSQLSimpleTypedDBFunctionSymbol(CURRENT_TIMESTAMP_STR, 0,
                dbDateTimestamp, true, abstractRootDBType);
        builder.put(CURRENT_TIMESTAMP_STR, 0, nowFunctionSymbol);

        // Common for many dialects
        DBBooleanFunctionSymbol regexpLike2 = new DefaultSQLSimpleDBBooleanFunctionSymbol(REGEXP_LIKE_STR, 2, dbBooleanType,
                abstractRootDBType);
        builder.put(REGEXP_LIKE_STR, 2, regexpLike2);

        DBBooleanFunctionSymbol regexpLike3 = new RegexpLike3FunctionSymbol(dbBooleanType, abstractRootDBType);
        builder.put(REGEXP_LIKE_STR, 3, regexpLike3);


        return builder.build();
    }

    @Override
    public DBConcatFunctionSymbol getNullRejectingDBConcat(int arity) {
        if (arity < 2)
            throw new IllegalArgumentException("Arity of CONCAT must be >= 2");
        return nullRejectingConcatMap
                .computeIfAbsent(arity, a -> createNullRejectingDBConcat(arity));
    }

    @Override
    public DBConcatFunctionSymbol getDBConcatOperator(int arity) {
        if (arity < 2)
            throw new IllegalArgumentException("Arity of CONCAT must be >= 2");
        return concatOperatorMap
                .computeIfAbsent(arity, a -> createDBConcatOperator(arity));
    }

    protected abstract DBConcatFunctionSymbol createNullRejectingDBConcat(int arity);
    protected abstract DBConcatFunctionSymbol createDBConcatOperator(int arity);

    @Override
    protected DBFunctionSymbol createRegularUntypedFunctionSymbol(String nameInDialect, int arity) {
        // TODO: avoid if-then-else
        if (isAnd(nameInDialect))
            return createDBAnd(arity);
        else if (isOr(nameInDialect))
            return createDBOr(arity);
        else if (isConcat(nameInDialect))
            return createRegularDBConcat(arity);
        // TODO: allow its recognition in the mapping. Challenging for detecting that NULLs are fitered out.
//        else if (isCoalesce(nameInDialect))
//            return getDBCoalesce(arity);
        return new DefaultUntypedDBFunctionSymbol(nameInDialect, arity, dbTypeFactory.getAbstractRootDBType());
    }

    @Override
    protected DBBooleanFunctionSymbol createRegularBooleanFunctionSymbol(String nameInDialect, int arity) {
        return new DefaultSQLSimpleDBBooleanFunctionSymbol(nameInDialect, arity, dbBooleanType, abstractRootDBType);
{'fraction_non_alphanumeric': 0.07027776449777692, 'fraction_numerical': 0.005163264330448917, 'mean_word_length': 3.8908113163432314, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6547099', 'n_tokens_mistral': 5736, 'n_tokens_neox': 5602, 'n_words': 1287}