Skip to content
Snippets Groups Projects
Commit 2bae06ce authored by Braden Shepherdson's avatar Braden Shepherdson Committed by Braden Shepherdson
Browse files

[MLv2] Implement `->legacy-MBQL` for converting pMBQL back

This is tested implicitly by round-tripping every legacy MBQL query
the BE tests pass to `mt/mbql-query` etc.
parent a66da6e7
No related branches found
No related tags found
No related merge requests found
(ns metabase.lib.convert
(:require
[clojure.set :as set]
[metabase.lib.dispatch :as lib.dispatch]
[metabase.lib.options :as lib.options]
[metabase.lib.util :as lib.util]))
......@@ -73,6 +74,83 @@
{:arglists '([x])}
lib.dispatch/dispatch-value)
(defn- disqualify [x]
#?(:cljs (when (number? x) (js-debugger)))
(select-keys x (remove qualified-keyword? (keys x))))
(defn- clause-with-options->legacy-MBQL [[k options & args]]
(if (map? options)
(into [k] (concat (map ->legacy-MBQL args)
(when-let [options (not-empty (disqualify options))]
[options])))
(into [k] (map ->legacy-MBQL (cons options args)))))
(defmethod ->legacy-MBQL :default
[x]
x)
(if (and (vector? x)
(keyword? (first x)))
(clause-with-options->legacy-MBQL x)
(do
#?(:cljs (when-not (or (nil? x) (string? x) (number? x) (boolean? x) (keyword? x))
(js/console.log "undefined ->legacy-MBQL for" (lib.dispatch/dispatch-value x) x)
(throw (ex-info "undefined ->legacy-MBQL" {:dispatch-value (lib.dispatch/dispatch-value x)
:value x}))))
x)))
(defn- chain-stages [x]
(let [stages (map ->legacy-MBQL (:stages x))]
(reduce (fn [inner stage]
(assoc stage :source-query inner))
(first stages)
(rest stages))))
(defmethod ->legacy-MBQL :dispatch-type/map [m]
(-> m
disqualify
(update-vals ->legacy-MBQL)))
(defmethod ->legacy-MBQL :dispatch-type/sequential [xs]
(mapv ->legacy-MBQL xs))
(defmethod ->legacy-MBQL :field [[_ opts id]]
;; Fields are not like the normal clauses - they need that options field even if it's null.
;; TODO: Sometimes the given field is in the legacy order - that seems wrong.
(let [[opts id] (if (or (nil? opts) (map? opts))
[opts id]
[id opts])]
[:field
(->legacy-MBQL id)
(not-empty (disqualify opts))]))
(defmethod ->legacy-MBQL :mbql/join [join]
(let [base (disqualify join)]
(merge (-> base
(dissoc :stages)
(update-vals ->legacy-MBQL))
(chain-stages base))))
(defmethod ->legacy-MBQL :mbql.stage/mbql [stage]
(-> stage
disqualify
(update-vals ->legacy-MBQL)))
(defmethod ->legacy-MBQL :mbql.stage/native [stage]
(-> stage
disqualify
(set/rename-keys {:native :query})
(update-vals ->legacy-MBQL)))
(defmethod ->legacy-MBQL :mbql/query [query]
(let [base (disqualify query)
inner-query (chain-stages base)
query-type (if (-> query :stages first :lib/type (= :mbql.stage/native))
:native
:query)
result
(merge (-> base
(dissoc :stages)
(update-vals ->legacy-MBQL))
{:type query-type
query-type inner-query})]
#?(:cljs (js/console.log "->legacy-MBQL on query" query result))
result))
......@@ -41,7 +41,7 @@
(get m2 k)))
m1-keys))))
(defmethod = :dispatch-type/sequence
(defmethod = :dispatch-type/sequential
[xs ys]
(and (clojure.core/= (count xs) (count ys))
(loop [[x & more-x] xs, [y & more-y] ys]
......@@ -54,6 +54,6 @@
(defmethod = :default
[x y]
(cond
(map? x) ((get-method = :dispatch-type/map) x y)
(sequential? x) ((get-method = :dispatch-type/sequence) x y)
:else (clojure.core/= x y)))
(map? x) ((get-method = :dispatch-type/map) x y)
(sequential? x) ((get-method = :dispatch-type/sequential) x y)
:else (clojure.core/= x y)))
......@@ -694,18 +694,18 @@
#?(:clj (defn- regexp? [x]
(instance? java.util.regex.Pattern x)))
(derive :dispatch-type/nil :dispatch-type/*)
(derive :dispatch-type/boolean :dispatch-type/*)
(derive :dispatch-type/string :dispatch-type/*)
(derive :dispatch-type/keyword :dispatch-type/*)
(derive :dispatch-type/number :dispatch-type/*)
(derive :dispatch-type/integer :dispatch-type/number)
(derive :dispatch-type/map :dispatch-type/*)
(derive :dispatch-type/sequence :dispatch-type/*)
(derive :dispatch-type/set :dispatch-type/*)
(derive :dispatch-type/symbol :dispatch-type/*)
(derive :dispatch-type/fn :dispatch-type/*)
(derive :dispatch-type/regex :dispatch-type/*)
(derive :dispatch-type/nil :dispatch-type/*)
(derive :dispatch-type/boolean :dispatch-type/*)
(derive :dispatch-type/string :dispatch-type/*)
(derive :dispatch-type/keyword :dispatch-type/*)
(derive :dispatch-type/number :dispatch-type/*)
(derive :dispatch-type/integer :dispatch-type/number)
(derive :dispatch-type/map :dispatch-type/*)
(derive :dispatch-type/sequential :dispatch-type/*)
(derive :dispatch-type/set :dispatch-type/*)
(derive :dispatch-type/symbol :dispatch-type/*)
(derive :dispatch-type/fn :dispatch-type/*)
(derive :dispatch-type/regex :dispatch-type/*)
(defn dispatch-type-keyword
"In Cljs `(type 1) is `js/Number`, but `(isa? 1 js/Number)` isn't truthy, so dispatching off of [[clojure.core/type]]
......
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