Compare commits

...

9 Commits

Author SHA1 Message Date
Oleksandr Yakushev
6ff6c2b2ce json-raw 2024-10-27 16:57:25 +02:00
Oleksandr Yakushev
d6233d16d3 more test fixes 2024-10-27 16:57:25 +02:00
Oleksandr Yakushev
2f7ef0d674 don't fail on empty beans 2024-10-27 16:57:25 +02:00
Oleksandr Yakushev
3dea11d46b Fix tests 2024-10-27 16:57:25 +02:00
Oleksandr Yakushev
1436561501 Add necessary custom encoders for Jsonista 2024-10-27 16:57:25 +02:00
Oleksandr Yakushev
c148c1ccdb Replace Cheshire with metabase.util.json 2024-10-27 16:57:24 +02:00
Oleksandr Yakushev
ca127a9eae Add metabase.util.json 2024-10-27 16:55:28 +02:00
Oleksandr Yakushev
368ac78a7a Add Jsonista dependency 2024-10-27 16:55:27 +02:00
Oleksandr Yakushev
9f00ee385e Make malli=-report a macro 2024-10-27 16:54:59 +02:00
134 changed files with 837 additions and 722 deletions

View File

@@ -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))))

View File

@@ -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

View File

@@ -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)))

View File

@@ -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

View File

@@ -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]}]

View File

@@ -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

View File

@@ -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]

View File

@@ -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]))

View File

@@ -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}

View File

@@ -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]))

View File

@@ -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]

View File

@@ -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

View File

@@ -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))

View File

@@ -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 {}))))))

View File

@@ -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])]

View File

@@ -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"})

View File

@@ -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)))

View File

@@ -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

View File

@@ -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))))

View File

@@ -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"}

View File

@@ -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

View File

@@ -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))))

View File

@@ -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)))

View File

@@ -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)]

View File

@@ -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"

View File

@@ -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!

View File

@@ -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}}])

View File

@@ -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)))

View File

@@ -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 --------------------------------------------------

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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))]

View File

@@ -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

View File

@@ -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

View File

@@ -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))

View File

@@ -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"

View File

@@ -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"

View File

@@ -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

View File

@@ -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))))

View File

@@ -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))))))

View File

@@ -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]

View File

@@ -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]))

View File

@@ -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.

View File

@@ -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")}]}])))

View File

@@ -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

View File

@@ -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)]

View File

@@ -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)

View File

@@ -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)]

View File

@@ -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))}}))

View File

@@ -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")))

View File

@@ -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

View File

@@ -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

View File

@@ -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]

View File

@@ -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]))

View File

@@ -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})))

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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]

View File

@@ -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)))

View File

@@ -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))

View File

@@ -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)))

View File

@@ -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

View File

@@ -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

View File

@@ -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)))

View File

@@ -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]

View File

@@ -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 ----------------------------------------------

View File

@@ -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)
"")))

View File

@@ -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]

View File

@@ -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)

View File

@@ -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

View File

@@ -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")

View File

@@ -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))

View File

@@ -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)

View File

@@ -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

View File

@@ -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."

View File

@@ -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"

View 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))

View File

@@ -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))]]

View File

@@ -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]

View File

@@ -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)

View File

@@ -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]

View File

@@ -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]))

View File

@@ -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

View File

@@ -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}))

View File

@@ -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]

View File

@@ -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))))))))))

View File

@@ -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)}

View File

@@ -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

View File

@@ -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})))

View File

@@ -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))))))))))

View File

@@ -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"

View File

@@ -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"

View File

@@ -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)

View File

@@ -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}

View File

@@ -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