Skip to content
Snippets Groups Projects
Unverified Commit df163979 authored by metamben's avatar metamben Committed by GitHub
Browse files

Add filter-parts conversion helper (#33419)

parent 9a9216fc
No related merge requests found
......@@ -7,6 +7,7 @@ import type {
ExternalOp,
FilterOperator,
FilterClause,
FilterParts,
Query,
} from "./types";
......@@ -50,3 +51,11 @@ export function filterOperator(
) {
return ML.filter_operator(query, stageIndex, filterClause);
}
export function filterParts(
query: Query,
stageIndex: number,
filterClause: FilterClause,
): FilterParts {
return ML.filter_parts(query, stageIndex, filterClause);
}
......@@ -156,6 +156,13 @@ export type ExternalOp = {
args: [ColumnMetadata, ...ExpressionArg[]];
};
export type FilterParts = {
operator: FilterOperator;
options: Record<string, unknown>;
column: ColumnWithOperators | null;
args: ExpressionArg[];
};
declare const Join: unique symbol;
export type Join = unknown & { _opaque: typeof Join };
......
......@@ -158,6 +158,7 @@
filterable-column-operators
filter-clause
filter-operator
filter-parts
and
or
not
......
......@@ -15,6 +15,7 @@
[metabase.lib.options :as lib.options]
[metabase.lib.ref :as lib.ref]
[metabase.lib.schema :as lib.schema]
[metabase.lib.schema.common :as lib.schema.common]
[metabase.lib.schema.expression :as lib.schema.expression]
[metabase.lib.schema.filter :as lib.schema.filter]
[metabase.lib.temporal-bucket :as lib.temporal-bucket]
......@@ -189,6 +190,11 @@
[filterable-column :- ColumnWithOperators]
(:operators filterable-column))
(defn- add-column-operators
[column]
(let [operators (lib.filter.operator/filter-operators column)]
(m/assoc-some column :operators (clojure.core/not-empty operators))))
(mu/defn filterable-columns :- [:sequential ColumnWithOperators]
"Get column metadata for all the columns that can be filtered in
the stage number `stage-number` of the query `query`
......@@ -209,15 +215,12 @@
([query :- ::lib.schema/query
stage-number :- :int]
(let [stage (lib.util/query-stage query stage-number)
columns (lib.metadata.calculation/visible-columns query stage-number stage)
with-operators (fn [column]
(when-let [operators (clojure.core/not-empty (lib.filter.operator/filter-operators column))]
(assoc column :operators operators)))]
(let [stage (lib.util/query-stage query stage-number)]
(clojure.core/not-empty
(into []
(keep with-operators)
columns)))))
(into []
(comp (map add-column-operators)
(clojure.core/filter :operators))
(lib.metadata.calculation/visible-columns query stage-number stage))))))
(mu/defn filter-clause :- ::lib.schema.expression/boolean
"Returns a standalone filter clause for a `filter-operator`,
......@@ -246,3 +249,34 @@
(clojure.core/or (m/find-first #(clojure.core/= (:short %) op)
(lib.filter.operator/filter-operators (ref->col col-ref)))
(lib.filter.operator/operator-def op)))))
(def ^:private FilterParts
[:map
[:lib/type [:= :mbql/filter-parts]]
[:operator ::lib.schema.filter/operator]
[:options ::lib.schema.common/options]
[:column [:maybe ColumnWithOperators]]
[:args [:sequential :any]]])
(mu/defn filter-parts :- FilterParts
"Return the parts of the filter clause `a-filter-clause` in query `query` at stage `stage-number`.
Might obsolate [[filter-operator]]."
([query a-filter-clause]
(filter-parts query -1 a-filter-clause))
([query :- ::lib.schema/query
stage-number :- :int
a-filter-clause :- ::lib.schema.expression/boolean]
(let [[op options first-arg & rest-args] a-filter-clause
stage (lib.util/query-stage query stage-number)
columns (lib.metadata.calculation/visible-columns query stage-number stage)
ref->col (m/index-by lib.ref/ref columns)
col-ref (lib.equality/find-closest-matching-ref query first-arg (keys ref->col))
col (ref->col col-ref)]
{:lib/type :mbql/filter-parts
:operator (clojure.core/or (m/find-first #(clojure.core/= (:short %) op)
(lib.filter.operator/filter-operators col))
(lib.filter.operator/operator-def op))
:options options
:column (some-> col add-column-operators)
:args (vec rest-args)})))
......@@ -372,6 +372,15 @@
[a-query stage-number a-filter-clause]
(lib.core/filter-operator a-query stage-number a-filter-clause))
(defn ^:export filter-parts
"Returns the parts (operator, args, and optionally, options) of `filter-clause`."
[a-query stage-number a-filter-clause]
(let [{:keys [operator options column args]} (lib.core/filter-parts a-query stage-number a-filter-clause)]
#js {:operator operator
:options (clj->js (select-keys options [:case-sensitive :include-current]))
:column column
:args (to-array args)}))
(defn ^:export filter
"Sets `boolean-expression` as a filter on `query`."
[a-query stage-number boolean-expression]
......
......@@ -318,6 +318,34 @@
(is (= op
(lib/filter-operator query filter-clause)))))))
(deftest ^:parallel filter-parts-test
(let [query (-> (lib/query meta/metadata-provider (meta/table-metadata :users))
(lib/join (-> (lib/join-clause (meta/table-metadata :checkins)
[(lib/=
(meta/field-metadata :checkins :user-id)
(meta/field-metadata :users :id))])
(lib/with-join-fields :all)))
(lib/join (-> (lib/join-clause (meta/table-metadata :venues)
[(lib/=
(meta/field-metadata :checkins :venue-id)
(meta/field-metadata :venues :id))])
(lib/with-join-fields :all))))]
(doseq [col (lib/filterable-columns query)
op (lib/filterable-column-operators col)
:let [filter-clause (case (:short op)
:between (lib/filter-clause op col 123 456)
(:contains :does-not-contain :starts-with :ends-with) (lib/filter-clause op col "123")
(:is-null :not-null :is-empty :not-empty) (lib/filter-clause op col)
:inside (lib/filter-clause op col 12 34 56 78 90)
(lib/filter-clause op col 123))]]
(testing (str (:short op) " with " (lib.types.isa/field-type col))
(is (=? {:lib/type :mbql/filter-parts
:operator op
:column {:lib/type :metadata/column
:operators (comp vector? not-empty)}
:args vector?}
(lib/filter-parts query filter-clause)))))))
(deftest ^:parallel replace-filter-clause-test
(testing "Make sure we are able to replace a filter clause using the lib functions for manipulating filters."
(let [query (lib/query meta/metadata-provider (meta/table-metadata :users))
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment