packages feed

language-avro 0.1.0.0 → 0.1.1.0

raw patch · 5 files changed

+306/−233 lines, 5 filesdep +containersdep +directorydep +hspec-megaparsecdep ~avroPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: containers, directory, hspec-megaparsec

Dependency ranges changed: avro

API changes (from Hackage documentation)

- Language.Avro.Types: type Schema = Type
+ Language.Avro.Parser: parseDecimal :: MonadParsec Char Text m => m Decimal
+ Language.Avro.Types: Array :: Schema -> Schema
+ Language.Avro.Types: Boolean :: Schema
+ Language.Avro.Types: Bytes :: Maybe LogicalTypeBytes -> Schema
+ Language.Avro.Types: Double :: Schema
+ Language.Avro.Types: Enum :: TypeName -> [TypeName] -> Maybe Text -> Vector Text -> Schema
+ Language.Avro.Types: Fixed :: TypeName -> [TypeName] -> Int -> Maybe LogicalTypeFixed -> Schema
+ Language.Avro.Types: Float :: Schema
+ Language.Avro.Types: Int :: Maybe LogicalTypeInt -> Schema
+ Language.Avro.Types: Long :: Maybe LogicalTypeLong -> Schema
+ Language.Avro.Types: Map :: Schema -> Schema
+ Language.Avro.Types: NamedType :: TypeName -> Schema
+ Language.Avro.Types: Null :: Schema
+ Language.Avro.Types: Record :: TypeName -> [TypeName] -> Maybe Text -> Maybe Order -> [Field] -> Schema
+ Language.Avro.Types: String :: Maybe LogicalTypeString -> Schema
+ Language.Avro.Types: Union :: Vector Schema -> Schema
+ Language.Avro.Types: [aliases] :: Schema -> [TypeName]
+ Language.Avro.Types: [doc] :: Schema -> Maybe Text
+ Language.Avro.Types: [fields] :: Schema -> [Field]
+ Language.Avro.Types: [item] :: Schema -> Schema
+ Language.Avro.Types: [logicalTypeB] :: Schema -> Maybe LogicalTypeBytes
+ Language.Avro.Types: [logicalTypeF] :: Schema -> Maybe LogicalTypeFixed
+ Language.Avro.Types: [logicalTypeI] :: Schema -> Maybe LogicalTypeInt
+ Language.Avro.Types: [logicalTypeL] :: Schema -> Maybe LogicalTypeLong
+ Language.Avro.Types: [logicalTypeS] :: Schema -> Maybe LogicalTypeString
+ Language.Avro.Types: [name] :: Schema -> TypeName
+ Language.Avro.Types: [options] :: Schema -> Vector Schema
+ Language.Avro.Types: [order] :: Schema -> Maybe Order
+ Language.Avro.Types: [size] :: Schema -> Int
+ Language.Avro.Types: [symbols] :: Schema -> Vector Text
+ Language.Avro.Types: [values] :: Schema -> Schema
+ Language.Avro.Types: data Schema
+ Language.Avro.Types: instance GHC.Classes.Ord Language.Avro.Types.Argument
+ Language.Avro.Types: instance GHC.Classes.Ord Language.Avro.Types.ImportType
+ Language.Avro.Types: instance GHC.Classes.Ord Language.Avro.Types.Method
+ Language.Avro.Types: instance GHC.Classes.Ord Language.Avro.Types.Namespace
+ Language.Avro.Types: instance GHC.Classes.Ord Language.Avro.Types.Protocol
+ Language.Avro.Types: pattern Bytes' :: Schema
+ Language.Avro.Types: pattern Int' :: Schema
+ Language.Avro.Types: pattern Long' :: Schema
+ Language.Avro.Types: pattern String' :: Schema
- Language.Avro.Types: Protocol :: Maybe Namespace -> Text -> [ImportType] -> [Schema] -> [Method] -> Protocol
+ Language.Avro.Types: Protocol :: Maybe Namespace -> Text -> Set ImportType -> Set Schema -> Set Method -> Protocol
- Language.Avro.Types: [imports] :: Protocol -> [ImportType]
+ Language.Avro.Types: [imports] :: Protocol -> Set ImportType
- Language.Avro.Types: [messages] :: Protocol -> [Method]
+ Language.Avro.Types: [messages] :: Protocol -> Set Method
- Language.Avro.Types: [types] :: Protocol -> [Schema]
+ Language.Avro.Types: [types] :: Protocol -> Set Schema

