Skip to content

Commit

Permalink
Move number formats to malli.swagger
Browse files Browse the repository at this point in the history
  • Loading branch information
Deraen committed Jan 26, 2021
1 parent 1e524eb commit 91cd37a
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 46 deletions.
24 changes: 10 additions & 14 deletions src/malli/json_schema.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,17 @@

(defmulti accept (fn [name _schema _children _options] name) :default ::default)

;; Note, format value for integer/number is from OpenAPI spec.
;; JSON Schema spesifies formats for strings like uuid and date-time, but
;; not numbers, but custom values are allowed.

(defmethod accept ::default [_ _ _ _] {})
(defmethod accept 'any? [_ _ _ _] {})
(defmethod accept 'some? [_ _ _ _] {})
(defmethod accept 'number? [_ _ _ _] {:type "number" :format "double"})
(defmethod accept 'integer? [_ _ _ _] {:type "integer" :format "int32"})
(defmethod accept 'int? [_ _ _ _] {:type "integer" :format "int64"})
(defmethod accept 'pos-int? [_ _ _ _] {:type "integer", :format "int64", :minimum 1})
(defmethod accept 'neg-int? [_ _ _ _] {:type "integer", :format "int64", :maximum -1})
(defmethod accept 'nat-int? [_ _ _ _] {:type "integer", :format "int64" :minimum 0})
(defmethod accept 'float? [_ _ _ _] {:type "number" :format "float"})
(defmethod accept 'double? [_ _ _ _] {:type "number" :format "double"})
(defmethod accept 'number? [_ _ _ _] {:type "number"})
(defmethod accept 'integer? [_ _ _ _] {:type "integer"})
(defmethod accept 'int? [_ _ _ _] {:type "integer"})
(defmethod accept 'pos-int? [_ _ _ _] {:type "integer", :minimum 1})
(defmethod accept 'neg-int? [_ _ _ _] {:type "integer", :maximum -1})
(defmethod accept 'nat-int? [_ _ _ _] {:type "integer", :minimum 0})
(defmethod accept 'float? [_ _ _ _] {:type "number"})
(defmethod accept 'double? [_ _ _ _] {:type "number"})
(defmethod accept 'pos? [_ _ _ _] {:type "number" :exclusiveMininum 0})
(defmethod accept 'neg? [_ _ _ _] {:type "number" :exclusiveMaximum 0})
(defmethod accept 'boolean? [_ _ _ _] {:type "boolean"})
Expand Down Expand Up @@ -71,7 +67,7 @@
(defmethod accept 'empty? [_ _ _ _] {:type "array" :maxItems 0 :minItems 0})
(defmethod accept 'associative? [_ _ _ _] {:type "object"})
(defmethod accept 'sequential? [_ _ _ _] {:type "array"})
(defmethod accept 'ratio? [_ _ _ _] {:type "number"})
#?(:clj (defmethod accept 'ratio? [_ _ _ _] {:type "number"}))
(defmethod accept 'bytes? [_ _ _ _] {:type "string" :format "byte"})

(defmethod accept :> [_ _ [value] _] {:type "number" :exclusiveMinimum value})
Expand Down Expand Up @@ -109,7 +105,7 @@
(merge {:type "integer"} (-> schema m/properties (select-keys [:min :max]) (set/rename-keys {:min :minimum, :max :maximum}))))

(defmethod accept :double [_ schema _ _]
(merge {:type "number" :format "double"}
(merge {:type "number"}
(-> schema m/properties (select-keys [:min :max]) (set/rename-keys {:min :minimum, :max :maximum}))))

(defmethod accept :boolean [_ _ _ _] {:type "boolean"})
Expand Down
24 changes: 21 additions & 3 deletions src/malli/swagger.cljc
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
(ns malli.swagger
(:require [malli.json-schema :as json-schema]
[malli.core :as m]))
[malli.core :as m]
[clojure.set :as set]))

(defprotocol SwaggerSchema
(-accept [this children options] "transforms schema to Swagger Schema"))

(defmulti accept (fn [name _schema _children _options] name) :default ::default)

(defmethod accept ::default [name schema children options] (json-schema/accept name schema children options))
(defmethod accept 'float? [_ _ _ _] {:type "number" :format "float"})
(defmethod accept 'double? [_ _ _ _] {:type "number" :format "double"})
(defmethod accept 'nil? [_ _ _ _] {})

(defmethod accept :and [_ _ children _] (assoc (first children) :x-allOf children))
Expand All @@ -22,6 +21,25 @@

(defmethod accept :tuple [_ _ children _] {:type "array" :items {} :x-items children})

;; Number formats are only defined in Swagger/OpenAPI spec.

(defmethod accept 'number? [_ _ _ _] {:type "number" :format "double"})
(defmethod accept 'integer? [_ _ _ _] {:type "integer" :format "int32"})
(defmethod accept 'int? [_ _ _ _] {:type "integer" :format "int64"})
(defmethod accept 'pos-int? [_ _ _ _] {:type "integer", :format "int64", :minimum 1})
(defmethod accept 'neg-int? [_ _ _ _] {:type "integer", :format "int64", :maximum -1})
(defmethod accept 'nat-int? [_ _ _ _] {:type "integer", :format "int64" :minimum 0})
(defmethod accept 'float? [_ _ _ _] {:type "number" :format "float"})
(defmethod accept 'double? [_ _ _ _] {:type "number" :format "double"})

(defmethod accept :int [_ schema _ _]
(merge {:type "integer" :format "int64"}
(-> schema m/properties (select-keys [:min :max]) (set/rename-keys {:min :minimum, :max :maximum}))))

(defmethod accept :double [_ schema _ _]
(merge {:type "number" :format "double"}
(-> schema m/properties (select-keys [:min :max]) (set/rename-keys {:min :minimum, :max :maximum}))))

(defn- -swagger-walker [schema _ children options]
(let [p (merge (m/type-properties schema) (m/properties schema))]
(or (json-schema/unlift p :swagger)
Expand Down
45 changes: 21 additions & 24 deletions test/malli/json_schema_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@

(def expectations
[;; predicates
[pos-int? {:type "integer", :format "int64", :minimum 1}]
[float? {:type "number" :format "float"}]
[pos-int? {:type "integer", :minimum 1}]
[float? {:type "number"}]
;; comparators
[[:> 6] {:type "number", :exclusiveMinimum 6}]
[[:>= 6] {:type "number", :minimum 6}]
[[:< 6] {:type "number", :exclusiveMaximum 6}]
[[:<= 6] {:type "number", :maximum 6}]
[[:= "x"] {:const "x"}]
;; base
[[:and int? pos-int?] {:allOf [{:type "integer", :format "int64"}
{:type "integer", :format "int64" :minimum 1}]}]
[[:or int? string?] {:anyOf [{:type "integer", :format "int64"} {:type "string"}]}]
[[:and int? pos-int?] {:allOf [{:type "integer"}
{:type "integer", :minimum 1}]}]
[[:or int? string?] {:anyOf [{:type "integer"} {:type "string"}]}]
[[:map
[:a string?]
[:b {:optional true} string?]
Expand All @@ -33,8 +33,7 @@
[:human [:map {:gen/fmap '#(assoc % :type :human)} [:type keyword?] [:name string?] [:address [:map [:country keyword?]]]]]]
{:oneOf [{:type "object",
:properties {:type {:type "string"}
:size {:type "integer"
:format "int64"}},
:size {:type "integer"}},
:required [:type :size]}
{:type "object",
:properties {:type {:type "string"},
Expand All @@ -58,16 +57,17 @@
[[:re "^[a-z]+\\.[a-z]+$"] {:type "string", :pattern "^[a-z]+\\.[a-z]+$"}]
[[:string {:min 1, :max 4}] {:type "string", :minLength 1, :maxLength 4}]
[[:int {:min 1, :max 4}] {:type "integer", :minimum 1, :maximum 4}]
[[:double {:min 1, :max 4}] {:type "number", :format "double", :minimum 1, :maximum 4}]
[[:double {:min 1, :max 4}] {:type "number", :minimum 1, :maximum 4}]
[:keyword {:type "string"}]
[:qualified-keyword {:type "string"}]
[:symbol {:type "string"}]
[:qualified-symbol {:type "string"}]
[:uuid {:type "string", :format "uuid"}]

[integer? {:type "integer" :format "int32"}]
[ratio? {:type "number"}]
#?(:clj [rational? {:type "number"}])
[integer? {:type "integer"}]
#?@(:clj [[ratio? {:type "number"}]
[rational? {:type "number"}]]
:cljs [])
;; protocols
[(reify
m/Schema
Expand Down Expand Up @@ -109,15 +109,15 @@
[:x5 {:json-schema {:type "x-string"}} [:string {:json-schema {:default "x"}}]]]))))

(testing "with properties"
(is (= {:allOf [{:type "integer", :format "int64"}]
(is (= {:allOf [{:type "integer"}]
:title "age"
:description "blabla"
:default 42}
(json-schema/transform
[:and {:title "age"
:description "blabla"
:default 42} int?])))
(is (= {:allOf [{:type "integer", :format "int64"}]
(is (= {:allOf [{:type "integer"}]
:title "age2"
:description "blabla2"
:default 422
Expand All @@ -137,9 +137,9 @@
(testing "merge"
(is (= {:title "merge",
:type "object",
:properties {:x {:type "integer", :format "int64", :example 42},
:y {:type "integer", :format "int64"},
:z {:type "integer", :format "int64"}},
:properties {:x {:type "integer", :example 42},
:y {:type "integer"},
:z {:type "integer"}},
:required [:x :y :z]}
(json-schema/transform
[:merge {:title "merge"}
Expand All @@ -150,8 +150,8 @@
(testing "union"
(is (= {:title "union",
:type "object",
:properties {:x {:anyOf [{:type "integer", :format "int64"} {:type "string"}]}
:y {:type "integer", :format "int64"}},
:properties {:x {:anyOf [{:type "integer"} {:type "string"}]}
:y {:type "integer"}},
:required [:x :y]}
(json-schema/transform
[:union {:title "union"}
Expand All @@ -162,7 +162,7 @@
(testing "select-keys"
(is (= {:title "select-keys"
:type "object"
:properties {:x {:type "integer", :format "int64"}}
:properties {:x {:type "integer"}}
:required [:x]}
(json-schema/transform
[:select-keys {:title "select-keys"}
Expand All @@ -182,13 +182,11 @@
:description {:type "string"},
:origin {:oneOf [{:$ref "#/definitions/Country"} {:type "null"}]},
:price {:type "integer"
:format "int64"
:minimum 1}},
:required [:name :origin :price]},
"OrderLine" {:type "object",
:properties {:burger {:$ref "#/definitions/Burger"},
:amount {:type "integer"
:format "int64"}},
:amount {:type "integer"}},
:required [:burger :amount]},
"Order" {:type "object",
:properties {:lines {:type "array"
Expand All @@ -197,8 +195,7 @@
:properties {:delivered {:type "boolean"},
:address {:type "object",
:properties {:street {:type "string"},
:zip {:type "integer",
:format "int64"},
:zip {:type "integer"},
:country {:$ref "#/definitions/Country"}},
:required [:street :zip :country]}},
:required [:delivered :address]}},
Expand Down
26 changes: 21 additions & 5 deletions test/malli/swagger_test.cljc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
(ns malli.swagger-test
(:require [clojure.test :refer [deftest testing is are]]
[malli.core-test]
[malli.swagger :as swagger]
[malli.core :as m]
[malli.util :as mu]))
Expand All @@ -9,10 +10,10 @@
[pos-int? {:type "integer", :format "int64", :minimum 1}]
[float? {:type "number" :format "float"}]
;; comparators
[[:> 6] {:type "number", :format "double", :exclusiveMinimum 6}]
[[:>= 6] {:type "number", :format "double", :minimum 6}]
[[:< 6] {:type "number", :format "double", :exclusiveMaximum 6}]
[[:<= 6] {:type "number", :format "double", :maximum 6}]
[[:> 6] {:type "number", :exclusiveMinimum 6}]
[[:>= 6] {:type "number", :minimum 6}]
[[:< 6] {:type "number", :exclusiveMaximum 6}]
[[:<= 6] {:type "number", :maximum 6}]
;; base
[[:and int? pos-int?] {:type "integer"
:format "int64"
Expand Down Expand Up @@ -66,11 +67,26 @@
{:type "string"}]}]
[[:re "^[a-z]+\\.[a-z]+$"] {:type "string", :pattern "^[a-z]+\\.[a-z]+$"}]
[[:string {:min 1, :max 4}] {:type "string", :minLength 1, :maxLength 4}]
[[:int {:min 1, :max 4}] {:type "integer", :format "int64", :minimum 1, :maximum 4}]
[[:double {:min 1, :max 4}] {:type "number", :format "double" :minimum 1, :maximum 4}]
[:keyword {:type "string"}]
[:qualified-keyword {:type "string"}]
[:symbol {:type "string"}]
[:qualified-symbol {:type "string"}]
[:uuid {:type "string", :format "uuid"}]

[integer? {:type "integer" :format "int32"}]
#?@(:clj [[ratio? {:type "number"}]
[rational? {:type "number"}]]
:cljs [])
;; protocols
[(reify
m/Schema
(-type-properties [_])
(-properties [_])
(-type [_])
(-form [_])
(-type-properties [_])
(-validator [_] int?)
(-walk [t w p o] (m/-outer w t p nil o))
swagger/SwaggerSchema
(-accept [_ _ _] {:type "custom"})) {:type "custom"}]
Expand Down

0 comments on commit 91cd37a

Please sign in to comment.