<commit_before>(ns metabase.api.qs
  (:require [clojure.data.csv :as csv]
            [compojure.core :refer [defroutes GET POST]]
            [metabase.api.common :refer :all]
            [metabase.db :refer :all]
            [metabase.driver :as driver]
            [metabase.driver.query-processor :as qp]
            (metabase.models [database :refer [Database]]
                             [hydrate :refer :all]
                             [query-execution :refer [QueryExecution all-fields]])
            [metabase.util :refer [contains-many? now-iso8601]]))


(declare execute-query build-response)


(defendpoint POST "/" [:as {{:keys [timezone database sql] :as body} :body}]
  (require-params database sql)
  (read-check Database database)
  (let [dataset-query {:type "native"
                       :database database
                       :native {:query sql
                                :timezone timezone}}
        options {:executed_by *current-user-id*
                 :synchronously false
                 :cache_result true}]
    (driver/dataset-query dataset-query options)))


(defendpoint GET "/:uuid" [uuid]
  (let-404 [query-execution (sel :one all-fields :uuid uuid)]
    (build-response query-execution)))


(defendpoint GET "/:uuid/csv" [uuid]
  (let-404 [{{:keys [columns rows]} :result_data} (sel :one all-fields :uuid uuid)]
    {:status 200
     :body (with-out-str
             (csv/write-csv *out* (into [columns] rows)))
     :headers {"Content-Type" "text/csv"
               "Content-Disposition" (str "attachment; filename=\"query_result_" (now-iso8601) ".csv\"")}}))

(define-routes)


;; ===============================================================================================================


(defn build-response
  "Build a query response from a QueryExecution record."
  [{{:keys [cols columns rows data]
     :or {cols []
          columns []}} :result_data :as query-execution}]
  (->
    (select-keys query-execution [:id :uuid :status])
    (assoc :data {:rows (or rows data [])
                  :cols cols
                  :columns columns})
    (cond->
      (= "failed" (:status query-execution)) (assoc :error (:error query-execution)
                                                    ;; TODO - sql error formatting FN
                                                    :sql_error (:error query-execution)))))<commit_msg>return row_count with GET /api/qs/:uuid response (expected by UI)<commit_after>(ns metabase.api.qs
  (:require [clojure.data.csv :as csv]
            [compojure.core :refer [defroutes GET POST]]
            [metabase.api.common :refer :all]
            [metabase.db :refer :all]
            [metabase.driver :as driver]
            [metabase.driver.query-processor :as qp]
            (metabase.models [database :refer [Database]]
                             [hydrate :refer :all]
                             [query-execution :refer [QueryExecution all-fields]])
            [metabase.util :refer [contains-many? now-iso8601]]))


(declare execute-query build-response)


(defendpoint POST "/" [:as {{:keys [timezone database sql] :as body} :body}]
  (require-params database sql)
  (read-check Database database)
  (let [dataset-query {:type "native"
                       :database database
                       :native {:query sql
                                :timezone timezone}}
        options {:executed_by *current-user-id*
                 :synchronously false
                 :cache_result true}]
    (driver/dataset-query dataset-query options)))


(defendpoint GET "/:uuid" [uuid]
  (let-404 [query-execution (sel :one all-fields :uuid uuid)]
    (build-response query-execution)))


(defendpoint GET "/:uuid/csv" [uuid]
  (let-404 [{{:keys [columns rows]} :result_data} (sel :one all-fields :uuid uuid)]
    {:status 200
     :body (with-out-str
             (csv/write-csv *out* (into [columns] rows)))
     :headers {"Content-Type" "text/csv"
               "Content-Disposition" (str "attachment; filename=\"query_result_" (now-iso8601) ".csv\"")}}))

(define-routes)


;; ===============================================================================================================


(defn build-response
  "Build a query response from a QueryExecution record."
  [{{:keys [cols columns rows data]
     :or {cols []
          columns []}} :result_data :as query-execution}]
  (let [rows (or rows data [])]
    (->
     (select-keys query-execution [:id :uuid :status])
     (assoc :data {:rows rows
                   :cols cols
                   :columns columns}
            :row_count (count rows))
     (cond->
         (= "failed" (:status query-execution)) (assoc :error (:error query-execution)
                                                       ;; TODO - sql error formatting FN
                                                       :sql_error (:error query-execution))))))
{'fraction_non_alphanumeric': 0.1726457399103139, 'fraction_numerical': 0.006930289441500204, 'mean_word_length': 2.1175349428208388, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1170130', 'n_tokens_mistral': 1404, 'n_tokens_neox': 1319, 'n_words': 365}