From 364b9766c948c976af028bc60926399da79e1771 Mon Sep 17 00:00:00 2001 From: Bruno do Nascimento Maciel Date: Sun, 11 Jan 2026 16:45:28 -0300 Subject: [PATCH] improve conditional schema support --- src/service_component/interceptors.clj | 28 +++++++++++++++++-- .../service_component/interceptors_test.clj | 6 ++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/service_component/interceptors.clj b/src/service_component/interceptors.clj index b68044c..7c7438d 100644 --- a/src/service_component/interceptors.clj +++ b/src/service_component/interceptors.clj @@ -38,9 +38,31 @@ (defn ^:private json-matcher [schema] - (or (when (and (instance? schema.core.EqSchema schema) - (keyword? (:v schema))) - (fn [x] (if (string? x) (keyword x) x))) + (or (when (instance? schema.core.EqSchema schema) + (when (keyword? (:v schema)) + (fn [x] (if (string? x) (keyword x) x)))) + + (when (instance? schema.core.ConditionalSchema schema) + (fn [data] + (let [preds-and-schemas-vec (:preds-and-schemas schema) + ;; Find the schema that corresponds to the first matching predicate + schema-to-use (loop [ps-pairs (partition-all 2 preds-and-schemas-vec)] + (if-let [[p s] (first ps-pairs)] + (cond + ;; Case 1: The 'else' clause. `s` is nil, so `p` is the schema. + (nil? s) p + ;; Case 2: The predicate `p` matches the data. Return the schema `s`. + (p data) s + ;; Case 3: No match, try the next pair. + :else (recur (next ps-pairs))) + ;; Default case if loop finishes (shouldn't happen with valid s/conditional) + nil))] + ;; If we found a schema, create a coercer for it and run it. + (if schema-to-use + ((coerce/coercer schema-to-use json-matcher) data) + ;; Otherwise, return the data as-is. + data)))) + (coerce/json-coercion-matcher schema))) (defn wire-in-body-schema [schema] diff --git a/test/unit/service_component/interceptors_test.clj b/test/unit/service_component/interceptors_test.clj index 7339193..fafd5dc 100644 --- a/test/unit/service_component/interceptors_test.clj +++ b/test/unit/service_component/interceptors_test.clj @@ -37,10 +37,16 @@ (schema.core/defschema EqKeywordSchema {:type (schema.core/eq :hello-world)}) +(schema.core/defschema ConditionalEqKeywordSchema + (schema.core/conditional #(= (:type #p %) :hello-world) EqKeywordSchema)) + (s/deftest wire-in-body-schema-test (is (match? {:request {:json-params {:type :hello-world}}} (chain/execute {:request {:json-params {:type "hello-world"}}} [(interceptors/wire-in-body-schema EqKeywordSchema)]))) + (is (match? {:request {:json-params {:type :hello-world}}} + (chain/execute {:request {:json-params {:type "hello-world"}}} [(interceptors/wire-in-body-schema ConditionalEqKeywordSchema)]))) + (let [ex (is (thrown? ExceptionInfo (chain/execute {:request {:json-params {:type "test"}}} [(interceptors/wire-in-body-schema EqKeywordSchema)])))] (is (match? {:status 422 :error "invalid-request-body-payload"