使用Plumatic Sc​​hema强制bigdec

cla*_*laj 3 clojure coercion plumatic-schema

我有类型的传入数据{:loan/amount 1200}.

是否有可能使用plumatic Schema强制执行此操作,即将{:loan/amount 1200M}数字(甚至是数字串)强制转换为大数字?

我不知道如何定义新的数据类型(如s/Bigdec),然后确保它用于clojure.core/bigdec强制某个值为a java.math.BigDecimal.

Pio*_*dyl 5

Schema中有两个独立的概念:验证和强制.

对于第一个,您需要定义架构.类被视为模式,因此您无需为其创建自定义类java.math.BigDecimal.您的架构可能如下所示:

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

(s/defschema Loan {:loan/amount java.math.BigDecimal})
Run Code Online (Sandbox Code Playgroud)

现在,您可以根据架构验证数据:

(s/validate Loan {:loan/amount 10M})
;; => {:loan/amount 10M}
Run Code Online (Sandbox Code Playgroud)

现在,如果你有一些你想要强制的数据,你需要定义一个强制函数,它是一个匹配器,从期望的目标模式(java.math.BigDecimal在你的情况下)到一个将实际值转换为所需bigdec值的函数.

(def safe-bigdec (c/safe bigdec)
Run Code Online (Sandbox Code Playgroud)

schema.coerce/safe是一个实用函数,它包装原始函数,如果原始函数在调用时抛出异常,safe将返回原始输入值而不是抛出异常.

我们的匹配器函数将检查当前模式元素是否为BigDecimal返回转换函数或nil其他(意味着没有其他类型的强制):

(defn big-decimal-matcher [schema]
  (when (= java.math.BigDecimal schema)
    safe-bigdec))
Run Code Online (Sandbox Code Playgroud)

最后我们需要一个强制执行实际强制:

(def loan-coercer (c/coercer Loan big-decimal-matcher))
Run Code Online (Sandbox Code Playgroud)

通过所有设置,我们现在可以使用我们的coercer:

(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"))}}
Run Code Online (Sandbox Code Playgroud)