Skip to content

Instantly share code, notes, and snippets.

@Deraen
Created January 5, 2016 19:06
Show Gist options
  • Save Deraen/ff5e0d376c03de046faa to your computer and use it in GitHub Desktop.
Save Deraen/ff5e0d376c03de046faa to your computer and use it in GitHub Desktop.
Silk Schema query params
(defprotocol ToUrlParam
(-to-url-param [this]))
(defn to-url-param [x]
(if (satisfies? ToUrlParam x)
(-to-url-param x)
x))
(extend-protocol ToUrlParam
PersistentHashSet
(-to-url-param [this]
; FIXME: Values must not contains commas
(string/join "," (map to-url-param this)))
ISequential
(-to-url-param [this]
; FIXME: Values must not contains commas
(string/join "," (map to-url-param this)))
Keyword
(-to-url-param [this] (name this)))
(defrecord SchemaQueryParams [schema coercer]
silk/Pattern
(-match [this that]
(coercer (util/map-keys keyword that)))
(-unmatch [this that]
(persistent!
(reduce-kv (fn [acc k v]
(assoc! acc (name k) (to-url-param v)))
(transient {}) (st/select-schema that schema))))
(-match-validator [_]
some?)
(-unmatch-validators [_]
{}))
(defn collection-matcher [schema]
(if (or (sequential? schema) (set? schema))
(fn [value]
(if (string? value)
(into (empty schema) (string/split value #","))
value))))
(defn query-string-coercion-matcher [schema]
(or (collection-matcher schema)
(sc/string-coercion-matcher schema)))
(defn schema-query [schema]
(map->SchemaQueryParams {:schema schema
:coercer (sc/coercer schema query-string-coercion-matcher)}))
;;
;; All routes
;;
(def routes
(silk/routes
[[:tickets [["dashboard"] (schema-query {(s/optional-key :limit) s/Int
(s/optional-key :sort) s/Keyword
(s/optional-key :q) s/Str
(s/optional-key :states) #{s/Keyword}
(s/optional-key :baskets) #{s/Int}
(s/optional-key :technicians) #{s/Int}
(s/optional-key :unsorted) s/Bool})]]
[:ticket [["tickets" :id] (data {:routing/nav :tickets})]]
]))
(deftest schema-query-test
(testing "single required option"
(let [routes (silk/routes [[:tickets [["tickets"] (schema-query {:q s/Str})]]])]
(is (= "/tickets?q=a"
(silk/depart routes :tickets {:q "a"})))
(is (thrown? js/Error (silk/depart routes :tickets)))
(is (= {:domkm.silk/name :tickets :q "a"}
(select-keys (silk/arrive routes "/tickets?q=a") [:domkm.silk/name :q])))
(is (thrown? js/Error (silk/arrive routes "/tickets"))) ))
(testing "single optional option"
(let [routes (silk/routes [[:tickets [["tickets"] (schema-query {(s/optional-key :q) s/Str})]]])]
(is (= "/tickets?q=a"
(silk/depart routes :tickets {:q "a"})))
(is (= "/tickets"
(silk/depart routes :tickets)))
(is (= {:domkm.silk/name :tickets :q "a"}
(select-keys (silk/arrive routes "/tickets?q=a") [:domkm.silk/name :q])))
(is (= {:domkm.silk/name :tickets}
(select-keys (silk/arrive routes "/tickets") [:domkm.silk/name :q])))))
(testing "optional set option"
(let [routes (silk/routes [[:tickets [["tickets"] (schema-query {(s/optional-key :baskets) #{s/Str}})]]])]
(is (= (str "/tickets?baskets=" (js/encodeURIComponent "a,b"))
(silk/depart routes :tickets {:baskets #{"a" "b"}})))
(is (= {:domkm.silk/name :tickets :baskets #{"a" "b"}}
(select-keys (silk/arrive routes (str "/tickets?baskets=" (js/encodeURIComponent "a,b"))) [:domkm.silk/name :baskets])))))
)
(test/run-tests)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment