<commit_before>package edu.northwestern.bioinformatics.studycalendar.test;

import org.dbunit.dataset.filter.SequenceTableFilter;
import org.dbunit.dataset.DataSetException;
import org.dbunit.database.IDatabaseConnection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.DirectedGraph;
import org.jgrapht.traverse.TopologicalOrderIterator;
import org.jgrapht.alg.StrongConnectivityInspector;

import java.sql.SQLException;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.Collection;
import java.util.Set;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * @author <NAME>
 */
public class ForeignKeySequenceFilter extends SequenceTableFilter {
    private static final Log log = LogFactory.getLog(ForeignKeySequenceFilter.class);

    public ForeignKeySequenceFilter(IDatabaseConnection conn, String[] tableNames) throws SQLException {
        super(new Reorderer(conn, tableNames).newOrder());
    }

    public ForeignKeySequenceFilter(IDatabaseConnection conn) throws SQLException, DataSetException {
        this(conn, conn.createDataSet().getTableNames());
    }

    private static class Reorderer {
        private String[] originalTableNames;
        private IDatabaseConnection conn;
        private DatabaseMetaData metadata;
        private DirectedGraph<String, DefaultEdge> graph;

        public Reorderer(IDatabaseConnection conn, String[] tableNames) throws SQLException {
            this.conn = conn;
            this.originalTableNames = tableNames;
            this.metadata = conn.getConnection().getMetaData();
            initGraph();
        }

        public String[] newOrder() {
            StrongConnectivityInspector<String,DefaultEdge> inspector
                = new StrongConnectivityInspector<String, DefaultEdge>(graph);

            for (Set<String> set : inspector.stronglyConnectedSets()) {
                if (set.size() > 1) {
                    log.warn("Table set contains a circular FK dependency: " + set + ".  Order of these tables will be arbitrary.");
                }
            }

            Iterator<String> topo
                = new TopologicalOrderIterator<String, DefaultEdge>(graph);
            List<String> ordered = new ArrayList<String>(graph.vertexSet().size());
            while (topo.hasNext()) {
                ordered.add(topo.next());
            }

            return ordered.toArray(new String[ordered.size()]);
        }

        private void initGraph() throws SQLException {
            graph = new DefaultDirectedGraph<String, DefaultEdge>(DefaultEdge.class);

            for (String tableName : originalTableNames) {
                graph.addVertex(tableName);
            }

            for (String parent : originalTableNames) {
                for (String child : getChildTableNames(parent)) {
                    graph.addEdge(parent, child);
                }
            }
        }

        private Collection<String> getChildTableNames(String parent) throws SQLException {
            ResultSet resultSet = metadata.getExportedKeys(null, conn.getSchema(), parent);
            try {
                Set<String> foreignTableSet = new HashSet<String>();

                while (resultSet.next()) {
                    foreignTableSet.add(resultSet.getString(7));
                }

                return foreignTableSet;
            } finally {
                resultSet.close();
            }
        }
    }

}<commit_msg>Throw exception on cycles; comment about algorithm, purpose<commit_after>package edu.northwestern.bioinformatics.studycalendar.test;

import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.filter.SequenceTableFilter;
import org.jgrapht.DirectedGraph;
import org.jgrapht.alg.StrongConnectivityInspector;
import org.jgrapht.graph.DefaultDirectedGraph;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.traverse.TopologicalOrderIterator;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * This is conceptually similar to dbunit's {@link org.dbunit.database.DatabaseSequenceFilter}
 * (it works as a drop-in replacement, in fact).  The difference is that it uses a topological
 * sort of a directed graph of the relationships instead of the iterative approach dbunit takes.
 * This seems to work better.
 * <p>
 * Note that reordering will fail with an IllegalStateException if there are dependency loops
 * in the given list of tables.  This may be correctable, if necessary.
 *
 * @author <NAME>
 */
public class ForeignKeySequenceFilter extends SequenceTableFilter {
    public ForeignKeySequenceFilter(IDatabaseConnection conn, String[] tableNames) throws SQLException {
        super(new Reorderer(conn, tableNames).newOrder());
    }

    public ForeignKeySequenceFilter(IDatabaseConnection conn) throws SQLException, DataSetException {
        this(conn, conn.createDataSet().getTableNames());
    }

    private static class Reorderer {
        private String[] originalTableNames;
        private IDatabaseConnection conn;
        private DatabaseMetaData metadata;
        private DirectedGraph<String, DefaultEdge> graph;

        public Reorderer(IDatabaseConnection conn, String[] tableNames) throws SQLException {
            this.conn = conn;
            this.originalTableNames = tableNames;
            this.metadata = conn.getConnection().getMetaData();
            initGraph();
        }

        public String[] newOrder() {
            StrongConnectivityInspector<String,DefaultEdge> inspector
                = new StrongConnectivityInspector<String, DefaultEdge>(graph);

            for (Set<String> set : inspector.stronglyConnectedSets()) {
                if (set.size() > 1) {
                    throw new IllegalStateException(
                        "Table set contains a circular FK dependency: " + set + ".  Cannot reorder.");
                }
            }

            Iterator<String> topo
                = new TopologicalOrderIterator<String, DefaultEdge>(graph);
            List<String> ordered = new ArrayList<String>(graph.vertexSet().size());
            while (topo.hasNext()) ordered.add(topo.next());

            return ordered.toArray(new String[ordered.size()]);
        }

        private void initGraph() throws SQLException {
            graph = new DefaultDirectedGraph<String, DefaultEdge>(DefaultEdge.class);

            for (String tableName : originalTableNames) {
                graph.addVertex(tableName);
            }

            for (String parent : originalTableNames) {
                for (String child : getChildTableNames(parent)) {
                    graph.addEdge(parent, child);
                }
            }
        }

        private Collection<String> getChildTableNames(String parent) throws SQLException {
            ResultSet rs = metadata.getExportedKeys(null, conn.getSchema(), parent);
            try {
                Set<String> children = new HashSet<String>();
                while (rs.next()) children.add(rs.getString(7));
                return children;
            } finally {
                rs.close();
            }
        }
    }

}
{'fraction_non_alphanumeric': 0.09092113982770046, 'fraction_numerical': 0.0005301524188204108, 'mean_word_length': 2.6560077519379846, 'pattern_counts': {'":': 0, '<': 30, '<?xml version=': 0, '>': 32, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6894846', 'n_tokens_mistral': 1946, 'n_tokens_neox': 1872, 'n_words': 454}