(ns metabase.lib.filter.operator (:require [metabase.lib.metadata.calculation :as lib.metadata.calculation] [metabase.lib.schema.common :as lib.schema.common] [metabase.lib.schema.filter :as lib.schema.filter] [metabase.lib.schema.metadata :as lib.schema.metadata] [metabase.lib.types.isa :as lib.types.isa] [metabase.util :as u] [metabase.util.i18n :as i18n] [metabase.util.malli :as mu])) | |
(mu/defn operator-def :- ::lib.schema.filter/operator "Get a filter operator definition for the MBQL filter with `tag`, e.g. `:=`. In some cases various tags have alternate display names used for different situations e.g. for numbers vs temporal values; pass in the `display-name-style` to choose a non-default display-name." ([tag] (operator-def tag :default)) ([tag display-name-style] {:lib/type :operator/filter :short tag :display-name-variant display-name-style})) | |
(def ^:private numeric-key-operators [(operator-def :=) (operator-def :!=) (operator-def :>) (operator-def :<) (operator-def :between) (operator-def :>=) (operator-def :<=) (operator-def :is-null :is-empty) (operator-def :not-null :not-empty)]) | |
(def ^:private temporal-operators [(operator-def :!= :excludes) (operator-def :=) (operator-def :< :before) (operator-def :> :after) (operator-def :between) (operator-def :is-null :is-empty) (operator-def :not-null :not-empty)]) | |
(def ^:private coordinate-operators [(operator-def :=) (operator-def :!=) (operator-def :inside) (operator-def :>) (operator-def :<) (operator-def :between) (operator-def :>=) (operator-def :<=)]) | |
(def ^:private number-operators [(operator-def := :equal-to) (operator-def :!= :not-equal-to) (operator-def :>) (operator-def :<) (operator-def :between) (operator-def :>=) (operator-def :<=) (operator-def :is-null :is-empty) (operator-def :not-null :not-empty)]) | |
(def ^:private text-operators [(operator-def :=) (operator-def :!=) (operator-def :contains) (operator-def :does-not-contain) (operator-def :is-empty) (operator-def :not-empty) (operator-def :starts-with) (operator-def :ends-with)]) | |
(def ^:private text-like-operators [(operator-def :=) (operator-def :!=) (operator-def :is-empty) (operator-def :not-empty)]) | |
(def ^:private boolean-operators [(operator-def :=) (operator-def :is-null :is-empty) (operator-def :not-null :not-empty)]) | |
(def ^:private default-operators [(operator-def :is-null :is-empty) (operator-def :not-null :not-empty)]) | |
Operators that should be listed as options in join conditions. | (def join-operators [(assoc (operator-def :=) :default true) (operator-def :>) (operator-def :<) (operator-def :>=) (operator-def :<=) (operator-def :!=)]) |
(mu/defn filter-operators :- [:sequential ::lib.schema.filter/operator] "The list of available filter operators. The order of operators is relevant for the front end. There are slight differences between names and ordering for the different base types." [column :- ::lib.schema.metadata/column] ;; The order of these clauses is important since we want to match the most relevant type ;; the order is different than `lib.types.isa/field-type` as filters need to operate ;; on the effective-type rather than the semantic-type, eg boolean and number cannot become ;; string if semantic type is type/Category (condp lib.types.isa/field-type? column :metabase.lib.types.constants/temporal temporal-operators :metabase.lib.types.constants/coordinate coordinate-operators :metabase.lib.types.constants/number (if ((some-fn lib.types.isa/primary-key? lib.types.isa/foreign-key?) column) numeric-key-operators number-operators) :metabase.lib.types.constants/boolean boolean-operators :metabase.lib.types.constants/string text-operators :metabase.lib.types.constants/string_like text-like-operators ;; default default-operators)) | |
(mu/defn- filter-operator-long-display-name :- ::lib.schema.common/non-blank-string [tag :- :keyword display-name-variant :- :keyword] (case tag := (case display-name-variant :equal-to (i18n/tru "Equal to") :default (i18n/tru "Is")) :!= (case display-name-variant :not-equal-to (i18n/tru "Not equal to") :excludes (i18n/tru "Excludes") :default (i18n/tru "Is not")) :> (case display-name-variant :after (i18n/tru "After") :default (i18n/tru "Greater than")) :< (case display-name-variant :before (i18n/tru "Before") :default (i18n/tru "Less than")) :>= (case display-name-variant :default (i18n/tru "Greater than or equal to")) :<= (case display-name-variant :default (i18n/tru "Less than or equal to")) :between (case display-name-variant :default (i18n/tru "Between")) :is-null (case display-name-variant :is-empty (i18n/tru "Is empty") :default (i18n/tru "Is null")) :not-null (case display-name-variant :not-empty (i18n/tru "Not empty") :default (i18n/tru "Not null")) :is-empty (case display-name-variant :default (i18n/tru "Is empty")) :not-empty (case display-name-variant :default (i18n/tru "Not empty")) :contains (case display-name-variant :default (i18n/tru "Contains")) :does-not-contain (case display-name-variant :default (i18n/tru "Does not contain")) :starts-with (case display-name-variant :default (i18n/tru "Starts with")) :ends-with (case display-name-variant :default (i18n/tru "Ends with")) :inside (case display-name-variant :default (i18n/tru "Inside")))) | |
(mu/defn- filter-operator-display-name :- ::lib.schema.common/non-blank-string [tag :- :keyword display-name-variant :- :keyword] (case tag := "=" :!= "≠" :> ">" :< "<" :>= "≥" :<= "≤" (filter-operator-long-display-name tag display-name-variant))) | |
(defmethod lib.metadata.calculation/display-name-method :operator/filter [_query _stage-number {short-name :short, :keys [display-name-variant]} display-name-style] (case display-name-style :default (filter-operator-display-name short-name display-name-variant) :long (filter-operator-long-display-name short-name display-name-variant))) | |
(defmethod lib.metadata.calculation/display-info-method :operator/filter [_query _stage-number {short-name :short, :keys [display-name-variant default]}] (cond-> {:short-name (u/qualified-name short-name) :display-name (filter-operator-display-name short-name display-name-variant) :long-display-name (filter-operator-long-display-name short-name display-name-variant)} default (assoc :default true))) | |