 (defmethod import/make-dataset-data-table "CSV"
   [tenant-conn {:keys [file-upload-path]} table-name spec]
   (try
-    (let [ ;; TODO a bit of "manual" integration work
-          path (get-path spec file-upload-path)
+    (let [path (get-path spec file-upload-path)
+          separator \,
           headers? (boolean (get spec "hasColumnHeaders"))
           encoding (get-encoding path)
-          n-cols (get-num-cols path \, encoding)
-          col-titles (if headers?
-                       (get-headers path \, encoding)
-                       (vec (for [i (range 1 (inc n-cols))]
-                              (str "Column " i))))
-          copy-sql (get-copy-sql table-name n-cols headers? encoding)]
-      (jdbc/execute! tenant-conn [(get-create-table-sql table-name n-cols)])
-      (with-open [conn (-> tenant-conn :datasource .getConnection)
-                  input-stream (-> (io/input-stream path)
-                                   import/unix-line-ending-input-stream)]
-        (let [copy-manager (.getCopyAPI (.unwrap conn PGConnection))]
-          (.copyIn copy-manager copy-sql input-stream)))
-      {:success? true
-       :columns (get-column-tuples col-titles)})
+          num-cols (get-num-cols path separator encoding)]
+      (create-table! tenant-conn table-name num-cols)
+      (insert-from-csv! tenant-conn table-name num-cols headers? path separator encoding)
+      (let [col-titles (if headers?
+                         (get-headers path separator encoding)
+                         (vec (map #(str "Column " %)
+                                   (range 1 (inc num-cols)))))]
+        {:success? true
+         :columns (get-column-tuples col-titles)}))
     (catch Exception e
       {:success? false
        :reason (str "Unexpected error: " (.getMessage e))})))


(defn get-encoding
  "Returns the character encoding reading some
  bytes from the file. It uses ICU's CharsetDetector"
  [path]
  (let [detector (CharsetDetector.)
        ;; 100kb
        ba (byte-array 100000)]
    (with-open [is (io/input-stream path)]
      (.read is ba))
    (-> (.setText detector ba)
        (.detect)
        (.getName))))

(defn get-column-tuples
  [col-titles]
  (vec
   (map-indexed (fn [idx title]
                  {:title title
                   :column-name (str "c" (inc idx))
                   :type "text"})
                col-titles)))

(defmethod import/valid? "CSV"
  [{:strs [url fileName hasColumnHeaders]}]

            [clojure.data.csv :as csv]
            [clojure.java.io :as io]
            [clojure.java.jdbc :as jdbc]
            [clojure.string :as s])
  (:import com.ibm.icu.text.CharsetDetector
           java.util.UUID
           org.postgresql.PGConnection
           org.postgresql.copy.CopyManager))


(defn- get-cols
  "Returns a vector of column names and PostgreSQL data types"
  [num-cols & [col-type]]
  (let [col-type-str (if col-type (str " " col-type) "")]
    (vec (map #(str "c" % col-type-str)
              (range 1 (inc num-cols))))))

(defn- create-table! ;; TODO handle column types other than "text"
  "Creates a table of the given name & number of columns"
  [tenant-conn table-name num-cols]
  (let [sql (format "CREATE TABLE %s (rnum serial primary key, %s)"
                    table-name
                    (s/join ", " (get-cols num-cols "text")))]
    (jdbc/execute! tenant-conn [sql])))

(defn get-headers
  "Returns the first line of the given CSV file"
  [path separator encoding]
  (with-open [reader (io/reader path :encoding encoding)]
    (first (csv/read-csv reader :separator separator))))

(defn get-num-cols
  "Returns the number of columns based on the
