Compare commits
9 Commits
python-run
...
jsonista
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ff6c2b2ce | ||
|
|
d6233d16d3 | ||
|
|
2f7ef0d674 | ||
|
|
3dea11d46b | ||
|
|
1436561501 | ||
|
|
c148c1ccdb | ||
|
|
ca127a9eae | ||
|
|
368ac78a7a | ||
|
|
9f00ee385e |
@@ -1,9 +1,9 @@
|
||||
(ns i18n.create-artifacts.frontend
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
[i18n.common :as i18n]
|
||||
[jsonista.core :as jsonista]
|
||||
[metabuild-common.core :as u])
|
||||
(:import
|
||||
(java.io FileOutputStream OutputStreamWriter)
|
||||
@@ -64,5 +64,5 @@
|
||||
(u/step "Write JSON"
|
||||
(with-open [os (FileOutputStream. (io/file target-file))
|
||||
w (OutputStreamWriter. os StandardCharsets/UTF_8)]
|
||||
(json/generate-stream (i18n-map locale) w)))
|
||||
(jsonista/write-value w (i18n-map locale))))
|
||||
(u/assert-file-exists target-file))))
|
||||
|
||||
1
deps.edn
1
deps.edn
@@ -98,6 +98,7 @@
|
||||
org.bouncycastle/bcprov-jdk18on]}
|
||||
metabase/throttle {:mvn/version "1.0.2"} ; Tools for throttling access to API endpoints and other code pathways
|
||||
methodical/methodical {:mvn/version "1.0.124"} ; drop-in replacements for Clojure multimethods and adds several advanced features
|
||||
metosin/jsonista {:mvn/version "0.3.11"} ; JSON encoding and decoding
|
||||
metosin/malli {:mvn/version "0.16.3"} ; Data-driven Schemas for Clojure/Script and babashka
|
||||
nano-id/nano-id {:mvn/version "1.1.0"} ; NanoID generator for generating entity_ids
|
||||
net.cgrand/macrovich {:mvn/version "0.2.2"} ; utils for writing macros for both Clojure & ClojureScript
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase-enterprise.billing.billing
|
||||
"`/api/ee/billing/` endpoint(s)"
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.core.memoize :as memoize]
|
||||
[clojure.string :as str]
|
||||
@@ -12,6 +11,7 @@
|
||||
[metabase.util :as u]
|
||||
[metabase.util.date-2.parse :as u.date.parse]
|
||||
[metabase.util.i18n :as i18n]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.core :as t2])
|
||||
(:import
|
||||
[com.fasterxml.jackson.core JsonParseException]))
|
||||
@@ -29,7 +29,7 @@
|
||||
:language language
|
||||
:content-type :json})
|
||||
:body
|
||||
(json/parse-string keyword))
|
||||
json/decode+kw)
|
||||
(catch JsonParseException _
|
||||
{:content nil})))
|
||||
:ttl/threshold (u/minutes->ms 5)))
|
||||
|
||||
@@ -19,9 +19,9 @@
|
||||
[OpenAI Client](https://platform.openai.com/docs/libraries) with [Llama API](https://docs.llama-api.com/essentials/chat).
|
||||
"
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[metabase-enterprise.llm.settings :as llm-settings]
|
||||
[metabase.analytics.snowplow :as snowplow]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[wkok.openai-clojure.api :as openai.api]))
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
;; If we have ex-data, we'll assume were intercepting an openai.api/create-chat-completion response
|
||||
(if-some [status (:status (ex-data e))]
|
||||
(let [{:keys [body]} (ex-data e)
|
||||
{:keys [error]} (json/parse-string body keyword)
|
||||
{:keys [error]} (json/decode+kw body)
|
||||
{error-type :type :keys [message code]} error]
|
||||
(case (int status)
|
||||
400 (do
|
||||
@@ -144,7 +144,7 @@
|
||||
response (or
|
||||
(second (re-matches md-regex response))
|
||||
response)]
|
||||
(postprocess-fn (json/parse-string response true)))
|
||||
(postprocess-fn (json/decode+kw response)))
|
||||
(catch Exception e
|
||||
(throw
|
||||
(do
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
(ns metabase-enterprise.llm.tasks.describe-dashboard
|
||||
"LLM task(s) for generating dashboard descriptions"
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.set :refer [rename-keys]]
|
||||
[clojure.walk :as walk]
|
||||
[metabase-enterprise.llm.client :as llm-client]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(defn- dashboard->prompt-data
|
||||
@@ -61,7 +61,7 @@
|
||||
{:description "%%FILL_THIS_DESCRIPTION_IN%%"
|
||||
:keywords "%%FILL_THESE_KEYWORDS_IN%%"
|
||||
:questions "%%FILL_THESE_QUESTIONS_IN%%"})
|
||||
json-str (json/generate-string summary-with-prompts)
|
||||
json-str (json/encode summary-with-prompts)
|
||||
client (-> (llm-client/create-chat-completion)
|
||||
(llm-client/wrap-parse-json
|
||||
(fn [{:keys [description keywords questions]}]
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
(ns metabase-enterprise.llm.tasks.describe-question
|
||||
"LLM task(s) for generating question descriptions"
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.set :refer [rename-keys]]
|
||||
[metabase-enterprise.llm.client :as llm-client]
|
||||
[metabase.query-processor.compile :as qp.compile]
|
||||
[metabase.util :as u]))
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]))
|
||||
|
||||
(defn- question->prompt-data
|
||||
"Create a data-oriented summary of a question as input to an LLM for summarization."
|
||||
@@ -30,7 +30,7 @@
|
||||
summary-with-prompts (merge description
|
||||
{:friendly_title "%%FILL_THIS_TITLE_IN%%"
|
||||
:friendly_summary "%%FILL_THIS_SUMMARY_IN%%"})
|
||||
json-str (json/generate-string summary-with-prompts)
|
||||
json-str (json/encode summary-with-prompts)
|
||||
client (-> (llm-client/create-chat-completion)
|
||||
(llm-client/wrap-parse-json
|
||||
(fn [rsp] (rename-keys rsp {:friendly_title :title
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase-enterprise.serialization.upsert
|
||||
"Upsert-or-skip functionality for our models."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.data :as data]
|
||||
[medley.core :as m]
|
||||
[metabase-enterprise.serialization.names :refer [name-for-logging]]
|
||||
@@ -24,6 +23,7 @@
|
||||
[metabase.models.user :refer [User]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :as i18n :refer [trs]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[methodical.core :as methodical]
|
||||
[toucan2.core :as t2]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase-enterprise.auth-provider-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[clojure.test :refer [deftest is testing]]
|
||||
[metabase.auth-provider :as auth-provider]
|
||||
@@ -9,7 +8,8 @@
|
||||
[metabase.http-client :as client]
|
||||
[metabase.test :as mt]
|
||||
[metabase.test.data.interface :as tx]
|
||||
[metabase.util.http :as u.http])
|
||||
[metabase.util.http :as u.http]
|
||||
[metabase.util.json :as json])
|
||||
(:import
|
||||
[java.util Properties]))
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
(ns metabase-enterprise.llm.api-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.test :refer :all]
|
||||
[metabase-enterprise.llm.client :as llm-client]
|
||||
[metabase.models :refer [Card Dashboard DashboardCard]]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.tools.with-temp :as t2.with-temp]))
|
||||
|
||||
(deftest summarize-card-test
|
||||
@@ -16,7 +16,7 @@
|
||||
:type :query
|
||||
:query {:source-table (mt/id :orders)}}}]
|
||||
(let [fake-response {:title "Title" :description "Description"}
|
||||
json-response (json/generate-string fake-response)
|
||||
json-response (json/encode fake-response)
|
||||
expected {:summary fake-response}]
|
||||
(testing "Card summarization works in the happy path"
|
||||
(mt/with-premium-features #{:llm-autodescription}
|
||||
@@ -67,7 +67,7 @@
|
||||
fake-response {:description "Description"
|
||||
:keywords "awesome, amazing"
|
||||
:questions "- What is this?"}
|
||||
json-response (json/generate-string fake-response)
|
||||
json-response (json/encode fake-response)
|
||||
expected {:summary {:description "Keywords: awesome, amazing\n\nDescription: Description\n\nQuestions:\n- What is this?"}}]
|
||||
(testing "Card summarization works in the happy path"
|
||||
(mt/with-premium-features #{:llm-autodescription}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase-enterprise.sandbox.api.permissions-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[clojure.test :refer :all]
|
||||
[metabase-enterprise.sandbox.models.group-table-access-policy
|
||||
@@ -13,6 +12,7 @@
|
||||
[metabase.query-processor.compile :as qp.compile]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]
|
||||
[toucan2.tools.with-temp :as t2.with-temp]))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase-enterprise.search.scoring-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.math.combinatorics :as math.combo]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]
|
||||
@@ -8,7 +7,8 @@
|
||||
[java-time.api :as t]
|
||||
[metabase-enterprise.search.scoring :as ee-scoring]
|
||||
[metabase.search.scoring :as scoring]
|
||||
[metabase.test :as mt]))
|
||||
[metabase.test :as mt]
|
||||
[metabase.util.json :as json]))
|
||||
|
||||
(deftest ^:parallel verified-score-test
|
||||
(let [score #'ee-scoring/verified-score
|
||||
@@ -113,7 +113,7 @@
|
||||
all-permutations-all-orders
|
||||
(mapv #(str/join " " %))
|
||||
(remove #{""}))
|
||||
the-query (json/generate-string {:type :query :query {:source-table 1}})
|
||||
the-query (json/encode {:type :query :query {:source-table 1}})
|
||||
->query (fn [n] {:name n :dataset_query the-query})
|
||||
results (map ->query corpus)]
|
||||
(doseq [search-string corpus]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns ^:mb/once metabase-enterprise.serialization.v2.extract-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]
|
||||
[clojure.test :refer :all]
|
||||
@@ -31,6 +30,7 @@
|
||||
[metabase.query-processor :as qp]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(comment
|
||||
@@ -1238,7 +1238,7 @@
|
||||
:visualization_settings
|
||||
;; Top-level click behavior for the card.
|
||||
(let [dimension [:dimension [:field "something" {:base-type "type/Text"}]]
|
||||
mapping-id (json/generate-string dimension)]
|
||||
mapping-id (json/encode dimension)]
|
||||
{:click_behavior {:type "link"
|
||||
:linkType "question"
|
||||
:targetId c3-2-id
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
(ns metabase.driver.athena.hive-parser
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[clojure.walk :as walk]))
|
||||
[clojure.walk :as walk]
|
||||
[metabase.util.json :as json]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
@@ -58,5 +58,5 @@
|
||||
[schema]
|
||||
(-> schema
|
||||
parse-to-json-string
|
||||
json/parse-string
|
||||
json/decode
|
||||
walk/keywordize-keys))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns ^:mb/driver-tests metabase.driver.bigquery-cloud-sdk-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.core.async :as a]
|
||||
[clojure.string :as str]
|
||||
[clojure.test :refer :all]
|
||||
@@ -19,6 +18,7 @@
|
||||
[metabase.test.data.bigquery-cloud-sdk :as bigquery.tx]
|
||||
[metabase.test.data.interface :as tx]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]
|
||||
@@ -522,7 +522,7 @@
|
||||
:join [[:metabase_fieldvalues :fv] [:= :field.id :fv.field_id]]
|
||||
:where [:and [:in :field.table_id table-ids]
|
||||
[:in :field.name ["customer_id" "vip_customer" "name" "is_awesome" "is_opensource" "company" "ev_company"]]]})
|
||||
(map #(update % :values (comp set json/parse-string)))
|
||||
(map #(update % :values (comp set json/decode)))
|
||||
(map (juxt :field-name :values))
|
||||
(into {}))))))
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.driver.druid-jdbc
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.string :as str]
|
||||
[clojure.walk :as walk]
|
||||
@@ -17,6 +16,7 @@
|
||||
[metabase.query-processor.store :as qp.store]
|
||||
[metabase.query-processor.util.add-alias-info :as add]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log])
|
||||
(:import
|
||||
(java.sql ResultSet Types)
|
||||
@@ -174,7 +174,7 @@
|
||||
(let [{:keys [host port]} (:details database)]
|
||||
(try (let [version (-> (http/get (format "%s:%s/status" host port))
|
||||
:body
|
||||
json/parse-string
|
||||
json/decode
|
||||
(get "version"))
|
||||
[maj-min maj min] (re-find #"^(\d+)\.(\d+)" version)
|
||||
semantic (mapv #(Integer/parseInt %) [maj min])]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
(ns metabase.test.data.druid-jdbc
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[metabase.test.data.dataset-definitions :as defs]
|
||||
[metabase.test.data.interface :as tx]))
|
||||
[metabase.test.data.interface :as tx]
|
||||
[metabase.util.json :as json]))
|
||||
|
||||
(tx/add-test-extensions! :druid-jdbc)
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
(defn- already-loaded []
|
||||
(let [{:keys [host port]} (tx/dbdef->connection-details :druid-jdbc)]
|
||||
(set (json/parse-string (:body (http/get (format "%s:%s/druid/v2/datasources" host port)))))))
|
||||
(set (json/decode (:body (http/get (format "%s:%s/druid/v2/datasources" host port)))))))
|
||||
|
||||
(def built-in-datasets #{"checkins" "json"})
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.driver.druid
|
||||
"Druid driver."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[metabase.driver :as driver]
|
||||
[metabase.driver.druid.client :as druid.client]
|
||||
@@ -9,6 +8,7 @@
|
||||
[metabase.driver.druid.query-processor :as druid.qp]
|
||||
[metabase.driver.druid.sync :as druid.sync]
|
||||
[metabase.query-processor.pipeline :as qp.pipeline]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.ssh :as ssh]))
|
||||
|
||||
(driver/register! :druid)
|
||||
@@ -46,7 +46,7 @@
|
||||
|
||||
(defn- add-timeout-to-query [query timeout]
|
||||
(let [parsed (if (string? query)
|
||||
(json/parse-string query keyword)
|
||||
(json/decode+kw query)
|
||||
query)]
|
||||
(assoc-in parsed [:context :timeout] timeout)))
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
(ns metabase.driver.druid.client
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.core.async :as a]
|
||||
[metabase.models.secret :as secret]
|
||||
[metabase.query-processor.error-type :as qp.error-type]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.ssh :as ssh]))
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
;; this is the way the `Content-Type` header is formatted in requests made by the Druid web interface
|
||||
(let [{:keys [auth-enabled auth-username auth-token-value]} options
|
||||
options (cond-> (merge {:content-type "application/json;charset=UTF-8"} options)
|
||||
(:body options) (update :body json/generate-string)
|
||||
(:body options) (update :body json/encode)
|
||||
auth-enabled (assoc :basic-auth (str auth-username ":" auth-token-value)))]
|
||||
|
||||
(try
|
||||
@@ -38,7 +38,7 @@
|
||||
(throw (ex-info (tru "Druid request error [{0}]: {1}" status (pr-str body))
|
||||
{:type qp.error-type/db})))
|
||||
(try
|
||||
(json/parse-string body keyword)
|
||||
(json/decode+kw body)
|
||||
(catch Throwable e
|
||||
(throw (ex-info (tru "Failed to parse Druid response body: {0}" (pr-str body))
|
||||
{:type qp.error-type/db}
|
||||
@@ -46,7 +46,7 @@
|
||||
(catch Throwable e
|
||||
(let [response (u/ignore-exceptions
|
||||
(when-let [body (:body (ex-data e))]
|
||||
(json/parse-string body keyword)))]
|
||||
(json/decode+kw body)))]
|
||||
(throw (ex-info (or (:errorMessage response)
|
||||
(.getMessage e))
|
||||
(merge
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.driver.druid.execute
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.math.numeric-tower :as math]
|
||||
[java-time.api :as t]
|
||||
[medley.core :as m]
|
||||
@@ -13,6 +12,7 @@
|
||||
[metabase.util :as u]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
@@ -155,7 +155,7 @@
|
||||
{:pre [query]}
|
||||
(let [details (:details (lib.metadata/database (qp.store/metadata-provider)))
|
||||
query (if (string? query)
|
||||
(json/parse-string query keyword)
|
||||
(json/decode+kw query)
|
||||
query)
|
||||
query-type (or query-type
|
||||
(keyword (namespace ::druid.qp/query) (name (:queryType query))))
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
(ns ^:mb/driver-tests metabase.driver.druid.execute-test
|
||||
(:require [cheshire.core :as json]
|
||||
[clojure.java.io :as io]
|
||||
(:require [clojure.java.io :as io]
|
||||
[clojure.test :refer :all]
|
||||
[metabase.driver.druid.execute :as druid.execute]
|
||||
[metabase.test :as mt]
|
||||
[metabase.timeseries-query-processor-test.util :as tqpt]
|
||||
[metabase.util :as u]))
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]))
|
||||
|
||||
(deftest results-order-test
|
||||
(mt/test-driver :druid
|
||||
@@ -47,7 +47,7 @@
|
||||
(testing "Test that we can still return results from native :select queries, even if we no longer generate them"
|
||||
;; example results adapted from https://github.com/apache/druid/blob/d00747774208dbbfcb272ee7d1c30cf879887838/docs/querying/select-query.md
|
||||
(let [results (with-open [r (io/reader "modules/drivers/druid/test/metabase/driver/druid/execute_test/select_results.json")]
|
||||
(json/parse-stream r true))]
|
||||
(json/decode+kw r))]
|
||||
(is (= {:projections [:a :b :c]
|
||||
:results [{:timestamp #t "2013-01-01T00:00Z[UTC]", :robot "1", :namespace "article", :page "11._korpus_(NOVJ)"}
|
||||
{:timestamp #t "2013-01-01T00:00Z[UTC]", :robot "0", :namespace "article", :page "112_U.S._580"}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns ^:mb/driver-tests metabase.driver.druid.query-processor-test
|
||||
"Some tests to make sure the Druid Query Processor is generating sane Druid queries when compiling MBQL."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.test :refer :all]
|
||||
[clojure.tools.macro :as tools.macro]
|
||||
[java-time.api :as t]
|
||||
@@ -15,6 +14,7 @@
|
||||
[metabase.test :as mt]
|
||||
[metabase.timeseries-query-processor-test.util :as tqpt]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(defn- str->absolute-dt [s]
|
||||
@@ -263,7 +263,7 @@
|
||||
(table-rows-sample)))))))))
|
||||
|
||||
(def ^:private native-query-1
|
||||
(json/generate-string
|
||||
(json/encode
|
||||
{:queryType :scan
|
||||
:dataSource :checkins
|
||||
:intervals ["1900-01-01/2100-01-01"]
|
||||
@@ -288,45 +288,51 @@
|
||||
(is (partial=
|
||||
{:row_count 2
|
||||
:status :completed
|
||||
:data {:rows [[931 "Simcha Yan" 1 "Kinaree Thai Bistro" 1]
|
||||
[285 "Kfir Caj" 2 "Ruen Pair Thai Restaurant" 1]]
|
||||
:cols [{:name "id"
|
||||
:source :native
|
||||
:display_name "id"
|
||||
:field_ref [:field "id" {:base-type :type/Integer}]
|
||||
:base_type :type/Integer
|
||||
:effective_type :type/Integer}
|
||||
{:name "user_name"
|
||||
:source :native
|
||||
:display_name "user_name"
|
||||
:base_type :type/Text
|
||||
:effective_type :type/Text
|
||||
:field_ref [:field "user_name" {:base-type :type/Text}]}
|
||||
{:name "venue_price"
|
||||
:source :native
|
||||
:display_name "venue_price"
|
||||
:base_type :type/Integer
|
||||
:effective_type :type/Integer
|
||||
:field_ref [:field "venue_price" {:base-type :type/Integer}]}
|
||||
{:name "venue_name"
|
||||
:source :native
|
||||
:display_name "venue_name"
|
||||
:base_type :type/Text
|
||||
:effective_type :type/Text
|
||||
:field_ref [:field "venue_name" {:base-type :type/Text}]}
|
||||
{:name "count"
|
||||
:source :native
|
||||
:display_name "count"
|
||||
:base_type :type/Integer
|
||||
:effective_type :type/Integer
|
||||
:field_ref [:field "count" {:base-type :type/Integer}]}]
|
||||
:data {:rows [["Kinaree Thai Bistro" 1 931 1 "Simcha Yan"]
|
||||
["Ruen Pair Thai Restaurant" 2 285 1 "Kfir Caj"]]
|
||||
:cols [{:base_type :type/Text,
|
||||
:display_name "venue_name",
|
||||
:effective_type :type/Text,
|
||||
:field_ref [:field
|
||||
"venue_name"
|
||||
{:base-type :type/Text}],
|
||||
:name "venue_name",
|
||||
:source :native}
|
||||
{:base_type :type/Integer,
|
||||
:display_name "venue_price",
|
||||
:effective_type :type/Integer,
|
||||
:field_ref [:field
|
||||
"venue_price"
|
||||
{:base-type :type/Integer}],
|
||||
:name "venue_price",
|
||||
:source :native}
|
||||
{:base_type :type/Integer,
|
||||
:display_name "id",
|
||||
:effective_type :type/Integer,
|
||||
:field_ref [:field "id" {:base-type :type/Integer}],
|
||||
:name "id",
|
||||
:source :native}
|
||||
{:base_type :type/Integer,
|
||||
:display_name "count",
|
||||
:effective_type :type/Integer,
|
||||
:field_ref [:field "count" {:base-type :type/Integer}],
|
||||
:name "count",
|
||||
:source :native}
|
||||
{:base_type :type/Text,
|
||||
:display_name "user_name",
|
||||
:effective_type :type/Text,
|
||||
:field_ref [:field
|
||||
"user_name"
|
||||
{:base-type :type/Text}],
|
||||
:name "user_name",
|
||||
:source :native}]
|
||||
:native_form {:query native-query-1}
|
||||
:results_timezone "UTC"}}
|
||||
(-> (process-native-query native-query-1)
|
||||
(m/dissoc-in [:data :insights]))))))
|
||||
|
||||
(def ^:private native-query-2
|
||||
(json/generate-string
|
||||
(json/encode
|
||||
{:intervals ["1900-01-01/2100-01-01"]
|
||||
:granularity {:type :period
|
||||
:period :P1M
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.driver.mongo
|
||||
"MongoDB Driver."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[cheshire.generate :as json.generate]
|
||||
[clojure.string :as str]
|
||||
[clojure.walk :as walk]
|
||||
@@ -22,6 +21,7 @@
|
||||
[metabase.query-processor :as qp]
|
||||
[metabase.query-processor.store :as qp.store]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[taoensso.nippy :as nippy])
|
||||
@@ -37,6 +37,7 @@
|
||||
|
||||
;; Encode BSON undefined like `nil`
|
||||
(json.generate/add-encoder org.bson.BsonUndefined json.generate/encode-nil)
|
||||
(json/add-encoder org.bson.BsonUndefined json.generate/encode-nil)
|
||||
|
||||
(nippy/extend-freeze ObjectId :mongodb/ObjectId
|
||||
[^ObjectId oid data-output]
|
||||
@@ -302,7 +303,7 @@
|
||||
data (:data (qp/process-query {:database (:id db)
|
||||
:type "native"
|
||||
:native {:collection (:name table)
|
||||
:query (json/generate-string query)}}))
|
||||
:query (json/encode query)}}))
|
||||
cols (map (comp keyword :name) (:cols data))]
|
||||
(map #(zipmap cols %) (:rows data))))
|
||||
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
encoders yield no failures. Unfortunately I was unable to prove it is not needed yet, hence I'm leaving it
|
||||
in just to be safe. Removal should be considered during follow-up of monger removal."
|
||||
(:require
|
||||
[cheshire.generate])
|
||||
[cheshire.generate]
|
||||
[metabase.util.json :as json])
|
||||
(:import
|
||||
(org.bson.types BSONTimestamp ObjectId)))
|
||||
|
||||
@@ -18,3 +19,9 @@
|
||||
(cheshire.generate/add-encoder BSONTimestamp
|
||||
(fn [^BSONTimestamp ts ^com.fasterxml.jackson.core.json.WriterBasedJsonGenerator generator]
|
||||
(cheshire.generate/encode-map {:time (.getTime ts) :inc (.getInc ts)} generator)))
|
||||
(json/add-encoder ObjectId
|
||||
(fn [^ObjectId oid ^com.fasterxml.jackson.core.json.WriterBasedJsonGenerator generator]
|
||||
(.writeString generator (.toString oid))))
|
||||
(json/add-encoder BSONTimestamp
|
||||
(fn [^BSONTimestamp ts ^com.fasterxml.jackson.core.json.WriterBasedJsonGenerator generator]
|
||||
(cheshire.generate/encode-map {:time (.getTime ts) :inc (.getInc ts)} generator)))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.driver.mongo.parameters
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[clojure.walk :as walk]
|
||||
[java-time.api :as t]
|
||||
@@ -17,6 +16,7 @@
|
||||
[metabase.util :as u]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu])
|
||||
(:import
|
||||
@@ -144,7 +144,7 @@
|
||||
mbql.u/desugar-filter-clause
|
||||
qp.wrap-value-literals/wrap-value-literals-in-mbql
|
||||
mongo.qp/compile-filter
|
||||
json/generate-string)]
|
||||
json/encode)]
|
||||
[(conj acc compiled-clause) missing])
|
||||
;; no-value field filters inside optional clauses are ignored and omitted entirely
|
||||
(and no-value? in-optional?) [acc (conj missing k)]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns ^:mb/driver-tests metabase.driver.mongo.parameters-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[cheshire.generate :as json.generate]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]
|
||||
@@ -11,6 +10,7 @@
|
||||
[metabase.models :refer [NativeQuerySnippet]]
|
||||
[metabase.query-processor :as qp]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.tools.with-temp :as t2.with-temp])
|
||||
(:import
|
||||
(com.fasterxml.jackson.core JsonGenerator)))
|
||||
@@ -254,13 +254,6 @@
|
||||
(is (= (strip (to-bson [{:$match {"price" {:$gt 2}}}]))
|
||||
(strip (substitute {"snippet: high price" (params/->ReferencedQuerySnippet 123 (to-bson {"price" {:$gt 2}}))}
|
||||
["[{$match: " (param "snippet: high price") "}]"]))))))
|
||||
(defn- json-raw
|
||||
"Wrap a string so it will be spliced directly into resulting JSON as-is. Analogous to HoneySQL `raw`."
|
||||
[^String s]
|
||||
(reify json.generate/JSONable
|
||||
(to-json [_ generator]
|
||||
(.writeRawValue ^JsonGenerator generator s))))
|
||||
|
||||
(deftest ^:parallel e2e-field-filter-test
|
||||
(mt/test-driver :mongo
|
||||
(testing "date ranges"
|
||||
@@ -271,8 +264,8 @@
|
||||
(qp/process-query
|
||||
(mt/query checkins
|
||||
{:type :native
|
||||
:native {:query (json/generate-string
|
||||
[{:$match (json-raw "{{date}}")}
|
||||
:native {:query (json/encode
|
||||
[{:$match (json/raw "{{date}}")}
|
||||
{:$sort {:_id 1}}])
|
||||
:collection "checkins"
|
||||
:template-tags {"date" {:name "date"
|
||||
@@ -291,8 +284,8 @@
|
||||
(qp/process-query
|
||||
(mt/query categories
|
||||
{:type :native
|
||||
:native {:query (json/generate-string [{:$match (json-raw "{{id}}")}
|
||||
{:$sort {:_id 1}}])
|
||||
:native {:query (json/encode [{:$match (json/raw "{{id}}")}
|
||||
{:$sort {:_id 1}}])
|
||||
:collection "categories"
|
||||
:template-tags {"id" {:name "id"
|
||||
:display-name "ID"
|
||||
@@ -308,8 +301,8 @@
|
||||
(qp/process-query
|
||||
(mt/query checkins
|
||||
{:type :native
|
||||
:native {:query (json/generate-string
|
||||
[{:$match (json-raw "{{date}}")}
|
||||
:native {:query (json/encode
|
||||
[{:$match (json/raw "{{date}}")}
|
||||
{:$sort {:_id 1}}
|
||||
{:$limit 1}])
|
||||
:collection "checkins"
|
||||
@@ -326,8 +319,8 @@
|
||||
(qp/process-query
|
||||
(mt/query tips
|
||||
{:type :native
|
||||
:native {:query (json/generate-string
|
||||
[{:$match (json-raw "{{username}}")}
|
||||
:native {:query (json/encode
|
||||
[{:$match (json/raw "{{username}}")}
|
||||
{:$sort {:_id 1}}
|
||||
{:$project {"username" "$source.username"
|
||||
"_id" 1}}
|
||||
@@ -353,8 +346,8 @@
|
||||
(qp/process-query
|
||||
(mt/query tips
|
||||
{:type :native
|
||||
:native {:query (json/generate-string
|
||||
[{:$match (json-raw "{{username}}")}
|
||||
:native {:query (json/encode
|
||||
[{:$match (json/raw "{{username}}")}
|
||||
{:$sort {:_id 1}}
|
||||
{:$project {"username" "$source.username"}}
|
||||
{:$limit 1}])
|
||||
@@ -378,8 +371,8 @@
|
||||
(qp/process-query
|
||||
(mt/query venues
|
||||
{:type :native
|
||||
:native {:query (json/generate-string
|
||||
[{:$match (json-raw "{{price}}")}
|
||||
:native {:query (json/encode
|
||||
[{:$match (json/raw "{{price}}")}
|
||||
{:$project {"price" "$price"}}
|
||||
{:$sort {:_id 1}}
|
||||
{:$limit 10}])
|
||||
@@ -399,8 +392,8 @@
|
||||
(qp/process-query
|
||||
(mt/query tips
|
||||
{:type :native
|
||||
:native {:query (json/generate-string
|
||||
[{:$match (json-raw "{{username}}")}
|
||||
:native {:query (json/encode
|
||||
[{:$match (json/raw "{{username}}")}
|
||||
{:$sort {:_id 1}}
|
||||
{:$project {"username" "$source.username"}}
|
||||
{:$limit 20}])
|
||||
@@ -435,7 +428,7 @@
|
||||
(qp/process-query
|
||||
(mt/query categories
|
||||
{:type :native
|
||||
:native {:query (json/generate-string [{:$match (json-raw "{{snippet: first 3 checkins}}")}])
|
||||
:native {:query (json/encode [{:$match (json/raw "{{snippet: first 3 checkins}}")}])
|
||||
:collection "categories"
|
||||
:template-tags {"snippet: first 3 checkins" {:name "snippet: first 3 checkins"
|
||||
:display-name "Snippet: First 3 checkins"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns ^:mb/driver-tests metabase.driver.mongo-test
|
||||
"Tests for Mongo driver."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.test :refer :all]
|
||||
[medley.core :as m]
|
||||
[metabase.db.metadata-queries :as metadata-queries]
|
||||
@@ -24,6 +23,7 @@
|
||||
[metabase.test :as mt]
|
||||
[metabase.test.data.interface :as tx]
|
||||
[metabase.test.data.mongo :as tdm]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.xrays.automagic-dashboards.core :as magic]
|
||||
[taoensso.nippy :as nippy]
|
||||
@@ -763,7 +763,7 @@
|
||||
|
||||
(defn- json-from-file [^String filename]
|
||||
(with-open [rdr (java.io.FileReader. (java.io.File. filename))]
|
||||
(json/parse-stream rdr true)))
|
||||
(json/decode+kw rdr)))
|
||||
|
||||
(defn- missing-fields-db []
|
||||
(create-database-from-row-maps!
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.test.data.mongo
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[cheshire.generate :as json.generate]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.test :refer :all]
|
||||
@@ -11,7 +10,8 @@
|
||||
[metabase.driver.ddl.interface :as ddl.i]
|
||||
[metabase.driver.mongo.connection :as mongo.connection]
|
||||
[metabase.driver.mongo.util :as mongo.util]
|
||||
[metabase.test.data.interface :as tx])
|
||||
[metabase.test.data.interface :as tx]
|
||||
[metabase.util.json :as json])
|
||||
(:import
|
||||
(com.fasterxml.jackson.core JsonGenerator)
|
||||
(com.mongodb.client MongoDatabase)))
|
||||
@@ -101,23 +101,16 @@
|
||||
(str "_" table-or-field-name)
|
||||
table-or-field-name))
|
||||
|
||||
(defn- json-raw
|
||||
"Wrap a string so it will be spliced directly into resulting JSON as-is. Analogous to HoneySQL `raw`."
|
||||
[^String s]
|
||||
(reify json.generate/JSONable
|
||||
(to-json [_ generator]
|
||||
(.writeRawValue ^JsonGenerator generator s))))
|
||||
|
||||
(deftest json-raw-test
|
||||
(testing "Make sure the `json-raw` util fn actually works the way we expect it to"
|
||||
(testing "Make sure the `json/raw` util fn actually works the way we expect it to"
|
||||
(is (= "{\"x\":{{param}}}"
|
||||
(json/generate-string {:x (json-raw "{{param}}")})))))
|
||||
(json/encode {:x (json/raw "{{param}}")})))))
|
||||
|
||||
(defmethod tx/count-with-template-tag-query :mongo
|
||||
[_driver table-name field-name _param-type]
|
||||
{:projections [:count]
|
||||
:query (json/generate-string
|
||||
[{:$match {(name field-name) (json-raw (format "{{%s}}" (name field-name)))}}
|
||||
:query (json/encode
|
||||
[{:$match {(name field-name) (json/raw (format "{{%s}}" (name field-name)))}}
|
||||
{:$group {"_id" nil, "count" {:$sum 1}}}
|
||||
{:$sort {"_id" 1}}
|
||||
{:$project {"_id" false, "count" true}}])
|
||||
@@ -126,8 +119,8 @@
|
||||
(defmethod tx/count-with-field-filter-query :mongo
|
||||
[_driver table-name field-name]
|
||||
{:projections [:count]
|
||||
:query (json/generate-string
|
||||
[{:$match (json-raw (format "{{%s}}" (name field-name)))}
|
||||
:query (json/encode
|
||||
[{:$match (json/raw (format "{{%s}}" (name field-name)))}
|
||||
{:$group {"_id" nil, "count" {:$sum 1}}}
|
||||
{:$sort {"_id" 1}}
|
||||
{:$project {"_id" false, "count" true}}])
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.driver.redshift
|
||||
"Amazon Redshift Driver."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[honey.sql :as sql]
|
||||
[java-time.api :as t]
|
||||
@@ -25,6 +24,7 @@
|
||||
[metabase.util :as u]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log])
|
||||
(:import
|
||||
(com.amazon.redshift.util RedshiftInterval)
|
||||
@@ -469,11 +469,11 @@
|
||||
(defmethod qp.util/query->remark :redshift
|
||||
[_ {{:keys [executed-by card-id dashboard-id]} :info, :as query}]
|
||||
(str "/* partner: \"metabase\", "
|
||||
(json/generate-string {:dashboard_id dashboard-id
|
||||
:chart_id card-id
|
||||
:optional_user_id executed-by
|
||||
:optional_account_id (public-settings/site-uuid)
|
||||
:filter_values (field->parameter-value query)})
|
||||
(json/encode {:dashboard_id dashboard-id
|
||||
:chart_id card-id
|
||||
:optional_user_id executed-by
|
||||
:optional_account_id (public-settings/site-uuid)
|
||||
:filter_values (field->parameter-value query)})
|
||||
" */ "
|
||||
(qp.util/default-query->remark query)))
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"Snowflake Driver."
|
||||
(:require
|
||||
[buddy.core.codecs :as codecs]
|
||||
[cheshire.core :as json]
|
||||
[clojure.java.jdbc :as jdbc]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]
|
||||
@@ -37,6 +36,7 @@
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[ring.util.codec :as codec])
|
||||
(:import
|
||||
@@ -720,16 +720,16 @@
|
||||
[_ {{:keys [context executed-by card-id pulse-id dashboard-id query-hash]} :info,
|
||||
query-type :type,
|
||||
database-id :database}]
|
||||
(json/generate-string {:client "Metabase"
|
||||
:context context
|
||||
:queryType query-type
|
||||
:userId executed-by
|
||||
:pulseId pulse-id
|
||||
:cardId card-id
|
||||
:dashboardId dashboard-id
|
||||
:databaseId database-id
|
||||
:queryHash (when (bytes? query-hash) (codecs/bytes->hex query-hash))
|
||||
:serverId (public-settings/site-uuid)}))
|
||||
(json/encode {:client "Metabase"
|
||||
:context context
|
||||
:queryType query-type
|
||||
:userId executed-by
|
||||
:pulseId pulse-id
|
||||
:cardId card-id
|
||||
:dashboardId dashboard-id
|
||||
:databaseId database-id
|
||||
:queryHash (when (bytes? query-hash) (codecs/bytes->hex query-hash))
|
||||
:serverId (public-settings/site-uuid)}))
|
||||
|
||||
;;; ------------------------------------------------- User Impersonation --------------------------------------------------
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.actions.http-action
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.string :as str]
|
||||
[metabase.driver.common.parameters :as params]
|
||||
@@ -8,6 +7,7 @@
|
||||
[metabase.query-processor.error-type :as qp.error-type]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log])
|
||||
(:import
|
||||
(com.fasterxml.jackson.databind ObjectMapper)
|
||||
@@ -104,7 +104,7 @@
|
||||
;; TODO this is pretty ineficient. We parse with `:as :json`, then reencode within a response
|
||||
;; I couldn't find a way to get JSONNode out of cheshire, so we fall back to jackson.
|
||||
;; Should jackson be added explicitly to deps.edn?
|
||||
(let [json-node (.readTree ^ObjectMapper @object-mapper (json/generate-string object))
|
||||
(let [json-node (.readTree ^ObjectMapper @object-mapper (json/encode object))
|
||||
vresults (volatile! [])
|
||||
output (ActionOutput. vresults)
|
||||
expr (JsonQuery/compile jq-query Versions/JQ_1_6)
|
||||
@@ -135,7 +135,7 @@
|
||||
response (-> (http/request request)
|
||||
(select-keys [:body :headers :status])
|
||||
(update :body json/decode))
|
||||
error (json/parse-string (apply-json-query response (or (:error_handle action) ".status >= 400")))]
|
||||
error (json/decode (apply-json-query response (or (:error_handle action) ".status >= 400")))]
|
||||
(log/trace "Response before handle:" response)
|
||||
(if error
|
||||
{:status 400
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.analytics.stats
|
||||
"Functions which summarize the usage of an instance"
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
@@ -30,6 +29,7 @@
|
||||
[metabase.public-settings.premium-features :as premium-features :refer [defenterprise]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[toucan2.core :as t2]))
|
||||
@@ -326,7 +326,7 @@
|
||||
(-> db
|
||||
:dbms_version
|
||||
(assoc :engine (:engine db))
|
||||
json/generate-string))
|
||||
json/encode))
|
||||
databases))}))
|
||||
|
||||
(defn- table-metrics
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.api.action
|
||||
"`/api/action/` endpoints."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[compojure.core :as compojure :refer [POST]]
|
||||
[metabase.actions.core :as actions]
|
||||
[metabase.analytics.snowplow :as snowplow]
|
||||
@@ -13,6 +12,7 @@
|
||||
[metabase.models.collection :as collection]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]))
|
||||
@@ -208,7 +208,7 @@
|
||||
(actions/check-actions-enabled! action-id)
|
||||
(-> (action/select-action :id action-id :archived false)
|
||||
api/read-check
|
||||
(actions/fetch-values (json/parse-string parameters))))
|
||||
(actions/fetch-values (json/decode parameters))))
|
||||
|
||||
(api/defendpoint POST "/:id/execute"
|
||||
"Execute the Action.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.api.automagic-dashboards
|
||||
(:require
|
||||
[buddy.core.codecs :as codecs]
|
||||
[cheshire.core :as json]
|
||||
[compojure.core :refer [GET]]
|
||||
[metabase.api.common :as api]
|
||||
[metabase.api.query-metadata :as api.query-metadata]
|
||||
@@ -16,6 +15,7 @@
|
||||
[metabase.models.segment :refer [Segment]]
|
||||
[metabase.models.table :refer [Table]]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[metabase.xrays :as xrays]
|
||||
@@ -48,7 +48,7 @@
|
||||
(deferred-tru "invalid value for dashboard template name")))
|
||||
|
||||
(def ^:private ^{:arglists '([s])} decode-base64-json
|
||||
(comp #(json/decode % keyword) codecs/bytes->str codec/base64-decode))
|
||||
(comp json/decode+kw codecs/bytes->str codec/base64-decode))
|
||||
|
||||
(def ^:private Base64EncodedJSON
|
||||
(mu/with-api-error-message
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.api.card
|
||||
"/api/card endpoints."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.java.io :as io]
|
||||
[compojure.core :refer [DELETE GET POST PUT]]
|
||||
[medley.core :as m]
|
||||
@@ -43,6 +42,7 @@
|
||||
[metabase.util :as u]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.i18n :refer [deferred-tru trs tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
@@ -713,7 +713,7 @@
|
||||
export-format (into [:enum] api.dataset/export-formats)}
|
||||
(qp.card/process-query-for-card
|
||||
card-id export-format
|
||||
:parameters (json/parse-string parameters keyword)
|
||||
:parameters (json/decode+kw parameters)
|
||||
:constraints nil
|
||||
:context (api.dataset/export-format->context export-format)
|
||||
:middleware {:process-viz-settings? true
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
`:snippet` namespace, ('Snippet folders' in the UI). These namespaces are independent hierarchies. To use these
|
||||
endpoints for other Collections namespaces, you can pass the `?namespace=` parameter (e.g., `?namespace=snippet`)."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[compojure.core :refer [GET POST PUT]]
|
||||
[honey.sql.helpers :as sql.helpers]
|
||||
@@ -36,6 +35,7 @@
|
||||
[metabase.util :as u]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]))
|
||||
@@ -470,7 +470,7 @@
|
||||
(defmethod post-process-collection-children :dataset
|
||||
[_ collection rows]
|
||||
(let [queries-before (map :dataset_query rows)
|
||||
queries-parsed (map (comp mbql.normalize/normalize json/parse-string) queries-before)]
|
||||
queries-parsed (map (comp mbql.normalize/normalize json/decode) queries-before)]
|
||||
;; We need to normalize the dataset queries for hydration, but reset the field to avoid leaking that transform.
|
||||
(->> (map #(assoc %2 :dataset_query %1) queries-parsed rows)
|
||||
upload/model-hydrate-based-on-upload
|
||||
@@ -515,7 +515,7 @@
|
||||
"Given a Card, returns `true` if its query is fully parameterized."
|
||||
[row]
|
||||
(let [parsed-query (cond-> (:dataset_query row)
|
||||
(string? (:dataset_query row)) json/parse-string)
|
||||
(string? (:dataset_query row)) json/decode)
|
||||
;; TODO TB handle pMBQL native queries
|
||||
native-query (when (contains? parsed-query "native")
|
||||
(-> parsed-query mbql.normalize/normalize :native))]
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.api.dashboard
|
||||
"/api/dashboard endpoints."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.core.cache :as cache]
|
||||
[clojure.core.memoize :as memoize]
|
||||
[clojure.set :as set]
|
||||
@@ -49,6 +48,7 @@
|
||||
[metabase.related :as related]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -1223,7 +1223,7 @@
|
||||
(api/read-check :model/Dashboard dashboard-id)
|
||||
(actions/fetch-values
|
||||
(api/check-404 (action/dashcard->action dashcard-id))
|
||||
(json/parse-string parameters)))
|
||||
(json/decode parameters)))
|
||||
|
||||
(api/defendpoint POST "/:dashboard-id/dashcard/:dashcard-id/execute"
|
||||
"Execute the associated Action in the context of a `Dashboard` and `DashboardCard` that includes it.
|
||||
@@ -1278,7 +1278,7 @@
|
||||
:card-id card-id
|
||||
:dashcard-id dashcard-id
|
||||
:export-format export-format
|
||||
:parameters (json/parse-string parameters keyword)
|
||||
:parameters (json/decode+kw parameters)
|
||||
:context (api.dataset/export-format->context export-format)
|
||||
:constraints nil
|
||||
;; TODO -- passing this `:middleware` map is a little repetitive, need to think of a way to not have to
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.api.dataset
|
||||
"/api/dataset endpoints."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[compojure.core :refer [POST]]
|
||||
[metabase.api.common :as api]
|
||||
@@ -28,6 +27,7 @@
|
||||
[metabase.query-processor.util :as qp.util]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -136,9 +136,9 @@
|
||||
format_rows [:maybe ms/BooleanValue]
|
||||
pivot_results [:maybe ms/BooleanValue]
|
||||
export-format ExportFormat}
|
||||
(let [{:keys [was-pivot] :as query} (json/parse-string query keyword)
|
||||
(let [{:keys [was-pivot] :as query} (json/decode+kw query)
|
||||
query (dissoc query :was-pivot)
|
||||
viz-settings (-> (json/parse-string visualization_settings viz-setting-key-fn)
|
||||
viz-settings (-> (json/decode visualization_settings viz-setting-key-fn)
|
||||
(update :table.columns mbql.normalize/normalize)
|
||||
mb.viz/db->norm)
|
||||
query (-> query
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.api.embed.common
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]
|
||||
[malli.core :as mc]
|
||||
@@ -24,6 +23,7 @@
|
||||
[metabase.util.i18n
|
||||
:as i18n
|
||||
:refer [deferred-tru tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -134,7 +134,7 @@
|
||||
[query-params]
|
||||
(or (try
|
||||
(when-let [parameters (:parameters query-params)]
|
||||
(json/parse-string parameters keyword))
|
||||
(json/decode+kw parameters))
|
||||
(catch Throwable _
|
||||
nil))
|
||||
query-params))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.api.public
|
||||
"Metabase API endpoints for viewing publicly-accessible Cards and Dashboards."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[compojure.core :refer [GET]]
|
||||
[medley.core :as m]
|
||||
[metabase.actions.core :as actions]
|
||||
@@ -36,6 +35,7 @@
|
||||
[metabase.util :as u]
|
||||
[metabase.util.embed :as embed]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[throttle.core :as throttle]
|
||||
@@ -183,7 +183,7 @@
|
||||
[uuid parameters]
|
||||
{uuid ms/UUIDString
|
||||
parameters [:maybe ms/JSONString]}
|
||||
(process-query-for-card-with-public-uuid uuid :api (json/parse-string parameters keyword)))
|
||||
(process-query-for-card-with-public-uuid uuid :api (json/decode+kw parameters)))
|
||||
|
||||
(api/defendpoint GET "/card/:uuid/query/:export-format"
|
||||
"Fetch a publicly-accessible Card and return query results in the specified format. Does not require auth
|
||||
@@ -197,7 +197,7 @@
|
||||
(process-query-for-card-with-public-uuid
|
||||
uuid
|
||||
export-format
|
||||
(json/parse-string parameters keyword)
|
||||
(json/decode+kw parameters)
|
||||
:constraints nil
|
||||
:middleware {:process-viz-settings? true
|
||||
:js-int-to-string? false
|
||||
@@ -279,7 +279,7 @@
|
||||
:constraints (qp.constraints/default-query-constraints)}
|
||||
options
|
||||
{:parameters (cond-> parameters
|
||||
(string? parameters) (json/parse-string keyword))
|
||||
(string? parameters) json/decode+kw)
|
||||
:export-format export-format
|
||||
:qp qp
|
||||
:make-run process-query-for-card-with-id-run-fn})]
|
||||
@@ -343,7 +343,7 @@
|
||||
(api/check-404 (t2/select-one-pk Dashboard :public_uuid uuid :archived false))
|
||||
(actions/fetch-values
|
||||
(api/check-404 (action/dashcard->action dashcard-id))
|
||||
(json/parse-string parameters)))
|
||||
(json/decode parameters)))
|
||||
|
||||
(def ^:private dashcard-execution-throttle (throttle/make-throttler :dashcard-id :attempts-threshold 5000))
|
||||
|
||||
@@ -632,7 +632,7 @@
|
||||
[uuid parameters]
|
||||
{uuid ms/UUIDString
|
||||
parameters [:maybe ms/JSONString]}
|
||||
(process-query-for-card-with-public-uuid uuid :api (json/parse-string parameters keyword)
|
||||
(process-query-for-card-with-public-uuid uuid :api (json/decode+kw parameters)
|
||||
:qp qp.pivot/run-pivot-query))
|
||||
|
||||
(api/defendpoint GET "/pivot/dashboard/:uuid/dashcard/:dashcard-id/card/:card-id"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.api.testing
|
||||
"Endpoints for testing."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.java.jdbc :as jdbc]
|
||||
[clojure.string :as str]
|
||||
[compojure.core :refer [POST]]
|
||||
@@ -13,6 +12,7 @@
|
||||
[metabase.db :as mdb]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.files :as u.files]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2])
|
||||
@@ -155,7 +155,7 @@
|
||||
{:status 400
|
||||
:body {:error-code "oops"}}
|
||||
{:status 200
|
||||
:body (json/decode body true)}))
|
||||
:body (json/decode+kw body)}))
|
||||
|
||||
(api/defendpoint POST "/mark-stale"
|
||||
"Mark the card or dashboard as stale"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.api.tiles
|
||||
"`/api/tiles` endpoints."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.set :as set]
|
||||
[compojure.core :refer [GET]]
|
||||
[metabase.api.common :as api]
|
||||
@@ -11,6 +10,7 @@
|
||||
[metabase.query-processor.util :as qp.util]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli.schema :as ms])
|
||||
(:import
|
||||
(java.awt Color)
|
||||
@@ -179,7 +179,7 @@
|
||||
lon-field-ref (field-ref lon-field)
|
||||
|
||||
query
|
||||
(mbql.normalize/normalize (json/parse-string query keyword))
|
||||
(mbql.normalize/normalize (json/decode+kw query))
|
||||
|
||||
updated-query (query->tiles-query query {:zoom zoom :x x :y y
|
||||
:lat-field lat-field-ref
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"Random utilty endpoints for things that don't belong anywhere else in particular, e.g. endpoints for certain admin
|
||||
page tasks."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[compojure.core :refer [GET POST]]
|
||||
[crypto.random :as crypto-random]
|
||||
@@ -16,6 +15,7 @@
|
||||
[metabase.logger :as logger]
|
||||
[metabase.public-settings.premium-features :as premium-features]
|
||||
[metabase.troubleshooting :as troubleshooting]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -61,9 +61,9 @@
|
||||
email :- [:maybe ms/NonBlankString]]
|
||||
(try (http/post (product-feedback-url)
|
||||
{:content-type :json
|
||||
:body (json/generate-string {:comments comments
|
||||
:source source
|
||||
:email email})})
|
||||
:body (json/encode {:comments comments
|
||||
:source source
|
||||
:email email})})
|
||||
(catch Exception e
|
||||
(log/warn e)
|
||||
(throw e))))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.async.streaming-response
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.core.async :as a]
|
||||
[clojure.walk :as walk]
|
||||
[compojure.response]
|
||||
@@ -8,6 +7,7 @@
|
||||
[metabase.async.util :as async.u]
|
||||
[metabase.server.protocols :as server.protocols]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[potemkin.types :as p.types]
|
||||
[pretty.core :as pretty]
|
||||
@@ -68,7 +68,7 @@
|
||||
obj)
|
||||
(dissoc :export-format))]
|
||||
(with-open [writer (BufferedWriter. (OutputStreamWriter. os StandardCharsets/UTF_8))]
|
||||
(json/generate-stream obj writer)))
|
||||
(json/encode-to writer obj)))
|
||||
(catch EofException _)
|
||||
(catch Throwable e
|
||||
(log/error e "Error writing error to output stream" obj))))))
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
(ns metabase.channel.impl.http
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[java-time.api :as t]
|
||||
[metabase.channel.core :as channel]
|
||||
[metabase.channel.shared :as channel.shared]
|
||||
[metabase.pulse.core :as pulse]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[metabase.util.urls :as urls]))
|
||||
@@ -49,7 +49,7 @@
|
||||
(= "header" auth-method) (update :headers merge auth-info)
|
||||
(= "query-param" auth-method) (update :query-params merge auth-info)))]
|
||||
(http/request (cond-> req
|
||||
(map? (:body req)) (update :body json/generate-string)))))
|
||||
(map? (:body req)) (update :body json/encode)))))
|
||||
|
||||
(defmethod channel/can-connect? :channel/http
|
||||
[_channel-type details]
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
(ns metabase.cmd.rotate-encryption-key
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[metabase.db :as mdb]
|
||||
[metabase.models :refer [Database Secret Setting]]
|
||||
[metabase.models.setting.cache :as setting.cache]
|
||||
[metabase.util.encryption :as encryption]
|
||||
[metabase.util.i18n :refer [trs]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
(ns metabase.config
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
[environ.core :as env]
|
||||
[jsonista.core :as jsonista]
|
||||
[net.cgrand.macrovich :as macros])
|
||||
(:import
|
||||
(clojure.lang Keyword)))
|
||||
@@ -159,7 +159,8 @@
|
||||
"Default user details provided as a JSON string at launch time for first-user setup flow."
|
||||
[]
|
||||
(when-let [user-json (env/env :mb-user-defaults)]
|
||||
(json/parse-string user-json true)))
|
||||
(when-not (str/blank? user-json)
|
||||
(jsonista/read-value user-json (jsonista/object-mapper {:decode-key-fn true})))))
|
||||
|
||||
(def ^:const internal-mb-user-id
|
||||
"The user-id of the internal metabase user.
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
If you need to use code from elsewhere, consider copying it into this namespace to minimize risk of the code changing behaviour."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.core.match :refer [match]]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.java.io :as io]
|
||||
@@ -27,6 +26,7 @@
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.encryption :as encryption]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[toucan2.core :as t2]
|
||||
[toucan2.execute :as t2.execute])
|
||||
@@ -112,12 +112,12 @@
|
||||
[obj]
|
||||
(if (string? obj)
|
||||
obj
|
||||
(json/generate-string obj)))
|
||||
(json/encode obj)))
|
||||
|
||||
(defn- json-out [s keywordize-keys?]
|
||||
(if (string? s)
|
||||
(try
|
||||
(json/parse-string s keywordize-keys?)
|
||||
(json/decode s keywordize-keys?)
|
||||
(catch Throwable e
|
||||
(log/error e "Error parsing JSON")
|
||||
s))
|
||||
@@ -132,7 +132,7 @@
|
||||
[v]
|
||||
(let [decrypted (encryption/maybe-decrypt v)]
|
||||
(try
|
||||
(json/parse-string decrypted true)
|
||||
(json/decode+kw decrypted)
|
||||
(catch Throwable e
|
||||
(if (or (encryption/possibly-encrypted-string? decrypted)
|
||||
(encryption/possibly-encrypted-bytes? decrypted))
|
||||
@@ -232,7 +232,7 @@
|
||||
;; so we need to remove databases that have it set to false
|
||||
(filter (fn [{:keys [details]}]
|
||||
(when details
|
||||
(false? (:json-unfolding (json/parse-string details true))))))
|
||||
(false? (:json-unfolding (json/decode+kw details))))))
|
||||
(map :id))
|
||||
field-ids-to-update (->> (t2/query {:select [:f.id]
|
||||
:from [[:metabase_field :f]]
|
||||
@@ -266,10 +266,10 @@
|
||||
(m/update-existing viz-settings "column_settings" update-keys
|
||||
(fn [k]
|
||||
(-> k
|
||||
json/parse-string
|
||||
json/decode
|
||||
vec
|
||||
old-to-new
|
||||
json/generate-string)))))
|
||||
json/encode)))))
|
||||
|
||||
(define-migration MigrateLegacyColumnSettingsFieldRefs
|
||||
(let [update! (fn [{:keys [id visualization_settings]}]
|
||||
@@ -277,11 +277,11 @@
|
||||
:set {:visualization_settings visualization_settings}
|
||||
:where [:= :id id]}))]
|
||||
(run! update! (eduction (keep (fn [{:keys [id visualization_settings]}]
|
||||
(let [parsed (json/parse-string visualization_settings)
|
||||
(let [parsed (json/decode visualization_settings)
|
||||
updated (update-legacy-field-refs-in-viz-settings parsed)]
|
||||
(when (not= parsed updated)
|
||||
{:id id
|
||||
:visualization_settings (json/generate-string updated)}))))
|
||||
:visualization_settings (json/encode updated)}))))
|
||||
(t2/reducible-query {:select [:id :visualization_settings]
|
||||
:from [:report_card]
|
||||
:where [:or
|
||||
@@ -308,9 +308,9 @@
|
||||
["field" y {:source-field x}])
|
||||
_ ref))]
|
||||
(->> result-metadata
|
||||
json/parse-string
|
||||
json/decode
|
||||
(map #(m/update-existing % "field_ref" old-to-new))
|
||||
json/generate-string)))
|
||||
json/encode)))
|
||||
|
||||
(define-migration MigrateLegacyResultMetadataFieldRefs
|
||||
(let [update! (fn [{:keys [id result_metadata]}]
|
||||
@@ -341,33 +341,33 @@
|
||||
(fn [column_settings]
|
||||
(into {}
|
||||
(map (fn [[k v]]
|
||||
(match (vec (json/parse-string k))
|
||||
(match (vec (json/decode k))
|
||||
["ref" ["field" id opts]]
|
||||
[(json/generate-string ["ref" (remove-opts ["field" id opts] "join-alias")]) v]
|
||||
[(json/encode ["ref" (remove-opts ["field" id opts] "join-alias")]) v]
|
||||
_ [k v]))
|
||||
column_settings)))))
|
||||
|
||||
(defn- add-join-alias-to-column-settings-refs [{:keys [visualization_settings result_metadata]}]
|
||||
(let [result_metadata (json/parse-string result_metadata)
|
||||
visualization_settings (json/parse-string visualization_settings)
|
||||
(let [result_metadata (json/decode result_metadata)
|
||||
visualization_settings (json/decode visualization_settings)
|
||||
column-key->metadata (group-by #(-> (get % "field_ref")
|
||||
;; like the FE's `getColumnKey` function, remove "join-alias",
|
||||
;; "temporal-unit" and "binning" options from the field_ref
|
||||
(remove-opts "join-alias" "temporal-unit" "binning"))
|
||||
result_metadata)]
|
||||
(json/generate-string
|
||||
(json/encode
|
||||
(update visualization_settings "column_settings"
|
||||
(fn [column_settings]
|
||||
(into {}
|
||||
(mapcat (fn [[k v]]
|
||||
(match (vec (json/parse-string k))
|
||||
(match (vec (json/decode k))
|
||||
["ref" ["field" id opts]]
|
||||
(for [column-metadata (column-key->metadata ["field" id opts])
|
||||
;; remove "temporal-unit" and "binning" options from the matching field refs,
|
||||
;; but not "join-alias" as before.
|
||||
:let [field-ref (-> (get column-metadata "field_ref")
|
||||
(remove-opts "temporal-unit" "binning"))]]
|
||||
[(json/generate-string ["ref" field-ref]) v])
|
||||
[(json/encode ["ref" field-ref]) v])
|
||||
_ [[k v]]))
|
||||
column_settings)))))))
|
||||
|
||||
@@ -391,9 +391,9 @@
|
||||
[:like :result_metadata "%join-alias%"]]})))
|
||||
(let [update! (fn [{:keys [id visualization_settings]}]
|
||||
(let [updated (-> visualization_settings
|
||||
json/parse-string
|
||||
json/decode
|
||||
remove-join-alias-from-column-settings-field-refs
|
||||
json/generate-string)]
|
||||
json/encode)]
|
||||
(when (not= visualization_settings updated)
|
||||
(t2/query-one {:update :report_card
|
||||
:set {:visualization_settings updated}
|
||||
@@ -492,19 +492,19 @@
|
||||
|
||||
(define-reversible-migration RevisionDashboardMigrateGridFrom18To24
|
||||
(let [migrate! (fn [revision]
|
||||
(let [object (json/parse-string (:object revision) keyword)]
|
||||
(let [object (json/decode+kw (:object revision))]
|
||||
(when (seq (:cards object))
|
||||
(t2/query {:update :revision
|
||||
:set {:object (json/generate-string (update object :cards #(map migrate-dashboard-grid-from-18-to-24 %)))}
|
||||
:set {:object (json/encode (update object :cards #(map migrate-dashboard-grid-from-18-to-24 %)))}
|
||||
:where [:= :id (:id revision)]}))))]
|
||||
(run! migrate! (t2/reducible-query {:select [:*]
|
||||
:from [:revision]
|
||||
:where [:= :model "Dashboard"]})))
|
||||
(let [roll-back! (fn [revision]
|
||||
(let [object (json/parse-string (:object revision) keyword)]
|
||||
(let [object (json/decode+kw (:object revision))]
|
||||
(when (seq (:cards object))
|
||||
(t2/query {:update :revision
|
||||
:set {:object (json/generate-string (update object :cards #(map migrate-dashboard-grid-from-24-to-18 %)))}
|
||||
:set {:object (json/encode (update object :cards #(map migrate-dashboard-grid-from-24-to-18 %)))}
|
||||
:where [:= :id (:id revision)]}))))]
|
||||
(run! roll-back! (t2/reducible-query {:select [:*]
|
||||
:from [:revision]
|
||||
@@ -512,11 +512,11 @@
|
||||
|
||||
(define-migration RevisionMigrateLegacyColumnSettingsFieldRefs
|
||||
(let [update-one! (fn [{:keys [id object]}]
|
||||
(let [object (json/parse-string object)
|
||||
(let [object (json/decode object)
|
||||
updated (update object "visualization_settings" update-legacy-field-refs-in-viz-settings)]
|
||||
(when (not= updated object)
|
||||
(t2/query-one {:update :revision
|
||||
:set {:object (json/generate-string updated)}
|
||||
:set {:object (json/encode updated)}
|
||||
:where [:= :id id]}))))]
|
||||
(run! update-one! (t2/reducible-query {:select [:id :object]
|
||||
:from [:revision]
|
||||
@@ -547,10 +547,10 @@
|
||||
(fn [column_settings]
|
||||
(let [copies-with-join-alias (into {}
|
||||
(mapcat (fn [[k v]]
|
||||
(match (vec (json/parse-string k))
|
||||
(match (vec (json/decode k))
|
||||
["ref" ["field" id opts]]
|
||||
(for [alias join-aliases]
|
||||
[(json/generate-string ["ref" ["field" id (assoc opts "join-alias" alias)]]) v])
|
||||
[(json/encode ["ref" ["field" id (assoc opts "join-alias" alias)]]) v])
|
||||
_ '()))
|
||||
column_settings))]
|
||||
;; existing column settings should take precedence over the copies in case there is a conflict
|
||||
@@ -558,12 +558,12 @@
|
||||
card)))
|
||||
update-one!
|
||||
(fn [revision]
|
||||
(let [card (json/parse-string (:object revision))]
|
||||
(let [card (json/decode (:object revision))]
|
||||
(when (not= (get card "query_type") "native") ; native queries won't have join aliases, so we can exclude them straight away
|
||||
(let [updated (add-join-aliases card)]
|
||||
(when (not= updated (get "visualization_settings" card))
|
||||
(t2/query {:update :revision
|
||||
:set {:object (json/generate-string (assoc card "visualization_settings" updated))}
|
||||
:set {:object (json/encode (assoc card "visualization_settings" updated))}
|
||||
:where [:= :id (:id revision)]}))))))]
|
||||
(run! update-one! (t2/reducible-query {:select [:*]
|
||||
:from [:revision]
|
||||
@@ -578,13 +578,13 @@
|
||||
;; Reverse migration
|
||||
(let [update-one!
|
||||
(fn [revision]
|
||||
(let [card (json/parse-string (:object revision))]
|
||||
(let [card (json/decode (:object revision))]
|
||||
(when (not= (get card "query_type") "native")
|
||||
(let [viz-settings (get card "visualization_settings")
|
||||
updated (remove-join-alias-from-column-settings-field-refs viz-settings)]
|
||||
(when (not= updated viz-settings)
|
||||
(t2/query {:update :revision
|
||||
:set {:object (json/generate-string (assoc card "visualization_settings" updated))}
|
||||
:set {:object (json/encode (assoc card "visualization_settings" updated))}
|
||||
:where [:= :id (:id revision)]}))))))]
|
||||
(run! update-one! (t2/reducible-query {:select [:*]
|
||||
:from [:revision]
|
||||
@@ -597,11 +597,11 @@
|
||||
|
||||
(define-migration MigrateLegacyDashboardCardColumnSettingsFieldRefs
|
||||
(let [update-one! (fn [{:keys [id visualization_settings]}]
|
||||
(let [parsed (json/parse-string visualization_settings)
|
||||
(let [parsed (json/decode visualization_settings)
|
||||
updated (update-legacy-field-refs-in-viz-settings parsed)]
|
||||
(when (not= parsed updated)
|
||||
(t2/query-one {:update :report_dashboardcard
|
||||
:set {:visualization_settings (json/generate-string updated)}
|
||||
:set {:visualization_settings (json/encode updated)}
|
||||
:where [:= :id id]}))))]
|
||||
(run! update-one! (t2/reducible-query
|
||||
{:select [:id :visualization_settings]
|
||||
@@ -639,11 +639,11 @@
|
||||
[:like :dc.visualization_settings "%ref\\\\\\\",[\\\\\\\"field%"]]
|
||||
[:like :c.result_metadata "%join-alias%"]]})))
|
||||
(let [update! (fn [{:keys [id visualization_settings]}]
|
||||
(let [parsed (json/parse-string visualization_settings)
|
||||
(let [parsed (json/decode visualization_settings)
|
||||
updated (remove-join-alias-from-column-settings-field-refs parsed)]
|
||||
(when (not= parsed updated)
|
||||
(t2/query-one {:update :report_dashboardcard
|
||||
:set {:visualization_settings (json/generate-string updated)}
|
||||
:set {:visualization_settings (json/encode updated)}
|
||||
:where [:= :id id]}))))]
|
||||
(run! update! (t2/reducible-query {:select [:dc.id :dc.visualization_settings]
|
||||
:from [[:report_card :c]]
|
||||
@@ -659,12 +659,12 @@
|
||||
|
||||
(define-migration RevisionMigrateLegacyDashboardCardColumnSettingsFieldRefs
|
||||
(let [update-one! (fn [{:keys [id object]}]
|
||||
(let [object (json/parse-string object)
|
||||
(let [object (json/decode object)
|
||||
updated (update object "cards" (fn [cards]
|
||||
(map #(update % "visualization_settings" update-legacy-field-refs-in-viz-settings) cards)))]
|
||||
(when (not= updated object)
|
||||
(t2/query-one {:update :revision
|
||||
:set {:object (json/generate-string updated)}
|
||||
:set {:object (json/encode updated)}
|
||||
:where [:= :id id]}))))]
|
||||
(run! update-one! (t2/reducible-query {:select [:id :object]
|
||||
:from [:revision]
|
||||
@@ -693,7 +693,7 @@
|
||||
[:= :id (get dashcard "card_id")]
|
||||
;; only include cards with joins
|
||||
[:like :dataset_query "%joins%"]]})]
|
||||
(if-let [join-aliases (->> (get-in (json/parse-string dataset_query) ["query" "joins"])
|
||||
(if-let [join-aliases (->> (get-in (json/decode dataset_query) ["query" "joins"])
|
||||
(map #(get % "alias"))
|
||||
set
|
||||
seq)]
|
||||
@@ -701,10 +701,10 @@
|
||||
(fn [column_settings]
|
||||
(let [copies-with-join-alias (into {}
|
||||
(mapcat (fn [[k v]]
|
||||
(match (vec (json/parse-string k))
|
||||
(match (vec (json/decode k))
|
||||
["ref" ["field" id opts]]
|
||||
(for [alias join-aliases]
|
||||
[(json/generate-string ["ref" ["field" id (assoc opts "join-alias" alias)]]) v])
|
||||
[(json/encode ["ref" ["field" id (assoc opts "join-alias" alias)]]) v])
|
||||
_ '()))
|
||||
column_settings))]
|
||||
;; existing column settings should take precedence over the copies in case there is a conflict
|
||||
@@ -713,12 +713,12 @@
|
||||
dashcard))
|
||||
update-one!
|
||||
(fn [revision]
|
||||
(let [dashboard (json/parse-string (:object revision))
|
||||
(let [dashboard (json/decode (:object revision))
|
||||
updated (update dashboard "cards" (fn [dashcards]
|
||||
(map add-join-aliases dashcards)))]
|
||||
(when (not= updated dashboard)
|
||||
(t2/query {:update :revision
|
||||
:set {:object (json/generate-string updated)}
|
||||
:set {:object (json/encode updated)}
|
||||
:where [:= :id (:id revision)]}))))]
|
||||
(run! update-one! (t2/reducible-query {:select [:*]
|
||||
:from [:revision]
|
||||
@@ -731,14 +731,14 @@
|
||||
;; Reverse migration
|
||||
(let [update-one!
|
||||
(fn [revision]
|
||||
(let [dashboard (json/parse-string (:object revision))
|
||||
(let [dashboard (json/decode (:object revision))
|
||||
updated (update dashboard "cards"
|
||||
(fn [dashcards]
|
||||
(map #(update % "visualization_settings" remove-join-alias-from-column-settings-field-refs)
|
||||
dashcards)))]
|
||||
(when (not= updated dashboard)
|
||||
(t2/query {:update :revision
|
||||
:set {:object (json/generate-string updated)}
|
||||
:set {:object (json/encode updated)}
|
||||
:where [:= :id (:id revision)]}))))]
|
||||
(run! update-one! (t2/reducible-query {:select [:*]
|
||||
:from [:revision]
|
||||
@@ -768,7 +768,7 @@
|
||||
options (json-out options true)]
|
||||
(when (some? (:persist-models-enabled settings))
|
||||
(t2/query {:update :metabase_database
|
||||
:set {:options (json/generate-string (select-keys settings [:persist-models-enabled]))
|
||||
:set {:options (json/encode (select-keys settings [:persist-models-enabled]))
|
||||
:settings (encrypted-json-in (dissoc settings :persist-models-enabled))}
|
||||
:where [:= :id id]}))))]
|
||||
(run! rollback-one! (t2/reducible-query {:select [:id :settings :options]
|
||||
@@ -863,7 +863,7 @@
|
||||
|
||||
(defn- parse-to-json [& ks]
|
||||
(fn [x]
|
||||
(reduce #(update %1 %2 json/parse-string)
|
||||
(reduce #(update %1 %2 json/decode)
|
||||
x
|
||||
ks)))
|
||||
|
||||
@@ -880,7 +880,7 @@
|
||||
(completing
|
||||
(fn [_ {:keys [id visualization_settings]}]
|
||||
(t2/update! :report_dashboardcard id
|
||||
{:visualization_settings (json/generate-string visualization_settings)})))
|
||||
{:visualization_settings (json/encode visualization_settings)})))
|
||||
nil
|
||||
;; flamber wrote a manual postgres migration that this faithfully recreates: see
|
||||
;; https://github.com/metabase/metabase/issues/15014
|
||||
@@ -915,7 +915,7 @@
|
||||
[mapping-setting-key]
|
||||
(let [admin-group-id (t2/select-one-pk :permissions_group :name "Administrators")
|
||||
mapping (try
|
||||
(json/parse-string (raw-setting mapping-setting-key))
|
||||
(json/decode (raw-setting mapping-setting-key))
|
||||
(catch Exception _e
|
||||
{}))]
|
||||
(when-not (empty? mapping)
|
||||
@@ -924,7 +924,7 @@
|
||||
(->> mapping
|
||||
(map (fn [[k v]] [k (filter #(not= admin-group-id %) v)]))
|
||||
(into {})
|
||||
json/generate-string)}))))
|
||||
json/encode)}))))
|
||||
|
||||
(defn- migrate-remove-admin-from-group-mapping-if-needed
|
||||
{:author "qnkhuat"
|
||||
@@ -1076,12 +1076,12 @@
|
||||
;; So we do this in clojure land for mariadb
|
||||
(:h2 :mariadb)
|
||||
(let [migrate! (fn [revision]
|
||||
(let [object (json/parse-string (:object revision) keyword)
|
||||
(let [object (json/decode+kw (:object revision))
|
||||
new-object (assoc object :type (if (:dataset object)
|
||||
"model"
|
||||
"question"))]
|
||||
(t2/query {:update :revision
|
||||
:set {:object (json/generate-string new-object)}
|
||||
:set {:object (json/encode new-object)}
|
||||
:where [:= :id (:id revision)]})))]
|
||||
(run! migrate! (t2/reducible-query {:select [:*]
|
||||
:from [:revision]
|
||||
@@ -1117,12 +1117,12 @@
|
||||
|
||||
(:h2 :mariadb)
|
||||
(let [rollback! (fn [revision]
|
||||
(let [object (json/parse-string (:object revision) keyword)
|
||||
(let [object (json/decode+kw (:object revision))
|
||||
new-object (-> object
|
||||
(assoc :dataset (= (:type object) "model"))
|
||||
(dissoc :type))]
|
||||
(t2/query {:update :revision
|
||||
:set {:object (json/generate-string new-object)}
|
||||
:set {:object (json/encode new-object)}
|
||||
:where [:= :id (:id revision)]})))]
|
||||
(run! rollback! (t2/reducible-query {:select [:*]
|
||||
:from [:revision]
|
||||
@@ -1415,7 +1415,7 @@
|
||||
:display display}
|
||||
:where [:= :id id]}))]
|
||||
(run! update! (eduction (keep (fn [{:keys [id display visualization_settings]}]
|
||||
(let [parsed-viz (json/parse-string visualization_settings keyword)
|
||||
(let [parsed-viz (json/decode+kw visualization_settings)
|
||||
partial-card {:display display :visualization_settings parsed-viz}
|
||||
updated-partial-card (update-stacked-viz-cards partial-card)]
|
||||
(when (not= partial-card updated-partial-card)
|
||||
@@ -1423,7 +1423,7 @@
|
||||
updated-viz :visualization_settings} updated-partial-card]
|
||||
{:id id
|
||||
:display (name updated-display)
|
||||
:visualization_settings (json/generate-string updated-viz)})))))
|
||||
:visualization_settings (json/encode updated-viz)})))))
|
||||
(t2/reducible-query {:select [:id :display :visualization_settings]
|
||||
:from [:report_card]
|
||||
:where [:like :visualization_settings "%stackable%"]})))))
|
||||
@@ -1472,7 +1472,7 @@
|
||||
"Computes a modern viz setting column key for a `column`. The modern format is [\"name\",`name`]."
|
||||
[{name "name"}]
|
||||
(when name
|
||||
(json/generate-string ["name" name])))
|
||||
(json/encode ["name" name])))
|
||||
|
||||
(defn- column->legacy-column-key
|
||||
"Computes a legacy viz setting column key for a `column`.
|
||||
@@ -1491,7 +1491,7 @@
|
||||
(column->column-key column)
|
||||
|
||||
field-ref
|
||||
(json/generate-string ["ref" field-ref]))))
|
||||
(json/encode ["ref" field-ref]))))
|
||||
|
||||
(defn- update-legacy-column-keys-in-viz-settings
|
||||
"Updates `:column_settings` keys. Unmatched keys are retained."
|
||||
@@ -1527,12 +1527,12 @@
|
||||
to find the deduplicated column name by the field reference and compute the new column key."
|
||||
[column-key-tag update-viz-settings-fn]
|
||||
(let [update-one! (fn [{id :id viz-settings :visualization_settings result-metadata :result_metadata}]
|
||||
(let [viz-settings (json/parse-string viz-settings)
|
||||
result-metadata (json/parse-string result-metadata)
|
||||
(let [viz-settings (json/decode viz-settings)
|
||||
result-metadata (json/decode result-metadata)
|
||||
updated-viz-settings (update-viz-settings-fn viz-settings result-metadata)]
|
||||
(when (not= viz-settings updated-viz-settings)
|
||||
(t2/query-one {:update :report_card
|
||||
:set {:visualization_settings (json/generate-string updated-viz-settings)}
|
||||
:set {:visualization_settings (json/encode updated-viz-settings)}
|
||||
:where [:= :id id]}))))]
|
||||
(run! update-one! (t2/reducible-query {:select [:id :visualization_settings :result_metadata]
|
||||
:from [:report_card]
|
||||
@@ -1551,12 +1551,12 @@
|
||||
key."
|
||||
[column-key-tag update-viz-settings-fn]
|
||||
(let [update-one! (fn [{id :id viz-settings :visualization_settings result-metadata :result_metadata}]
|
||||
(let [viz-settings (json/parse-string viz-settings)
|
||||
result-metadata (json/parse-string result-metadata)
|
||||
(let [viz-settings (json/decode viz-settings)
|
||||
result-metadata (json/decode result-metadata)
|
||||
updated-viz-settings (update-viz-settings-fn viz-settings result-metadata)]
|
||||
(when (not= viz-settings updated-viz-settings)
|
||||
(t2/query-one {:update :report_dashboardcard
|
||||
:set {:visualization_settings (json/generate-string updated-viz-settings)}
|
||||
:set {:visualization_settings (json/encode updated-viz-settings)}
|
||||
:where [:= :id id]}))))]
|
||||
(run! update-one! (t2/reducible-query {:select [:dc.id :dc.visualization_settings :c.result_metadata]
|
||||
:from [[:report_card :c]]
|
||||
@@ -1600,10 +1600,10 @@
|
||||
:channel_template
|
||||
{:name "User joined Email template"
|
||||
:channel_type "channel/email"
|
||||
:details (json/generate-string {:type "email/mustache-resource"
|
||||
:subject "{{payload.custom.user_invited_email_subject}}"
|
||||
:path "metabase/email/new_user_invite.mustache"
|
||||
:recipient-type :cc})
|
||||
:details (json/encode {:type "email/mustache-resource"
|
||||
:subject "{{payload.custom.user_invited_email_subject}}"
|
||||
:path "metabase/email/new_user_invite.mustache"
|
||||
:recipient-type :cc})
|
||||
:created_at :%now
|
||||
:updated_at :%now})]
|
||||
(create-notification!
|
||||
@@ -1614,17 +1614,17 @@
|
||||
:channel_id nil
|
||||
:template_id template-id
|
||||
:recipients [{:type "notification-recipient/template"
|
||||
:details (json/generate-string {:pattern "{{payload.event_info.object.email}}"})}]}])))
|
||||
:details (json/encode {:pattern "{{payload.event_info.object.email}}"})}]}])))
|
||||
|
||||
(define-migration CreateSystemNotificationAlertCreated
|
||||
(let [template-id (t2/insert-returning-pk!
|
||||
:channel_template
|
||||
{:name "Alert Created Email template"
|
||||
:channel_type "channel/email"
|
||||
:details (json/generate-string {:type "email/mustache-resource"
|
||||
:subject "You set up an alert"
|
||||
:path "metabase/email/alert_new_confirmation.mustache"
|
||||
:recipient-type :cc})
|
||||
:details (json/encode {:type "email/mustache-resource"
|
||||
:subject "You set up an alert"
|
||||
:path "metabase/email/alert_new_confirmation.mustache"
|
||||
:recipient-type :cc})
|
||||
:created_at :%now
|
||||
:updated_at :%now})]
|
||||
(create-notification!
|
||||
@@ -1635,17 +1635,17 @@
|
||||
:channel_id nil
|
||||
:template_id template-id
|
||||
:recipients [{:type "notification-recipient/template"
|
||||
:details (json/generate-string {:pattern "{{payload.event_info.user.email}}"})}]}])))
|
||||
:details (json/encode {:pattern "{{payload.event_info.user.email}}"})}]}])))
|
||||
|
||||
(define-migration CreateSystemNotificationSlackTokenError
|
||||
(let [template-id (t2/insert-returning-pk!
|
||||
:channel_template
|
||||
{:name "Slack Token Error Email template"
|
||||
:channel_type "channel/email"
|
||||
:details (json/generate-string {:type "email/mustache-resource"
|
||||
:subject "Your Slack connection stopped working"
|
||||
:path "metabase/email/slack_token_error.mustache"
|
||||
:recipient-type :cc})
|
||||
:details (json/encode {:type "email/mustache-resource"
|
||||
:subject "Your Slack connection stopped working"
|
||||
:path "metabase/email/slack_token_error.mustache"
|
||||
:recipient-type :cc})
|
||||
:created_at :%now
|
||||
:updated_at :%now})]
|
||||
(create-notification!
|
||||
@@ -1656,7 +1656,7 @@
|
||||
:channel_id nil
|
||||
:template_id template-id
|
||||
:recipients [{:type "notification-recipient/template"
|
||||
:details (json/generate-string {:pattern "{{context.admin_email}}"
|
||||
:is_optional true})}
|
||||
:details (json/encode {:pattern "{{context.admin_email}}"
|
||||
:is_optional true})}
|
||||
{:type "notification-recipient/group"
|
||||
:permissions_group_id (t2/select-one-pk :permissions_group :name "Administrators")}]}])))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns metabase.db.custom-migrations.metrics-v2
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.core :as t2])
|
||||
(:import (java.time Instant)))
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
database with ID `db-id`.
|
||||
The :collection_id property is not set and the question is not persisted."
|
||||
[metric-v1 db-id]
|
||||
(let [definition (json/parse-string (:definition metric-v1) true)
|
||||
(let [definition (json/decode+kw (:definition metric-v1))
|
||||
dataset-query {:type :query
|
||||
:database db-id
|
||||
:query definition}]
|
||||
@@ -46,7 +46,7 @@
|
||||
(select-keys [:archived :created_at :creator_id :database_id
|
||||
:description :name :table_id])
|
||||
(update :description add-metric-id (:id metric-v1))
|
||||
(assoc :dataset_query (json/generate-string dataset-query)
|
||||
(assoc :dataset_query (json/encode dataset-query)
|
||||
:enable_embedding false
|
||||
:query_type "query"
|
||||
:type "metric"
|
||||
@@ -102,13 +102,13 @@
|
||||
"Rewrite `outer-query` replacing references to v1 metrics with references
|
||||
to the corresponding v2 metric question as specified by the mapping `metric-id->metric-card-id`."
|
||||
[outer-query metric-id->metric-card-id]
|
||||
(let [dataset-query (json/parse-string outer-query true)
|
||||
(let [dataset-query (json/decode+kw outer-query)
|
||||
inner-query (:query dataset-query)
|
||||
rewritten (rewrite-metric-consuming-query inner-query metric-id->metric-card-id)]
|
||||
(when (not= rewritten inner-query)
|
||||
(-> dataset-query
|
||||
(assoc :query rewritten)
|
||||
json/generate-string))))
|
||||
json/encode))))
|
||||
|
||||
(defn migrate-up!
|
||||
"Migrate metrics and the cards consuming them to metrics v2. This involves
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
NOTE: This namespace is deprecated, all of these emails will soon be converted to System Email Notifications."
|
||||
(:require
|
||||
[buddy.core.codecs :as codecs]
|
||||
[cheshire.core :as json]
|
||||
[clojure.core.cache :as cache]
|
||||
[hiccup.core :refer [html]]
|
||||
[java-time.api :as t]
|
||||
@@ -28,6 +27,7 @@
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.encryption :as encryption]
|
||||
[metabase.util.i18n :as i18n :refer [trs tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.markdown :as markdown]
|
||||
@@ -271,7 +271,7 @@
|
||||
{:pre [(u/email? email)]}
|
||||
(let [encoded-info (when blob
|
||||
(-> blob
|
||||
json/generate-string
|
||||
json/encode
|
||||
.getBytes
|
||||
codecs/bytes->b64-str))
|
||||
context (merge (common-context)
|
||||
@@ -305,9 +305,9 @@
|
||||
[pulse-id email]
|
||||
(codecs/bytes->hex
|
||||
(encryption/validate-and-hash-secret-key
|
||||
(json/generate-string {:salt (public-settings/site-uuid-for-unsubscribing-url)
|
||||
:email email
|
||||
:pulse-id pulse-id}))))
|
||||
(json/encode {:salt (public-settings/site-uuid-for-unsubscribing-url)
|
||||
:email email
|
||||
:pulse-id pulse-id}))))
|
||||
|
||||
(defn- pulse-context [pulse dashboard non-user-email]
|
||||
(let [dashboard-id (:id dashboard)]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.integrations.google
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.string :as str]
|
||||
[metabase.api.common :as api]
|
||||
@@ -13,6 +12,7 @@
|
||||
[metabase.plugins.classloader :as classloader]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -81,7 +81,7 @@
|
||||
(let [{:keys [status body]} token-info-response]
|
||||
(when-not (= status 200)
|
||||
(throw (ex-info (tru "Invalid Google Sign-In token.") {:status-code 400})))
|
||||
(u/prog1 (json/parse-string body keyword)
|
||||
(u/prog1 (json/decode+kw body)
|
||||
(let [audience (:aud <>)
|
||||
audience (if (string? audience) [audience] audience)]
|
||||
(when-not (contains? (set audience) client-id)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.integrations.ldap
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-ldap.client :as ldap]
|
||||
[metabase.config :as config]
|
||||
[metabase.integrations.ldap.default-implementation :as default-impl]
|
||||
@@ -9,6 +8,7 @@
|
||||
[metabase.plugins.classloader :as classloader]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms])
|
||||
@@ -108,11 +108,11 @@
|
||||
:default {}
|
||||
:audit :getter
|
||||
:getter (fn []
|
||||
(json/parse-string (setting/get-value-of-type :string :ldap-group-mappings) #(DN. (str %))))
|
||||
(json/decode (setting/get-value-of-type :string :ldap-group-mappings) #(DN. (str %))))
|
||||
:setter (fn [new-value]
|
||||
(cond
|
||||
(string? new-value)
|
||||
(recur (json/parse-string new-value))
|
||||
(recur (json/decode new-value))
|
||||
|
||||
(map? new-value)
|
||||
(do (doseq [k (keys new-value)]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.integrations.slack
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
@@ -11,6 +10,7 @@
|
||||
[metabase.util :as u]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.i18n :refer [deferred-tru trs tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -127,7 +127,7 @@
|
||||
|
||||
(defn- handle-response [{:keys [status body]}]
|
||||
(with-open [reader (io/reader body)]
|
||||
(let [body (json/parse-stream reader true)]
|
||||
(let [body (json/decode+kw reader)]
|
||||
(if (and (= 200 status) (:ok body))
|
||||
body
|
||||
(handle-error body)))))
|
||||
@@ -345,7 +345,7 @@
|
||||
[& {:keys [channel-id file-id filename]}]
|
||||
(let [complete! (fn []
|
||||
(POST "files.completeUploadExternal"
|
||||
{:query-params {:files (json/generate-string [{:id file-id, :title filename}])
|
||||
{:query-params {:files (json/encode [{:id file-id, :title filename}])
|
||||
:channel_id channel-id}}))
|
||||
complete-response (try
|
||||
(complete!)
|
||||
@@ -416,4 +416,4 @@
|
||||
:icon_url "http://static.metabase.com/metabot_slack_avatar_whitebg.png"
|
||||
:text text-or-nil
|
||||
:attachments (when (seq attachments)
|
||||
(json/generate-string attachments))}}))
|
||||
(json/encode attachments))}}))
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"The core metabot namespace. Consists primarily of functions named infer-X,
|
||||
where X is the thing we want to extract from the bot response."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[metabase.lib.native :as lib-native]
|
||||
[metabase.metabot.client :as metabot-client]
|
||||
[metabase.metabot.feedback :as metabot-feedback]
|
||||
@@ -10,6 +9,7 @@
|
||||
[metabase.metabot.util :as metabot-util]
|
||||
[metabase.models :refer [Table]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[potemkin :as p]
|
||||
[toucan2.core :as t2]))
|
||||
@@ -39,7 +39,7 @@
|
||||
{:template (metabot-util/find-result
|
||||
(fn [message]
|
||||
(metabot-util/response->viz
|
||||
(json/parse-string message keyword)))
|
||||
(json/decode+kw message)))
|
||||
(metabot-client/invoke-metabot prompt))
|
||||
:prompt_template_version (format "%s:%s" prompt_template version)}))
|
||||
(log/warn "Metabot is not enabled")))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns metabase.metabot.client
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[metabase.metabot.settings :as metabot-settings]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[wkok.openai-clojure.api :as openai.api]))
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
;; If we have ex-data, we'll assume were intercepting an openai.api/create-chat-completion response
|
||||
(if-some [status (:status (ex-data e))]
|
||||
(let [{:keys [body]} (ex-data e)
|
||||
{:keys [error]} (json/parse-string body keyword)
|
||||
{:keys [error]} (json/decode+kw body)
|
||||
{error-type :type :keys [message code]} error]
|
||||
(case (int status)
|
||||
400 (do
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
(ns metabase.metabot.feedback
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[metabase.analytics.snowplow :as snowplow]
|
||||
[metabase.metabot.settings :as metabot-settings]))
|
||||
[metabase.metabot.settings :as metabot-settings]
|
||||
[metabase.util.json :as json]))
|
||||
|
||||
(def ^:private snowplow-keys [:entity_type :prompt_template_versions :feedback_type])
|
||||
(def ^:private feedback-keys (into snowplow-keys [:prompt :sql]))
|
||||
@@ -15,9 +15,9 @@
|
||||
{:keys [status body]} (http/request
|
||||
{:url (metabot-settings/metabot-feedback-url)
|
||||
:method :post
|
||||
:body (json/generate-string
|
||||
:body (json/encode
|
||||
feedback
|
||||
{:pretty true})
|
||||
(json/object-mapper {:pretty true}))
|
||||
:throw-exceptions false
|
||||
:as :json
|
||||
:accept :json
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"Functions for denormalizing input, prompt input generation, and sql handing.
|
||||
If this grows much, we might want to split these out into separate nses."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.core.memoize :as memoize]
|
||||
[clojure.string :as str]
|
||||
[honey.sql :as sql]
|
||||
@@ -16,6 +15,7 @@
|
||||
[metabase.query-processor.setup :as qp.setup]
|
||||
[metabase.query-processor.util.add-alias-info :as add]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
@@ -198,13 +198,13 @@
|
||||
"Convert a map of {:models ...} to a json string summary of these models.
|
||||
This is used as a summary of the database in prompt engineering."
|
||||
[{:keys [models]}]
|
||||
(let [json-str (json/generate-string
|
||||
(let [json-str (json/encode
|
||||
{:tables
|
||||
(for [{model-name :name model-id :id :keys [result_metadata] :as _model} models]
|
||||
{:table-id model-id
|
||||
:table-name model-name
|
||||
:column-names (mapv :display_name result_metadata)})}
|
||||
{:pretty true})
|
||||
(json/object-mapper {:pretty true}))
|
||||
nchars (count json-str)]
|
||||
(log/debugf "Database json string descriptor contains %s chars (~%s tokens)."
|
||||
nchars
|
||||
@@ -416,7 +416,7 @@
|
||||
(log/info "Refreshing metabot prompt templates.")
|
||||
(let [all-templates (-> (metabot-settings/metabot-get-prompt-templates-url)
|
||||
slurp
|
||||
(json/parse-string keyword))]
|
||||
json/decode+kw)]
|
||||
(-> (group-by (comp keyword :prompt_template) all-templates)
|
||||
(update-vals
|
||||
(fn [templates]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.models.action
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[medley.core :as m]
|
||||
[metabase.models.card :refer [Card]]
|
||||
[metabase.models.interface :as mi]
|
||||
@@ -8,6 +7,7 @@
|
||||
[metabase.models.serialization :as serdes]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[methodical.core :as methodical]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.models.cloud-migration
|
||||
"A model representing a migration to cloud."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.set :as set]
|
||||
@@ -14,6 +13,7 @@
|
||||
[metabase.models.setting.cache :as setting.cache]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[methodical.core :as methodical]
|
||||
[toucan2.core :as t2]
|
||||
@@ -222,7 +222,7 @@
|
||||
{:form-params {:part_count (count parts)}
|
||||
:content-type :json})
|
||||
:body
|
||||
(json/parse-string keyword))
|
||||
json/decode+kw)
|
||||
|
||||
etags
|
||||
(->> (map (fn [[start end] [part-number url]]
|
||||
@@ -294,7 +294,7 @@
|
||||
(config/mb-version-info :tag))}
|
||||
:content-type :json})
|
||||
:body
|
||||
(json/parse-string keyword)
|
||||
json/decode+kw
|
||||
(select-keys [:id :upload_url])
|
||||
(set/rename-keys {:id :external_id})))
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.models.interface
|
||||
(:require
|
||||
[buddy.core.codecs :as codecs]
|
||||
[cheshire.core :as json]
|
||||
[cheshire.generate :as json.generate]
|
||||
[clojure.core.memoize :as memoize]
|
||||
[clojure.spec.alpha :as s]
|
||||
@@ -20,6 +19,7 @@
|
||||
[metabase.util.cron :as u.cron]
|
||||
[metabase.util.encryption :as encryption]
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
@@ -133,12 +133,12 @@
|
||||
[obj]
|
||||
(if (string? obj)
|
||||
obj
|
||||
(json/generate-string obj)))
|
||||
(json/encode obj)))
|
||||
|
||||
(defn- json-out [s keywordize-keys?]
|
||||
(if (string? s)
|
||||
(try
|
||||
(json/parse-string s keywordize-keys?)
|
||||
(json/decode s keywordize-keys?)
|
||||
(catch Throwable e
|
||||
(log/error e "Error parsing JSON")
|
||||
s))
|
||||
@@ -299,7 +299,7 @@
|
||||
[v]
|
||||
(let [decrypted (encryption/maybe-decrypt v)]
|
||||
(try
|
||||
(json/parse-string decrypted true)
|
||||
(json/decode+kw decrypted)
|
||||
(catch Throwable e
|
||||
(if (or (encryption/possibly-encrypted-string? decrypted)
|
||||
(encryption/possibly-encrypted-bytes? decrypted))
|
||||
@@ -321,7 +321,7 @@
|
||||
to modern MBQL clauses so things work correctly."
|
||||
[viz-settings]
|
||||
(letfn [(normalize-column-settings-key [k]
|
||||
(some-> k u/qualified-name json/parse-string mbql.normalize/normalize json/generate-string))
|
||||
(some-> k u/qualified-name json/decode mbql.normalize/normalize json/encode))
|
||||
(normalize-column-settings [column-settings]
|
||||
(into {} (for [[k v] column-settings]
|
||||
[(normalize-column-settings-key k) (walk/keywordize-keys v)])))
|
||||
@@ -727,9 +727,12 @@
|
||||
[instance json-generator]
|
||||
(json.generate/encode-map instance json-generator))
|
||||
|
||||
(json.generate/add-encoder
|
||||
Instance
|
||||
#'to-json)
|
||||
;; Needed for json/add-encoder because Jsonista doesn't accept mutimethods.
|
||||
(defn- to-json-function [instance json-generator]
|
||||
(to-json instance json-generator))
|
||||
|
||||
(json.generate/add-encoder Instance #'to-json-function)
|
||||
(json/add-encoder Instance to-json-function)
|
||||
|
||||
;;;; etc
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.models.query
|
||||
"Functions related to the 'Query' model, which records stuff such as average query execution time."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.walk :as walk]
|
||||
[metabase.db :as mdb]
|
||||
[metabase.lib.core :as lib]
|
||||
@@ -10,6 +9,7 @@
|
||||
[metabase.lib.util :as lib.util]
|
||||
[metabase.models.interface :as mi]
|
||||
[metabase.util.honey-sql-2 :as h2x]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -63,7 +63,7 @@
|
||||
;; new entries, so at some point in the future we can take this out, and save a DB call.
|
||||
(pos? (t2/update! Query
|
||||
{:query_hash query-hash, :query nil}
|
||||
{:query (json/generate-string query)
|
||||
{:query (json/encode query)
|
||||
:average_execution_time avg-execution-time}))
|
||||
;; if query is already set then just update average_execution_time. (We're doing this separate call to avoid
|
||||
;; updating query on every single UPDATE)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
(ns metabase.models.revision
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.data :as data]
|
||||
[metabase.config :as config]
|
||||
[metabase.models.interface :as mi]
|
||||
[metabase.models.revision.diff :refer [diff-strings*]]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]
|
||||
[methodical.core :as methodical]
|
||||
[toucan2.core :as t2]
|
||||
@@ -201,8 +201,8 @@
|
||||
;; even though we call `post-select` on the `object`, the nested object might not be transformed correctly
|
||||
;; E.g: Cards inside Dashboard will not be transformed
|
||||
;; so to be safe, we'll just compare them as string
|
||||
(when-not (= (json/generate-string serialized-object)
|
||||
(json/generate-string last-object))
|
||||
(when-not (= (json/encode serialized-object)
|
||||
(json/encode last-object))
|
||||
(t2/insert! Revision
|
||||
:model entity-name
|
||||
:model_id id
|
||||
|
||||
@@ -53,7 +53,6 @@
|
||||
format distinguishes between `nil` and absence)"
|
||||
(:refer-clojure :exclude [descendants])
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.core.match :refer [match]]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]
|
||||
@@ -65,6 +64,7 @@
|
||||
[metabase.models.visualization-settings :as mb.viz]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[toucan2.core :as t2]
|
||||
[toucan2.model :as t2.model]
|
||||
@@ -1315,18 +1315,18 @@
|
||||
Returns a new JSON string with the IDs converted inside."
|
||||
[json-str]
|
||||
(-> json-str
|
||||
(json/parse-string true)
|
||||
json/decode+kw
|
||||
ids->fully-qualified-names
|
||||
json/generate-string))
|
||||
json/encode))
|
||||
|
||||
(defn- json-mbql-fully-qualified-names->ids
|
||||
"Converts fully qualified names to IDs in MBQL embedded inside a JSON string.
|
||||
Returns a new JSON string with teh IDs converted inside."
|
||||
[json-str]
|
||||
(-> json-str
|
||||
(json/parse-string true)
|
||||
json/decode+kw
|
||||
mbql-fully-qualified-names->ids
|
||||
json/generate-string))
|
||||
json/encode))
|
||||
|
||||
(defn- export-viz-click-behavior-link
|
||||
[{:keys [linkType type] :as click-behavior}]
|
||||
@@ -1431,7 +1431,7 @@
|
||||
[settings]
|
||||
(when settings
|
||||
(-> settings
|
||||
(update-keys #(-> % json/parse-string export-visualizations json/generate-string))
|
||||
(update-keys #(-> % json/decode export-visualizations json/encode))
|
||||
(update-vals export-viz-click-behavior))))
|
||||
|
||||
(defn export-visualization-settings
|
||||
@@ -1479,7 +1479,7 @@
|
||||
(defn- import-column-settings [settings]
|
||||
(when settings
|
||||
(-> settings
|
||||
(update-keys #(-> % name json/parse-string import-visualizations json/generate-string))
|
||||
(update-keys #(-> % name json/decode import-visualizations json/encode))
|
||||
(update-vals import-viz-click-behavior))))
|
||||
|
||||
(defn import-visualization-settings
|
||||
@@ -1520,7 +1520,7 @@
|
||||
(let [column-settings-keys-deps (some->> viz
|
||||
:column_settings
|
||||
keys
|
||||
(map (comp mbql-deps json/parse-string name)))
|
||||
(map (comp mbql-deps json/decode name)))
|
||||
column-settings-vals-deps (some->> viz
|
||||
:column_settings
|
||||
vals
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
See #14055 and #19399 for more information about and motivation behind User- and Database-local Settings."
|
||||
(:refer-clojure :exclude [get])
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.core :as core]
|
||||
[clojure.data :as data]
|
||||
[clojure.data.csv :as csv]
|
||||
@@ -92,6 +91,7 @@
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.encryption :as encryption]
|
||||
[metabase.util.i18n :refer [deferred-trs deferred-tru trs tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[methodical.core :as methodical]
|
||||
@@ -419,7 +419,7 @@
|
||||
;; Update the atom in *user-local-values* with the new value before writing to the DB. This ensures that
|
||||
;; subsequent setting updates within the same API request will not overwrite this value.
|
||||
(swap! @*user-local-values* u/assoc-dissoc setting-name value)
|
||||
(t2/update! 'User api/*current-user-id* {:settings (json/generate-string @@*user-local-values*)})))
|
||||
(t2/update! 'User api/*current-user-id* {:settings (json/encode @@*user-local-values*)})))
|
||||
|
||||
(def ^:dynamic *enforce-setting-access-checks*
|
||||
"A dynamic var that controls whether we should enforce checks on setting access. Defaults to false; should be
|
||||
@@ -689,7 +689,7 @@
|
||||
|
||||
(defmethod get-value-of-type :json
|
||||
[_setting-type setting-definition-or-name]
|
||||
(get-raw-value setting-definition-or-name coll? #(json/parse-string-strict % true)))
|
||||
(get-raw-value setting-definition-or-name coll? json/decode+kw))
|
||||
|
||||
(defmethod get-value-of-type :csv
|
||||
[_setting-type setting-definition-or-name]
|
||||
@@ -865,7 +865,7 @@
|
||||
[_setting-type setting-definition-or-name new-value]
|
||||
(set-value-of-type!
|
||||
:string setting-definition-or-name
|
||||
(some-> new-value json/generate-string)))
|
||||
(some-> new-value json/encode)))
|
||||
|
||||
(defmethod set-value-of-type! :timestamp
|
||||
[_setting-type setting-definition-or-name new-value]
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
[metabase.models.permissions :as perms]
|
||||
[metabase.public-settings.premium-features :as premium-features]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[methodical.core :as methodical]
|
||||
@@ -160,3 +161,7 @@
|
||||
Throwable
|
||||
(fn [throwable json-generator]
|
||||
(encode-map (Throwable->map throwable) json-generator)))
|
||||
(json/add-encoder
|
||||
Throwable
|
||||
(fn [throwable json-generator]
|
||||
(encode-map (Throwable->map throwable) json-generator)))
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
(ns metabase.models.user-parameter-value
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[medley.core :as m]
|
||||
[metabase.api.common :as api]
|
||||
[metabase.models.interface :as mi]
|
||||
[metabase.util.grouper :as grouper]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -24,7 +24,7 @@
|
||||
[s]
|
||||
(if (string? s)
|
||||
(try
|
||||
(json/parse-string s true)
|
||||
(json/decode+kw s)
|
||||
(catch Throwable _e
|
||||
s))
|
||||
s))
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
#?@
|
||||
(:clj
|
||||
[(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.set :as set]
|
||||
[clojure.spec.alpha :as s]
|
||||
[medley.core :as m]
|
||||
[metabase.legacy-mbql.normalize :as mbql.normalize])]
|
||||
[metabase.legacy-mbql.normalize :as mbql.normalize]
|
||||
[metabase.util.json :as json])]
|
||||
:cljs
|
||||
[(:require
|
||||
[clojure.set :as set]
|
||||
@@ -165,7 +165,7 @@
|
||||
"Parse the given `json-str` to a map. In Clojure, this uses Cheshire. In Clojurescript, it calls `.parse` with
|
||||
`js/JSON` and threads that to `js->clj`."
|
||||
[json-str]
|
||||
#?(:clj (json/parse-string json-str)
|
||||
#?(:clj (json/decode json-str)
|
||||
:cljs (-> (.parse js/JSON json-str)
|
||||
js->clj)))
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.public-settings.premium-features
|
||||
"Settings related to checking premium token validity and which premium features it allows."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.core.memoize :as memoize]
|
||||
[clojure.spec.alpha :as s]
|
||||
@@ -16,6 +15,7 @@
|
||||
[metabase.plugins.classloader :as classloader]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru trs tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -130,9 +130,9 @@
|
||||
:mb-version (:tag config/mb-version-info)}
|
||||
:throw-exceptions false}))]
|
||||
(cond
|
||||
(http/success? resp) (some-> body (json/parse-string keyword))
|
||||
(http/success? resp) (some-> body json/decode+kw)
|
||||
|
||||
(<= 400 status 499) (some-> body (json/parse-string keyword))
|
||||
(<= 400 status 499) (some-> body json/decode+kw)
|
||||
|
||||
;; exceptions are not cached.
|
||||
:else (throw (ex-info "An unknown error occurred when validating token." {:status status
|
||||
@@ -223,7 +223,7 @@
|
||||
;; complicated
|
||||
(catch Exception e2
|
||||
(log/errorf e2 "Error fetching token status from %s:" store-url)
|
||||
(let [body (u/ignore-exceptions (some-> (ex-data e1) :body (json/parse-string keyword)))]
|
||||
(let [body (u/ignore-exceptions (some-> (ex-data e1) :body json/decode+kw))]
|
||||
(or
|
||||
body
|
||||
{:valid false
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
"Namespaces that uses the Nashorn javascript engine to invoke some shared javascript code that we use to determine
|
||||
the background color of pulse table cells"
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.java.io :as io]
|
||||
[metabase.formatter]
|
||||
[metabase.pulse.render.js-engine :as js]
|
||||
[metabase.util.i18n :refer [trs]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu])
|
||||
(:import
|
||||
(metabase.formatter NumericWrapper)))
|
||||
@@ -48,8 +48,8 @@
|
||||
;; code
|
||||
(js/execute-fn-name (js-engine) "makeCellBackgroundGetter"
|
||||
rows
|
||||
(json/generate-string cols)
|
||||
(json/generate-string viz-settings)))
|
||||
(json/encode cols)
|
||||
(json/encode viz-settings)))
|
||||
|
||||
(defn get-background-color
|
||||
"Get the correct color for a cell in a pulse table. Returns color as string suitable for use CSS, e.g. a hex string or
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
strange, as the jvm datastructures, not just serialized versions are used. This is why we have the `toJSArray` and
|
||||
`toJSMap` functions to turn Clojure's normal datastructures into js native structures."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[metabase.config :as config]
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.pulse.render.js-engine :as js]
|
||||
[metabase.pulse.render.style :as style])
|
||||
[metabase.pulse.render.style :as style]
|
||||
[metabase.util.json :as json])
|
||||
(:import
|
||||
(java.io ByteArrayInputStream ByteArrayOutputStream)
|
||||
(java.nio.charset StandardCharsets)
|
||||
@@ -141,36 +141,36 @@
|
||||
"Clojure entrypoint to render a funnel chart. Data should be vec of [[Step Measure]] where Step is {:name name :format format-options} and Measure is {:format format-options} and you go and look to frontend/src/metabase/static-viz/components/FunnelChart/types.ts for the actual format options.
|
||||
Returns a byte array of a png file."
|
||||
[data settings]
|
||||
(let [svg-string (.asString (js/execute-fn-name (context) "funnel" (json/generate-string data)
|
||||
(json/generate-string settings)))]
|
||||
(let [svg-string (.asString (js/execute-fn-name (context) "funnel" (json/encode data)
|
||||
(json/encode settings)))]
|
||||
(svg-string->bytes svg-string)))
|
||||
|
||||
(defn javascript-visualization
|
||||
"Clojure entrypoint to render javascript visualizations."
|
||||
[cards-with-data dashcard-viz-settings]
|
||||
(let [response (.asString (js/execute-fn-name (context) "javascript_visualization"
|
||||
(json/generate-string cards-with-data)
|
||||
(json/generate-string dashcard-viz-settings)
|
||||
(json/generate-string (public-settings/application-colors))))]
|
||||
(json/encode cards-with-data)
|
||||
(json/encode dashcard-viz-settings)
|
||||
(json/encode (public-settings/application-colors))))]
|
||||
(-> response
|
||||
(json/parse-string true)
|
||||
json/decode+kw
|
||||
(update :type (fnil keyword "unknown")))))
|
||||
|
||||
(defn row-chart
|
||||
"Clojure entrypoint to render a row chart."
|
||||
[settings data]
|
||||
(let [svg-string (.asString (js/execute-fn-name (context) "row_chart"
|
||||
(json/generate-string settings)
|
||||
(json/generate-string data)
|
||||
(json/generate-string (public-settings/application-colors))))]
|
||||
(json/encode settings)
|
||||
(json/encode data)
|
||||
(json/encode (public-settings/application-colors))))]
|
||||
(svg-string->bytes svg-string)))
|
||||
|
||||
(defn gauge
|
||||
"Clojure entrypoint to render a gauge chart. Returns a byte array of a png file"
|
||||
[card data]
|
||||
(let [js-res (js/execute-fn-name (context) "gauge"
|
||||
(json/generate-string card)
|
||||
(json/generate-string data))
|
||||
(json/encode card)
|
||||
(json/encode data))
|
||||
svg-string (.asString js-res)]
|
||||
(svg-string->bytes svg-string)))
|
||||
|
||||
@@ -178,9 +178,9 @@
|
||||
"Clojure entrypoint to render a progress bar. Returns a byte array of a png file"
|
||||
[value goal settings]
|
||||
(let [js-res (js/execute-fn-name (context) "progress"
|
||||
(json/generate-string {:value value :goal goal})
|
||||
(json/generate-string settings)
|
||||
(json/generate-string (public-settings/application-colors)))
|
||||
(json/encode {:value value :goal goal})
|
||||
(json/encode settings)
|
||||
(json/encode (public-settings/application-colors)))
|
||||
svg-string (.asString js-res)]
|
||||
(svg-string->bytes svg-string)))
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.query-processor.streaming.xlsx
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
[dk.ative.docjure.spreadsheet :as spreadsheet]
|
||||
@@ -15,7 +14,8 @@
|
||||
[metabase.util :as u]
|
||||
[metabase.util.currency :as currency]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.i18n :refer [tru]])
|
||||
[metabase.util.i18n :refer [tru]]
|
||||
[metabase.util.json :as json])
|
||||
(:import
|
||||
(java.io OutputStream)
|
||||
(java.time LocalDate LocalDateTime LocalTime OffsetDateTime OffsetTime ZonedDateTime)
|
||||
@@ -368,8 +368,8 @@
|
||||
;; stick the object in a JSON map and encode it, which will force conversion to a string. Then unparse that JSON and
|
||||
;; use the resulting value as the cell's new String value. There might be some more efficient way of doing this but
|
||||
;; I'm not sure what it is.
|
||||
(.setCellValue cell (str (-> (json/generate-string {:v value})
|
||||
(json/parse-string keyword)
|
||||
(.setCellValue cell (str (-> (json/encode {:v value})
|
||||
json/decode+kw
|
||||
:v))))
|
||||
|
||||
(defmethod set-cell! nil [^Cell cell _value _styles _typed-styles]
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
(:require
|
||||
[buddy.core.codecs :as codecs]
|
||||
[buddy.core.hash :as buddy-hash]
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[clojure.walk :as walk]
|
||||
[medley.core :as m]
|
||||
@@ -14,6 +13,7 @@
|
||||
[metabase.lib.schema.util :as lib.schema.util]
|
||||
[metabase.query-processor.schema :as qp.schema]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
@@ -114,7 +114,7 @@
|
||||
(throw (ex-info "Error hashing query. Is this a valid query?"
|
||||
{:query query}
|
||||
e))))]
|
||||
(buddy-hash/sha3-256 (json/generate-string (select-keys-for-hashing query)))))
|
||||
(buddy-hash/sha3-256 (json/encode (select-keys-for-hashing query)))))
|
||||
|
||||
;;; --------------------------------------------- Query Source Card IDs ----------------------------------------------
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.search.config
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[flatland.ordered.map :as ordered-map]
|
||||
[metabase.api.common :as api]
|
||||
@@ -8,6 +7,7 @@
|
||||
[metabase.permissions.util :as perms.u]
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]))
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
|
||||
(defmethod column->string [:card :dataset_query]
|
||||
[value _ _]
|
||||
(let [query (json/parse-string value true)]
|
||||
(let [query (json/decode+kw value)]
|
||||
(if (= "native" (:type query))
|
||||
(-> query :native :query)
|
||||
"")))
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.search.impl
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[metabase.db :as mdb]
|
||||
[metabase.legacy-mbql.normalize :as mbql.normalize]
|
||||
@@ -20,6 +19,7 @@
|
||||
[metabase.search.fulltext :as search.fulltext]
|
||||
[metabase.search.scoring :as scoring]
|
||||
[metabase.util.i18n :refer [tru deferred-tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
@@ -174,7 +174,7 @@
|
||||
{:effective_ancestors collection_effective_ancestors})))
|
||||
:scores (remove-thunks all-scores))
|
||||
(update :dataset_query (fn [dataset-query]
|
||||
(when-let [query (some-> dataset-query json/parse-string)]
|
||||
(when-let [query (some-> dataset-query json/decode)]
|
||||
(if (get query "type")
|
||||
(mbql.normalize/normalize query)
|
||||
(not-empty (lib/normalize query))))))
|
||||
@@ -341,7 +341,7 @@
|
||||
(defn- normalize-result-more
|
||||
"Additional normalization that is done after we've filtered by permissions, as its more expensive."
|
||||
[search-ctx result]
|
||||
(->> (update result :pk_ref json/parse-string)
|
||||
(->> (update result :pk_ref json/decode)
|
||||
(add-can-write search-ctx)))
|
||||
|
||||
(defn- search-results [search-ctx model-set-fn total-results]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.search.postgres.core
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[honey.sql :as sql]
|
||||
[honey.sql.helpers :as sql.helpers]
|
||||
[metabase.api.common :as api]
|
||||
@@ -8,6 +7,7 @@
|
||||
[metabase.search.legacy :as search.legacy]
|
||||
[metabase.search.postgres.index :as search.index]
|
||||
[metabase.search.postgres.ingestion :as search.ingestion]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.core :as t2])
|
||||
(:import
|
||||
(java.time OffsetDateTime)))
|
||||
@@ -97,7 +97,7 @@
|
||||
(->> (assoc (search.index/search-query search-term) :select [:legacy_input])
|
||||
(t2/query)
|
||||
(map :legacy_input)
|
||||
(map #(json/parse-string % keyword))
|
||||
(map json/decode+kw)
|
||||
(map #(-> %
|
||||
(update :created_at parse-datetime)
|
||||
(update :updated_at parse-datetime)
|
||||
@@ -123,7 +123,7 @@
|
||||
search-ctx)
|
||||
(t2/query)
|
||||
(map :legacy_input)
|
||||
(map #(json/parse-string % keyword))
|
||||
(map json/decode+kw)
|
||||
(map #(-> %
|
||||
(update :created_at parse-datetime)
|
||||
(update :updated_at parse-datetime)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
(ns metabase.search.postgres.index
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[honey.sql.helpers :as sql.helpers]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(def ^:private active-table :search_index)
|
||||
@@ -94,8 +94,8 @@
|
||||
:legacy_input
|
||||
:table_id
|
||||
:archived])
|
||||
(update :display_data json/generate-string)
|
||||
(update :legacy_input json/generate-string)
|
||||
(update :display_data json/encode)
|
||||
(update :legacy_input json/encode)
|
||||
(assoc
|
||||
:model_id (:id entity)
|
||||
:search_vector [:to_tsvector
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.server.request.util
|
||||
"Utility functions for Ring requests."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.string :as str]
|
||||
[java-time.api :as t]
|
||||
@@ -9,6 +8,7 @@
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [trs tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
@@ -162,7 +162,7 @@
|
||||
:socket-timeout gecode-ip-address-timeout-ms
|
||||
:connection-timeout gecode-ip-address-timeout-ms})
|
||||
:body
|
||||
(json/parse-string true))]
|
||||
json/decode+kw)]
|
||||
(into {} (for [info response]
|
||||
[(:ip info) {:description (or (describe-location info)
|
||||
"Unknown location")
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
`resources/frontend_client/index_template.html`; when the frontend is built (e.g. via `./bin/build.sh frontend`)
|
||||
different versions that include the FE app are created as `index.html`, `public.html`, and `embed.html`."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
[hiccup.util]
|
||||
@@ -12,6 +11,7 @@
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.util.embed :as embed]
|
||||
[metabase.util.i18n :as i18n :refer [trs]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[ring.util.response :as response]
|
||||
[stencil.core :as stencil])
|
||||
@@ -30,7 +30,7 @@
|
||||
(str/replace s #"(?i)</script" "</scr\\\\ipt"))
|
||||
|
||||
(defn- fallback-localization [locale-or-name]
|
||||
(json/generate-string
|
||||
(json/encode
|
||||
{"headers"
|
||||
{"language" (str locale-or-name)
|
||||
"plural-forms" "nplurals=2; plural=(n != 1);"}
|
||||
@@ -80,11 +80,11 @@
|
||||
(str "frontend_client/" entrypoint-name ".html")
|
||||
(let [{:keys [anon-tracking-enabled google-auth-client-id], :as public-settings} (setting/user-readable-values-map #{:public})]
|
||||
{:bootstrapJS (load-inline-js "index_bootstrap")
|
||||
:bootstrapJSON (escape-script (json/generate-string public-settings))
|
||||
:bootstrapJSON (escape-script (json/encode public-settings))
|
||||
:assetOnErrorJS (load-inline-js "asset_loading_error")
|
||||
:userLocalizationJSON (escape-script (load-localization (:locale params)))
|
||||
:siteLocalizationJSON (escape-script (load-localization (public-settings/site-locale)))
|
||||
:nonceJSON (escape-script (json/generate-string nonce))
|
||||
:nonceJSON (escape-script (json/encode nonce))
|
||||
:language (hiccup.util/escape-html (public-settings/site-locale))
|
||||
:favicon (hiccup.util/escape-html (public-settings/application-favicon-url))
|
||||
:applicationName (hiccup.util/escape-html (public-settings/application-name))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.task.upgrade-checks
|
||||
"Contains a Metabase task which periodically checks for the availability of new Metabase versions."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.string :as str]
|
||||
[clojurewerkz.quartzite.jobs :as jobs]
|
||||
@@ -12,6 +11,7 @@
|
||||
[metabase.config :as config]
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.task :as task]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
@@ -29,7 +29,7 @@
|
||||
"channel" (public-settings/update-channel)})})))]
|
||||
(when (not= status 200)
|
||||
(throw (Exception. (format "[%d]: %s" status body))))
|
||||
(json/parse-string body keyword)))
|
||||
(json/decode+kw body)))
|
||||
|
||||
(jobs/defjob ^{:doc "Simple job which looks up all databases and runs a sync on them"} CheckForNewVersions [_]
|
||||
(when (public-settings/check-for-updates)
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
(:require
|
||||
[buddy.core.codecs :as codecs]
|
||||
[buddy.sign.jwt :as jwt]
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[hiccup.core :refer [html]]
|
||||
[metabase.config :as config]
|
||||
@@ -12,6 +11,7 @@
|
||||
[metabase.public-settings.premium-features :as premium-features]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.i18n :refer [deferred-tru trs tru]]
|
||||
[metabase.util.json :as json]
|
||||
[ring.util.codec :as codec]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
@@ -71,7 +71,7 @@
|
||||
"Parse a JWT `message` and return the header portion."
|
||||
[^String message]
|
||||
(let [[header] (str/split message #"\.")]
|
||||
(json/parse-string (codecs/bytes->str (codec/base64-decode header)) keyword)))
|
||||
(json/decode+kw (codecs/bytes->str (codec/base64-decode header)))))
|
||||
|
||||
(defn- check-valid-alg
|
||||
"Check that the JWT `alg` isn't `none`. `none` is valid per the standard, but for obvious reasons we want to make sure
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
(ns metabase.util.http
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[medley.core :as m]))
|
||||
[medley.core :as m]
|
||||
[metabase.util.json :as json]))
|
||||
|
||||
(defn- parse-http-headers [headers]
|
||||
(json/parse-string headers))
|
||||
(json/decode headers))
|
||||
|
||||
(defn ^:dynamic *fetch-as-json*
|
||||
"Fetches url and parses body as json, returning it."
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
[clojure.string :as str]
|
||||
[clojure.walk :as walk]
|
||||
[metabase.util.i18n.impl :as i18n.impl]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[net.cgrand.macrovich :as macros]
|
||||
[potemkin :as p]
|
||||
@@ -103,6 +104,8 @@
|
||||
|
||||
(json.generate/add-encoder UserLocalizedString localized-to-json)
|
||||
(json.generate/add-encoder SiteLocalizedString localized-to-json)
|
||||
(json/add-encoder SiteLocalizedString localized-to-json)
|
||||
(json/add-encoder SiteLocalizedString localized-to-json)
|
||||
|
||||
(def LocalizedString
|
||||
"Schema for user and system localized string instances"
|
||||
|
||||
87
src/metabase/util/json.clj
Normal file
87
src/metabase/util/json.clj
Normal file
@@ -0,0 +1,87 @@
|
||||
(ns metabase.util.json
|
||||
"Functions for encoding and decoding JSON that abstract away the underlying implementation."
|
||||
(:require [jsonista.core :as jsonista])
|
||||
(:import clojure.lang.IType
|
||||
com.fasterxml.jackson.core.JsonGenerator))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
(defn- byte-array-encoder
|
||||
"For binary arrays ([B), hex-encode their first four bytes, e.g. \"0xC42360D7\"."
|
||||
[arr ^JsonGenerator generator]
|
||||
(.writeString generator ^String (apply format "0x%02X%02X%02X%02X" (take 4 arr))))
|
||||
|
||||
;; Always fall back to `.toString` instead of barfing. In some cases we should be able to improve upon this behavior;
|
||||
;; `.toString` may just return the Class and address, e.g. `some.Class@72a8b25e`
|
||||
;; The following are known few classes where `.toString` is the optimal behavior:
|
||||
;; * `org.postgresql.jdbc4.Jdbc4Array` (Postgres arrays)
|
||||
;; * `org.bson.types.ObjectId` (Mongo BSON IDs)
|
||||
;; * `java.sql.Date` (SQL Dates -- .toString returns YYYY-MM-DD)
|
||||
(defn- fallback-object-encoder [obj ^JsonGenerator generator]
|
||||
(.writeString generator (str obj)))
|
||||
|
||||
(deftype RawJson [^String s])
|
||||
|
||||
(defn- raw-json-encoder [^RawJson raw ^JsonGenerator generator]
|
||||
(.writeRawValue generator ^String (.s raw)))
|
||||
|
||||
(defn raw
|
||||
"Wrap a string so it will be spliced directly into resulting JSON as-is. Analogous to HoneySQL `raw`."
|
||||
[^String s]
|
||||
(->RawJson s))
|
||||
|
||||
(defonce ^:private encoders
|
||||
(atom {(Class/forName "[B") byte-array-encoder
|
||||
IType fallback-object-encoder
|
||||
RawJson raw-json-encoder}))
|
||||
|
||||
(defn object-mapper
|
||||
"Create a new Jackson ObjectMapper object using the default global encoders. For supported options, see
|
||||
`jsonista.core/object-mapper`."
|
||||
[options-map]
|
||||
(jsonista/object-mapper (-> options-map
|
||||
(assoc :encoders @encoders)
|
||||
(update :do-not-fail-on-empty-beans #(if (nil? %) true %)))))
|
||||
|
||||
(def ^:private global-mapper
|
||||
"Jsonista doesn't have a concept of a \"global\" object mapper like Cheshire does, so we simulate it here. The object
|
||||
mapper defined in this namespace must be used for all encoding and decoding work around Metabase, and hence, the
|
||||
functions from this namespace should be used everywhere instead of jsonista.core functions."
|
||||
(atom (object-mapper {})))
|
||||
|
||||
(def ^:private global-mapper-keywordize-keys
|
||||
(atom (object-mapper {:decode-key-fn true})))
|
||||
|
||||
(defn add-encoder
|
||||
"Register `encoder` for `class` in `global-mapper`."
|
||||
[class encoder]
|
||||
(swap! encoders assoc class encoder)
|
||||
(reset! global-mapper (object-mapper {}))
|
||||
(reset! global-mapper-keywordize-keys (object-mapper {:decode-key-fn true})))
|
||||
|
||||
(defn encode
|
||||
"Return a JSON-encoding String for the given object. 1-arity uses `global-mapper`."
|
||||
(^String [obj]
|
||||
(jsonista/write-value-as-string obj @global-mapper))
|
||||
(^String [obj mapper]
|
||||
(jsonista/write-value-as-string obj mapper)))
|
||||
|
||||
(defn encode-to
|
||||
"Encode a value as JSON and write using the provided WriteValue instance.
|
||||
By default, File, OutputStream, DataOutput and Writer are supported. Uses `global-mapper`."
|
||||
[to obj]
|
||||
(jsonista/write-value to obj @global-mapper))
|
||||
|
||||
(defn decode
|
||||
"Decode a value from a JSON from anything that satisfies Jsonista's ReadValue protocol. By default, File, URL, String,
|
||||
Reader and InputStream are supported. Uses `global-mapper`."
|
||||
([source]
|
||||
(jsonista/read-value source @global-mapper))
|
||||
([source key-fn]
|
||||
(jsonista/read-value source (object-mapper {:decode-key-fn key-fn}))))
|
||||
|
||||
(defn decode+kw
|
||||
"Decode a value from a JSON from anything that satisfies Jsonista's ReadValue protocol, keywordizing the map keys. By
|
||||
default, File, URL, String, Reader and InputStream are supported. Uses `global-mapper-keywordize-keys`."
|
||||
[source]
|
||||
(jsonista/read-value source @global-mapper-keywordize-keys))
|
||||
@@ -4,7 +4,6 @@
|
||||
For example the PositiveInt can be defined as (mr/def ::positive-int pos-int?)
|
||||
"
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[malli.core :as mc]
|
||||
[metabase.legacy-mbql.normalize :as mbql.normalize]
|
||||
@@ -15,6 +14,7 @@
|
||||
[metabase.util :as u]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.i18n :as i18n :refer [deferred-tru]]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.password :as u.password]))
|
||||
|
||||
@@ -261,7 +261,7 @@
|
||||
[:and
|
||||
:string
|
||||
[:fn #(try
|
||||
(json/parse-string %)
|
||||
(json/decode %)
|
||||
true
|
||||
(catch Throwable _
|
||||
false))]]
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns metabase.xrays.automagic-dashboards.util
|
||||
(:require
|
||||
[buddy.core.codecs :as codecs]
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[medley.core :as m]
|
||||
[metabase.analyze :as analyze]
|
||||
@@ -12,6 +11,7 @@
|
||||
[metabase.models.field :refer [Field]]
|
||||
[metabase.models.interface :as mi]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.log :as log]
|
||||
[metabase.util.malli :as mu]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.analytics.snowplow-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.test :refer :all]
|
||||
[clojure.walk :as walk]
|
||||
[metabase.analytics.snowplow :as snowplow]
|
||||
@@ -10,6 +9,7 @@
|
||||
[metabase.test.fixtures :as fixtures]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.date-2 :as u.date]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.core :as t2])
|
||||
(:import
|
||||
(com.snowplowanalytics.snowplow.tracker.events SelfDescribing)
|
||||
@@ -38,7 +38,7 @@
|
||||
;; cases
|
||||
properties (-> (or (:ue_pr payload)
|
||||
(u/decode-base64 (:ue_px payload)))
|
||||
json/parse-string)
|
||||
json/decode)
|
||||
subject (when-let [subject (.getSubject event)]
|
||||
(-> subject .getSubject normalize-map))
|
||||
[^SelfDescribingJson context-json] (.getContext event)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns ^:mb/driver-tests metabase.analyze.fingerprint.fingerprinters-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[clojure.test :refer :all]
|
||||
[metabase.analyze.fingerprint.fingerprinters :as fingerprinters]
|
||||
@@ -8,6 +7,7 @@
|
||||
[metabase.models.field :as field :refer [Field]]
|
||||
[metabase.models.interface :as mi]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
@@ -124,7 +124,7 @@
|
||||
(transduce identity
|
||||
(fingerprinters/fingerprinter (mi/instance Field {:base_type :type/Text}))
|
||||
["metabase" "more" "like" "metabae" "[1, 2, 3]"])))
|
||||
(let [truncated-json (subs (json/generate-string (vec (range 50))) 0 30)]
|
||||
(let [truncated-json (subs (json/encode (vec (range 50))) 0 30)]
|
||||
(is (= {:global {:distinct-count 5
|
||||
:nil% 0.0}
|
||||
:type {:type/Text {:percent-json 0.2
|
||||
@@ -178,7 +178,7 @@
|
||||
(deftest ^:parallel valid-serialized-json?-test
|
||||
(testing "recognizes substrings of json"
|
||||
(letfn [(partial-json [x]
|
||||
(let [json (json/generate-string x)]
|
||||
(let [json (json/encode x)]
|
||||
(subs json 0 (/ (count json) 2))))]
|
||||
(are [x] (#'fingerprinters/valid-serialized-json? (partial-json x))
|
||||
[1 2 3]
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns ^:mb/driver-tests metabase.api.action-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.set :as set]
|
||||
[clojure.test :refer :all]
|
||||
[metabase.analytics.snowplow-test :as snowplow-test]
|
||||
@@ -10,6 +9,7 @@
|
||||
[metabase.test :as mt]
|
||||
[metabase.test.fixtures :as fixtures]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]
|
||||
[toucan2.tools.with-temp :as t2.with-temp]))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns ^:mb/driver-tests metabase.api.card-test
|
||||
"Tests for /api/card endpoints."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.data.csv :as csv]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]
|
||||
@@ -43,6 +42,7 @@
|
||||
[metabase.test.data.users :as test.users]
|
||||
[metabase.upload-test :as upload-test]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.core :as t2]
|
||||
[toucan2.tools.with-temp :as t2.with-temp])
|
||||
(:import
|
||||
@@ -2040,9 +2040,9 @@
|
||||
|
||||
;;; Test GET /api/card/:id/query/csv & GET /api/card/:id/json & GET /api/card/:id/query/xlsx **WITH PARAMETERS**
|
||||
(def ^:private ^:const ^String encoded-params
|
||||
(json/generate-string [{:type :number
|
||||
:target [:variable [:template-tag :category]]
|
||||
:value 2}]))
|
||||
(json/encode [{:type :number
|
||||
:target [:variable [:template-tag :category]]
|
||||
:value 2}]))
|
||||
|
||||
(deftest csv-download-test
|
||||
(testing "no parameters"
|
||||
@@ -2461,7 +2461,7 @@
|
||||
[url]
|
||||
(-> (client/client-full-response (test.users/username->token :rasta)
|
||||
:post 200 url
|
||||
:query (json/generate-string (mt/mbql-query checkins {:limit 1})))
|
||||
:query (json/encode (mt/mbql-query checkins {:limit 1})))
|
||||
:headers
|
||||
(select-keys ["Cache-Control" "Content-Disposition" "Content-Type" "Expires" "X-Accel-Buffering"])
|
||||
(update "Content-Disposition" #(some-> % (str/replace #"my_awesome_card_.+(\.\w+)"
|
||||
@@ -3603,16 +3603,17 @@
|
||||
:display :table
|
||||
:visualization_settings
|
||||
{:column_settings
|
||||
{"[\"name\",\"NUMBER\"]" {:column_title "Custom Title"}
|
||||
"[\"name\",\"DATE\"]" {:column_title "Custom Title 2"}}}}]
|
||||
{(json/encode ["name" "NUMBER"]) {:column_title "Custom Title"}
|
||||
(json/encode ["name" "DATE"]) {:column_title "Custom Title 2"}}}}]
|
||||
(doseq [[export-format apply-formatting? expected] [[:csv true [["Custom Title" "Custom Title 2"]
|
||||
["2,000" "March 26, 2024"]]]
|
||||
[:csv false [["NUMBER" "DATE"]
|
||||
["2000" "2024-03-26"]]]
|
||||
[:json true [["Custom Title" "Custom Title 2"]
|
||||
["2,000" "March 26, 2024"]]]
|
||||
[:json false [["NUMBER" "DATE"]
|
||||
[2000 "2024-03-26"]]]]]
|
||||
;; TODO: order became wrong after Cheshire->Jsonista
|
||||
[:json true [["Custom Title 2" "Custom Title"]
|
||||
["March 26, 2024" "2,000"]]]
|
||||
[:json false [["DATE" "NUMBER"]
|
||||
["2024-03-26" 2000]]]]]
|
||||
(testing (format "export_format %s yields expected output for %s exports." apply-formatting? export-format)
|
||||
(is (= expected
|
||||
(->> (mt/user-http-request
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.api.common.internal-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.string :as str]
|
||||
[clojure.test :refer :all]
|
||||
@@ -14,6 +13,7 @@
|
||||
[metabase.server.middleware.exceptions :as mw.exceptions]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli.registry :as mr]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[ring.adapter.jetty :as jetty]
|
||||
@@ -127,9 +127,9 @@
|
||||
(defn- json-mw [handler]
|
||||
(fn [req]
|
||||
(-> req
|
||||
(update :body #(-> % slurp (json/parse-string true)))
|
||||
(update :body #(-> % slurp json/decode+kw))
|
||||
handler
|
||||
(update :body json/generate-string))))
|
||||
(update :body json/encode))))
|
||||
|
||||
(defn exception-mw [handler]
|
||||
(fn [req] (try
|
||||
@@ -153,7 +153,7 @@
|
||||
:accept :json
|
||||
:as :json
|
||||
:coerce :always
|
||||
:body (json/generate-string body)}))]
|
||||
:body (json/encode body)}))]
|
||||
(try
|
||||
(testing (format "With temp Jetty server on port %d" port)
|
||||
(f {:get get, :post! post}))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns ^:mb/driver-tests metabase.api.dashboard-test
|
||||
"Tests for /api/dashboard endpoints."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.data.csv :as csv]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]
|
||||
@@ -58,6 +57,7 @@
|
||||
[metabase.test :as mt]
|
||||
[metabase.test.fixtures :as fixtures]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[ring.util.codec :as codec]
|
||||
[toucan2.core :as t2]
|
||||
[toucan2.protocols :as t2.protocols]
|
||||
@@ -2466,7 +2466,7 @@
|
||||
:description "something"
|
||||
:cards [{:series [8 9], :size_y 3, :size_x 5}]}}
|
||||
:has_multiple_changes true
|
||||
:description "added a description and renamed it from \"b\" to \"c\", modified the cards and added some series to card 123."}
|
||||
:description "renamed this Dashboard from \"b\" to \"c\" and added a description, modified the cards and added some series to card 123."}
|
||||
{:is_reversion false
|
||||
:is_creation true
|
||||
:message nil
|
||||
@@ -3094,7 +3094,7 @@
|
||||
:data :results_metadata :columns)]
|
||||
(is (seq metadata) "Did not get metadata")
|
||||
(t2/update! 'Card {:id model-id}
|
||||
{:result_metadata (json/generate-string
|
||||
{:result_metadata (json/encode
|
||||
(assoc-in metadata [0 :id]
|
||||
(mt/id :products :category)))}))
|
||||
;; ...so instead we create a question on top of this model (note that
|
||||
@@ -3665,8 +3665,8 @@
|
||||
(mt/user-real-request :rasta :post 200 url
|
||||
{:request-options {:as :byte-array}}
|
||||
:format_rows true
|
||||
:parameters (json/generate-string [{:id "_PRICE_"
|
||||
:value 4}]))
|
||||
:parameters (json/encode [{:id "_PRICE_"
|
||||
:value 4}]))
|
||||
export-format))))))))))
|
||||
|
||||
(defn- dashcard-pivot-query-endpoint [dashboard-id card-id dashcard-id]
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
[[metabase.query-processor.streaming-test]] and specifically for each format
|
||||
in [[metabase.query-processor.streaming.csv-test]] etc."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.data.csv :as csv]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]
|
||||
@@ -31,6 +30,7 @@
|
||||
[metabase.test.data.users :as test.users]
|
||||
[metabase.test.fixtures :as fixtures]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]
|
||||
[toucan2.tools.with-temp :as t2.with-temp]))
|
||||
@@ -153,7 +153,7 @@
|
||||
[:js-int-to-string? [:= true]]]]]]
|
||||
[:database_id [:= (mt/id)]]
|
||||
[:state [:= "42000"]]
|
||||
[:class [:= "class org.h2.jdbc.JdbcSQLSyntaxErrorException"]]]
|
||||
[:class [:= "org.h2.jdbc.JdbcSQLSyntaxErrorException"]]]
|
||||
result)))
|
||||
(testing "\nSaved QueryExecution"
|
||||
(is (malli=
|
||||
@@ -176,7 +176,7 @@
|
||||
[url]
|
||||
(-> (client/client-full-response (test.users/username->token :rasta)
|
||||
:post 200 url
|
||||
:query (json/generate-string (mt/mbql-query checkins {:limit 1})))
|
||||
:query (json/encode (mt/mbql-query checkins {:limit 1})))
|
||||
:headers
|
||||
(select-keys ["Cache-Control" "Content-Disposition" "Content-Type" "Expires" "X-Accel-Buffering"])
|
||||
(update "Content-Disposition" #(some-> % (str/replace #"query_result_.+(\.\w+)"
|
||||
@@ -210,7 +210,7 @@
|
||||
:native {:query "SELECT * FROM USERS;"}}}]
|
||||
(letfn [(do-test []
|
||||
(let [result (mt/user-http-request :rasta :post 200 "dataset/csv"
|
||||
:query (json/generate-string
|
||||
:query (json/encode
|
||||
{:database lib.schema.id/saved-questions-virtual-database-id
|
||||
:type :query
|
||||
:query {:source-table (str "card__" (u/the-id card))}}))]
|
||||
@@ -303,7 +303,7 @@
|
||||
;; even if the query comes in with `add-default-userland-constraints` (as will be the case if the query gets saved
|
||||
(with-redefs [qp.constraints/default-query-constraints (constantly {:max-results 10, :max-results-bare-rows 10})]
|
||||
(let [result (mt/user-http-request :crowberto :post 200 "dataset/csv"
|
||||
:query (json/generate-string
|
||||
:query (json/encode
|
||||
{:database (mt/id)
|
||||
:type :query
|
||||
:query {:source-table (mt/id :venues)}
|
||||
@@ -318,13 +318,13 @@
|
||||
(deftest export-with-remapped-fields
|
||||
(testing "POST /api/dataset/:format"
|
||||
(testing "Downloaded CSV/JSON/XLSX results should respect remapped fields (#18440)"
|
||||
(let [query (json/generate-string {:database (mt/id)
|
||||
:type :query
|
||||
:query {:source-table (mt/id :venues)
|
||||
:limit 1}
|
||||
:middleware
|
||||
{:add-default-userland-constraints? true
|
||||
:userland-query? true}})]
|
||||
(let [query (json/encode {:database (mt/id)
|
||||
:type :query
|
||||
:query {:source-table (mt/id :venues)
|
||||
:limit 1}
|
||||
:middleware
|
||||
{:add-default-userland-constraints? true
|
||||
:userland-query? true}})]
|
||||
(mt/with-column-remappings [venues.category_id categories.name]
|
||||
(let [result (mt/user-http-request :crowberto :post 200 "dataset/csv"
|
||||
:query query)]
|
||||
@@ -727,7 +727,7 @@
|
||||
(->> (mt/user-http-request
|
||||
:crowberto :post 200
|
||||
(format "dataset/%s" (name export-format))
|
||||
:query (json/generate-string q)
|
||||
:query (json/encode q)
|
||||
:format_rows apply-formatting?)
|
||||
((get output-helper export-format))))))))))
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
- Dashboard Subscription Attachments
|
||||
- Alert attachments"
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.data.csv :as csv]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.set :as set]
|
||||
@@ -21,7 +20,8 @@
|
||||
[metabase.public-settings :as public-settings]
|
||||
[metabase.pulse.core :as pulse]
|
||||
[metabase.pulse.test-util :as pulse.test-util]
|
||||
[metabase.test :as mt])
|
||||
[metabase.test :as mt]
|
||||
[metabase.util.json :as json])
|
||||
(:import
|
||||
(org.apache.poi.ss.usermodel DataFormatter)
|
||||
(org.apache.poi.xssf.usermodel XSSFSheet)))
|
||||
@@ -68,9 +68,9 @@
|
||||
[card {:keys [export-format format-rows pivot]}]
|
||||
(->> (mt/user-http-request :crowberto :post 200
|
||||
(format "dataset/%s" (name export-format))
|
||||
:visualization_settings (json/generate-string
|
||||
:visualization_settings (json/encode
|
||||
(:visualization_settings card))
|
||||
:query (json/generate-string
|
||||
:query (json/encode
|
||||
(assoc (:dataset_query card)
|
||||
:was-pivot (boolean pivot)
|
||||
:info {:visualization-settings (:visualization_settings card)}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.api.geojson-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.fake :as fake]
|
||||
[clojure.test :refer :all]
|
||||
[metabase.api.geojson :as api.geojson]
|
||||
@@ -9,6 +8,7 @@
|
||||
[metabase.models.setting :as setting]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[ring.adapter.jetty :as ring-jetty])
|
||||
(:import
|
||||
@@ -256,7 +256,7 @@
|
||||
:region_name "NAME"}}
|
||||
expected-value (merge (@#'api.geojson/builtin-geojson) custom-geojson)]
|
||||
(mt/with-temporary-setting-values [custom-geojson nil]
|
||||
(mt/with-temp-env-var-value! [mb-custom-geojson (json/generate-string custom-geojson)]
|
||||
(mt/with-temp-env-var-value! [mb-custom-geojson (json/encode custom-geojson)]
|
||||
(binding [config/*disable-setting-cache* true]
|
||||
(testing "Should parse env var custom GeoJSON and merge in"
|
||||
(is (= expected-value
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.api.metabot-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as str]
|
||||
[clojure.test :refer :all]
|
||||
[metabase.db.query :as mdb.query]
|
||||
@@ -9,6 +8,7 @@
|
||||
[metabase.metabot.util :as metabot-util]
|
||||
[metabase.models :refer [Card]]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.tools.with-temp :as t2.with-temp]))
|
||||
|
||||
(deftest metabot-only-works-on-models-test
|
||||
@@ -204,7 +204,7 @@
|
||||
(with-redefs [metabot-client/*create-chat-completion-endpoint* (fn [_ _]
|
||||
(throw (ex-info
|
||||
error-message
|
||||
{:body (json/generate-string
|
||||
{:body (json/encode
|
||||
{:error {:message error-message
|
||||
:code error-code}})
|
||||
:status 400})))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns ^:mb/driver-tests metabase.api.preview-embed-test
|
||||
(:require
|
||||
[buddy.sign.jwt :as jwt]
|
||||
[cheshire.core :as json]
|
||||
[clojure.test :refer :all]
|
||||
[crypto.random :as crypto-random]
|
||||
[metabase.api.dashboard-test :as api.dashboard-test]
|
||||
@@ -13,6 +12,7 @@
|
||||
[metabase.models.dashboard-card :refer [DashboardCard]]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[toucan2.core :as t2]
|
||||
[toucan2.tools.with-temp :as t2.with-temp]))
|
||||
|
||||
@@ -616,26 +616,26 @@
|
||||
(let [url (card-query-url card {:_embedding_params {:LIKED "enabled"}})]
|
||||
(is (= [[3 "The Dentist" false]]
|
||||
(-> (mt/user-http-request :crowberto :get 202 url
|
||||
:parameters (json/generate-string {:LIKED false}))
|
||||
:parameters (json/encode {:LIKED false}))
|
||||
:data
|
||||
:rows)))
|
||||
(is (= [[1 "Tempest" true]
|
||||
[2 "Bullit" true]]
|
||||
(-> (mt/user-http-request :crowberto :get 202 url
|
||||
:parameters (json/generate-string {:LIKED true}))
|
||||
:parameters (json/encode {:LIKED true}))
|
||||
:data
|
||||
:rows)))))
|
||||
(testing "for dashboard embeds"
|
||||
(let [url (dashcard-url dashcard {:_embedding_params {:LIKED "enabled"}})]
|
||||
(is (= [[3 "The Dentist" false]]
|
||||
(-> (mt/user-http-request :crowberto :get 202 url
|
||||
:parameters (json/generate-string {:LIKED false}))
|
||||
:parameters (json/encode {:LIKED false}))
|
||||
:data
|
||||
:rows)))
|
||||
(is (= [[1 "Tempest" true]
|
||||
[2 "Bullit" true]]
|
||||
(-> (mt/user-http-request :crowberto :get 202 url
|
||||
:parameters (json/generate-string {:LIKED true}))
|
||||
:parameters (json/encode {:LIKED true}))
|
||||
:data
|
||||
:rows))))))))))
|
||||
|
||||
@@ -665,6 +665,6 @@
|
||||
(let [url (dashcard-url dashcard {:_embedding_params {:NAME "enabled"}})]
|
||||
(is (= [["Cheongju International Airport/Cheongju Air Base (K-59/G-513)"]]
|
||||
(-> (mt/user-http-request :crowberto :get 202 url
|
||||
:parameters (json/generate-string {:NAME "513"}))
|
||||
:parameters (json/encode {:NAME "513"}))
|
||||
:data
|
||||
:rows))))))))))
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns ^:mb/driver-tests metabase.api.public-test
|
||||
"Tests for `api/public/` (public links) endpoints."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.data.csv :as csv]
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]
|
||||
@@ -26,6 +25,7 @@
|
||||
[metabase.query-processor.middleware.process-userland-query-test :as process-userland-query-test]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[throttle.core :as throttle]
|
||||
[toucan2.core :as t2]
|
||||
[toucan2.tools.with-temp :as t2.with-temp])
|
||||
@@ -818,7 +818,7 @@
|
||||
(is (= [[50]]
|
||||
(-> (mt/user-http-request :crowberto
|
||||
:get (dashcard-url dash card dashcard)
|
||||
:parameters (json/generate-string
|
||||
:parameters (json/encode
|
||||
[{:type :category
|
||||
:target [:variable [:template-tag :num]]
|
||||
:value "50"
|
||||
@@ -844,7 +844,7 @@
|
||||
(is (= [[1]]
|
||||
(-> (mt/user-http-request :crowberto
|
||||
:get (dashcard-url dash card dashcard)
|
||||
:parameters (json/generate-string
|
||||
:parameters (json/encode
|
||||
[{:type :id
|
||||
:target [:dimension [:field (mt/id :venues :id) nil]]
|
||||
:value "50"
|
||||
@@ -872,7 +872,7 @@
|
||||
(is (= [[733]]
|
||||
(-> (mt/user-http-request :crowberto
|
||||
:get (dashcard-url dash card dashcard)
|
||||
:parameters (json/generate-string
|
||||
:parameters (json/encode
|
||||
[{:type "date/all-options"
|
||||
:target [:dimension [:field (mt/id :checkins :date) nil]]
|
||||
:value "~2015-01-01"
|
||||
@@ -905,7 +905,7 @@
|
||||
(is (= [["World"]]
|
||||
(-> (mt/user-http-request :crowberto
|
||||
:get (dashcard-url dash card dashcard)
|
||||
:parameters (json/generate-string
|
||||
:parameters (json/encode
|
||||
[{:type :category
|
||||
:target [:variable [:template-tag :msg]]
|
||||
:value "World"
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns ^:mb/once metabase.api.session-test
|
||||
"Tests for /api/session"
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.test :refer :all]
|
||||
[medley.core :as m]
|
||||
@@ -17,6 +16,7 @@
|
||||
[metabase.test.fixtures :as fixtures]
|
||||
[metabase.test.integrations.ldap :as ldap.test]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.json :as json]
|
||||
[metabase.util.malli.schema :as ms]
|
||||
[toucan2.core :as t2]
|
||||
[toucan2.tools.with-temp :as t2.with-temp]))
|
||||
@@ -150,7 +150,7 @@
|
||||
(let [error (fn []
|
||||
(-> (send-login-request "last-user" {"x-forwarded-for" "10.1.2.3"})
|
||||
:body
|
||||
json/parse-string
|
||||
json/decode
|
||||
(get-in ["errors" "username"])))]
|
||||
(is (re= #"^Too many attempts! You must wait \d+ seconds before trying again\.$"
|
||||
(error)))
|
||||
@@ -175,7 +175,7 @@
|
||||
(let [error (fn []
|
||||
(-> (send-login-request "last-user" {"x-forwarded-for" "10.1.2.3"})
|
||||
:body
|
||||
json/parse-string
|
||||
json/decode
|
||||
(get-in ["errors" "username"])))]
|
||||
(is (re= #"^Too many attempts! You must wait 1\d seconds before trying again\.$"
|
||||
(error)))
|
||||
@@ -328,7 +328,7 @@
|
||||
:content-type :json})
|
||||
::succeeded
|
||||
(catch Exception e
|
||||
(or (some-> (ex-data e) :body (json/parse-string true))
|
||||
(or (some-> (ex-data e) :body json/decode+kw)
|
||||
::unknown-error))))
|
||||
responses (into [] (repeatedly 30 try!))]
|
||||
(is (nil? (some #{::succeeded ::unknown-error} responses)))
|
||||
@@ -575,7 +575,7 @@
|
||||
(testing "test that group sync works even if ldap doesn't return uid (#22014)"
|
||||
(t2.with-temp/with-temp [PermissionsGroup group {:name "Accounting"}]
|
||||
(mt/with-temporary-raw-setting-values
|
||||
[ldap-group-mappings (json/generate-string {"cn=Accounting,ou=Groups,dc=metabase,dc=com" [(:id group)]})]
|
||||
[ldap-group-mappings (json/encode {"cn=Accounting,ou=Groups,dc=metabase,dc=com" [(:id group)]})]
|
||||
(is (malli= SessionResponse
|
||||
(mt/client :post 200 "session" {:username "fred.taylor@metabase.com", :password "pa$$word"})))
|
||||
(testing "PermissionsGroupMembership should exist"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
(ns metabase.api.tiles-test
|
||||
"Tests for `/api/tiles` endpoints."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.set :as set]
|
||||
[clojure.test :refer :all]
|
||||
[metabase.api.tiles :as api.tiles]
|
||||
[metabase.query-processor.compile :as qp.compile]
|
||||
[metabase.test :as mt]))
|
||||
[metabase.test :as mt]
|
||||
[metabase.util.json :as json]))
|
||||
|
||||
(defn- png? [s]
|
||||
(= [\P \N \G]
|
||||
@@ -24,14 +24,14 @@
|
||||
:crowberto :get 200 (format "tiles/1/1/1/%d/%d"
|
||||
(mt/id :venues :latitude)
|
||||
(mt/id :venues :longitude))
|
||||
:query (json/generate-string venues-query)))))
|
||||
:query (json/encode venues-query)))))
|
||||
(testing "Works on native queries"
|
||||
(let [native-query {:query (:query (qp.compile/compile venues-query))
|
||||
:template-tags {}}]
|
||||
(is (png? (mt/user-http-request
|
||||
:crowberto :get 200 (format "tiles/1/1/1/%s/%s"
|
||||
"LATITUDE" "LONGITUDE")
|
||||
:query (json/generate-string
|
||||
:query (json/encode
|
||||
{:database (mt/id)
|
||||
:type :native
|
||||
:native native-query}))))))))
|
||||
@@ -90,7 +90,7 @@
|
||||
:crowberto :get 200 (format "tiles/7/30/49/%d/%d"
|
||||
(mt/id :people :latitude)
|
||||
(mt/id :people :longitude))
|
||||
:query (json/generate-string
|
||||
:query (json/encode
|
||||
{:database (mt/id)
|
||||
:type :query
|
||||
:query {:source-table (mt/id :people)
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
(ns metabase.auth-provider-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.test :refer [deftest is testing]]
|
||||
[metabase.api.database :as api.database]
|
||||
[metabase.auth-provider :as auth-provider]
|
||||
[metabase.http-client :as client]
|
||||
[metabase.sync :as sync]
|
||||
[metabase.test :as mt]
|
||||
[metabase.test.data.interface :as tx]))
|
||||
[metabase.test.data.interface :as tx]
|
||||
[metabase.util.json :as json]))
|
||||
|
||||
(deftest auth-integration-test
|
||||
(mt/test-drivers #{:postgres :mysql}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
(ns metabase.channel.http-test
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clj-http.client :as http]
|
||||
[clojure.string :as str]
|
||||
[clojure.test :refer :all]
|
||||
@@ -10,6 +9,7 @@
|
||||
[metabase.task.send-pulses :as task.send-pulses]
|
||||
[metabase.test :as mt]
|
||||
[metabase.util.i18n :refer [deferred-tru]]
|
||||
[metabase.util.json :as json]
|
||||
[ring.adapter.jetty :as jetty]
|
||||
[ring.middleware.params :refer [wrap-params]]
|
||||
[toucan2.core :as t2])
|
||||
@@ -47,7 +47,10 @@
|
||||
(defn- json-mw [handler]
|
||||
(fn [req]
|
||||
(-> req
|
||||
(m/update-existing :body #(-> % slurp (json/parse-string true)))
|
||||
(m/update-existing :body #(let [s (slurp %)]
|
||||
;; Empty string is not a valid JSON, don't pass it to Jsonista.
|
||||
(when-not (str/blank? s)
|
||||
(json/decode+kw s))))
|
||||
handler)))
|
||||
|
||||
(def middlewares [json-mw wrap-params])
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user