;; project.clj or build.boot
[modelizer/core "0.0.5"]
;; deps.edn
{:deps {modelizer {:mvn/version "0.0.5"}}}
Attention: This library is currently under active development and still in alpha
A fast data-driven Clojure(Script) library for describing data and metadata that helps ensure data quality and governance.
Simple data-driven syntax
Fast
Extensible
Serializable
Add the following dependency in your project:
;; project.clj or build.boot
[modelizer/core "0.0.5"]
;; deps.edn
{:deps {modelizer {:mvn/version "0.0.5"}}}
You can see a full example {example-your-app}[here].
(ns your.app
(:require
[modelizer.core :as m]
[modelizer.generator :as gen]))
;;;;
;; Registry
;;;;
;; Available functions for working with registry:
;; - (m/get-schemas)
;; - (m/get-schemas name)
;; - (m/get-schema name)
;; - (m/get-schema name version)
;; - (m/register schema)
;; - (m/register-generator validator generator)
;; - (m/defschema [schema])
;; - (m/defschema [name form])
;; - (m/defschema [name doc form])
;; - (m/defschema [name doc meta form])
;; - (m/defschema [name version doc meta form])
;; - (m/defschema [name version status doc meta form])
;; Create schema
(m/defschema :example
[:or :string? [:and :pos-int? [:not :zero?]]])
;; => #modelizer/schema{:name :example
;; :form [:or :string? [:and :pos-int? [:not :zero?]]]
;; :version :schema.version/not-specified
;; :status :schema.status/not-specified
;; :validator #object[...]
;; :generator #clojure.test.check.generators.Generator[...]}
;; Create schema with a docstring
(m/defschema :example
"Example schema"
[:or :string? [:and :pos-int? [:not :zero?]]])
;; => #modelizer/schema{:name :example
;; :form [:or :string? [:and :pos-int? [:not :zero?]]]
;; :doc "Example schema"
;; :version :schema.version/not-specified
;; :status :schema.status/not-specified
;; :validator #object[...]
;; :generator #clojure.test.check.generators.Generator[...]}
;; Create schema with a metadata
(m/defschema :example
"Example schema"
{:added "0.0.2"}
[:or :string? [:and :pos-int? [:not :zero?]]])
;; => #modelizer/schema{:name :example
;; :meta {:added "0.0.2"}
;; :form [:or :string? [:and :pos-int? [:not :zero?]]]
;; :doc "Example schema"
;; :version :schema.version/not-specified
;; :status :schema.status/not-specified
;; :validator #object[...]
;; :generator #clojure.test.check.generators.Generator[...]}
;; Create schema with a specified version
(m/defschema :example "v1"
"Example schema"
{:added "0.0.2"}
[:or :string? [:and :pos-int? [:not :zero?]]])
;; => #modelizer/schema{:name :example
;; :meta {:added "0.0.2"}
;; :form [:or :string? [:and :pos-int? [:not :zero?]]]
;; :doc "Example schema"
;; :version "v1"
;; :status :schema.status/not-specified
;; :validator #object[...]
;; :generator #clojure.test.check.generators.Generator[...]}
;; Create schema with a specified status
(m/defschema :example "v2" :production
"Example schema"
{:added "0.0.2"}
[:or :string? [:and :pos-int? [:not :zero?]]])
;; => #modelizer/schema{:name :example
;; :meta {:added "0.0.2"}
;; :form [:or :string? [:and :pos-int? [:not :zero?]]]
;; :doc "Example schema"
;; :version "v2"
;; :status :production
;; :validator #object[...]
;; :generator #clojure.test.check.generators.Generator[...]}
;; Create schema from a map
(m/defschema
{:name :example
:doc "Example schema"
:version "v3"
:status :production
:meta {:added "0.0.2"}
:form [:or :string? [:and :pos-int? [:not :zero?]]]})
;; => #modelizer/schema{:name :example
;; :meta {:added "0.0.2"}
;; :form [:or :string? [:and :pos-int? [:not :zero?]]]
;; :doc "Example schema"
;; :version "v3"
;; :status :production
;; :validator #object[...]
;; :generator #clojure.test.check.generators.Generator[...]}
;; If necessary, use the function instead of the macro
(m/register
{:name :example
:doc "Example schema"
:version "v4"
:status :production
:meta {:added "0.0.2"}
:form [:or :string? [:and :pos-int? [:not :zero?]]]})
;; => #modelizer/schema{:name :example
;; :meta {:added "0.0.2"}
;; :form [:or :string? [:and :pos-int? [:not :zero?]]]
;; :doc "Example schema"
;; :version "v4"
;; :status :production
;; :validator #object[...]
;; :generator #clojure.test.check.generators.Generator[...]}
;; Get all registered schemas
(m/get-schemas)
;; => {...}
;; Get all schema versions
(m/get-schemas :example)
;; => {"v4" #modelizer/schema{...}
;; ...
;; "v1" #modelizer/schema{:name :example
;; :doc "Example schema"
;; :version "v1"
;; :status :production
;; :meta {:added "0.0.2"}
;; :form [:or :string? [:and :pos-int? [:not :zero?]]]
;; :validator #object[...]
;; :generator #clojure.test.check.generators.Generator[...]}
;;
;; :schema.version/not-specified #modelizer/schema{:meta {:added "0.0.2"}
;; :name :example
;; :form [:or :string? [:and :pos-int? [:not :zero?]]]
;; :doc "Example schema"
;; :version :schema.version/not-specified
;; :status :schema.status/not-specified
;; :validator #object[...]
;; :generator #clojure.test.check.generators.Generator[...]}}
;; Get schema default version
;; NOTE: You will soon be able to specify a strategy to get the required schema version
(m/get-schema :example)
;; => #modelizer/schema{:meta {:added "0.0.2"}
;; :name :example
;; :form [:or :string? [:and :pos-int? [:not :zero?]]]
;; :doc "Example schema"
;; :version :schema.version/not-specified
;; :status :schema.status/not-specified
;; :validator #object[...]
;; :generator #clojure.test.check.generators.Generator[...]}
;; Get specified schema version
(m/get-schema :example "v4")
;; => #modelizer/schema{:name :example
;; :doc "Example schema"
;; :version "v4"
;; :status :production
;; :meta {:added "0.0.2"}
;; :form [:or :string? [:and :pos-int? [:not :zero?]]]
;; :validator #object[...]
;; :generator #clojure.test.check.generators.Generator[...]}
;;;;
;; Schema
;;;;
;; Available functions for working with schemas:
;; - (m/get-name schema)
;; - (m/get-version schema)
;; - (m/get-status schema)
;; - (m/get-doc schema)
;; - (m/get-meta schema)
;; - (m/get-form schema)
;; - (m/unwrap schema)
;; - (m/get-validator schema)
;; - (m/validate schema data)
;; - (m/validate schema data meta)
;; - (m/get-generator schema)
;; - (m/generate schema)
;; - (m/generate schema opts)
;; - (m/sample schema)
;; - (m/sample schema opts)
;;;;
;; Schema validators
;;;;
;; Save schema into variable
(def example1 (m/get-schema :example "v4"))
(m/validate example1 "1") ;; => true
(m/validate example1 1) ;; => true
(m/validate example1 -1) ;; => false
(m/validate example1 0) ;; => false
;; Save schema validator into variable
(def valid1? (m/get-validator example1))
(valid1? "1") ;; => true
(valid1? 1) ;; => true
(valid1? -1) ;; => false
(valid1? 0) ;; => false
;; Use aliases and versions
(m/defschema :example "v5" :production
"Example schema"
{:added "0.0.2"
:require {:my-example [:example "v4"]}}
:my-example)
;; => #modelizer/schema{:meta {:added "0.0.2"
;; :require {:my-example [:example "v4"]}}
;; :name :example
;; :status :production
;; :form :my-example
;; :version "v5"
;; :doc "Example schema"
;; :validator #object[...]
;; :generator #clojure.test.check.generators.Generator[...]}
(def example2 (m/get-schema :example "v5"))
(m/validate example2 "1") ;; => true
(m/validate example2 1) ;; => true
(m/validate example2 -1) ;; => false
(m/validate example2 0) ;; => false
(def valid2? (m/get-validator example2))
(valid2? "1") ;; => true
(valid2? 1) ;; => true
(valid2? -1) ;; => false
(valid2? 0) ;; => false
;;;;
;; Schema generators
;;;;
;; simple
(m/defschema :example "v6"
"Example schema"
{}
:string?)
(def example3 (m/get-schema :example "v6"))
(m/generate example3) ;; => "W"
(m/generate example3 {:size 10}) ;; => "MIt"
(m/sample example3) ;; => ("" "g" "HK" "5" "y" "Q" "48L3" "wAk5Fz9" "W1l" "")
(m/sample example3 {:size 5}) ;; => ("" "9" "lE" "979" "UOi5")
;; :or
(m/defschema :example "v7"
"Example schema"
{}
[:or :string? :pos-int?])
(def example4 (m/get-schema :example "v7"))
(m/generate example4) ;; => 2
(m/generate example4 {:size 10}) ;; => "hjE5W"
(m/sample example4) ;; => (1 1 2 2 3 3 4 "7PuTp" 1 "66Gb")
(m/sample example4 {:size 5}) ;; => (1 2 1 "16" "Av")
;; :and
(m/defschema :example "v8"
"Example schema"
{}
[:and :pos-int? :even?])
(def example5 (m/get-schema :example "v8"))
(m/generate example5) ;; => 6
(m/generate example5 {:size 10}) ;; => 240
(m/sample example5) ;; => (4 2 2 52 2 10 58 4 14 8)
(m/sample example5 {:size 5}) ;; => (2 4 2 64 8)
;; :not
(m/defschema :example "v8"
"Example schema"
{}
[:not :string?])
(def example6 (m/get-schema :example "v8"))
(m/generate example6) ;; => (:*D/w)
(m/generate example6 {:size 10}) ;; => (0.5 (\a 0.2568359375))
(m/sample example6) ;; => ({} [false] nil nil nil [] nil nil nil nil)
(m/sample example6 {:size 5}) ;; => (() nil nil #{false} [zS8/o8])
;; Use aliases and versions
(m/defschema :example "v9"
"Example schema"
{:require {:pos-int [:pos-int?]}}
[:and :pos-int [:not :even?]])
(def example7 (m/get-schema :example "v9"))
(m/generate example7) ;; => 9
(m/generate example7 {:size 10}) ;; => 20453
(m/sample example7) ;; => (5 31 7 5 1 7 1 1 5 243)
(m/sample example7 {:size 5}) ;; => (5 23 1 3 15)
;;;;
;; Example with a custom validator and generator
;;;
;; Create a custom validator
(defn custom-validator
;; Default validator
([x]
(custom-validator x false))
;; 2-arity validator uses for specified cases when the result depends on external metadata.
;; E.g. you can add strict mode or whatever you want
([x randomize?]
(if-not randomize?
(uuid? x)
(rand-nth [false true]))))
;; Create a custom generator
(def custom-generator gen/gen-uuid?)
;; Create a schema with a specified generator (explicitly)
(m/defschema :custom "v1"
"Example schema"
{:generator custom-generator}
#'custom-validator)
(def custom-example1 (m/get-schema :custom "v1"))
(m/validate custom-example1 (m/generate custom-example1)) ;; => true
(m/validate custom-example1 (m/generate custom-example1) true) ;; => random result true/false
;; Register global validator and generator
(m/register-generator custom-validator custom-generator)
;; Create a schema without a specified generator (implicitly)
(m/defschema :custom "v2"
"Example schema"
{}
#'custom-validator)
(def custom-example2 (m/get-schema :custom "v2"))
(m/validate custom-example2 (m/generate custom-example2)) ;; => true
(m/validate custom-example2 (m/generate custom-example2) true) ;; => random result true/false
;; :enum
(m/defschema :example "v10"
"Example schema"
{}
[:enum "Steve Jobs" "Bill Gates"])
(def example8 (m/get-schema :example "v10"))
(m/generate example8) ;; => => "Steve Jobs"
(m/sample example8 {:size 2}) ;; => ("Steve Jobs" "Bill Gates")
(m/validate example8 "Steve Jobs") ;; => true
(m/validate example8 "Elon Musk") ;; => false
;; :<
(def example9
(m/defschema :example "v11"
"Example schema"
{}
[:< 42]))
(m/sample example9) ;; => (-1 -1 -1 1 -4 -7 -1 -14 -2 -7)
(m/validate example9 41) ;; => true
(m/validate example9 42) ;; => false
(m/validate example9 43) ;; => false
;; :<=
(def example10
(m/defschema :example "v12"
"Example schema"
{}
[:<= 42]))
(m/sample example10) ;; => (0 -1 0 -1 0 3 9 -9 -5 -52)
(m/validate example10 41) ;; => true
(m/validate example10 42) ;; => true
(m/validate example10 43) ;; => false
;; :=
(def example11
(m/defschema :example "v13"
"Example schema"
{}
[:= 42]))
(m/sample example11) ;; => (42 42 42 42 42 42 42 42 42 42)
(m/validate example11 41) ;; => false
(m/validate example11 42) ;; => true
(m/validate example11 43) ;; => false
;; :>
(def example12
(m/defschema :example "v14"
"Example schema"
{}
[:> 42]))
(m/sample example12) ;; => (43 44 43 46 43 44 43 51 57 66)
(m/validate example12 41) ;; => false
(m/validate example12 42) ;; => false
(m/validate example12 43) ;; => true
;; :>=
(def example13
(m/defschema :example "v15"
"Example schema"
{}
[:>= 42]))
(m/sample example13) ;; => (42 42 42 43 43 45 45 51 50 45)
(m/validate example13 41) ;; => false
(m/validate example13 42) ;; => true
(m/validate example13 43) ;; => true
;; :not=
(def example14
(m/defschema :example "v15"
"Example schema"
{}
[:not= 42]))
(m/sample example14) ;; => (0 0 0 0 -1 -1 10 0 -16 0)
(m/validate example14 41) ;; => true
(m/validate example14 42) ;; => false
(m/validate example14 43) ;; => true
;; The creation of the generator based on the inferred data type.
;; Otherwise, uses `gen-any?` generator
(m/sample (m/schema {:name :sample, :form [:> 42]})) ;;=> (44 43 44 44 44 43 60 45 44 245)
(m/sample (m/schema {:name :sample, :form [:> 42.0]})) ;;=> (43.0 64.0 43.0 72.0 88.0 96.0 54.0 43.0 54.25 171.5)
(m/sample (m/schema {:name :sample, :form [:not= "42"]})) ;; => ("" "" "6" "" "3" "7" "" "N8nonW6" "" "K08IcFx")
TBD
This library inspired by the following excellent libraries:
Copyright © 2019-2020 Ilshat Sultanov
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close