(ns metabase.lib.cache #?@(:clj ((:import [java.util Collections Map WeakHashMap] [java.util.function Function])) :cljs ((:require [goog.object :as gobject])))) | |
#?(:clj (def ^:private atom-function (reify Function (apply [_this _arg] (atom {}))))) | |
Caching wrapper for use in [[side-channel-cache]]. CLJS Attaches the cache to the CLJ Attaches the cache to the host's metadata, if present. See [[attach-query-cache]]. Does nothing if that
key is not found. The outer cache is a synchronized | (defn- atomic-map-cache-fn #?(:cljs ([^js host] (if-let [cache (.-__mbcache host)] cache (set! (.-__mbcache host) (atom {})))) :clj ([host] (when-let [^Map outer-cache (-> host meta :lib/__cache)] (.computeIfAbsent outer-cache host atom-function)))) ([cache subkey _x] (get @cache subkey)) ([cache subkey _x value] (swap! cache assoc subkey value))) |
Attaches the cache to a newly constructed query. This uses metadata on CLJ and does nothing on CLJS. | #?(:cljs (defn- js-weak-map-cache-fn "Caching wrapper for use in [[side-channel-cache*]]. Uses a two-layer cache: the outer layer is a vanilla JS object with string `subkey`s as its keys. The values are `WeakMap`s, using the input value `x` as the key and holding the cached result. For example, this works for caching by `:database-id` and then by legacy query object." ([^js host] (if-let [cache (.-__mbcache host)] cache (set! (.-__mbcache host) #js {}))) ([^js cache subkey x] (when-let [inner-cache (gobject/get cache subkey)] (.get inner-cache x))) ([^js cache subkey x value] (let [inner-cache (gobject/setWithReturnValueIfNotSet cache subkey #(js/WeakMap.))] (.set inner-cache x value))))) (defn attach-query-cache [query] #?(:cljs query :clj (vary-meta query (fn [mmeta] (cond-> mmeta (not (contains? mmeta :lib/__cache)) (assoc :lib/__cache (Collections/synchronizedMap (WeakHashMap.)))))))) |
Removes the cache from the given query. Does nothing if no cache is present. | (defn discard-query-cache [query] #?(:cljs query :clj (when query (vary-meta query dissoc :lib/__cache)))) |
(CLJS only; this is a pass-through in CLJ.) Attaches a JS property This cache forms a "personal" cache attached to If the If the The caches are passed both If there is no existing value in the cache for Options:
- The optional By default, the cache is an | (defn- side-channel-cache* [subkey host x f {:keys [cache-fn force?] :or {cache-fn atomic-map-cache-fn}}] (if (or force? (map? host) #?(:cljs (object? host))) (if-let [cache (cache-fn host)] (if-let [cached (cache-fn cache subkey x)] cached ;; Cache miss - generate the value and cache it. (let [value (f x)] (cache-fn cache subkey x value) value)) (f x)) (f x))) |
Creates a cache on the given See [[atomic-map-cache-fn]] for more details on how the caches are created and stored. The cache is intended to be a "personal" cache attached to the NOTE: The 3-arity uses If there is no existing value at The inner cache is an CLJS Notes If the If the Options:
- | (defn side-channel-cache ([subkey x f] (side-channel-cache subkey x f false)) ([subkey x f force?] (side-channel-cache* subkey x x f {:cache-fn atomic-map-cache-fn :force? force?})) ([subkey host x f opts] (side-channel-cache* subkey host x f (merge {:cache-fn atomic-map-cache-fn} opts)))) |