bidi icon indicating copy to clipboard operation
bidi copied to clipboard

Om.next/tempid support.

Open currentoor opened this issue 9 years ago • 2 comments

Om.next defines these custom types called tempids. https://github.com/omcljs/om/blob/ee4c7ac33934fcd9b3ea663045ced1408dd7df24/src/main/om/tempid.cljc#L8

I want bidi to support routing to them. So far I'm dealing with them by calling (.-id tempid) and using a uuid regex in my bidi routes to handle them.

I tried extending the ParameterEncoding protocol but it results in an error. Is there a way to do this?

(def id+
  "Matches both a uuid and a datoic db/id."
  #"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}|-?\d+")

(extend-protocol bidi/ParameterEncoding
  om.tempid/TempId
  (bidi.bidi/encode-parameter [tempid]
    (str (.-id tempid))))

(defn tempid [id]
  (om.next/tempid id))

(def routes
  ["/"
   {
    "dashboards/" {""                  :dashboards/index
                   "new"               :dashboards/new
                   [[id+ :id] "/edit"] :dashboards/edit
                   [[tempid :id] "/edit"] :dashboards/edit2
                   }
    ""            [[true :dashboards/index]]}])

(bidi.bidi/path-for routes :dashboards/edit :id (.-id (om.next/tempid)))
=> "/dashboards/eaf9396e-c840-4a70-aa68-36e7b8bc6177/edit"

(bidi.bidi/path-for routes :dashboards/edit2 :id (om.next/tempid))
=> #object[Error Error: No matching clause: function arc$router$tempid(id)

currentoor avatar Oct 29 '16 21:10 currentoor

Update, after looking at the bidi source code I don't think bidi supports custom types in the routes. Is that correct?

If so, what would it take to make bidi more extensible? Any desire to do this?

currentoor avatar Nov 03 '16 17:11 currentoor

I was able to make it work like this. But I would love for the function types to be more extensible rather than monkey-patching bidi. The problem IMO is that the bidi/PatternSegment protocol for function is not extensible. I think this could be addressed by using multimethods in the bodies of the function type protocol methods.

If there is interest in doing this I would be happy to submit a PR.

(ns arc.router
  (:require
   [om.next :as om]
   [bidi.bidi :as bidi]))

(extend-protocol bidi/PatternSegment
  function
  (segment-regex-group [this]
    (condp = this
      keyword    "[A-Za-z]+[A-Za-z0-9\\*\\+\\!\\-\\_\\?\\.]*(?:%2F[A-Za-z]+[A-Za-z0-9\\*\\+\\!\\-\\_\\?\\.]*)?"
      long       "-?\\d{1,19}"
      bidi/uuid  "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}"
      om/tempid  "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}"
      :otherwise (throw (ex-info (str "Unidentified function qualifier to pattern segment: " this) {}))))
  (transform-param [this]
    (condp = this
      ;; keyword is close, but must be applied to a decoded string, to work with namespaced keywords
      keyword   (comp keyword bidi/url-decode)
      long      #(js/Number %)
      bidi/uuid bidi/uuid
      om/tempid om/tempid
      (throw (ex-info (str "Unrecognized function " this) {}))))
  (matches? [this s]
    (condp = this
      keyword   (keyword? s)
      long      (not (js/isNaN s))
      bidi/uuid (instance? cljs.core.UUID s)
      om/tempid (om/tempid? s))))

(def routes
  ["/"
   {"dashboards/" {[[long :id] "/edit"]       :dashboards/edit
                   [[bidi/uuid :id] "/edit2"] :dashboards/edit2
                   [[om/tempid :id] "/edit3"] :dashboards/edit3}
    ""            [[true :dashboards/index]]}])

;; Long
(bidi.bidi/path-for routes :dashboards/edit :id 34)
=> "/dashboards/34/edit"

(bidi.bidi/match-route routes "/dashboards/34/edit")
=> {:route-params {:id 34}, :handler :dashboards/edit}

;; UUID
(bidi/path-for routes :dashboards/edit2 :id (random-uuid))
=> "/dashboards/0079f19d-2a52-476a-a454-b9a28aae1d7c/edit2"

(bidi.bidi/match-route routes "/dashboards/e544018a-e3c8-4123-b555-fdf66336eb0e/edit2")
=> {:route-params {:id #uuid "e544018a-e3c8-4123-b555-fdf66336eb0e"}, :handler :dashboards/edit2}

;; om.next/tempid
(bidi/path-for routes :dashboards/edit3 :id (om/tempid))
=> "/dashboards/64033318-13e0-4683-9475-e9743589bd73/edit3"

(bidi/match-route routes "/dashboards/e544018a-e3c8-4123-b555-fdf66336eb0e/edit3")
=> {:route-params {:id #om/id["e544018a-e3c8-4123-b555-fdf66336eb0e"]}, :handler :dashboards/edit3}

currentoor avatar Nov 03 '16 21:11 currentoor