Last active
March 8, 2023 20:51
-
-
Save camsaul/fff51d9f46ad34371d3cedd536fb0360 to your computer and use it in GitHub Desktop.
Malli MBQL Clause Schemas improvements PoC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns metabase.lib.schema.mbql-clause | |
(:require | |
[metabase.lib.schema.common :as common] | |
[metabase.util.malli.registry :as mr])) | |
(defonce ^:private ^{:doc "map of clause keyword -> schema"} clause-schema-registry | |
(atom {})) | |
(defn- keyword-schema | |
"Build the schema for `::keyword`, for a valid MBQL clause type keyword." | |
[] | |
(into [:enum] (sort (keys @clause-schema-registry)))) | |
(defn- update-keyword-schema! [] | |
(mr/def ::keyword | |
(keyword-schema))) | |
(defn- clause*-schema | |
"Build the schema for `::clause*`, a `:multi` schema that maps MBQL clause type -> the schema | |
in [[clause-schema-registry]]." | |
[] | |
(into [:multi {:dispatch first}] | |
@clause-schema-registry)) | |
(defn- update-clause-schema! [] | |
(mr/def ::clause* | |
(clause*-schema))) | |
(update-keyword-schema!) | |
(update-clause-schema!) | |
(mr/def ::clause | |
[:and | |
[:schema | |
[:cat | |
[:schema [:ref ::keyword]] | |
[:* any?]]] | |
[:ref ::clause*]]) | |
(defn define-mbql-clause [clause-name schema] | |
(let [schema-name (keyword "mbql-clause" (name clause-name))] | |
(mr/def schema-name schema) | |
(swap! clause-schema-registry assoc clause-name [:ref schema-name]) | |
(update-keyword-schema!) | |
(update-clause-schema!) | |
;; return the newly created schema name for useful feedback when in a REPL! | |
schema-name)) | |
(defmulti clause-type | |
"Return the [[metabase.types]] base type this `mbql-clause` should return." | |
{:arglists '([mbql-clause])} | |
(fn [[clause-keyword]] | |
(keyword "mbql-clause" (name clause-keyword)))) | |
(defmethod clause-type :default | |
[_clause] | |
:type/*) | |
(defmethod clause-type :mbql-clause.type/boolean | |
[_clause] | |
:type/Boolean) | |
(defn mbql-clause-of-type | |
"Create a schema that: | |
1. this is a valid MBQL clause matching the `:metabase.lib.schema.mbql-clause/clause` schema | |
2. the clause returns a [[metabase.types]] [[clause-type]] that isa? `base-type`" | |
[base-type] | |
[:and | |
::clause | |
[:fn | |
{:error/message (str "Not an MBQL clause of type " clause-type)} | |
(fn [clause] | |
(isa? (clause-type clause) base-type))]]) | |
(mr/def ::clause.boolean | |
(mbql-clause-of-type :type/Boolean)) | |
(mr/def ::clause.string | |
(mbql-clause-of-type :type/Text)) | |
;;; examples | |
(define-mbql-clause | |
:starts-with | |
[:tuple | |
[:= :starts-with] | |
::common/options | |
#_whole [:ref :metabase.lib.schema.expression/string] | |
#_part [:ref :metabase.lib.schema.expression/string]]) | |
(derive :mbql-clause/starts-with :mbql-clause.type/boolean) | |
(malli.core/validate ::clause [:starts-with {:lib/uuid (str (random-uuid))} "X" "XY"]) | |
;; => true | |
(malli.core/validate ::clause [:starts-with {:lib/uuid (str (random-uuid))} 1 "XY"]) | |
;; => false | |
(clause-type [:starts-with]) | |
;; => :type/Boolean | |
(malli.core/validate ::clause.boolean [:starts-with {:lib/uuid (str (random-uuid))} "X" "XY"]) | |
;; => true | |
(malli.core/validate ::clause.string [:starts-with {:lib/uuid (str (random-uuid))} "X" "XY"]) | |
;;; => false |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment