Schema DSL - moxaj/mikron GitHub Wiki

This page describes the building blocks from which you can assemble your schemas. In the scope of this document, consider mikron.runtime.core implicitly loaded and aliased to mikron.

Each built-in schema has syntax of [name options & args] (you may recognize this from Hiccup), where:

  • name is the name of the schema (like :int or :list)
  • options is an optional map of schema-specific options
  • & args is list of schema-specific positional parameters

Furthermore, if a schema has no positional parameters and you wish to omit the options parameter, you may represent the schema solely with its name. Therefore, as the :int schema has no positional parameters, all of the following have the same semantics:

  • [:int {}]
  • [:int]
  • :int

Schemas can be nested arbitrarily. Circular references are allowed, though be aware that the generator can overflow the stack if no nested schemas can 'terminate':

(mikron/gen (mikron/schema ::foo [:tuple [:byte ::foo]]))
;; => stack overflow

(defschema ::foo-1 [:tuple [:byte ::foo-2]])
(defschema ::foo-2 [:tuple [:byte ::foo-1]])

(mikron/gen ::foo-1)
;; => stack overflow

In this document, valid schema can stand for either:

  • a symbol which refers to a reified schema
  • an inline schema definition (like [:tuple [...]])
  • a qualified keyword.

Built-in schemas

:byte

Syntax

[:byte {}]

Semantics

8-bit signed integer

Diff paths

true to process, false to ignore


:ubyte

Syntax

[:ubyte {}]

Semantics

8-bit unsigned integer

Diff paths

true to process, false to ignore


:short

Syntax

[:short {}]

Semantics

16-bit signed integer

Diff paths

true to process, false to ignore


:ushort

Syntax

[:ushort {}]

Semantics

16-bit unsigned integer

Diff paths

true to process, false to ignore


:int

Syntax

[:int {}]

Semantics

32-bit signed integer

Diff paths

true to process, false to ignore


:uint

Syntax

[:uint {}]

Semantics

32-bit unsigned integer

Diff paths

true to process, false to ignore


:long

Syntax

[:long {}]

Semantics

64-bit signed integer

Diff paths

true to process, false to ignore


:varint

Syntax

[:varint {}]

Semantics

variable length encoded integer

Diff paths

true to process, false to ignore


:float

Syntax

[:float {}]

Semantics

32-bit floating point number

Diff paths

true to process, false to ignore


:double

Syntax

[:double {}]

Semantics

64-bit floating point number

Diff paths

true to process, false to ignore


:char

Syntax

[:char {}]

Semantics

unicode character

Diff paths

true to process, false to ignore


:boolean

Syntax

[:boolean {}]

Semantics

either true or false

Diff paths

true to process, false to ignore


:nil

Syntax

[:nil {}]

Semantics

the literal nil

Diff paths

always ignored


:binary

Syntax

[:binary {}]

Semantics

binary blob, byte[] (Clojure) or ArrayBuffer (ClojureScript)

Diff paths

always ignored


:string

Syntax

[:string {}]

Semantics

a regular Clojure(Script) string

Diff paths

true to process, false to ignore


:keyword

Syntax

[:keyword {}]

Semantics

a regular Clojure(Script) keyword, can be namespaced

Diff paths

true to process, false to ignore


:symbol

Syntax

[:symbol {}]

Semantics

a regular Clojure(Script) symbol, can be namespaced

Diff paths

true to process, false to ignore


:any

Syntax

[:any {}]

Semantics

any value, ignored by the processors

Diff paths

always ignored


:constant

Syntax

[:constant {} constant-value], where

  • constant-value is any value
Semantics

a constant value

Diff paths

true to process, false to ignore

Examples
(mikron/schema [:constant [42 {:foo "bar"}]])

:enum

Syntax

[:enum {} enum-values], where

  • enum-values is a set of keywords
Semantics

a keyword from a predefined set

Diff paths

true to process, false to ignore

