2016-05-30 18 views
3

Ich habe eingehende Daten des Typs {:loan/amount 1200}.Verwendung von Plumatic Schema zu bigdec

Wäre es möglich, plumatic Schema zu verwenden, um dies zu {:loan/amount 1200M} zu zwingen, dh Zahlen (oder sogar Ziffernfolgen) zu bigdecimals zu zwingen?

Ich weiß nicht, wie man einen neuen Datentyp (wie s/Bigdec) zu definieren, und dann stellen Sie sicher, dass es clojure.core/bigdec verwendet einen bestimmten Wert zu einem java.math.BigDecimal zu zwingen.

Antwort

5

Es gibt zwei getrennte Konzepte in Schema: Validierung und Zwang.

Für die erste müssen Sie Ihr Schema definieren. Klassen werden als Schemas behandelt, sodass Sie keine benutzerdefinierte für java.math.BigDecimal erstellen müssen. Ihr Schema könnte wie folgt aussehen:

(require '[schema.core :as s]) 
(require '[schema.coerce :as c]) 

(s/defschema Loan {:loan/amount java.math.BigDecimal}) 

Jetzt können Sie Ihre Daten gegen das Schema validieren:

(s/validate Loan {:loan/amount 10M}) 
;; => {:loan/amount 10M} 

Nun, wenn Sie einige Daten haben, die Sie möchten Sie zwingen, müssen eine Zwangsfunktion definieren, die ist ein Matcher von einem gewünschten Zielschema (java.math.BigDecimal in Ihrem Fall) zu einer Funktion, die den tatsächlichen Wert in den gewünschten bigdec Wert konvertiert.

(def safe-bigdec (c/safe bigdec) 

schema.coerce/safe ist eine Hilfsfunktion, die die ursprüngliche Funktion wickelt, und wenn das Original eine Ausnahme auslöst, wenn sie aufgerufen wird safe ursprünglichen Eingangswert zurück, anstatt die Ausnahme zu werfen.

wird unsere Matcher-Funktion überprüfen, ob das aktuelle Schema Element BigDecimal und zurück ist Funktion oder nil sonst Umwandlung (dh kein Zwang für andere Arten gibt es):

(defn big-decimal-matcher [schema] 
    (when (= java.math.BigDecimal schema) 
    safe-bigdec)) 

Und wir brauchen endlich eine coercer für die tatsächliche Durchführung Zwang:

(def loan-coercer (c/coercer Loan big-decimal-matcher)) 

Mit all Setup können wir nun unsere coercer verwenden:

(loan-coercer {:loan/amount "12.34"}) 
;; => {:loan/amount 12.34M} 

(loan-coercer {:loan/amount 1234}) 
;; => {:loan/amount 1234M} 

(loan-coercer {:loan/amount "abc"}) 
;; => #schema.utils.ErrorContainer{:error {:loan/amount (not (instance? java.math.BigDecimal "abc"))}} 
+1

Wow, vielen Dank @ piotrek-bzdyl! Das war genau das, was ich brauchte (und ich hoffe, dass andere es auch brauchen). – claj