-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Encode and decode separated values (CSV, PSV, ...) -- -- -- sv-core is the decoding and encoding for the sv CSV library. -- This is split off into its own package so that one swap out sv's -- parser without incurring a dependency on the default parser -- (hw-dsv) -- -- For an example, see sv-cassava @package sv-core @version 0.2 module Data.Sv.Decode.Type -- | A Decode e s a is for decoding some fields from a CSV -- row into our type a. -- -- The second type parameter (s) is the input string type -- (usually ByteString or Text). The first type -- parameter (e) is the type of strings which occur in errors. -- Under most circumstances you want these type paraters to coincide, but -- they don't have to. They are two separate type parameters instead of -- one so that Decode can have a Profunctor instance. -- -- There are primitive Decodes, and combinators for composing or -- otherwise manipulating them. In particular, Decode is an -- Applicative functor and an Alt from the semigroupoids -- package, also known as a SemiAlternative. -- -- Decode is not a Monad, but we can perform monad-like -- operations on it with >>== or bindDecode newtype Decode e s a Decode :: Compose (DecodeState s) (Compose (Writer (Last Bool)) (DecodeValidation e)) a -> Decode e s a [unwrapDecode] :: Decode e s a -> Compose (DecodeState s) (Compose (Writer (Last Bool)) (DecodeValidation e)) a -- | Decode' is Decode with the input and error types the -- same. You usually want them to be the same, and most primitives are -- set up this way. type Decode' s = Decode s s -- | Convenient constructor for Decode that handles all the newtype -- noise for you. buildDecode :: (Vector s -> Ind -> (DecodeValidation e a, Last Bool, Ind)) -> Decode e s a -- | NameDecode is a decoder that looks for a column by name rather -- than by position. newtype NameDecode e s a Named :: ReaderT (Map s Ind) (Compose (DecodeValidation e) (Decode e s)) a -> NameDecode e s a [unNamed] :: NameDecode e s a -> ReaderT (Map s Ind) (Compose (DecodeValidation e) (Decode e s)) a -- | NameDecode' is NameDecode with both type parameters the -- same, as should usually be the case type NameDecode' s = NameDecode s s -- | As we decode a row of data, we walk through its fields. This -- Monad keeps track of our position. newtype DecodeState s a DecodeState :: ReaderT (Vector s) (State Ind) a -> DecodeState s a [getDecodeState] :: DecodeState s a -> ReaderT (Vector s) (State Ind) a -- | Convenient function to run a DecodeState runDecodeState :: DecodeState s a -> Vector s -> Ind -> (a, Ind) -- | Newtype for indices into the field vector newtype Ind Ind :: Int -> Ind -- | DecodeError is a value indicating what went wrong during a -- parse or decode. Its constructor indictates the type of error which -- occured, and there is usually an associated string with more -- finely-grained details. data DecodeError e -- | I was looking for another field, but I am at the end of the row UnexpectedEndOfRow :: DecodeError e -- | I should be at the end of the row, but I found extra fields ExpectedEndOfRow :: (Vector e) -> DecodeError e -- | This decoder was built using the categorical primitive for -- categorical data UnknownCategoricalValue :: e -> [[e]] -> DecodeError e -- | Looked for a column with this name, but could not find it MissingColumn :: e -> DecodeError e -- | There should have been a header but there was nothing MissingHeader :: DecodeError e -- | sv is misconfigured BadConfig :: e -> DecodeError e -- | The parser failed, meaning decoding proper didn't even begin BadParse :: e -> DecodeError e -- | Some other kind of decoding failure occured BadDecode :: e -> DecodeError e -- | DecodeErrors is a Semigroup full of DecodeError. -- It is used as the error side of a DecodeValidation. When -- multiple errors occur, they will be collected. newtype DecodeErrors e DecodeErrors :: (NonEmpty (DecodeError e)) -> DecodeErrors e -- | DecodeValidation is the error-accumulating Applicative -- underlying Decode type DecodeValidation e = Validation (DecodeErrors e) -- | An Validation is either a value of the type err or -- a, similar to Either. However, the Applicative -- instance for Validation accumulates errors using a -- Semigroup on err. In contrast, the -- Applicative for Either returns only the first error. -- -- A consequence of this is that Validation has no Bind -- or Monad instance. This is because such an instance would -- violate the law that a Monad's ap must equal the -- Applicative's <*> -- -- An example of typical usage can be found here. data Validation err a Failure :: err -> Validation err a Success :: a -> Validation err a instance GHC.Base.Applicative (Data.Sv.Decode.Type.NameDecode e s) instance GHC.Base.Functor (Data.Sv.Decode.Type.NameDecode e s) instance GHC.Base.Applicative (Data.Sv.Decode.Type.Decode e s) instance Data.Functor.Bind.Class.Apply (Data.Sv.Decode.Type.Decode e s) instance GHC.Base.Functor (Data.Sv.Decode.Type.Decode e s) instance GHC.Generics.Generic (Data.Sv.Decode.Type.DecodeErrors e) instance GHC.Base.Semigroup (Data.Sv.Decode.Type.DecodeErrors e) instance GHC.Show.Show e => GHC.Show.Show (Data.Sv.Decode.Type.DecodeErrors e) instance GHC.Classes.Ord e => GHC.Classes.Ord (Data.Sv.Decode.Type.DecodeErrors e) instance GHC.Classes.Eq e => GHC.Classes.Eq (Data.Sv.Decode.Type.DecodeErrors e) instance GHC.Generics.Generic (Data.Sv.Decode.Type.DecodeError e) instance GHC.Show.Show e => GHC.Show.Show (Data.Sv.Decode.Type.DecodeError e) instance GHC.Classes.Ord e => GHC.Classes.Ord (Data.Sv.Decode.Type.DecodeError e) instance GHC.Classes.Eq e => GHC.Classes.Eq (Data.Sv.Decode.Type.DecodeError e) instance Control.Monad.State.Class.MonadState Data.Sv.Decode.Type.Ind (Data.Sv.Decode.Type.DecodeState s) instance Control.Monad.Reader.Class.MonadReader (Data.Vector.Vector s) (Data.Sv.Decode.Type.DecodeState s) instance GHC.Base.Monad (Data.Sv.Decode.Type.DecodeState s) instance GHC.Base.Applicative (Data.Sv.Decode.Type.DecodeState s) instance Data.Functor.Bind.Class.Apply (Data.Sv.Decode.Type.DecodeState s) instance GHC.Base.Functor (Data.Sv.Decode.Type.DecodeState s) instance GHC.Show.Show Data.Sv.Decode.Type.Ind instance GHC.Classes.Ord Data.Sv.Decode.Type.Ind instance GHC.Classes.Eq Data.Sv.Decode.Type.Ind instance Data.Functor.Alt.Alt (Data.Sv.Decode.Type.NameDecode e s) instance Data.Functor.Alt.Alt (Data.Sv.Decode.Type.Decode e s) instance Data.Profunctor.Unsafe.Profunctor (Data.Sv.Decode.Type.Decode e) instance Data.Semigroupoid.Semigroupoid (Data.Sv.Decode.Type.Decode e) instance GHC.Base.Functor Data.Sv.Decode.Type.DecodeErrors instance Control.DeepSeq.NFData e => Control.DeepSeq.NFData (Data.Sv.Decode.Type.DecodeErrors e) instance GHC.Base.Functor Data.Sv.Decode.Type.DecodeError instance Control.DeepSeq.NFData e => Control.DeepSeq.NFData (Data.Sv.Decode.Type.DecodeError e) instance Data.Functor.Bind.Class.Bind (Data.Sv.Decode.Type.DecodeState s) instance Data.Profunctor.Unsafe.Profunctor Data.Sv.Decode.Type.DecodeState module Data.Sv.Decode.Error -- | DecodeError is a value indicating what went wrong during a -- parse or decode. Its constructor indictates the type of error which -- occured, and there is usually an associated string with more -- finely-grained details. data DecodeError e -- | I was looking for another field, but I am at the end of the row UnexpectedEndOfRow :: DecodeError e -- | I should be at the end of the row, but I found extra fields ExpectedEndOfRow :: (Vector e) -> DecodeError e -- | This decoder was built using the categorical primitive for -- categorical data UnknownCategoricalValue :: e -> [[e]] -> DecodeError e -- | Looked for a column with this name, but could not find it MissingColumn :: e -> DecodeError e -- | There should have been a header but there was nothing MissingHeader :: DecodeError e -- | sv is misconfigured BadConfig :: e -> DecodeError e -- | The parser failed, meaning decoding proper didn't even begin BadParse :: e -> DecodeError e -- | Some other kind of decoding failure occured BadDecode :: e -> DecodeError e -- | DecodeErrors is a Semigroup full of DecodeError. -- It is used as the error side of a DecodeValidation. When -- multiple errors occur, they will be collected. newtype DecodeErrors e DecodeErrors :: (NonEmpty (DecodeError e)) -> DecodeErrors e -- | Build a failing DecodeValidation decodeError :: DecodeError e -> DecodeValidation e a -- | Fail with UnexpectedEndOfRow unexpectedEndOfRow :: DecodeValidation e a -- | Fail with ExpectedEndOfRow. This takes the rest of the row, so -- that it can be displayed to the user. expectedEndOfRow :: Vector e -> DecodeValidation e a -- | Fail with UnknownCategoricalValue. It takes the unknown value -- and the list of good categorical values. -- -- This mostly exists to be used by the categorical function. unknownCategoricalValue :: e -> [[e]] -> DecodeValidation e a -- | Fail with MissingColumn with the given column name. This is for -- when a NameDecode looks for a column that doesn't exist. missingColumn :: e -> DecodeValidation e a -- | Fail with MissingHeader. This is for when the user asks for a -- header but the input document is completely empty (that is, it has -- nothing that could be considered a header). missingHeader :: DecodeValidation e a -- | Fail with badConfig. This is for when the user has asked for -- something impossible, like to decode a CSV by column name while -- asserting there's no header. badConfig :: e -> DecodeValidation e a -- | Fail with BadParse with the given message. This is for when the -- parse step fails, and decoding does not even begin. badParse :: e -> DecodeValidation e a -- | Fail with BadDecode with the given message. This is something -- of a generic error for when decoding a field goes wrong. badDecode :: e -> DecodeValidation e a -- | Build a DecodeValidation from an Either validateEither :: Either (DecodeError e) a -> DecodeValidation e a -- | Build a DecodeValidation from an Either, given a -- function to build the error. validateEitherWith :: (e -> DecodeError e') -> Either e a -> DecodeValidation e' a -- | Build a DecodeValidation from a Maybe. You have to -- supply an error to use in the Nothing case validateMaybe :: DecodeError e -> Maybe b -> DecodeValidation e b -- | Convert a Text.Trifecta Result to a -- DecodeValidation validateTrifectaResult :: (String -> DecodeError e) -> Result a -> DecodeValidation e a -- | bindValidation binds through an Validation, which is useful -- for composing Validations sequentially. Note that despite having a -- bind function of the correct type, Validation is not a monad. The -- reason is, this bind does not accumulate errors, so it does not agree -- with the Applicative instance. -- -- There is nothing wrong with using this function, it just does not make -- a valid Monad instance. bindValidation :: () => Validation e a -> a -> Validation e b -> Validation e b -- | This module contains data structures, combinators, and primitives for -- decoding a CSV into a list of your Haskell datatype. -- -- A Decode can be built using the primitives in this file. -- Decode is an Applicative and an Alt, allowing for -- composition of these values with <*> and <!> -- -- The primitive Decodes in this file which use ByteString -- expect UTF-8 encoding. The Decode type has an instance of -- Profunctor, so you can lmap or alterInput to -- reencode on the way in. -- -- This module is intended to be imported qualified like so -- --
--   import qualified Data.Sv.Decode.Core as D
--   
module Data.Sv.Decode.Core -- | A Decode e s a is for decoding some fields from a CSV -- row into our type a. -- -- The second type parameter (s) is the input string type -- (usually ByteString or Text). The first type -- parameter (e) is the type of strings which occur in errors. -- Under most circumstances you want these type paraters to coincide, but -- they don't have to. They are two separate type parameters instead of -- one so that Decode can have a Profunctor instance. -- -- There are primitive Decodes, and combinators for composing or -- otherwise manipulating them. In particular, Decode is an -- Applicative functor and an Alt from the semigroupoids -- package, also known as a SemiAlternative. -- -- Decode is not a Monad, but we can perform monad-like -- operations on it with >>== or bindDecode newtype Decode e s a Decode :: Compose (DecodeState s) (Compose (Writer (Last Bool)) (DecodeValidation e)) a -> Decode e s a [unwrapDecode] :: Decode e s a -> Compose (DecodeState s) (Compose (Writer (Last Bool)) (DecodeValidation e)) a -- | Decode' is Decode with the input and error types the -- same. You usually want them to be the same, and most primitives are -- set up this way. type Decode' s = Decode s s -- | DecodeValidation is the error-accumulating Applicative -- underlying Decode type DecodeValidation e = Validation (DecodeErrors e) -- | DecodeError is a value indicating what went wrong during a -- parse or decode. Its constructor indictates the type of error which -- occured, and there is usually an associated string with more -- finely-grained details. data DecodeError e -- | I was looking for another field, but I am at the end of the row UnexpectedEndOfRow :: DecodeError e -- | I should be at the end of the row, but I found extra fields ExpectedEndOfRow :: (Vector e) -> DecodeError e -- | This decoder was built using the categorical primitive for -- categorical data UnknownCategoricalValue :: e -> [[e]] -> DecodeError e -- | Looked for a column with this name, but could not find it MissingColumn :: e -> DecodeError e -- | There should have been a header but there was nothing MissingHeader :: DecodeError e -- | sv is misconfigured BadConfig :: e -> DecodeError e -- | The parser failed, meaning decoding proper didn't even begin BadParse :: e -> DecodeError e -- | Some other kind of decoding failure occured BadDecode :: e -> DecodeError e -- | DecodeErrors is a Semigroup full of DecodeError. -- It is used as the error side of a DecodeValidation. When -- multiple errors occur, they will be collected. newtype DecodeErrors e DecodeErrors :: (NonEmpty (DecodeError e)) -> DecodeErrors e -- | Decodes a sv into a list of its values using the provided -- Decode decode :: Traversable f => Decode' ByteString a -> f (Vector ByteString) -> DecodeValidation ByteString (f a) -- | Build a Decode, given a function that returns Maybe. -- -- Return the given error if the function returns Nothing. decodeMay :: DecodeError e -> (s -> Maybe a) -> Decode e s a -- | Build a Decode, given a function that returns Either. decodeEither :: (s -> Either (DecodeError e) a) -> Decode e s a -- | Build a Decode, given a function that returns Either, -- and a function to build the error. decodeEither' :: (e -> DecodeError e') -> (s -> Either e a) -> Decode e' s a -- | Map over the errors of a Decode -- -- To map over the other two parameters, use the Profunctor -- instance. mapErrors :: (e -> x) -> Decode e s a -> Decode x s a -- | This transforms a Decode' s a into a Decode' t a. It -- needs functions in both directions because the errors can include -- fragments of the input. -- --
--   alterInput :: (s -> t) -> (t -> s) -> Decode' s a -> Decode' t a
--   
alterInput :: (e -> x) -> (t -> s) -> Decode e s a -> Decode x t a -- | This is the primitive for building decoders that work with columns -- -- Look for the column with the given name and run the given decoder on -- it column :: Ord s => s -> Decode' s a -> NameDecode' s a -- | Infix alias for column (.:) :: Ord s => s -> Decode' s a -> NameDecode' s a infixl 5 .: -- | Get the contents of a field without doing any decoding. This never -- fails. contents :: Decode e s s -- | Get a field that's a single char. This will fail if there are mulitple -- characters in the field. char :: Decode' ByteString Char -- | Get the contents of a field as a bytestring. -- -- Alias for contents byteString :: Decode' ByteString ByteString -- | Get the contents of a UTF-8 encoded field as Text -- -- This will also work for ASCII text, as ASCII is a subset of UTF-8 utf8 :: Decode' ByteString Text -- | Get the contents of a field as a lazy Text lazyUtf8 :: Decode' ByteString Text -- | Get the contents of a field as a lazy ByteString lazyByteString :: Decode' ByteString ByteString -- | Get the contents of a field as a String string :: Decode' ByteString String -- | Decode a UTF-8 ByteString field as an Int int :: Decode' ByteString Int -- | Decode a UTF-8 ByteString field as an Integer integer :: Decode' ByteString Integer -- | Decode a UTF-8 ByteString field as a Float float :: Decode' ByteString Float -- | Decode a UTF-8 ByteString field as a Double double :: Decode' ByteString Double -- | Decode a field as a Bool -- -- This aims to be tolerant to different forms a boolean might take. boolean :: (IsString s, Ord s) => Decode' s Bool -- | Decode a field as a Bool. This version lets you provide the -- fromString function that's right for you, since IsString on a -- ByteString will do the wrong thing in the case of many -- encodings such as UTF-16 or UTF-32. -- -- This aims to be tolerant to different forms a boolean might take. boolean' :: Ord s => (String -> s) -> Decode' s Bool -- | Throw away the contents of a field. This is useful for skipping -- unneeded fields. ignore :: Decode e s () -- | Throw away the contents of a field, and return the given value. replace :: a -> Decode e s a -- | Decode exactly the given string, or else fail. exactly :: (Semigroup s, Eq s, IsString s) => s -> Decode' s s -- | Succeed only when the given field is the empty string. -- -- The empty string surrounded in quotes or spaces is still the empty -- string. emptyField :: (Eq s, IsString s, Semigroup s) => Decode' s () -- | Grab the whole row as a Vector row :: Decode e s (Vector s) -- | Choose the leftmost Decode that succeeds. Alias for -- <!> choice :: Decode e s a -> Decode e s a -> Decode e s a -- | Choose the leftmost Decode that succeeds. Alias for -- asum1 element :: NonEmpty (Decode e s a) -> Decode e s a -- | Try the given Decode. If it fails, succeed without consuming -- anything. -- -- This usually isn't what you want. ignoreFailure and -- orEmpty are more likely what you are after. optionalField :: Decode e s a -> Decode e s (Maybe a) -- | Try the given Decode. If it fails, instead succeed with -- Nothing. ignoreFailure :: Decode e s a -> Decode e s (Maybe a) -- | If the field is the empty string, succeed with Nothing. -- Otherwise try the given Decode. orEmpty :: (Eq s, IsString s, Semigroup s) => Decode' s a -> Decode' s (Maybe a) -- | Try the first, then try the second, and wrap the winner in an -- Either. -- -- This is left-biased, meaning if they both succeed, left wins. either :: Decode e s a -> Decode e s b -> Decode e s (Either a b) -- | Try the given decoder, otherwise succeed with the given value. orElse :: Decode e s a -> a -> Decode e s a -- | Try the given decoder, or if it fails succeed with the given value, in -- an Either. orElseE :: Decode e s b -> a -> Decode e s (Either a b) -- | Decode categorical data, given a list of the values and the strings -- which match them. -- -- Usually this is used with sum types with nullary constructors. -- --
--   data TrafficLight = Red | Amber | Green
--   categorical [(Red, "red"), (Amber, "amber"), (Green, "green")]
--   
categorical :: (Ord s, Show a) => [(a, s)] -> Decode' s a -- | Decode categorical data, given a list of the values and lists of -- strings which match them. -- -- This version allows for multiple strings to match each value, which is -- useful for when the categories are inconsistently labelled. -- --
--   data TrafficLight = Red | Amber | Green
--   categorical' [(Red, ["red", "R"]), (Amber, ["amber", "orange", "A"]), (Green, ["green", "G"])]
--   
-- -- For another example of its usage, see the source for boolean. categorical' :: forall s a. (Ord s, Show a) => [(a, [s])] -> Decode' s a -- | This can be used to build a Decode whose value depends on the -- result of another Decode. This is especially useful since -- Decode is not a Monad. -- -- If you need something like this but with more power, look at -- bindDecode (>>==) :: Decode e s a -> (a -> DecodeValidation e b) -> Decode e s b infixl 1 >>== -- | flipped >>== (==<<) :: (a -> DecodeValidation e b) -> Decode e s a -> Decode e s b infixr 1 ==<< -- | Bind through a Decode. -- -- This bind does not agree with the Applicative instance because -- it does not accumulate multiple error values. This is a violation of -- the Monad laws, meaning Decode is not a Monad. -- -- That is not to say that there is anything wrong with using this -- function. It can be quite useful. bindDecode :: Decode e s a -> (a -> Decode e s b) -> Decode e s b -- | Use the Readable instance to try to decode the given value. decodeRead :: Readable a => Decode' ByteString a -- | Use the Readable instance to try to decode the given value, or -- fail with the given error message. decodeRead' :: Readable a => ByteString -> Decode' ByteString a -- | Use the Readable instance to try to decode the given value, or -- use the value to build an error message. decodeReadWithMsg :: Readable a => (ByteString -> e) -> Decode e ByteString a -- | Build a Decode from a Trifecta parser withTrifecta :: Parser a -> Decode' ByteString a -- | Build a Decode from an Attoparsec parser withAttoparsec :: Parser a -> Decode' ByteString a -- | Build a Decode from a Parsec parser withParsec :: Parsec ByteString () a -> Decode' ByteString a -- | Run a Decode, and based on its errors build a new -- Decode. onError :: Decode e s a -> (DecodeErrors e -> Decode e s a) -> Decode e s a -- | Build a failing DecodeValidation decodeError :: DecodeError e -> DecodeValidation e a -- | Fail with UnexpectedEndOfRow unexpectedEndOfRow :: DecodeValidation e a -- | Fail with ExpectedEndOfRow. This takes the rest of the row, so -- that it can be displayed to the user. expectedEndOfRow :: Vector e -> DecodeValidation e a -- | Fail with UnknownCategoricalValue. It takes the unknown value -- and the list of good categorical values. -- -- This mostly exists to be used by the categorical function. unknownCategoricalValue :: e -> [[e]] -> DecodeValidation e a -- | Fail with BadParse with the given message. This is for when the -- parse step fails, and decoding does not even begin. badParse :: e -> DecodeValidation e a -- | Fail with BadDecode with the given message. This is something -- of a generic error for when decoding a field goes wrong. badDecode :: e -> DecodeValidation e a -- | Build a DecodeValidation from an Either validateEither :: Either (DecodeError e) a -> DecodeValidation e a -- | Build a DecodeValidation from an Either, given a -- function to build the error. validateEitherWith :: (e -> DecodeError e') -> Either e a -> DecodeValidation e' a -- | Build a DecodeValidation from a Maybe. You have to -- supply an error to use in the Nothing case validateMaybe :: DecodeError e -> Maybe b -> DecodeValidation e b -- | Convenience to get the underlying function out of a Decode in a -- useful form runDecode :: Decode e s a -> Vector s -> Ind -> (DecodeValidation e a, Last Bool, Ind) -- | Convenient constructor for Decode that handles all the newtype -- noise for you. buildDecode :: (Vector s -> Ind -> (DecodeValidation e a, Last Bool, Ind)) -> Decode e s a -- | Build a Decode from a function. mkDecode :: (s -> DecodeValidation e a) -> Decode e s a -- | Promotes a Decode to work on a whole Record at once. -- This does not need to be called by the user. Instead use -- decode. promote :: Decode' s a -> Vector s -> DecodeValidation s a -- | Promotes a Decode to work on a whole Record at once. -- This does not need to be called by the user. Instead use -- decode. -- -- This version lets the error string and input string type pararms -- differ, but needs a function to convert between them. promote' :: (s -> e) -> Decode e s a -> Vector s -> DecodeValidation e a -- | Convenience to get the underlying function out of a NameDecode -- in a useful form runNamed :: NameDecode e s a -> Map s Ind -> DecodeValidation e (Decode e s a) -- | Promote a Decode to a NameDecode that doesn't look for -- any names anonymous :: Decode e s a -> NameDecode e s a -- | Given a header and a NameDecode, resolve header names to -- positions and return a Decode makePositional :: Ord s => Vector s -> NameDecode e s a -> DecodeValidation e (Decode e s a) module Data.Sv.Structure.Headedness -- | Does the CSV have a Header or not? A header is a row at the -- beginning of a file which contains the string names of each of the -- columns. -- -- If a header is present, it must not be decoded with the rest of the -- data. data Headedness Unheaded :: Headedness Headed :: Headedness -- | Classy lens for Headedness class HasHeadedness c headedness :: HasHeadedness c => Lens' c Headedness instance GHC.Show.Show Data.Sv.Structure.Headedness.Headedness instance GHC.Classes.Ord Data.Sv.Structure.Headedness.Headedness instance GHC.Classes.Eq Data.Sv.Structure.Headedness.Headedness instance Data.Sv.Structure.Headedness.HasHeadedness Data.Sv.Structure.Headedness.Headedness module Data.Sv.Structure.Newline -- | Newline is a newtype around ByteString newtype Newline UnsafeMkNewline :: ByteString -> Newline [toByteString] :: Newline -> ByteString -- | Convert a Newline to a ByteString Builder. This is used -- by encoding. newlineToBuilder :: Newline -> Builder -- | DOS newlines: a carriage return character followed by a line feed -- character crlf :: Newline -- | Unix/Linux newlines: a line feed character lf :: Newline instance GHC.Classes.Ord Data.Sv.Structure.Newline.Newline instance GHC.Classes.Eq Data.Sv.Structure.Newline.Newline instance GHC.Show.Show Data.Sv.Structure.Newline.Newline module Data.Sv.Structure.Separator -- | By what are your values separated? The answer is often comma, -- but not always. -- -- A Separator is just a Word8. It could be a sum type -- instead, since it will usually be comma or pipe, but our preference -- has been to be open here so that you can use whatever you'd like. type Separator = Word8 -- | The venerable comma separator. Used for CSV documents. comma :: Separator -- | The pipe separator. Used for PSV documents. pipe :: Separator -- | Tab is a separator too - why not? tab :: Separator -- | Classy lens for Separator class HasSeparator c separator :: HasSeparator c => Lens' c Separator instance Data.Sv.Structure.Separator.HasSeparator GHC.Word.Word8 module Data.Sv.Structure.Core -- | By what are your values separated? The answer is often comma, -- but not always. -- -- A Separator is just a Word8. It could be a sum type -- instead, since it will usually be comma or pipe, but our preference -- has been to be open here so that you can use whatever you'd like. type Separator = Word8 -- | The venerable comma separator. Used for CSV documents. comma :: Separator -- | The pipe separator. Used for PSV documents. pipe :: Separator -- | Tab is a separator too - why not? tab :: Separator -- | Classy lens for Separator class HasSeparator c separator :: HasSeparator c => Lens' c Separator -- | Does the CSV have a Header or not? A header is a row at the -- beginning of a file which contains the string names of each of the -- columns. -- -- If a header is present, it must not be decoded with the rest of the -- data. data Headedness Unheaded :: Headedness Headed :: Headedness -- | Classy lens for Headedness class HasHeadedness c headedness :: HasHeadedness c => Lens' c Headedness -- | Options to configure encoding module Data.Sv.Encode.Options -- | These are options to configure encoding. A default is provided as -- defaultEncodeOptions. data EncodeOptions EncodeOptions :: Separator -> Quoting -> Newline -> Bool -> EncodeOptions -- | Are your values separated by commas, tabs, or something else? Default: -- comma [_encodeSeparator] :: EncodeOptions -> Separator -- | Would you like quotes around your values? If so, double quotes or -- single? Deafult: Double quotes [_quoting] :: EncodeOptions -> Quoting -- | What kind of newline would you like? Default: LF [_newline] :: EncodeOptions -> Newline -- | Should the file be terminated with a newline? Default: No [_terminalNewline] :: EncodeOptions -> Bool -- | Classy lenses for EncodeOptions -- --
--   import Control.Lens
--   
--   defaultEncodeOptions & newline .~ crlf & quoting .~ Always
--   
class HasSeparator c => HasEncodeOptions c encodeOptions :: HasEncodeOptions c => Lens' c EncodeOptions quoting :: HasEncodeOptions c => Lens' c Quoting newline :: HasEncodeOptions c => Lens' c Newline terminalNewline :: HasEncodeOptions c => Lens' c Bool -- | Classy lens for Separator class HasSeparator c separator :: HasSeparator c => Lens' c Separator -- | Should the output file have quotes around every value, or only when -- they are required? -- -- Beware the Never constructor. It can construct malformed CSV -- files if there are fields containing quotes, newlines, or separators. -- It is the fastest option though, so you might like to use it if you're -- sure none of your encoded data will include those characters. data Quoting Always :: Quoting AsNeeded :: Quoting Never :: Quoting -- | The default options for encoding. -- -- The default is a CSV file with quotes when necessary, LF lines, and no -- terminating newline. defaultEncodeOptions :: EncodeOptions instance Data.Sv.Encode.Options.HasEncodeOptions Data.Sv.Encode.Options.EncodeOptions instance Data.Sv.Structure.Separator.HasSeparator Data.Sv.Encode.Options.EncodeOptions -- | The core type for encoding module Data.Sv.Encode.Type -- | An Encode converts its argument into one or more textual -- fields, to be written out as CSV. -- -- It is Semigroup, Contravariant, Divisible, and -- Decidable, allowing for composition of these values to build -- bigger Encodes from smaller ones. newtype Encode a Encode :: EncodeOptions -> a -> Seq Builder -> Encode a [getEncode] :: Encode a -> EncodeOptions -> a -> Seq Builder instance GHC.Base.Monoid (Data.Sv.Encode.Type.Encode a) instance GHC.Base.Semigroup (Data.Sv.Encode.Type.Encode a) instance Data.Functor.Contravariant.Contravariant Data.Sv.Encode.Type.Encode instance Data.Functor.Contravariant.Divisible.Divisible Data.Sv.Encode.Type.Encode instance Data.Functor.Contravariant.Divisible.Decidable Data.Sv.Encode.Type.Encode -- | This module is intended to be imported qualified as follows -- --
--   import Data.Sv.Encode.Core as E
--   
-- -- To produce a CSV file from data types, build an Encode for your -- data type. This module contains primitives, combinators, and type -- class instances to help you to do so. -- -- Encode is a Contravariant functor, as well as a -- Divisible and Decidable. Divisible is the -- contravariant form of Applicative, while Decidable is -- the contravariant form of Alternative. These type classes will -- provide useful combinators for working with Encodes. -- -- Specialised to Encode, the function divide from -- Divisible has the type: -- --
--   divide :: (a -> (b,c)) -> Encode b -> Encode c -> Encode a
--   
-- -- which can be read "if a can be split into b and -- c, and I can handle b, and I can handle c, -- then I can handle a". -- -- Here the "I can handle" part corresponds to the Encode. If we -- think of (covariant) functors as being "full of" a, then we -- can think of contravariant functors as being "able to handle" -- a. -- -- How does it work? Perform the split on the a, handle the -- b by converting it into some text, handle the c by -- also converting it to some text, then put each of those text fragments -- into their own field in the CSV. -- -- Similarly, the function choose from Decidable, -- specialsed to Encode, has the type: -- --
--   choose :: (a -> Either b c) -> Encode b -> Encode c -> Encode a
--   
-- -- which can be read "if a is either b or c, -- and I can handle b, and I can handle c, then I can -- handle a". -- -- This works by performing the split, then checking whether b -- or c resulted, then using the appropriate Encode. -- -- For an example of encoding, see Encoding.hs module Data.Sv.Encode.Core -- | An Encode converts its argument into one or more textual -- fields, to be written out as CSV. -- -- It is Semigroup, Contravariant, Divisible, and -- Decidable, allowing for composition of these values to build -- bigger Encodes from smaller ones. newtype Encode a Encode :: EncodeOptions -> a -> Seq Builder -> Encode a [getEncode] :: Encode a -> EncodeOptions -> a -> Seq Builder -- | Make an Encode from a function that builds one Field. mkEncodeBS :: (a -> ByteString) -> Encode a -- | Make an Encode from a function that builds one Field. mkEncodeWithOpts :: (EncodeOptions -> a -> Builder) -> Encode a -- | Encode the given list with the given Encode, configured by the -- given EncodeOptions. encode :: Encode a -> EncodeOptions -> [a] -> ByteString -- | Encode, writing the output to a file handle. encodeToHandle :: Encode a -> EncodeOptions -> [a] -> Handle -> IO () -- | Encode, writing to a file. This way is more efficient than encoding to -- a ByteString and then writing to file. encodeToFile :: Encode a -> EncodeOptions -> [a] -> FilePath -> IO () -- | Encode to a ByteString Builder, which is useful if you are -- going to combine the output with other ByteStrings. encodeBuilder :: Encode a -> EncodeOptions -> [a] -> Builder -- | Encode one row only encodeRow :: Encode a -> EncodeOptions -> a -> ByteString -- | Encode one row only, as a ByteString Builder encodeRowBuilder :: Encode a -> EncodeOptions -> a -> Builder -- | Classy lens for Separator class HasSeparator c separator :: HasSeparator c => Lens' c Separator -- | Classy lenses for EncodeOptions -- --
--   import Control.Lens
--   
--   defaultEncodeOptions & newline .~ crlf & quoting .~ Always
--   
class HasSeparator c => HasEncodeOptions c encodeOptions :: HasEncodeOptions c => Lens' c EncodeOptions quoting :: HasEncodeOptions c => Lens' c Quoting newline :: HasEncodeOptions c => Lens' c Newline terminalNewline :: HasEncodeOptions c => Lens' c Bool -- | These are options to configure encoding. A default is provided as -- defaultEncodeOptions. data EncodeOptions EncodeOptions :: Separator -> Quoting -> Newline -> Bool -> EncodeOptions -- | Are your values separated by commas, tabs, or something else? Default: -- comma [_encodeSeparator] :: EncodeOptions -> Separator -- | Would you like quotes around your values? If so, double quotes or -- single? Deafult: Double quotes [_quoting] :: EncodeOptions -> Quoting -- | What kind of newline would you like? Default: LF [_newline] :: EncodeOptions -> Newline -- | Should the file be terminated with a newline? Default: No [_terminalNewline] :: EncodeOptions -> Bool -- | Should the output file have quotes around every value, or only when -- they are required? -- -- Beware the Never constructor. It can construct malformed CSV -- files if there are fields containing quotes, newlines, or separators. -- It is the fastest option though, so you might like to use it if you're -- sure none of your encoded data will include those characters. data Quoting Always :: Quoting AsNeeded :: Quoting Never :: Quoting -- | The default options for encoding. -- -- The default is a CSV file with quotes when necessary, LF lines, and no -- terminating newline. defaultEncodeOptions :: EncodeOptions -- | Encode this ByteString every time, ignoring the input. const :: ByteString -> Encode a -- | Build an Encode using a type's Show instance. show :: Show a => Encode a -- | Don't encode anything. nop :: Encode a -- | Encode anything as the empty string. empty :: Encode a -- | Lift an Encode to be able to hanlde Maybe, by using the empty -- string in the case of Nothing orEmpty :: Encode a -> Encode (Maybe a) -- | Encode a single Char char :: Encode Char -- | Encode an Int int :: Encode Int -- | Encode an Integer integer :: Encode Integer -- | Encode a Float float :: Encode Float -- | Encode a Double double :: Encode Double -- | Encode a Bool as True or False boolTrueFalse :: Encode Bool -- | Encode a Bool as true of false booltruefalse :: Encode Bool -- | Encode a Bool as yes or no boolyesno :: Encode Bool -- | Encode a Bool as Yes or No boolYesNo :: Encode Bool -- | Encode a Bool as Y or N boolYN :: Encode Bool -- | Encode a Bool as 1 or 0 bool10 :: Encode Bool -- | Encode a String string :: Encode String -- | Encode a Text text :: Encode Text -- | Encode a strict ByteString byteString :: Encode ByteString -- | Encode a lazy ByteString lazyByteString :: Encode ByteString -- | Encode a list as a whole row at once, using the same Encode for -- every element row :: Encode s -> Encode [s] -- | Build an Encode for Maybe given a Just and a -- Nothing encode. (?>) :: Encode a -> Encode () -> Encode (Maybe a) -- | Build an Encode for Maybe given a Nothing and a -- Just encode. ( Encode a -> Encode (Maybe a) -- | Build an Encode for Maybe given a Just encode and -- a ByteString for the Nothing case. (?>>) :: Encode a -> ByteString -> Encode (Maybe a) -- | Build an Encode for Maybe given a ByteString for -- the Nothing case and a Just encode. (< Encode a -> Encode (Maybe a) -- | Given an optic from s to a, Try to use it to build -- an encode. -- --
--   encodeOf :: Iso'       s a -> Encode a -> Encode s
--   encodeOf :: Lens'      s a -> Encode a -> Encode s
--   encodeOf :: Prism'     s a -> Encode a -> Encode s
--   encodeOf :: Traversal' s a -> Encode a -> Encode s
--   encodeOf :: Fold       s a -> Encode a -> Encode s
--   encodeOf :: Getter     s a -> Encode a -> Encode s
--   
-- -- This is very useful when you have a prism for each constructor of your -- type. You can define an Encode as follows: -- --
--   myEitherEncode :: Encode a -> Encode b -> Encode (Either a b)
--   myEitherEncode encA encB = encodeOf _Left encA <> encodeOf _Right encB
--   
-- -- In this example, when the prism lookup returns Nothing, the -- empty encoder is returned. This is the mempty for the -- Encode monoid, so it won't add a field to the resulting CSV. -- This is the behaviour you want for combining a collection of prisms. -- -- But this encoder also works with lenses (or weaker optics), which will -- never fail their lookup, in which case it never returns mempty. -- So this actually does the right thing for both sum and product types. encodeOf :: Getting (First a) s a -> Encode a -> Encode s -- | Like encodeOf, but you can handle Nothing however you'd -- like. In encodeOf, it is handled by the Encode which does -- nothing, but for example you might like to use orEmpty to -- encode an empty field. encodeOfMay :: Getting (First a) s a -> Encode (Maybe a) -> Encode s -- | Make an encode from any function that returns a ByteString -- Builder. unsafeBuilder :: (a -> Builder) -> Encode a -- | Encode a String really quickly. If the string has quotes in it, -- they will not be escaped properly, so the result maybe not be valid -- CSV unsafeString :: Encode String -- | Encode Text really quickly. If the text has quotes in it, they -- will not be escaped properly, so the result maybe not be valid CSV unsafeText :: Encode Text -- | Encode a ByteString really quickly. If the string has quotes in -- it, they will not be escaped properly, so the result maybe not be -- valid CSV unsafeByteString :: Encode ByteString -- | Encode a ByteString really quickly. If the string has quotes in -- it, they will not be escaped properly, so the result maybe not be -- valid CSV unsafeLazyByteString :: Encode ByteString -- | Encode ByteString Builder really quickly. If the builder builds -- a string with quotes in it, they will not be escaped properly, so the -- result maybe not be valid CSV unsafeByteStringBuilder :: Encode Builder -- | Encode this ByteString really quickly every time, ignoring the -- input. If the string has quotes in it, they will not be escaped -- properly, so the result maybe not be valid CSV unsafeConst :: ByteString -> Encode a