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