如何为Datomic返回的带命名空间关键字的数据编写Clojure Spec?
问题根源与解决方案
核心问题
你遇到的问题来自两个关键误解:
- 混淆了关键字命名空间与代码命名空间:
schema.event是你的Clojure代码命名空间,但你定义的Spec是针对关键字:event/date(命名空间为event),两者没有绑定关系——关键字的命名空间是其自身属性,和代码所在的命名空间无关。 - 错误使用了
:req-un选项:s/keys的:req-un参数用于要求Map中存在不带命名空间的关键字,并将其关联到带命名空间的Spec;而你需要验证的是Datomic返回的带命名空间的:event/date,因此:req-un完全不匹配你的需求。
正确的Spec写法
1. 保持schema.event的定义不变
(ns schema.event (:require [clojure.spec.alpha :as s])) ; 定义针对关键字:event/date的全局Spec (s/def :event/date string?)
2. 在主命名空间编写验证Spec
(ns your.app.namespace (:require [clojure.spec.alpha :as s] [schema.event])) ; 引入schema.event,让其中的Spec定义生效 ; 定义::id的Spec (s/def ::id string?) ; 使用:req参数指定必须存在的带命名空间关键字 (s/def ::result (s/keys :req [::id :event/date]))
验证测试
; 验证Datomic返回的带命名空间的Map (s/valid? ::result {:id "123abc" :event/date "1/1/2020"}) ; => true ; 验证不带命名空间的Map(会失败,符合预期) (s/valid? ::result {:id "123abc" :date "1/1/2020"}) ; => false
额外说明
如果需要用别名关联关键字(比如想在Spec里用::event-date对应:event/date),可以用s/keys的:req配合别名定义:
(ns your.app.namespace (:require [clojure.spec.alpha :as s] [schema.event])) (s/def ::id string?) (s/def ::event-date :event/date) ; 给:event/date的Spec起别名 (s/def ::result (s/keys :req [::id ::event-date])) ; 使用别名验证
内容的提问来源于stack exchange,提问作者newBieDev
相关产品推荐
相关产品推荐

