Reputation: 715
I'm writing some code that looks like this:
(def
authorized-access-levels
{:sales-rep-manager (fn [{{user :user} :session}]
)
:regional-sales-manager (fn [{{user :user} :session}]
)
:vp-of-sales (fn [{{user :user} :session}]
)
})
Later in the code:
(defn
get-my-housing
[{{user :user} :session :as request}]
(let [data-fn (authorized-access-levels (user :access-level))]
(data-fn request)))
This at surface level seems like a great use case for multi methods where the defmulti
would look like this:
(defmulti get-my-housing (fn [{{{access-level :access-level} :user} :session}] access-level))
(defmethod get-my-housing :vp-of-sales [{{user :user} :session}]
)
but I have another need that looks like this:
:auth-fn (fn [user] (contains? authorized-access-levels (user :access-level)))
So (long story short) I need the keys to determine if a user is authorized to get data but then I use the key to dispatch to a function via a map.
Can I query a multimethod to see what it's dispatch values are? If so then I can write this as a multimethod and then query it for authorization. Any other ideas?
Upvotes: 3
Views: 1063
Reputation: 13941
Can I query a multimethod to see what it's dispatch values are?
Yes, you can do introspection on a multimethod using the methods
function to get the dispatch table for a multimethod, and the get-method
to look up the method for a given dispatch value.
user=> (defmulti authorized? :access-level)
user=> (defmethod authorized? :admin [_] true)
user=> (defmethod authorized? :user [_] false)
user=> (keys (methods authorized?))
(:user :admin)
user=> ((get-method authorized? :admin) {:access-level :admin})
true
Upvotes: 9
Reputation: 1511
I'm not sure if I understood correctly but let me try. You have three different concepts that we want to model as three different functions: get a users access-level, get a users authorization from the access level, and finally get the housing. I would model it like this:
(defn get-access-level [user]
(:access-level user))
(defn authorized? [user]
(contains? authorized-access-levels (get-access-level user)))
(defmulti get-my-housing (fn [req]
(get-access-level (get-in req [:session :user]))
(defmethod get-my-housing :vp-of-sales
[req]
((:vp-of-sales authorized-access-levels) req))
This is worth it if each defmethod
has a different behavior. If they all access the same map with a different key the extra indirection is probably not worth it.
Upvotes: 0