Examples
(mikron/schema [:enum #{:a :b :c :d}])

:optional

Syntax

[:optional {} schema], where

  • schema is a valid schema
Semantics

the literal nil or any value which conforms to schema

Diff paths

the paths are interpreted for the subschema

Examples
(mikron/schema [:optional :string])

:wrapped

Syntax

[:wrapped {} pre post schema], where

  • pre and post resolve to arbitrary functions
  • schema is a valid schema
Semantics

any value which, with functions pre and post, can be mapped to and from another value (respectively) which conforms to schema

Diff paths

the paths are interpreted for the subschema

Examples
;; Date values don't travel directly on the wire, convert them to and from longs instead
(defn date->long ^long [^java.util.Date date]
  (.getTime date))

(defn long->date ^java.util.Date [^long time]
  (java.util.Date. time))

(mikron/schema [:wrapped date->long long->date :long])

:multi

Syntax

[:multi {} selector schemas], where

  • selector resolves to an arbitrary function
  • schemas is a map from arbitrary values to valid schemas
Semantics

a value whose actual schema will be selected at runtime by the selector function

Diff paths
  • true: process, including all subvalues
  • false: ignore
  • map: keys are from the values returned by selector, values are subpaths for the appropriate subschemas
Examples
(defn selector [value]
  (cond
    (string? value)  :a-string
    (integer? value) :an-integer
    :else            :something-else))

(mikron/schema [:multi selector {:a-string       :string
                                 :an-integer     :varint
                                 :something-else :any}]
  :diff-paths {:a-string   true
               :an-integer false})
               ;; something else is implicitly :false


:list

Syntax

[:list {} schema], where

  • schema is a valid schema
Semantics

a list of values, where each conforms to schema

Diff paths
  • true: process, including all subvalues
  • false: ignore
  • map: the singular key :all mapped to the subpath for the subschema
Examples
(mikron/schema [:list :int]
  :diff-path {:all true})

:vector

Syntax

[:vector {} schema], where

  • schema is a valid schema
Semantics

a vector of values, where each conforms to schema

Diff paths
  • true: process, including all subvalues
  • false: ignore
  • map: the single key :all mapped to the subpath for the subschema
Examples
(mikron/schema [:vector :long]
  :diff-path true) ;; equivalent to {:all true} in this case

:set

Syntax

[:set {:sorted-by sorter} schema], where

  • sorter resolves to an arbitrary function
  • schema is a valid schema
Semantics

a set of values, where each conforms to schema, optionally sorted by sorter

a vector of values, where each conforms to schema

Diff paths

always ignored

Examples
(mikron/schema [:set :keyword])

(mikron/schema [:set {:sorted-by >} :ubyte])

:map

Syntax

[:map {:sorted-by sorter} key-schema value-schema], where

  • sorter resolves to an arbitrary function
  • key-schema and value-schema are valid schemas
Semantics

a map from keys, each conforming to key-schema, to values, each conforming to value-schema, optionally sorted by sorter

Diff paths
  • true: process, including all subvalues
  • false: ignore
  • map: the single key :all mapped to the subpath for the value subschema
Examples
(mikron/schema [:map :keyword :short]
  :diff-paths {:all true})

(mikron/schema [:map {:sorted-by <} :byte :string])

:tuple

Syntax

[:tuple {} schemas], where

  • schemas is a vector of valid schemas
Semantics

a tuple with schemas schemas, in order.

Diff paths
  • true: process, including all subvalues
  • false: ignore
  • map: keys are tuple indices, values are subpaths for the appropriate subschemas
Examples
(mikron/schema [:tuple [:byte :keyword :keyword]]
  :diff-paths {0 true
               1 true
               2 false})

:record

Syntax

[:record {:type type} schemas], where

  • type is a vector of symbols
  • schemas is a map from keywords to valid schemas
Semantics

a record with fields as specified in schemas. If type is specified, it must be a vector of symbols where the first symbol is the name of the type (defined with either defrecord or deftype) and the rest are the symbols used to represent its fields (in the exact same order, none omitted).

Diff paths
  • true: process, including all subvalues
  • false: ignore
  • map: keys are record keys, values are subpaths for the appropriate subschemas
Examples
[:record {:a :int
          :b :string}]

(defrecord Foo [a b c])

(mikron/schema [:record {:type [Foo a b c]}
                        {:a :int
                         :b :byte
                         :c :long}]
  :diff-paths {:a false
               :b true
               :c false})