избегать повторения при использовании schema.core

Я определил следующую схему:

(s/defschema Card
 {:cardNumber s/Str
  :cvv s/Str
  :creditCardMonthValidity s/Str
  :creditCardYearValidity s/Str
  :cpf s/Str
  :name s/Str
  :phoneNumber s/Str})

а затем в маршруте я использую те же ключи в ответе JSON:

(GET "/card" []
        :summary "fetches card info given the access token & checkout id"
        :query-params [accessToken :- String checkoutId :- String]
        :return Card
        (let [checkout  (CheckoutApi/show checkoutId accessToken)
              card      (.getCard checkout)
              contact   (.getContact checkout)
              (ok {:cardNumber (.getAccountNumber card)
                   :cvv "000"
                   :creditCardMonthValidity (.getExpiryMonth card)
                   :creditCardYearValidity (.getExpiryYear card)
                   :cpf (.getNationalID contact)
                   :name (.getFirstName contact)
                   :phoneNumber (.getPhoneNumber contact)})]))

есть ли элегантный способ избежать повторения имен ключей? Что-то вроде метода конструктора, где я могу просто передать значения? (возможно, в каком-то определенном порядке)


person prog keys    schedule 12.01.2017    source источник


Ответы (1)


может работать что-то вроде этого: вы можете определить макрос, который определяет схему и конструктор одновременно.

user> (defmacro defresponse [schema constructor-name constructor-params data]
        `(do
           (s/defschema ~schema ~(into {} (map (fn [[k [t _]]] [k t])
                                               data)))
           (defn ~constructor-name ~constructor-params
             ~(into {} (map (fn [[k [_ init]]] [k init])
                            data)))))
#'user/defresponse
user> (defresponse Card card-response [card contact]
        {:cardNumber [s/Str (.getAccountNumber card)]
         :cvv [s/Str "000"]
         :creditCardMonthValidity [s/Str (.getExpiryMonth card)]
         :creditCardYearValidity [s/Str (.getExpiryYear card)]
         :cpf [s/Str (.getNationalID contact)]
         :name [s/Str (.getFirstName contact)]
         :phoneNumber [s/Str (.getPhoneNumber contact)]})

эта отсрочка ответа будет расширена до следующего:

(do
  (s/defschema
    Card
    {:cardNumber s/Str,
     :cvv s/Str,
     :creditCardMonthValidity s/Str,
     :creditCardYearValidity s/Str,
     :cpf s/Str,
     :name s/Str,
     :phoneNumber s/Str})
  (defn card-response [card contact]
    {:cardNumber (.getAccountNumber card),
     :cvv "000",
     :creditCardMonthValidity (.getExpiryMonth card),
     :creditCardYearValidity (.getExpiryYear card),
     :cpf (.getNationalID contact),
     :name (.getFirstName contact),
     :phoneNumber (.getPhoneNumber contact)}))

а затем вы можете использовать свою схему, как обычно, и card-response вот так:

(let [checkout  (CheckoutApi/show checkoutId accessToken)
      card      (.getCard checkout)
      contact   (.getContact checkout)]
  (ok (card-response card contact)))

(этот не проверял, но он должен работать. В противном случае обновлю его утром)

person leetwinski    schedule 12.01.2017