Files

README.md view
@@ -2,6 +2,8 @@  [![Actions Status](https://github.com/kutyel/avro-parser-haskell/workflows/Haskell%20CI/badge.svg)](https://github.com/kutyel/avro-parser-haskell/actions) [![Hackage](https://img.shields.io/hackage/v/language-avro.svg?logo=haskell)](https://hackage.haskell.org/package/language-avro)+[![Stackage Nightly](http://stackage.org/package/language-avro/badge/nightly)](http://stackage.org/nightly/package/language-avro)+[![Stackage LTS](http://stackage.org/package/language-avro/badge/lts)](http://stackage.org/lts/package/language-avro) [![ormolu](https://img.shields.io/badge/styled%20with-ormolu-blueviolet)](https://github.com/tweag/ormolu)  Language definition and parser for AVRO (`.avdl`) files.@@ -9,119 +11,146 @@ ## Example  ```haskell-#! /usr/bin/env runhaskell+#!/usr/bin/env stack+-- stack --resolver lts-15.0 script --package language-avro,megaparsec,pretty-simple  module Main where  import Language.Avro.Parser (readWithImports)+import Text.Megaparsec.Error (ShowErrorComponent (..), errorBundlePretty)+import Text.Pretty.Simple (pPrint) +instance ShowErrorComponent Char where+  showErrorComponent = show+ main :: IO ()-main = readWithImports "test" "PeopleService.avdl"+main =+  readWithImports "test" "PeopleService.avdl"+    >>= either (putStrLn . errorBundlePretty) pPrint -- λ>--- Right---   (Protocol {---     ns = Just (Namespace ["example","seed","server","protocol","avro"]),---     pname = "PeopleService", imports = [IdlImport "People.avdl"],---     types = [---       Record {---         name = "Person",---         aliases = [],---         doc = Nothing,---         order = Nothing,---         fields = [---           Field {---             fldName = "name",---             fldAliases = [],---             fldDoc = Nothing,---             fldOrder = Nothing,---             fldType = String,---             fldDefault = Nothing---           },---           Field {---             fldName = "age",---             fldAliases = [],---             fldDoc = Nothing,---             fldOrder = Nothing,---             fldType = Int,---             fldDefault = Nothing+-- Protocol+--   { ns = Just+--       ( Namespace+--           [ "example"+--           , "seed"+--           , "server"+--           , "protocol"+--           , "avro"+--           ]+--       )+--   , pname = "PeopleService"+--   , imports = [ IdlImport "People.avdl" ]+--   , types =+--       [ Record+--           { name = "Person"+--           , aliases = []+--           , doc = Nothing+--           , order = Nothing+--           , fields =+--               [ Field+--                   { fldName = "name"+--                   , fldAliases = []+--                   , fldDoc = Nothing+--                   , fldOrder = Nothing+--                   , fldType = String { logicalTypeS = Nothing }+--                   , fldDefault = Nothing+--                   }+--               , Field+--                   { fldName = "age"+--                   , fldAliases = []+--                   , fldDoc = Nothing+--                   , fldOrder = Nothing+--                   , fldType = Int { logicalTypeI = Nothing }+--                   , fldDefault = Nothing+--                   }+--               ] --           }---         ]---       },---       Record {---         name = "NotFoundError",---         aliases = [],---         doc = Nothing,---         order = Nothing,---         fields = [---           Field {---             fldName = "message",---             fldAliases = [],---             fldDoc = Nothing,---             fldOrder = Nothing,---             fldType = String,---             fldDefault = Nothing+--       , Record+--           { name = "NotFoundError"+--           , aliases = []+--           , doc = Nothing+--           , order = Nothing+--           , fields =+--               [ Field+--                   { fldName = "message"+--                   , fldAliases = []+--                   , fldDoc = Nothing+--                   , fldOrder = Nothing+--                   , fldType = String { logicalTypeS = Nothing }+--                   , fldDefault = Nothing+--                   }+--               ] --           }---         ]---       },---       Record {---         name = "DuplicatedPersonError",---         aliases = [],---         doc = Nothing,---         order = Nothing,---         fields = [---           Field {---             fldName = "message",---             fldAliases = [],---             fldDoc = Nothing,---             fldOrder = Nothing,---             fldType = String,---             fldDefault = Nothing+--       , Record+--           { name = "DuplicatedPersonError"+--           , aliases = []+--           , doc = Nothing+--           , order = Nothing+--           , fields =+--               [ Field+--                   { fldName = "message"+--                   , fldAliases = []+--                   , fldDoc = Nothing+--                   , fldOrder = Nothing+--                   , fldType = String { logicalTypeS = Nothing }+--                   , fldDefault = Nothing+--                   }+--               ] --           }---         ]---       },---       Record {---         name = "PeopleRequest",---         aliases = [],---         doc = Nothing,---         order = Nothing,---         fields = [---           Field {---             fldName = "name",---             fldAliases = [],---             fldDoc = Nothing,---             fldOrder = Nothing,---             fldType = String,---             fldDefault = Nothing+--       , Record+--           { name = "PeopleRequest"+--           , aliases = []+--           , doc = Nothing+--           , order = Nothing+--           , fields =+--               [ Field+--                   { fldName = "name"+--                   , fldAliases = []+--                   , fldDoc = Nothing+--                   , fldOrder = Nothing+--                   , fldType = String { logicalTypeS = Nothing }+--                   , fldDefault = Nothing+--                   }+--               ] --           }---         ]---       },---       Record {---         name = "PeopleResponse",---         aliases = [],---         doc = Nothing,---         order = Nothing,---         fields = [---           Field {---             fldName = "result",---             fldAliases = [],---             fldDoc = Nothing,---             fldOrder = Nothing,---             fldType = Union {options = [NamedType "Person",NamedType "NotFoundError",NamedType "DuplicatedPersonError"]},---             fldDefault = Nothing+--       , Record+--           { name = "PeopleResponse"+--           , aliases = []+--           , doc = Nothing+--           , order = Nothing+--           , fields =+--               [ Field+--                   { fldName = "result"+--                   , fldAliases = []+--                   , fldDoc = Nothing+--                   , fldOrder = Nothing+--                   , fldType = Union+--                       { options =+--                           [ NamedType "Person"+--                           , NamedType "NotFoundError"+--                           , NamedType "DuplicatedPersonError"+--                           ]+--                       }+--                   , fldDefault = Nothing+--                   }+--               ] --           }---         ]---       }---     ],---     messages = [---       Method {---         mname = "getPerson",---         args = [Argument {atype = NamedType "example.seed.server.protocol.avro.PeopleRequest", aname = "request"}],---         result = NamedType "example.seed.server.protocol.avro.PeopleResponse",---         throws = Null,---         oneway = False---       }---     ]---   })+--       ]+--   , messages =+--       [ Method+--           { mname = "getPerson"+--           , args =+--               [ Argument+--                   { atype = NamedType "example.seed.server.protocol.avro.PeopleRequest"+--                   , aname = "request"+--                   }+--               ]+--           , result = NamedType "example.seed.server.protocol.avro.PeopleResponse"+--           , throws = Null+--           , oneway = False+--           }+--       ]+--   } ```  ⚠️ Warning: `readWithImports` only works right now if the import type is `"idl"`!
language-avro.cabal view
@@ -1,5 +1,5 @@ name:                language-avro-version:             0.1.0.0+version:             0.1.1.0 synopsis:            Language definition and parser for AVRO files. description:         Parser for the AVRO language specification, see README.md for more details. homepage:            https://github.com/kutyel/avro-parser-haskell#readme@@ -17,7 +17,9 @@   exposed-modules:     Language.Avro.Types,                        Language.Avro.Parser   build-depends:       base >=4.12 && <5-                     , avro+                     , avro >=0.4.7+                     , containers+                     , directory                      , filepath                      , megaparsec                      , text@@ -37,9 +39,10 @@       -with-rtsopts=-N   build-depends:       base >=4.12 && <5-    , avro+    , avro >=0.4.7     , language-avro     , megaparsec     , text     , hspec+    , hspec-megaparsec     , vector
src/Language/Avro/Parser.hs view
@@ -3,32 +3,37 @@ {-# LANGUAGE OverloadedStrings #-}  -- | Parser for AVRO (@.avdl@) files, as defined in <http://avro.apache.org/docs/1.8.2/spec.html>.-module Language.Avro.Parser (-  -- * Main parsers-    parseProtocol-  , readWithImports-  -- * Intermediate parsers-  , parseAliases-  , parseAnnotation-  , parseImport-  , parseMethod-  , parseNamespace-  , parseOrder-  , parseSchema-  ) where+module Language.Avro.Parser+  ( -- * Main parsers+    parseProtocol,+    readWithImports, +    -- * Intermediate parsers+    parseAliases,+    parseAnnotation,+    parseDecimal,+    parseImport,+    parseMethod,+    parseNamespace,+    parseOrder,+    parseSchema,+  )+where++import Control.Monad (filterM) import Data.Avro import Data.Avro.Schema import Data.Either (partitionEithers)-import Data.List (foldl')+import qualified Data.Set as S import qualified Data.Text as T import qualified Data.Text.IO as T-import Data.Vector (Vector, fromList)+import qualified Data.Vector as V import Language.Avro.Types+import System.Directory (doesFileExist)+import System.FilePath import Text.Megaparsec import Text.Megaparsec.Char import qualified Text.Megaparsec.Char.Lexer as L-import System.FilePath  spaces :: MonadParsec Char T.Text m => m () spaces = L.space space1 (L.skipLineComment "//") (L.skipBlockComment "/*" "*/")@@ -121,9 +126,9 @@       Protocol         ns         name-        [i | ProtocolThingImport i <- things]-        [t | ProtocolThingType t <- things]-        [m | ProtocolThingMethod m <- things]+        (S.fromList [i | ProtocolThingImport i <- things])+        (S.fromList [t | ProtocolThingType t <- things])+        (S.fromList [m | ProtocolThingMethod m <- things])  data ProtocolThing   = ProtocolThingImport ImportType@@ -133,11 +138,11 @@ serviceThing :: MonadParsec Char T.Text m => m ProtocolThing serviceThing =   try (ProtocolThingImport <$> parseImport)-  <|> try (ProtocolThingMethod <$> parseMethod)-  <|> ProtocolThingType <$> parseSchema+    <|> try (ProtocolThingMethod <$> parseMethod)+    <|> ProtocolThingType <$> parseSchema <* optional (symbol ";") -parseVector :: MonadParsec Char T.Text m => m a -> m (Vector a)-parseVector t = fromList <$> braces (lexeme $ sepBy1 t $ symbol ",")+parseVector :: MonadParsec Char T.Text m => m a -> m (V.Vector a)+parseVector t = V.fromList <$> braces (lexeme $ sepBy1 t $ symbol ",")  parseTypeName :: MonadParsec Char T.Text m => m TypeName parseTypeName = toNamedType . pure <$> identifier@@ -159,12 +164,12 @@  parseField :: MonadParsec Char T.Text m => m Field parseField =-  (\o t a n -> Field n a Nothing o t Nothing) -- FIXME: docs and default values are not supported yet.+  (\o t a n -> Field n a Nothing o t Nothing) -- FIXME: docs are not supported yet.     <$> optional parseOrder     <*> parseSchema     <*> option [] parseFieldAlias     <*> identifier-    <* symbol ";"+    <* (symbol ";" <|> symbol "=" <* manyTill anySingle (symbol ";")) -- FIXME: default values are not supported yet.  -- | Parses arguments of methods into the 'Argument' structure. parseArgument :: MonadParsec Char T.Text m => m Argument@@ -181,17 +186,28 @@     <*> option False (True <$ reserved "oneway")     <* symbol ";" +-- | Parses the special type @decimal@ into it's corresponding 'Decimal' structure.+parseDecimal :: MonadParsec Char T.Text m => m Decimal+parseDecimal = toDec <$ reserved "decimal" <*> parens (lexeme $ sepBy1 number $ symbol ",")+  where+    toDec :: [Int] -> Decimal+    toDec [precision] = Decimal (fromIntegral precision) 0+    toDec [precision, scale] = Decimal (fromIntegral precision) (fromIntegral scale)+    toDec _ = error "decimal types can only be specified using two numbers!"+ -- | Parses a single type respecting @Data.Avro.Schema@'s 'Schema'. parseSchema :: MonadParsec Char T.Text m => m Schema parseSchema =   Null <$ (reserved "null" <|> reserved "void")     <|> Boolean <$ reserved "boolean"-    <|> Int <$ reserved "int"-    <|> Long <$ reserved "long"+    <|> Int' <$ reserved "int"+    <|> Long' <$ reserved "long"+    <|> Long . Just . DecimalL <$> parseDecimal     <|> Float <$ reserved "float"     <|> Double <$ reserved "double"-    <|> Bytes <$ reserved "bytes"-    <|> String <$ reserved "string"+    <|> Bytes' <$ reserved "bytes"+    <|> String (Just UUID) <$ reserved "uuid"+    <|> String' <$ reserved "string"     <|> Array <$ reserved "array" <*> diamonds parseSchema     <|> Map <$ reserved "map" <*> diamonds parseSchema     <|> Union <$ reserved "union" <*> parseVector parseSchema@@ -200,6 +216,7 @@           <$> option [] parseAliases <* reserved "fixed"           <*> parseTypeName           <*> parens number+          <*> pure Nothing       )     <|> try       ( flip Enum@@ -221,17 +238,38 @@ parseFile :: Parsec e T.Text a -> String -> IO (Either (ParseErrorBundle T.Text e) a) parseFile p file = runParser p file <$> T.readFile file +(>>>=) :: Applicative m => Either a b -> (b -> m (Either a c)) -> m (Either a c)+Left x >>>= _ = pure (Left x)+Right y >>>= f = f y+ -- | Reads and parses a whole file and its imports, recursively.-readWithImports :: FilePath -- ^ base directory-                -> FilePath -- ^ initial file-                -> IO (Either (ParseErrorBundle T.Text Char) Protocol)+readWithImports ::+  -- | base directory+  FilePath ->+  -- | initial file+  FilePath ->+  IO (Either (ParseErrorBundle T.Text Char) Protocol) readWithImports baseDir initialFile = do   initial <- parseFile parseProtocol (baseDir </> initialFile)   case initial of     Left e -> pure $ Left e     Right p -> do-      let imps = [i | IdlImport i <- imports p]-      (lefts, rights) <- partitionEithers <$> traverse (readWithImports baseDir . T.unpack) imps+      possibleImps <- traverse (oneOfTwo . T.unpack) [i | IdlImport i <- S.toList $ imports p]+      (lefts, rights) <- partitionEithers <$> traverse (>>>= readWithImports baseDir) possibleImps       pure $ case lefts of-        e:_ -> Left e-        _ -> Right $ foldl' (<>) p rights+        e : _ -> Left e+        _ -> Right $ S.foldl' (<>) p (S.fromList rights)+  where+    oneOfTwo :: FilePath -> IO (Either (ParseErrorBundle T.Text Char) FilePath)+    oneOfTwo p = do+      let dir = takeDirectory initialFile+          path1 = baseDir </> p+          path2 = baseDir </> dir </> p+      options <- (,) <$> doesFileExist path1 <*> doesFileExist path2+      pure $ case options of+        (True, False) -> Right p+        (False, True) -> Right $ dir </> p+        (False, False) -> runParser (fail $ "Import not found: " ++ p) initialFile ""+        (True, True)+          | normalise dir == "." -> Right p+          | otherwise -> runParser (fail $ "Duplicate files found: " ++ p) initialFile ""
src/Language/Avro/Types.hs view
@@ -1,10 +1,14 @@ -- | Language definition for AVRO (@.avdl@) files, --   as defined in <http://avro.apache.org/docs/1.8.2/spec.html>.-module Language.Avro.Types (-  module Language.Avro.Types, Schema (..)-) where+module Language.Avro.Types+  ( module Language.Avro.Types,+    Schema (..),+  )+where  import Data.Avro.Schema+import Data.Avro.Types.Value+import Data.Set import qualified Data.Text as T  -- | Whole definition of protocol.@@ -12,11 +16,11 @@   = Protocol       { ns :: Maybe Namespace,         pname :: T.Text,-        imports :: [ImportType],-        types :: [Schema],-        messages :: [Method]+        imports :: Set ImportType,+        types :: Set Schema,+        messages :: Set Method       }-  deriving (Eq, Show)+  deriving (Eq, Show, Ord)  instance Semigroup Protocol where   p1 <> p2 =@@ -30,7 +34,7 @@ -- | Newtype for the namespace of methods and protocols. newtype Namespace   = Namespace [T.Text]-  deriving (Eq, Show)+  deriving (Eq, Show, Ord)  type Aliases = [TypeName] @@ -47,7 +51,7 @@   = IdlImport T.Text   | ProtocolImport T.Text   | SchemaImport T.Text-  deriving (Eq, Show)+  deriving (Eq, Show, Ord)  -- | Helper type for the arguments of 'Method'. data Argument@@ -55,7 +59,7 @@       { atype :: Schema,         aname :: T.Text       }-  deriving (Eq, Show)+  deriving (Eq, Show, Ord)  -- | Type for methods/messages that belong to a protocol. data Method@@ -66,4 +70,4 @@         throws :: Schema,         oneway :: Bool       }-  deriving (Eq, Show)+  deriving (Eq, Show, Ord)
test/Spec.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-}  module Main@@ -6,13 +7,18 @@ where  import Data.Avro.Schema-import Data.Text as T hiding (tail)+import qualified Data.Text as T import Data.Vector (fromList) import Language.Avro.Parser import Language.Avro.Types import Test.Hspec+import Test.Hspec.Megaparsec import Text.Megaparsec (parse)+import Text.Megaparsec.Error +instance ShowErrorComponent Char where+  showErrorComponent = show+ enumTest :: T.Text enumTest =   T.unlines@@ -62,105 +68,107 @@   describe "Parse annotations" $ do     it "should parse namespaces" $ do       parse parseNamespace "" "@namespace(\"mynamespace\")"-        `shouldBe` (Right $ Namespace ["mynamespace"])+        `shouldParse` Namespace ["mynamespace"]       parse parseNamespace "" "@namespace(\"org.apache.avro.test\")"-        `shouldBe` (Right $ Namespace ["org", "apache", "avro", "test"])+        `shouldParse` Namespace ["org", "apache", "avro", "test"]     it "should parse ordering" $ do-      parse parseOrder "" "@order(\"ascending\")" `shouldBe` Right Ascending-      parse parseOrder "" "@order(\"descending\")" `shouldBe` Right Descending-      parse parseOrder "" "@order(\"ignore\")" `shouldBe` Right Ignore+      parse parseOrder "" "@order(\"ascending\")" `shouldParse` Ascending+      parse parseOrder "" "@order(\"descending\")" `shouldParse` Descending+      parse parseOrder "" "@order(\"ignore\")" `shouldParse` Ignore     it "should parse aliases" $ do       parse parseAliases "" "@aliases([\"org.foo.KindOf\"])"-        `shouldBe` Right [TN "KindOf" ["org", "foo"]]+        `shouldParse` [TN "KindOf" ["org", "foo"]]       parse parseAliases "" "@aliases([\"org.old.OldRecord\", \"org.ancient.AncientRecord\"])"-        `shouldBe` Right [TN "OldRecord" ["org", "old"], TN "AncientRecord" ["org", "ancient"]]+        `shouldParse` [TN "OldRecord" ["org", "old"], TN "AncientRecord" ["org", "ancient"]]     it "should parse other annotations" $ do       parse parseAnnotation "" "@java-class(\"java.util.ArrayList\")"-        `shouldBe` (Right $ Annotation "java-class" "java.util.ArrayList")+        `shouldParse` Annotation "java-class" "java.util.ArrayList"       parse parseAnnotation "" "@java-key-class(\"java.io.File\")"-        `shouldBe` (Right $ Annotation "java-key-class" "java.io.File")+        `shouldParse` Annotation "java-key-class" "java.io.File"   describe "Parse imports" $ do     it "should parse idl" $       parse parseImport "" "import idl \"foo.avdl\";"-        `shouldBe` (Right $ IdlImport "foo.avdl")+        `shouldParse` IdlImport "foo.avdl"     it "should parse protocol" $       parse parseImport "" "import protocol \"foo.avpr\";"-        `shouldBe` (Right $ ProtocolImport "foo.avpr")+        `shouldParse` ProtocolImport "foo.avpr"     it "should parse schema" $       parse parseImport "" "import schema \"foo.avsc\";"-        `shouldBe` (Right $ SchemaImport "foo.avsc")+        `shouldParse` SchemaImport "foo.avsc"   describe "Parse Data.Avro.Schema" $ do     it "should parse null" $-      parse parseSchema "" "null" `shouldBe` Right Null+      parse parseSchema "" "null" `shouldParse` Null     it "should parse boolean" $-      parse parseSchema "" "boolean" `shouldBe` Right Boolean+      parse parseSchema "" "boolean" `shouldParse` Boolean     it "should parse int" $-      parse parseSchema "" "int" `shouldBe` Right Int+      parse parseSchema "" "int" `shouldParse` Int'     it "should parse long" $-      parse parseSchema "" "long" `shouldBe` Right Long+      parse parseSchema "" "long" `shouldParse` Long'     it "should parse float" $-      parse parseSchema "" "float" `shouldBe` Right Float+      parse parseSchema "" "float" `shouldParse` Float     it "should parse double" $-      parse parseSchema "" "double" `shouldBe` Right Double+      parse parseSchema "" "double" `shouldParse` Double+    it "should parse decimal" $ do+      parse parseDecimal "" "decimal(4)" `shouldParse` Decimal 4 0+      parse parseDecimal "" "decimal(15,2)" `shouldParse` Decimal 15 2     it "should parse bytes" $-      parse parseSchema "" "bytes" `shouldBe` Right Bytes+      parse parseSchema "" "bytes" `shouldParse` Bytes'     it "should parse string" $-      parse parseSchema "" "string" `shouldBe` Right String+      parse parseSchema "" "string" `shouldParse` String'+    it "should parse uuid" $+      parse parseSchema "" "uuid" `shouldParse` String (Just UUID)     it "should parse array" $ do-      parse parseSchema "" "array<int>" `shouldBe` (Right $ Array Int)+      parse parseSchema "" "array<int>" `shouldParse` Array Int'       parse parseSchema "" "array<array<string>>"-        `shouldBe` (Right $ Array $ Array String)+        `shouldParse` Array (Array String')     it "should parse map" $ do-      parse parseSchema "" "map<int>" `shouldBe` (Right $ Map Int)+      parse parseSchema "" "map<int>" `shouldParse` Map Int'       parse parseSchema "" "map<map<string>>"-        `shouldBe` (Right $ Map $ Map String)+        `shouldParse` Map (Map String')     it "should parse unions" $       parse parseSchema "" "union { string, int, null }"-        `shouldBe` (Right $ Union $ fromList [String, Int, Null])+        `shouldParse` Union (fromList [String', Int', Null])     it "should parse fixeds" $ do       parse parseSchema "" "fixed MD5(16)"-        `shouldBe` (Right $ Fixed (TN "MD5" []) [] 16)+        `shouldParse` Fixed (TN "MD5" []) [] 16 Nothing       parse parseSchema "" "@aliases([\"org.foo.MD5\"])\nfixed MD5(16)"-        `shouldBe` (Right $ Fixed (TN "MD5" []) ["org.foo.MD5"] 16)+        `shouldParse` Fixed (TN "MD5" []) ["org.foo.MD5"] 16 Nothing     it "should parse enums" $ do       parse parseSchema "" enumTest-        `shouldBe` (Right $ Enum (TN "Kind" []) [TN "KindOf" ["org", "foo"]] Nothing (fromList ["FOO", "BAR", "BAZ"]))+        `shouldParse` Enum (TN "Kind" []) [TN "KindOf" ["org", "foo"]] Nothing (fromList ["FOO", "BAR", "BAZ"])       parse parseSchema "" "enum Suit { SPADES, DIAMONDS, CLUBS, HEARTS }"-        `shouldBe` (Right $ Enum (TN "Suit" []) [] Nothing (fromList ["SPADES", "DIAMONDS", "CLUBS", "HEARTS"]))+        `shouldParse` Enum (TN "Suit" []) [] Nothing (fromList ["SPADES", "DIAMONDS", "CLUBS", "HEARTS"])     it "should parse named types" $       parse parseSchema "" "example.seed.server.protocol.avro.PeopleResponse"-        `shouldBe` ( Right $ NamedType $ TN-                       { baseName = "PeopleResponse",-                         namespace = ["example", "seed", "server", "protocol", "avro"]-                       }-                   )+        `shouldParse` NamedType+          ( TN+              { baseName = "PeopleResponse",+                namespace = ["example", "seed", "server", "protocol", "avro"]+              }+          )     it "should parse simple records" $       parse parseSchema "" simpleRecord-        `shouldBe` ( Right $-                       Record-                         (TN "Person" [])-                         [TN "Person" ["org", "foo"]]-                         Nothing -- docs are ignored for now...-                         Nothing -- order is ignored for now...-                         [ Field "name" [] Nothing Nothing String Nothing,-                           Field "age" [] Nothing Nothing Int Nothing-                         ]-                   )+        `shouldParse` Record+          (TN "Person" [])+          [TN "Person" ["org", "foo"]]+          Nothing -- docs are ignored for now...+          Nothing -- order is ignored for now...+          [ Field "name" [] Nothing Nothing String' Nothing,+            Field "age" [] Nothing Nothing Int' Nothing+          ]     it "should parse complex records" $       parse parseSchema "" complexRecord-        `shouldBe` ( Right $-                       Record-                         (TN "TestRecord" [])-                         []-                         Nothing -- docs are ignored for now...-                         Nothing -- order is ignored for now...-                         [ Field "name" [] Nothing (Just Ignore) String Nothing,-                           Field "kind" [] Nothing (Just Descending) (NamedType "Kind") Nothing,-                           Field "hash" [] Nothing Nothing (NamedType "MD5") Nothing,-                           Field "nullableHash" ["hash"] Nothing Nothing (Union $ fromList [NamedType "MD5", Null]) Nothing,-                           Field "arrayOfLongs" [] Nothing Nothing (Array Long) Nothing-                         ]-                   )+        `shouldParse` Record+          (TN "TestRecord" [])+          []+          Nothing -- docs are ignored for now...+          Nothing -- order is ignored for now...+          [ Field "name" [] Nothing (Just Ignore) String' Nothing,+            Field "kind" [] Nothing (Just Descending) (NamedType "Kind") Nothing,+            Field "hash" [] Nothing Nothing (NamedType "MD5") Nothing,+            Field "nullableHash" ["hash"] Nothing Nothing (Union $ fromList [NamedType "MD5", Null]) Nothing,+            Field "arrayOfLongs" [] Nothing Nothing (Array Long') Nothing+          ]   describe "Parse protocols" $ do     let getPerson =           Method@@ -171,41 +179,32 @@             False     it "should parse with imports" $       parse parseProtocol "" (T.unlines . tail $ simpleProtocol)-        `shouldBe` ( Right $-                       Protocol-                         Nothing-                         "PeopleService"-                         [IdlImport "People.avdl"]-                         []-                         [getPerson]-                   )+        `shouldParse` Protocol Nothing "PeopleService" [IdlImport "People.avdl"] [] [getPerson]     it "should parse with namespace" $       parse parseProtocol "" (T.unlines simpleProtocol)-        `shouldBe` ( Right $-                       Protocol-                         (Just (Namespace ["example", "seed", "server", "protocol", "avro"]))-                         "PeopleService"-                         [IdlImport "People.avdl"]-                         []-                         [getPerson]-                   )+        `shouldParse` Protocol+          (Just (Namespace ["example", "seed", "server", "protocol", "avro"]))+          "PeopleService"+          [IdlImport "People.avdl"]+          []+          [getPerson]   describe "Parse services" $ do     it "should parse simple messages" $       parse parseMethod "" "string hello(string greeting);"-        `shouldBe` (Right $ Method "hello" [Argument String "greeting"] String Null False)+        `shouldParse` Method "hello" [Argument String' "greeting"] String' Null False     it "should parse more simple messages" $       parse parseMethod "" "bytes echoBytes(bytes data);"-        `shouldBe` (Right $ Method "echoBytes" [Argument Bytes "data"] Bytes Null False)+        `shouldParse` Method "echoBytes" [Argument Bytes' "data"] Bytes' Null False     it "should parse custom type messages" $-      let custom = NamedType "TestRecord" in-        parse parseMethod "" "TestRecord echo(TestRecord `record`);"-          `shouldBe` (Right $ Method "echo" [Argument custom "record"] custom Null False)+      let custom = NamedType "TestRecord"+       in parse parseMethod "" "TestRecord echo(TestRecord `record`);"+            `shouldParse` Method "echo" [Argument custom "record"] custom Null False     it "should parse multiple argument messages" $       parse parseMethod "" "int add(int arg1, int arg2);"-        `shouldBe` (Right $ Method "add" [Argument Int "arg1", Argument Int "arg2"] Int Null False)+        `shouldParse` Method "add" [Argument Int' "arg1", Argument Int' "arg2"] Int' Null False     it "should parse escaped and throwing messages" $       parse parseMethod "" "void `error`() throws TestError;"-        `shouldBe` (Right $ Method "error" [] Null (NamedType $ TN "TestError" []) False)+        `shouldParse` Method "error" [] Null (NamedType $ TN "TestError" []) False     it "should parse oneway messages" $       parse parseMethod "" "void ping() oneway;"-        `shouldBe` (Right $ Method "ping" [] Null Null True)+        `shouldParse` Method "ping" [] Null Null True