Home

Awesome

malli-keys-relations

Proof of concept implementation for a discussion on the malli channel on Clojurians slack of schemas describing relations between keys in a map.

Hopefully it gets integrated with malli in the future.

Usage

(require com.github.bsless.malli-keys-relations)

Either use -comparator-relation-schemas to get a map of all current schemas and add it to your registry, or use the provided registry var which includes them and the default registry.

New schemas:

:keys/=
:keys/==
:keys/<
:keys/>
:keys/>=
:keys/<=
:keys/not=

Both validation and generation work:

(m/validate
   (m/schema
    [:and
     [:map
      [:x nat-int?]
      [:y nat-int?]]
     [:keys/not= :x :y]]
    {:registry registry})
   {:x 1 :y 1})

(mg/generate
   (m/schema
    [:and
     [:map
      [:x nat-int?]
      [:y nat-int?]]
     [:keys/< :x :y]]
    {:registry registry}))

Implementation notes

:and generators wouldn't work without overriding the default behavior.

Originally:

(defmethod -schema-generator :and [schema options]
  (gen/such-that
   (m/validator schema options)
   (-> schema (m/children options) first (generator options)) 100))

Validation is done according to entire schema but generation only by the first child

Now:

(defn- derive-from-fmap
  [schema options gen]
  (let [props (merge (m/type-properties schema)
                     (m/properties schema))]
    (when-some [fmap (:gen/fmap props)]
      (gen/fmap (m/eval fmap (or options (m/options schema)))
                gen))))

(defmethod mg/-schema-generator :and [schema options]
  (let [[h & t] (m/children schema options)
        base-gen (mg/generator h options)
        gen (reduce (fn [gen schema]
                      (or (derive-from-fmap schema options gen) gen))
                    base-gen
                    t)]
    (gen/such-that (m/validator schema options) gen 100)))

Try to gradually construct a generator from all children if they provide a :gen/fmap and not just a generator.

This could be a general enhancement of :and generators.

License

Copyright © 2021 Ben Sless

This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0.

This Source Code may also be made available under the following Secondary Licenses when the conditions for such availability set forth in the Eclipse Public License, v. 2.0 are satisfied: GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version, with the GNU Classpath Exception which is available at https://www.gnu.org/software/classpath/license.html.