Skip to content

Commit

Permalink
Support Offset() as an expression with no breakouts [backend] (#42132)
Browse files Browse the repository at this point in the history
* Only nest expressions referenced in breakouts or aggregations

* Support Offset() as expression with no breakouts

* Test fixes 🔧

* Oracle test update

* Improved Oracle test

* Test update 🔧

* Fix busted test

* Fix running and saving Offset over the REST API

* Remove stray :wow

* More test fixes 🔧
  • Loading branch information
camsaul committed May 7, 2024
1 parent 2c1deca commit 5406087
Show file tree
Hide file tree
Showing 12 changed files with 213 additions and 66 deletions.
13 changes: 8 additions & 5 deletions src/metabase/legacy_mbql/normalize.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
[medley.core :as m]
[metabase.legacy-mbql.schema :as mbql.s]
[metabase.legacy-mbql.util :as mbql.u]
[metabase.lib.normalize :as lib.normalize]
[metabase.lib.util.match :as lib.util.match]
[metabase.shared.util.i18n :as i18n]
[metabase.util :as u]
Expand Down Expand Up @@ -90,10 +91,11 @@

(defn- normalize-ref-opts [opts]
(let [opts (normalize-tokens opts :ignore-path)]
(cond-> opts
(:base-type opts) (update :base-type keyword)
(:temporal-unit opts) (update :temporal-unit keyword)
(:binning opts) (update :binning (fn [binning]
(cond-> opts
(:base-type opts) (update :base-type keyword)
(:effective-type opts) (update :effective-type keyword)
(:temporal-unit opts) (update :temporal-unit keyword)
(:binning opts) (update :binning (fn [binning]
(cond-> binning
(:strategy binning) (update :strategy keyword)))))))

Expand Down Expand Up @@ -207,7 +209,8 @@
(defmethod normalize-mbql-clause-tokens :offset
[[_tag opts expr n, :as clause]]
{:pre [(= (count clause) 4)]}
[:offset (or opts {}) (normalize-tokens expr :ignore-path) n])
(let [opts (lib.normalize/normalize :metabase.lib.schema.common/options (or opts {}))]
[:offset opts (normalize-tokens expr :ignore-path) n]))

(defmethod normalize-mbql-clause-tokens :default
;; MBQL clauses by default are recursively normalized.
Expand Down
13 changes: 11 additions & 2 deletions src/metabase/lib/schema.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,23 @@
(= ref-type (first x))
(not (contains? valid-ids (get x 2)))))

(defn- stage-with-joins-and-namespaced-keys-removed
"For ref validation purposes we should ignore `:joins` and any namespaced keys that might be used to record additional
info e.g. `:lib/metadata`."
[stage]
(select-keys stage (into []
(comp (filter simple-keyword?)
(remove (partial = :joins)))
(keys stage))))

(defn- expression-ref-errors-for-stage [stage]
(let [expression-names (into #{} (map (comp :lib/expression-name second)) (:expressions stage))]
(mbql.u/matching-locations (dissoc stage :joins :lib/stage-metadata)
(mbql.u/matching-locations (stage-with-joins-and-namespaced-keys-removed stage)
#(bad-ref-clause? :expression expression-names %))))

(defn- aggregation-ref-errors-for-stage [stage]
(let [uuids (into #{} (map (comp :lib/uuid second)) (:aggregation stage))]
(mbql.u/matching-locations (dissoc stage :joins :lib/stage-metadata)
(mbql.u/matching-locations (stage-with-joins-and-namespaced-keys-removed stage)
#(bad-ref-clause? :aggregation uuids %))))

(defn ref-errors-for-stage
Expand Down
2 changes: 1 addition & 1 deletion src/metabase/lib/schema/expression/window.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

;;; added 0.50.0
(mbql-clause/define-tuple-mbql-clause :offset
#_expr :any
#_expr [:ref ::expression/expression]
#_n ::offset.n)

(defmethod expression/type-of-method :offset
Expand Down
2 changes: 1 addition & 1 deletion src/metabase/lib/schema/util.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
[our-uuid]
[])
(comp (remove (fn [[k _v]]
(#{:lib/metadata :lib/stage-metadata :lib/options} k)))
(qualified-keyword? k)))
(mapcat (fn [[_k v]]
(collect-uuids v))))
m))
Expand Down
15 changes: 15 additions & 0 deletions test/metabase/legacy_mbql/normalize_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -1510,3 +1510,18 @@
k {"x" 1, "y" {"z" 2}, "a" nil}}]
(t/is (= query
(mbql.normalize/normalize query)))))))

(t/deftest ^:parallel normalize-offset-test
(t/is (=? [:offset
{:effective-type :type/Float, :lib/uuid string?}
[:field
1
{:base-type :type/Float, :effective-type :type/Float}]
-1]
(mbql.normalize/normalize
["offset"
{"effective-type" "type/Float"}
["field"
1
{"base-type" "type/Float", "effective-type" "type/Float"}]
-1]))))
29 changes: 29 additions & 0 deletions test/metabase/lib/schema/expression/window_test.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
(ns metabase.lib.schema.expression.window-test
(:require
#?@(:cljs ([metabase.test-runner.assert-exprs.approximately-equal]))
[clojure.test :refer [deftest are]]
[metabase.lib.normalize :as lib.normalize]))

#?(:cljs (comment metabase.test-runner.assert-exprs.approximately-equal/keep-me))

(deftest ^:parallel normalize-offset-test
(are [x] (=? [:offset
{:lib/uuid string?, :effective-type :type/Float}
[:field
{:base-type :type/Float, :effective-type :type/Float, :lib/uuid string?}
1]
-1]
(lib.normalize/normalize x))
[:offset
{:effective-type "type/Float"}
[:field
{:base-type "type/Float", :effective-type "type/Float"}
1]
-1]

["offset"
{"effective-type" "type/Float"}
["field"
{"base-type" "type/Float", "effective-type" "type/Float"}
1]
-1]))
9 changes: 5 additions & 4 deletions test/metabase/lib/schema/expression_test.cljc
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
(ns metabase.lib.schema.expression-test
(:require [clojure.test :refer [deftest are testing]]
[metabase.lib.core :as lib]
[metabase.lib.schema.expression :as lib.schema.expression]
[metabase.lib.test-metadata :as meta]))
(:require
[clojure.test :refer [deftest are testing]]
[metabase.lib.core :as lib]
[metabase.lib.schema.expression :as lib.schema.expression]
[metabase.lib.test-metadata :as meta]))

(deftest ^:parallel comparable-expressions?-test
(let [abs-datetime [:absolute-datetime {:lib/uuid (str (random-uuid))}
Expand Down
4 changes: 2 additions & 2 deletions test/metabase/lib/schema_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
[(str "Invalid :aggregation reference: no aggregation with uuid " bad-ref)]

;; if we forget to remove legacy ag refs from some part of the query make sure we get a useful error message.
{:lib/type :mbql.stage/mbql
:metabase.lib.stage/cached-metadata {:field-ref [:aggregation 0]}}
{:lib/type :mbql.stage/mbql
:some-other-section {:field-ref [:aggregation 0]}}
["Invalid :aggregation reference: [:aggregation 0]"]

;; don't recurse into joins.
Expand Down
8 changes: 4 additions & 4 deletions test/metabase/query_processor/test_util.clj
Original file line number Diff line number Diff line change
Expand Up @@ -437,12 +437,12 @@
when [[metabase.config/is-test?]] is true."
false)

(defn mock-fks-metadata-provider
(defn mock-fks-application-database-metadata-provider
"Impl for [[with-mock-fks-for-drivers-without-fk-constraints]]. A mock metadata provider composed with the application
database metadata provider that adds FK relationships for Tables that would normally have them in drivers that have
formal FK constraints."
([]
(mock-fks-metadata-provider (lib.metadata.jvm/application-database-metadata-provider (data/id))))
(mock-fks-application-database-metadata-provider (lib.metadata.jvm/application-database-metadata-provider (data/id))))

([parent-metadata-provider]
(lib.tu/merged-mock-metadata-provider
Expand All @@ -460,8 +460,8 @@
(binding [qp.store/*TESTS-ONLY-allow-replacing-metadata-provider* true
*enable-fk-support-for-disabled-drivers-in-tests* true]
(qp.store/with-metadata-provider (if (qp.store/initialized?)
(mock-fks-metadata-provider (qp.store/metadata-provider))
(mock-fks-metadata-provider))
(mock-fks-application-database-metadata-provider (qp.store/metadata-provider))
(mock-fks-application-database-metadata-provider))
(thunk))))

(defmacro with-mock-fks-for-drivers-without-fk-constraints
Expand Down

0 comments on commit 5406087

Please sign in to comment.