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

ru.curs.celesta.dbutils.h2.AbstractMaterializedViewTrigger Maven / Gradle / Ivy

The newest version!
package ru.curs.celesta.dbutils.h2;

import org.h2.api.Trigger;
import ru.curs.celesta.event.TriggerType;
import ru.curs.celesta.score.AbstractScore;
import ru.curs.celesta.score.BasicTable;
import ru.curs.celesta.score.Column;
import ru.curs.celesta.score.Count;
import ru.curs.celesta.score.DateTimeColumn;
import ru.curs.celesta.score.Expr;
import ru.curs.celesta.score.Grain;
import ru.curs.celesta.score.MaterializedView;
import ru.curs.celesta.score.ParseException;
import ru.curs.celesta.score.Sum;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;


/**
 * Base class for all triggers of materialized view.
 *
 * @author ioann
 * @since 2017-07-07
 */
public abstract class AbstractMaterializedViewTrigger implements Trigger {

    private static final Map TRIGGER_TYPE_MAP = new HashMap<>();
    private static final AtomicReference SCORE = new AtomicReference<>();

    static {
        TRIGGER_TYPE_MAP.put(1, TriggerType.POST_INSERT);
        TRIGGER_TYPE_MAP.put(2, TriggerType.POST_UPDATE);
        TRIGGER_TYPE_MAP.put(4, TriggerType.POST_DELETE);
    }

    private BasicTable t;
    private MaterializedView mv;

    private String tFullName;
    private String mvFullName;
    private String keySearchTerm;
    private String mvAllColumns;
    private final HashMap tGroupByColumnIndices = new LinkedHashMap<>();
    private final HashMap mvColumnRefs = new LinkedHashMap<>();

    /**
     * Sets up the score with which the current H2 instance should work.
     * @param score The current score.
     */
    public static void initScore(AbstractScore score) {
        SCORE.set(Objects.requireNonNull(score));
    }

    @Override
    public void init(Connection connection, String schemaName, String triggerName, String tableName,
                     boolean before, int type) {

        try {
            AbstractScore score = Objects.requireNonNull(SCORE.get());
            Map grains = score.getGrains();
            Grain g = grains.get(schemaName);
            t = g.getElement(tableName, BasicTable.class);

            mv = g.getElements(MaterializedView.class).values().stream()
                    .filter(view -> triggerName.equals(view.getTriggerName(TRIGGER_TYPE_MAP.get(type))))
                    .findFirst().get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        tFullName = String.format("\"%s\".\"%s\"", t.getGrain().getName(), t.getName());
        mvFullName = String.format("\"%s\".\"%s\"", mv.getGrain().getName(), mv.getName());

        mvAllColumns = mv.getColumns().keySet().stream()
                .filter(alias -> !MaterializedView.SURROGATE_COUNT.equals(alias))
                .map(v -> "\"" + v + "\"")
                .collect(Collectors.joining(", "));

        List keySearchTerms = new ArrayList<>();
        List columnRefNames = mv.getColumnRefNames();
        int curIndex = 0;
        for (String tCol : t.getColumns().keySet()) {
            for (Map.Entry> col : mv.getColumns().entrySet()) {
                if (mv.isGroupByColumn(col.getKey()) && tCol.equals(mv.getColumnRef(col.getKey()).getName())) {
                    tGroupByColumnIndices.put(curIndex, tCol);
                    keySearchTerms.add(String.format("(\"%s\" = %s)",
                            col.getKey(),
                            DateTimeColumn.CELESTA_TYPE.equals(
                                    col.getValue().getCelestaType()) ? "DATE_TRUNC(DAY, CAST(? AS TIMESTAMP))" : "?"));
                    break;
                }
            }

            if (columnRefNames.contains(tCol)) {
                mvColumnRefs.put(curIndex, tCol);
            }
            ++curIndex;
        }
        keySearchTerm = String.join(" and ", keySearchTerms);
    }


    final void delete(Connection conn, Object[] row) throws SQLException {

        HashMap groupByColumnValues = getTableRowGroupByColumns(row);

        String deleteSql = String.format("DELETE FROM %s WHERE %s", mvFullName, keySearchTerm);

        setParamsAndRun(conn, groupByColumnValues, deleteSql);
    }

    final void insert(Connection conn, Object[] row) throws SQLException {

        HashMap groupByColumnValues = getTableRowGroupByColumns(row);

        String whereCondition = groupByColumnValues.keySet().stream()
                .map(alias -> {
                    try {
                        return DateTimeColumn.CELESTA_TYPE.equals(
                                t.getColumn(alias).getCelestaType())
                                ? "DATE_TRUNC(DAY, \"" + alias + "\") = DATE_TRUNC(DAY, CAST(? AS TIMESTAMP))"
                                : "\"" + alias + "\" = ?";
                    } catch (ParseException e) {
                        throw new RuntimeException(e);
                    }
                })
                .collect(Collectors.joining(" AND "));


        String selectPartOfScript = mv.getColumns().keySet().stream()
                .filter(alias -> !MaterializedView.SURROGATE_COUNT.equals(alias))
                .map(alias -> {
                    Column colRef = mv.getColumnRef(alias);

                    Map aggrCols = mv.getAggregateColumns();
                    if (aggrCols.containsKey(alias)) {
                        if (colRef == null) {
                            if (aggrCols.get(alias) instanceof Count) {
                                return "COUNT(*) as \"" + alias + "\"";
                            }
                            return "";
                        } else if (aggrCols.get(alias) instanceof Sum) {
                            return "SUM(\"" + colRef.getName() + "\") as \"" + alias + "\"";
                        } else {
                            return "";
                        }
                    }

                    if (DateTimeColumn.CELESTA_TYPE.equals(colRef.getCelestaType())) {
                        return "DATE_TRUNC(DAY, \"" + colRef.getName() + "\") as \"" + alias + "\"";
                    }

                    return "\"" + colRef.getName() + "\" as " + "\"" + alias + "\"";
                })
                .filter(str -> !str.isEmpty())
                .collect(Collectors.joining(", "))
                .concat(", COUNT(*) AS " + MaterializedView.SURROGATE_COUNT);

        StringBuilder selectStmtBuilder = new StringBuilder("SELECT ")
                .append(selectPartOfScript)
                .append(" FROM ").append(tFullName).append(" ");
        selectStmtBuilder.append(" WHERE ").append(whereCondition)
                .append(mv.getGroupByPartOfScript());

        String insertSql = String.format("INSERT INTO %s (%s) %s", mvFullName,
                mvAllColumns + ", \"" + MaterializedView.SURROGATE_COUNT + "\"", selectStmtBuilder);


        setParamsAndRun(conn, groupByColumnValues, insertSql);
    }

    private void setParamsAndRun(
            Connection conn, HashMap groupByColumnValues, String insertSql) throws SQLException {

        try (PreparedStatement stmt = conn.prepareStatement(insertSql)) {
            int i = 0;
            for (Object value : groupByColumnValues.values()) {
                stmt.setObject(++i, value);
            }
            stmt.execute();
        }
    }

    @Override
    public void close() {
        //nothing to do
    }

    @Override
    public void remove() {
        //nothing to do
    }

    abstract String getNamePrefix();

    private HashMap getTableRowGroupByColumns(Object[] row) {
        HashMap result = new LinkedHashMap<>();

        tGroupByColumnIndices.forEach((key, value) -> result.put(value, row[key]));

        return result;
    }

    final HashMap getMvColumnRefs() {
        return mvColumnRefs;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy