packages feed

hydra-0.15.0: src/main/haskell/Hydra/Sources/Avro/Schema.hs

module Hydra.Sources.Avro.Schema where

-- Standard imports for type-level sources outside of the kernel
import           Hydra.Kernel
import           Hydra.Dsl.Annotations
import           Hydra.Dsl.Bootstrap
import           Hydra.Dsl.Types                 ((>:))
import qualified Hydra.Dsl.Types                 as T
import qualified Hydra.Sources.Kernel.Types.Core as Core
import qualified Data.List                       as L
import qualified Data.Map                        as M
import qualified Data.Set                        as S
import qualified Data.Maybe                      as Y

-- Additional imports
import qualified Hydra.Sources.Json.Model        as JsonModel


ns :: Namespace
ns = Namespace "hydra.avro.schema"

define :: String -> Type -> Binding
define = defineType ns

avro :: String -> Type
avro = typeref ns

json :: String -> Type
json = typeref $ JsonModel.ns

module_ :: Module
module_ = Module {
            moduleNamespace = ns,
            moduleDefinitions = (map toTypeDef definitions),
            moduleTermDependencies = [JsonModel.ns],
            moduleTypeDependencies = [Core.ns],
            moduleDescription = Just ("A model for Avro schemas. Based on the Avro 1.11.1 specification:\n" ++
      "  https://avro.apache.org/docs/1.11.1/specification")}
  where
    definitions = [
      array_,
      enum_,
      field_,
      fixed_,
      map_,
      named,
      namedType,
      order,
      primitive,
      record_,
      schema,
      union_]

array_ :: Binding
array_ = define "Array" $
  T.record [
    "items">: avro "Schema"]

enum_ :: Binding
enum_ = define "Enum" $
  T.record [
    "symbols">:
      doc ("a JSON array, listing symbols, as JSON strings. All symbols in an enum must be unique; " ++
        "duplicates are prohibited. Every symbol must match the regular expression [A-Za-z_][A-Za-z0-9_]* " ++
        "(the same requirement as for names)") $
      T.list T.string,
    "default">:
      doc ("A default value for this enumeration, used during resolution when the reader encounters " ++
        "a symbol from the writer that isn't defined in the reader's schema. " ++
        "The value provided here must be a JSON string that's a member of the symbols array") $
      T.maybe T.string]

field_ :: Binding
field_ = define "Field" $
  T.record [
    "name">:
      doc "a JSON string providing the name of the field"
      T.string,
    "doc">:
      doc "a JSON string describing this field for users" $
      T.maybe T.string,
    "type">:
      doc "a schema" $
      avro "Schema",
    "default">:
      doc "default value for this field, only used when reading instances that lack the field for schema evolution purposes" $
      T.maybe $ json "Value",
    "order">:
      doc "specifies how this field impacts sort ordering of this record" $
      T.maybe $ avro "Order",
    "aliases">:
      doc "a JSON array of strings, providing alternate names for this field" $
      T.maybe $ T.list T.string,
    "annotations">:
      doc "Any additional key/value pairs attached to the field" $
      T.map T.string $ json "Value"]

fixed_ :: Binding
fixed_ = define "Fixed" $
  T.record [
    "size">:
      doc "an integer, specifying the number of bytes per value"
      T.int32]

map_ :: Binding
map_ = define "Map" $
  T.record [
    "values">: avro "Schema"]

named :: Binding
named = define "Named" $
  T.record [
    "name">:
      doc "a string naming this schema"
      T.string,
    "namespace">:
      doc "a string that qualifies the name" $
      T.maybe T.string,
    "aliases">:
      doc "a JSON array of strings, providing alternate names for this schema" $
      T.maybe $ T.list T.string,
    "doc">:
      doc "a JSON string providing documentation to the user of this schema" $
      T.maybe T.string,
    "type">: avro "NamedType",
    "annotations">:
      doc "Any additional key/value pairs attached to the type" $
      T.map T.string $ json "Value"]

namedType :: Binding
namedType = define "NamedType" $
  T.union [
    "enum">: avro "Enum",
    "fixed">: avro "Fixed",
    "record">: avro "Record"]

order :: Binding
order = define "Order" $
  T.enum ["ascending", "descending", "ignore"]

primitive :: Binding
primitive = define "Primitive" $
  T.union [
    "null">:
      doc "no value" T.unit,
    "boolean">:
      doc "A binary value" T.unit,
    "int">:
      doc "32-bit signed integer" T.unit,
    "long">:
      doc "64-bit signed integer" T.unit,
    "float">:
      doc "single precision (32-bit) IEEE 754 floating-point number" T.unit,
    "double">:
      doc "double precision (64-bit) IEEE 754 floating-point number" T.unit,
    "bytes">:
      doc "sequence of 8-bit unsigned bytes" T.unit,
    "string">:
      doc "unicode character sequence" T.unit]

record_ :: Binding
record_ = define "Record" $
  T.record [
    "fields">:
      doc "a JSON array, listing fields" $
      T.list $ avro "Field"]

schema :: Binding
schema = define "Schema" $
  T.union [
    "array">: avro "Array",
    "map">: avro "Map",
    "named">: avro "Named",
    "primitive">: avro "Primitive",
    "reference">: -- Note: "reference" is not described in the Avro specification; this has been added
      doc "A reference by name to a previously defined type" T.string,
    "union">: avro "Union"
  ]

union_ :: Binding
union_ = define "Union" $
  T.wrap $ T.list $ avro "Schema"