A Segment is a saved MBQL query stage snippet with | (ns metabase.lib.segment (:require [metabase.lib.filter :as lib.filter] [metabase.lib.metadata :as lib.metadata] [metabase.lib.metadata.calculation :as lib.metadata.calculation] [metabase.lib.metadata.protocols :as lib.metadata.protocols] [metabase.lib.options :as lib.options] [metabase.lib.ref :as lib.ref] [metabase.lib.schema :as lib.schema] [metabase.lib.schema.metadata :as lib.schema.metadata] [metabase.lib.util :as lib.util] [metabase.util.i18n :as i18n] [metabase.util.malli :as mu])) |
(defn- resolve-segment [query segment-id] (when (integer? segment-id) (lib.metadata/segment query segment-id))) | |
(defmethod lib.ref/ref-method :metadata/segment [{:keys [id]}] (lib.options/ensure-uuid [:segment {} id])) | |
(defmethod lib.metadata.calculation/type-of-method :metadata/segment [_query _stage-number _metric-metadata] :type/Boolean) | |
(defmethod lib.metadata.calculation/type-of-method :segment [_query _stage-number _segment-clause] :type/Boolean) | |
(defn- fallback-display-name [] (i18n/tru "[Unknown Segment]")) | |
(defmethod lib.metadata.calculation/display-name-method :metadata/segment [_query _stage-number segment-metadata _style] (or (:display-name segment-metadata) (:name segment-metadata) (fallback-display-name))) | |
(defmethod lib.metadata.calculation/display-name-method :segment [query stage-number [_tag _opts segment-id-or-name] style] (or (when (integer? segment-id-or-name) (when-let [segment-metadata (lib.metadata/segment query segment-id-or-name)] (lib.metadata.calculation/display-name query stage-number segment-metadata style))) (fallback-display-name))) | |
(defmethod lib.metadata.calculation/display-info-method :metadata/segment [query stage-number {:keys [description filter-positions], :as segment-metadata}] (let [default-display-info-method (get-method lib.metadata.calculation/display-info-method :default) default-display-info (default-display-info-method query stage-number segment-metadata)] (cond-> default-display-info description (assoc :description description) filter-positions (assoc :filter-positions filter-positions)))) | |
(defmethod lib.metadata.calculation/display-info-method :segment [query stage-number [_tag _opts segment-id-or-name]] (if-let [segment-metadata (resolve-segment query segment-id-or-name)] (lib.metadata.calculation/display-info query stage-number segment-metadata) {:effective-type :type/Boolean :display-name (fallback-display-name) :long-display-name (fallback-display-name)})) | |
(mu/defn available-segments :- [:maybe [:sequential {:min 1} ::lib.schema.metadata/segment]] "Get a list of Segments that you may consider using as filter for a query. Only Segments that have the same `table-id` as the `source-table` for this query will be suggested." ([query] (available-segments query -1)) ([query :- ::lib.schema/query stage-number :- :int] (when (zero? (lib.util/canonical-stage-index query stage-number)) (when-let [source-table-id (lib.util/source-table-id query)] (let [segments (lib.metadata.protocols/segments (lib.metadata/->metadata-provider query) source-table-id) segment-filters (into {} (keep-indexed (fn [index filter-clause] (when (lib.util/clause-of-type? filter-clause :segment) [(get filter-clause 2) index]))) (lib.filter/filters query 0))] (cond (empty? segments) nil (empty? segment-filters) (vec segments) :else (mapv (fn [segment-metadata] (let [filter-pos (-> segment-metadata :id segment-filters)] (cond-> segment-metadata ;; even though at most one filter can reference a given segment ;; we use plural in order to keep the interface used with ;; plain filters referencing columns filter-pos (assoc :filter-positions [filter-pos])))) segments))))))) | |