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

live.document.mavenplugin.sql.TableWriteStatementExporter Maven / Gradle / Ivy

package live.document.mavenplugin.sql;

import com.github.vertical_blank.sqlformatter.SqlFormatter;
import com.github.vertical_blank.sqlformatter.core.FormatConfig;
import com.github.vertical_blank.sqlformatter.languages.Dialect;
import live.document.generator.model.CallNode;
import live.document.generator.model.CallTree;
import live.document.plsqlscanner.PlSqlExplained;
import live.document.scanner.CallGraph;
import live.document.scanner.CallProcedureObject;
import live.document.scanner.DbObjectTypeEnum;
import live.document.scanner.MethodObject;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class TableWriteStatementExporter {
    private static final String[] STATEMENT_STARTS = new String[]{"INSERT INTO ", "UPDATE ", "DELETE FROM ", "SELECT "};
    public static final String SEPERATOR = "-----------------------------------------------------------------";
    private Set tables = new HashSet<>();
    private PlSqlExplained plSqlExplained;
    private CallGraph callGraph;


    public TableWriteStatementExporter(String[] tables, PlSqlExplained plSqlExplained, CallGraph callGraph) {
        if (tables != null) {
            this.tables.addAll(Arrays.asList(tables));
        }
        this.plSqlExplained = plSqlExplained;
        this.callGraph = callGraph;
    }

    public String export() {
        return getExportResult(new HashSet<>(), new HashSet<>());
    }

    public String export(CallTree callTree) {
        Set allMethodsOfCallTree = getAllMethodsOfCallTree(callTree);
        Set allPlsqlObjectNamesOfCallTree = getAllPlsqlObjectNamesOfCallTree(callTree);

        return getExportResult(allMethodsOfCallTree, allPlsqlObjectNamesOfCallTree);
    }

    @NotNull
    private String getExportResult(Set allMethodsOfCallTree, Set allPlsqlObjectNamesOfCallTree) {
        Map> results = new HashMap<>();

        if (tables.isEmpty()) {
            tables = getDefaultAllTables(allMethodsOfCallTree, allPlsqlObjectNamesOfCallTree);
        }

        for (String table : tables) {
            results.put(table, getTableStatements(table, allMethodsOfCallTree, allPlsqlObjectNamesOfCallTree));
        }

        Map> tableWriteFunctions = findTableWriteFunctions(allMethodsOfCallTree, allPlsqlObjectNamesOfCallTree);

        StringBuilder stringBuilder = new StringBuilder();
        for (Map.Entry> entry : results.entrySet()) {
            stringBuilder
                    .append(SEPERATOR).append(System.lineSeparator())
                    .append("-------- TABLE: ").append(entry.getKey()).append(" --------").append(System.lineSeparator())
                    .append(SEPERATOR).append(System.lineSeparator()).append(System.lineSeparator());

            List procedures = tableWriteFunctions.get(entry.getKey());
            stringBuilder.append("-- Total procedure/Functions/Java Method which modify this table directly: ").append(procedures.size()).append(System.lineSeparator());
            procedures.stream()
                    .forEach(p -> stringBuilder.append("-- ").append(p).append(System.lineSeparator()));

            stringBuilder.append(System.lineSeparator());
            entry.getValue().stream().forEach(s -> stringBuilder.append(s)
                    .append(System.lineSeparator()).append(System.lineSeparator()));
        }
        return stringBuilder.toString();
    }

    private Set getAllPlsqlObjectNamesOfCallTree(CallTree callTree) {
        return callTree.getNodes()
                .stream()
                .flatMap(n -> getAllPlsqlObjectNamesOfCallNode(n).stream())
                .collect(Collectors.toSet());
    }

    private List getAllPlsqlObjectNamesOfCallNode(CallNode node) {
        List results = new ArrayList<>();
        if (node.isLink() || !node.isVisible()) {
            return results;
        }

        if (node.getMethodObject() != null) {
            List collect = node.getMethodObject().calleeStream(CallProcedureObject.class)
                    .map(CallProcedureObject::getProcedure)
                    .collect(Collectors.toList());
            results.addAll(collect);
        }

        if (node.getDbOperation() != null) {
            if (node.getDbOperation().getObjectType() == DbObjectTypeEnum.PROCEDURE_FUNCTION) {
                results.add(node.getDbOperation().getName());
            }
        }

        List collect = node.getChildren().stream()
                .flatMap(n -> getAllPlsqlObjectNamesOfCallNode(n).stream())
                .collect(Collectors.toList());
        results.addAll(collect);

        return results;
    }

    private Set getAllMethodsOfCallTree(CallTree callTree) {
        return callTree.getNodes()
                .stream()
                .flatMap(n -> getAllMethodsOfCallNode(n).stream())
                .collect(Collectors.toSet());
    }

    private List getAllMethodsOfCallNode(CallNode node) {
        List results = new ArrayList<>();
        if (node.getMethodObject() != null) {
            results.add(node.getMethodObject());

            List collect = node.getChildren().stream()
                    .filter(n -> ! n.isLink() && n.isVisible())
                    .flatMap(c -> getAllMethodsOfCallNode(c).stream())
                    .collect(Collectors.toList());

            results.addAll(collect);
        }
        return results;
    }

    /**
     * 找到对Table写操作存储过程或函数,以及Java方法(在方法中调用sql直接修改表)
     * @return
     * @param methodScope
     * @param plsqlObjectNameScope
     */
    private Map> findTableWriteFunctions(Set methodScope, Set plsqlObjectNameScope) {

        Map> results = new HashMap<>();

        for (String table : tables) {
            results.put(table,
                    plSqlExplained.getPlSqlObjects()
                            .stream()
                            .filter(p -> plsqlObjectNameScope.isEmpty() || plsqlObjectNameScope.contains(p.getFullName()))
                            .filter(p -> p.getTableWriteStatements().containsKey(table))
                            .map(p -> p.getFullName())
                            .sorted()
                            .collect(Collectors.toList())
            );
        }

        Stream allMethods = callGraph.getClasses()
                .stream()
                .flatMap(c -> c.getMethods().stream());
        allMethods
                .filter(m -> methodScope.isEmpty() || methodScope.contains(m))
                .forEach(method -> {
            for (String table : tables) {
                if (method.getTableWriteStatements().containsKey(table)) {
                    results.get(table).add(method.getFullName());
                }
            }
        });

        for (String table : tables) {
            List sorted = results.get(table).stream().sorted().collect(Collectors.toList());
            results.put(table, sorted);
        }

        return results;
    }

    private Set getDefaultAllTables(Set methodScope, Set plsqlObjectNameScope) {
        List results = new ArrayList<>();

        callGraph.getClasses().stream()
                .flatMap(c -> c.getMethods().stream())
                .filter(m -> methodScope.isEmpty() || methodScope.contains(m))
                .forEach(m -> results.addAll(m.getTableWriteStatements().keySet()));

        plSqlExplained.getPlSqlObjects()
                .stream()
                .filter(p -> plsqlObjectNameScope.isEmpty() || plsqlObjectNameScope.contains(p.getFullName()))
                .forEach(o -> results.addAll(o.getTableWriteStatements().keySet()));

        return new HashSet<>(results);
    }

    private List getTableStatements(String table, Set methodScope, Set plsqlObjectNameScope) {
        List results = callGraph.getClasses().stream()
                .flatMap(c -> c.getMethods().stream())
                .filter(m -> methodScope.isEmpty() || methodScope.contains(m))
                .flatMap(m -> {
                        if (m.getTableWriteStatements().containsKey(table)) {
                            return m.getTableWriteStatements().get(table)
                                    .stream()
                                    .map(s -> String.format("%s;%s---%s", s, System.lineSeparator(), m.getFullName()));
                        } else {
                            return new ArrayList().stream();
                        }
                    })
                .collect(Collectors.toList());

        results.addAll(plSqlExplained.getPlSqlObjects()
                .stream()
                .filter(p -> plsqlObjectNameScope.isEmpty() || plsqlObjectNameScope.contains(p.getFullName()))
                .flatMap(o -> {
                        if (o.getTableWriteStatements().containsKey(table)) {
                            return o.getTableWriteStatements().get(table)
                                    .stream()
                                    .map(s -> String.format("%s;%s---%s", s, System.lineSeparator(), o.getFullName()))
                                    ;
                        } else {
                            return new ArrayList().stream();
                        }
                    })
                .collect(Collectors.toList()));

        return sortAndFormatStatements(results);
    }

    List sortAndFormatStatements(List statements) {
        Set sqls = new HashSet<>(statements);

        FormatConfig build = FormatConfig.builder()
                .indent("    ") // Defaults to two spaces
                .uppercase(true) // Defaults to false (not safe to use when SQL dialect has case-sensitive identifiers)
                .maxColumnLength(140) // Defaults to 50
                .build();

        SqlFormatter.Formatter formatter = SqlFormatter.of(Dialect.PlSql);
        return sqls.stream().map(s -> formatter.format(s, build))
                .sorted()
                .collect(Collectors.toList());
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy