2017-07-06 4 views
1

Ich habe diesen Code Clojure mein Schema für die Antwort Objekte zu definieren, die entwederClojure spec: Wie validieren entweder die eine oder andere Karte

sein kann {:message {:text "Hello"} :delay 3000}

oder

{:action "typing_on" :duration 5000}

Die Karte reply kann entweder :message oder :action bzw. die optionalen Tasten :delay und :duration haben.

Ich versuche, es auf diese Weise mit clojure.spec auszudrücken:

(s/def ::action #{"typing_on" "typing_off" "mark_seen"}) 
(s/def ::duration int?) 
(s/def ::delay int?) 
(s/def ::message map?) 

(s/def ::message-reply (s/keys :req-un [::message] 
           :opt-un [::delay])) 

(s/def ::action-reply (s/keys :req-un [::action] 
           :opt-un [::duration])) 

(s/def ::reply (or ::action-reply ::message-reply)) 

Allerdings werden diese Spezifikationen validieren mit true nur dem ersten Schema sie innerhalb der or Klausel finden, in diesem Fall ::action-reply. Was ich stattdessen erreichen möchte, ist, dass entweder ::action-reply oder ::message-reply gültige Schemas für ::reply sind.

Antwort

5

Ich denke, Sie wollten s/or, nicht or verwenden (was macht in diesem Zusammenhang eigentlich keinen Sinn)?

(s/def ::reply (s/or :action-reply ::action-reply 
        :message-reply ::message-reply)) 

Vielleicht s/conform auf einer Ihrer Werte versuchen, um zu sehen, wie Sie die angepasst verwenden können (‚best-destructured‘) Wert:

(s/conform ::reply {:message {:text "Hello"} :delay 3000}) 
; => [:message-reply {:message {:text "Hello"}, :delay 3000}] 
+0

ich noch nicht sicher bin, warum ich Schlüssel in der s benötigen/oder Klausel, aber das scheint richtig zu beschreiben, was ich will. – feychou

+4

@feychou Mit den Schlüsseln in der '/' -Klausel können Sie sehen, welcher Zweig erstellt wurde, wenn Daten übereinstimmen oder ein Fehler auftritt – Josh

Verwandte Themen