(ns metabase.models.user-parameter-value (:require [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] [methodical.core :as methodical] [toucan2.core :as t2])) | |
----------------------------------------------- Entity & Lifecycle ----------------------------------------------- | |
(methodical/defmethod t2/table-name :model/UserParameterValue [_model] :user_parameter_value) | |
(doto :model/UserParameterValue (derive :metabase/model)) | |
A version of | (defn- json-out
[s]
(if (string? s)
(try
(json/decode+kw s)
(catch Throwable _e
s))
s)) |
(t2/deftransforms :model/UserParameterValue
{:value {:in mi/json-in
:out json-out}}) | |
Delete param with nil value and upsert the rest. | (defn batched-upsert!
[parameters]
(let [to-insert (remove #(and (nil? (:value %)) (nil? (:default %))) parameters)]
(t2/with-transaction [_conn]
(doseq [batch (partition-all 1000 parameters)]
(t2/delete! :model/UserParameterValue
{:where (into [:or] (for [p batch]
[:and
[:= :user_id (:user_id p)]
[:= :dashboard_id (:dashboard_id p)]
[:= :parameter_id (:parameter_id p)]]))}))
(doseq [batch (partition-all 1000 to-insert)]
(t2/insert! :model/UserParameterValue
(map #(select-keys % [:user_id :dashboard_id :parameter_id :value]) batch)))))) |
(defonce ^:private user-parameter-value-queue
(delay (grouper/start!
(fn [inputs]
(try
(batched-upsert!
(->> (for [input inputs
parameter (:parameters input)]
{:user_id (:user-id input)
:dashboard_id (:dashboard-id input)
:parameter_id (:id parameter)
:value (:value parameter)
:default (:default parameter)})
(m/index-by (juxt :user_id :dashboard_id :parameter_id))
vals))
(catch Exception e
(log/error e "Error saving user parameters for a dashboard"))))
:capacity 5000
:interval 5000))) | |
Asynchronously delete params with a nil | (mu/defn store!
[user-id :- ms/PositiveInt
dashboard-id :- ms/PositiveInt
parameters :- [:sequential :map]]
(grouper/submit! @user-parameter-value-queue {:user-id user-id
:dashboard-id dashboard-id
:parameters parameters})) |
hydration | |
(methodical/defmethod t2/batched-hydrate [:model/Dashboard :last_used_param_values]
"Hydrate a map of parameter-id->last-used-value for the dashboards."
[_model _k dashboards]
(if-let [user-id api/*current-user-id*]
(mi/instances-with-hydrated-data
dashboards
:last_used_param_values
(fn [] ;; return a map of {dashboard-id {parameter-id value}}
(let [upvs (t2/select :model/UserParameterValue
:dashboard_id [:in (map :id dashboards)]
:user_id user-id)]
(as-> upvs result
(group-by :dashboard_id result)
(update-vals result (fn [upvs]
(into {}
(map (juxt :parameter_id :value) upvs)))))))
:id
{:default {}})
dashboards)) | |