(ns metabase.util.connection (:require [clojure.set :as set] [metabase.util :as u] [toucan2.core :as t2]) (:import (java.sql Connection DatabaseMetaData ResultSet ResultSetMetaData))) | |
(set! *warn-on-reflection* true) | |
(defn- consume-rset [^ResultSet rset cb] (into {} (iteration (fn [_] (when (.next rset) (cb rset)))))) | |
Returns a map of all column names to their respective type names for the given | (defn app-db-column-types [app-db table-name'] (let [table-name (cond-> (name table-name') (= (:db-type app-db) :h2) u/upper-case-en)] (t2/with-connection [^Connection conn] (let [md (.getMetaData conn)] (with-open [cols (.getColumns md nil nil table-name nil) pks (.getPrimaryKeys md nil nil table-name) fks (.getImportedKeys md nil nil table-name)] (let [pks (consume-rset pks (fn [^ResultSet pks] [(.getString pks "COLUMN_NAME") true])) fks (consume-rset fks (fn [^ResultSet fks] [(.getString fks "FKCOLUMN_NAME") (str (.getString fks "PKTABLE_NAME") "." (.getString fks "PKCOLUMN_NAME"))]))] (consume-rset cols (fn [^ResultSet cols] (let [col (.getString cols "COLUMN_NAME")] [col {:type (.getString cols "TYPE_NAME") :notnull (= (.getInt cols "NULLABLE") ResultSetMetaData/columnNoNulls) :pk (get pks col) :fk (get fks col)}]))))))))) |
(defn- group-rset [^ResultSet rset cb] (u/group-by first some? second (constantly true) conj #{} (iteration (fn [_] (when (.next rset) (or (cb rset) [])))))) | |
Returns a map of the downstream relations that will have deletes cascade to them, for the given table. | (defn app-db-cascading-deletes [app-db table-names] (t2/with-connection [^Connection conn] (let [md (.getMetaData conn)] (reduce (partial merge-with set/union) nil (for [table-name' table-names] (let [table-name (cond-> (name table-name') (= (:db-type app-db) :h2) u/upper-case-en)] (with-open [fks (.getImportedKeys md nil nil table-name)] (group-rset fks (fn [^ResultSet fks] (when (= (.getInt fks "DELETE_RULE") DatabaseMetaData/importedKeyCascade) [(u/lower-case-en (.getString fks "PKTABLE_NAME")) {:child-table (name table-name') :child-column (u/lower-case-en (.getString fks "FKCOLUMN_NAME")) :parent-column (u/lower-case-en (.getString fks "PKCOLUMN_NAME"))}])))))))))) |