deercreeklabs / lancaster

Apache Avro library for Clojure and ClojureScript
Other
60 stars 5 forks source link

plumatic schema - Any? #12

Closed mischac closed 3 years ago

mischac commented 3 years ago

I get an Any Any for each avro record when converting to a plumatic schema via a lancaster schema.

Example:

{Any Any :version Int}

It might relate to this line, not sure.

chadharrington commented 3 years ago

@mischac This is desired behavior. As in Clojure spec, Lancaster takes the view that a schema should not exclude extra information from being included in the map/record. You can define the keys and types of the things you care about and check that they match those definitions. However, leaving the map/record open to containing extra things that you don't care about greatly improves reuse and compatibility. It enables the common pattern of creating a map of information and passing it along to various functions that manipulate it. Step 2 of a process may add a key that is used by Step 7. However Steps 3-6 don't need that key nor do they care about it. However, if they excluded it, Step 7 would have to get the key some other way. Rich Hickey has discussed this principle a few times and Lancaster follows his approach. Lancaster's conversion to Plumatic schema enables open maps/records by adding {Any Any}.

Here's some a REPL session exploring this:

user> (require '[deercreeklabs.lancaster :as l])
nil
user> (l/def-record-schema person-schema
        [:name l/string-schema]
        [:age l/int-schema])
#'user/person-schema
user> (l/edn person-schema)
{:name :user/person,
 :type :record,
 :fields
 [{:name :name, :type [:null :string], :default nil}
  {:name :age, :type [:null :int], :default nil}]}
user> (l/plumatic-schema person-schema)
{Any Any,
 {:k :name}
 (conditional
  nil?
  (eq nil)
  deercreeklabs.lancaster.utils/valid-bytes-or-string?
  (pred deercreeklabs.lancaster.utils/valid-bytes-or-string?)),
 {:k :age} (conditional nil? (eq nil) int? Int)}
user> (def plu (l/plumatic-schema person-schema))
#'user/plu
user> (require '[schema.core :as s])
nil
user> (s/check plu {:name "Alice" :age 37})
nil
user> (s/check plu {:name "Alice" :age "not an int"})
{:age (not (some-matching-condition? "not an int"))}
user> (s/check plu {:name "Alice" :age 37 :fav-color :red})
nil