Last active
April 20, 2022 20:12
-
-
Save camsaul/fa4f29bdc2a6aa6f92b2192d398639be to your computer and use it in GitHub Desktop.
defenterprise macro 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.public-settings.premium-features.defenterprise | |
(:require [clojure.string :as str] | |
[metabase.plugins.classloader :as classloader] | |
[metabase.public-settings.premium-features :as premium-features] | |
[metabase.util :as u])) | |
;;; Map of (qualified) function name -> {:oss <oss/fallback fn> | |
;;; :ee <ee fn>} | |
(defonce ^:private registry | |
(atom {})) | |
(defn ee-namespace? [] | |
(str/starts-with? (ns-name *ns*) "metabase-enterprise")) | |
(defn register-fn! [fn-name ee-or-oss f] | |
(swap! registry update fn-name assoc ee-or-oss f)) | |
(defn dynamic-ee-oss-fn | |
"Picks the appropriate function `fn-name` defined with [[defenterprise]] when invoked based on whether `feature` is | |
available." | |
[fn-name feature] | |
(fn [& args] | |
(let [f (or (when (premium-features/has-feature? feature) | |
(let [ee-namespace (symbol (namespace fn-name))] | |
(u/ignore-exceptions | |
(classloader/require ee-namespace) | |
(get-in @registry [fn-name :ee])))) | |
(get-in @registry [fn-name :oss]))] | |
(apply f args)))) | |
(defmacro defenterprise | |
{:style/indent :defn} | |
[fn-name feature & fn-tail] | |
{:pre [(symbol? fn-name) (namespace fn-name) (keyword? feature)]} | |
(let [ee-or-oss (if (ee-namespace?) :ee :oss)] | |
`(do | |
(register-fn! '~fn-name ~ee-or-oss (fn ~@fn-tail)) | |
(def ~(vary-meta (symbol (name fn-name)) assoc :arglists ''([& args])) (dynamic-ee-oss-fn '~fn-name ~feature))))) | |
;;; Sample usage | |
(defenterprise metabase-enterprise.core/my-fn :audit-app | |
[x] | |
[:oss x]) |
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
;; Supporting schema | |
(defmacro defenterprise-fn | |
[fn-name feature f] | |
{:pre [(symbol? fn-name) (namespace fn-name) (keyword? feature)]} | |
(let [ee-or-oss (if (ee-namespace?) :ee :oss)] | |
`(do | |
(register-fn! '~fn-name ~ee-or-oss ~f) | |
(def ~(vary-meta (symbol (name fn-name)) assoc :arglists ''([& args])) (dynamic-ee-oss-fn '~fn-name ~feature))))) | |
(defmacro defenterprise | |
{:style/indent :defn} | |
[fn-name feature & fn-tail] | |
`(defenterprise-fn ~fn-name ~feature (fn ~@fn-tail))) | |
(s/def ::defenterprise-schema-args | |
(s/cat :return-schema (s/? (s/cat :- (partial = :-) | |
:schema any?)) | |
:feature (every-pred keyword? (partial not= :-)) | |
:fn-tail (s/* any?))) | |
(defmacro defenterprise-schema | |
[fn-name & args] | |
{:style/indent :defn} | |
(let [parsed (s/conform ::defenterprise-schema-args args)] | |
(when (s/invalid? parsed) | |
(throw (ex-info (s/explain-str ::defenterprise-schema-args args) | |
(s/explain-data ::defenterprise-schema-args args)))) | |
(let [{:keys [feature fn-tail], {:keys [schema]} :return-schema} parsed] | |
`(defenterprise-fn ~fn-name ~feature (schema/fn ~@(when schema [:- schema]) | |
~@fn-tail))))) | |
;;; Sample usage | |
(defenterprise-schema metabase-enterprise.core/my-fn :- schema/Int :audit-app | |
[x] | |
[:oss x]) | |
;; => | |
(defenterprise-fn metabase-enterprise.core/my-fn :audit-app (schema/fn :- schema/Int [x] [:oss x])) |
Not implemented:
- Docstring or metadata map support
- Support for only having an EE impl and conditionally calling it only if we have the appropriate features
- Support for
:any
or:none
as the feature - This doesn't properly propogates metadata on the
fn-name
symbol like:^private
. e.g.defenterprise ^:private metabase-enterprise.core/my-fn
definesmy-fn
but doesn't make it^:private
as well. Should be an easy fix tho
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Something like
macroexpands to