Skip to content

Instantly share code, notes, and snippets.

@vvvvalvalval
Last active August 29, 2015 14:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vvvvalvalval/1269001937f91eb5fd8a to your computer and use it in GitHub Desktop.
Save vvvvalvalval/1269001937f91eb5fd8a to your computer and use it in GitHub Desktop.
discarding unknown key in schema
(ns bs.utils.schema-cleaner "TL;DR look in the tests how the `cleaner` function is used."
(:require [schema.core :as s]
[schema.coerce :as sco]
[schema.utils :as scu]
)
(:use clojure.repl clojure.pprint))
(deftype ^:private GarbageType [])
(def ^:private garbage-const (GarbageType.))
(def Garbage "Garbage schema, use it to flag schema attributes to be removed by `cleaner`." GarbageType)
(defn- garbage-flagging-matcher "schema.coerce matcher to detect and flag garbage values." [schema]
(cond (= schema Garbage) (constantly garbage-const)
:else identity))
(defn- garbage-flagger "Accepts a schema (supposedly that uses Garbage as a sub-schema),
and returns a function that flags garbage values by coercing them to `garbage-const`"
[schema] (sco/coercer schema garbage-flagging-matcher))
(defn- clean-garbage "Accepts a clojure data structures, and removes the values equal to `garbage-const."
[v]
(cond
(= garbage-const v) nil
(map? v) (->> v seq
(reduce (fn [m [k nv]]
(if (= garbage-const nv)
(dissoc m k)
(assoc m k (clean-garbage nv)))
) v))
(vector? v) (->> v (remove #(= % garbage-const)) (map clean-garbage) vec)
(sequential? v) (->> v (remove #(= % garbage-const)) (map clean-garbage) doall)
:else v
))
(defn cleaner "Accepts a Schema, which presumably uses Garbage to match illegal values,
and returns a function that accepts a data structure (potentially an instance of the schema)
and will remove its values that are not anticipated in the schema, e.g illegal map keys."
[schema]
(let [flag (garbage-flagger schema)]
(fn [data]
(-> data flag clean-garbage)
)))
(ns bs.test.utils.schema-cleaner
(:require [clojure.test :refer :all]
[midje.sweet :as midje :refer :all]
[schema.core :as sc]
[bs.utils.schema-cleaner :as target :refer :all]
))
(facts
"About `cleaner`"
(let [MySchema {:a sc/Int
:b {:c sc/Str
(sc/optional-key :d) sc/Bool
sc/Any Garbage}
:e [{:f sc/Inst
sc/Any Garbage}]
sc/Any Garbage}]
(fact
"Will remove keys matched to Garbage by the schema"
((cleaner MySchema) {:a 1
:garbage-key "hello"
:b {:c "Hellow world"
:d false
42432424 23/2}
:e [{:f #inst "2015-07-23T15:49:33.073-00:00"
'a-garbage-key "remove me!!"
"another garbage key" :remove-me!!}
{:f #inst "2015-07-23T15:53:33.073-00:00"}]})
=> {:a 1
:b {:c "Hellow world"
:d false}
:e [{:f #inst "2015-07-23T15:49:33.073-00:00"}
{:f #inst "2015-07-23T15:53:33.073-00:00"}]}
((cleaner MySchema) {:a 1
:garbage-key "hello"
:b {:c "Hellow world"
42432424 23/2}
:e [{:f #inst "2015-07-23T15:49:33.073-00:00"
'a-garbage-key "remove me!!"
"another garbage key" :remove-me!!}
{:f #inst "2015-07-23T15:53:33.073-00:00"}]})
=> {:a 1
:b {:c "Hellow world"}
:e [{:f #inst "2015-07-23T15:49:33.073-00:00"}
{:f #inst "2015-07-23T15:53:33.073-00:00"}]}
)
(fact
"Will still fail if the schema is not otherwise respected"
(type ((cleaner MySchema) {:a "11"
:b {:c "Hellow world"
:d false}
:e [{:f #inst "2015-07-23T15:49:33.073-00:00"}
{:f #inst "2015-07-23T15:53:33.073-00:00"}]}))
=> schema.utils.ErrorContainer
(type ((cleaner MySchema) {:a 1
:e [{:f #inst "2015-07-23T15:49:33.073-00:00"}
{:f #inst "2015-07-23T15:53:33.073-00:00"}]}))
=> schema.utils.ErrorContainer
)
)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment