detour-via-uom-1.0.0: JSON and CSV encoding for quantities.

Copyright© 2018 Phil de Joux
© 2018 Block Scope Limited
LicenseMPL-2.0
MaintainerPhil de Joux <phil.dejoux@blockscope.com>
Stabilityexperimental
Safe HaskellNone
LanguageHaskell2010

Data.Via.UnitsOfMeasure

Contents

Description

For encoding and decoding newtype quantities as scientific with a fixed number of decimal places and with units.

Synopsis

Usage

With these unit definitons;

[u| m |]
[u| km = 1000 m |]

Let's say we have distances in kilometres we'd like encoded with 3 decimal places.

>>> :{
newtype Distance a = Distance a deriving (Eq, Ord, Show)
instance (q ~ Quantity Double [u| km |]) => DefaultDecimalPlaces (Distance q) where
    defdp _ = DecimalPlaces 3
instance (q ~ Quantity Double [u| km |]) => Newtype (Distance q) q where
    pack = Distance
    unpack (Distance a) = a
:}

Encoding and decoding JSON.

>>> :{
instance (q ~ Quantity Double [u| km |]) => ToJSON (Distance q) where
    toJSON x = toJSON $ ViaQ x
instance (q ~ Quantity Double [u| km |]) => FromJSON (Distance q) where
    parseJSON o = do ViaQ x <- parseJSON o; return x
:}
>>> [u| 112233.445566 km |]
[u| 112233.445566 km |]
>>> encode (Distance [u| 112233.445566 km |])
"\"112233.446 km\""
>>> let Just x :: Maybe (Distance (Quantity Double [u| km |])) = decode (encode (Distance [u| 112233.445566 km |])) in x
Distance [u| 112233.446 km |]

Similarly for CSV.

>>> :{
instance (q ~ Quantity Double [u| km |]) => ToField (Distance q) where
    toField x = toField $ ViaQ x
instance (q ~ Quantity Double [u| km |]) => FromField (Distance q) where
    parseField c = do ViaQ x <- parseField c; return x
:}
>>> let d = Distance [u| 112233.445566 km |]
>>> Csv.encode [("A", d)]
"A,112233.446 km\r\n"
>>> Csv.decode NoHeader (Csv.encode [("B", d)]) == Right (fromList [("B", d)])
False
>>> Csv.decode NoHeader (Csv.encode [("C", d)]) == Right (fromList [("C", Distance [u| 112233.446 km |])])
True

Decimal Places and Units

data ViaQ n a u where Source #

An intermediate type used during encoding to JSON with aeson and during encoding to CSV with cassava. It's also used during decoding.

The original type, a newtype Quantity, goes to and fro via this quantity so that the rational value can be encoded as a scientific value with a fixed number of decimal places and with units.

Constructors

ViaQ :: (DefaultDecimalPlaces n, Newtype n (Quantity a u)) => n -> ViaQ n a u 

Instances

(DefaultDecimalPlaces n, Newtype n (Quantity a u), Real a, KnownUnit (Unpack u)) => ToJSON (ViaQ n a u) Source # 

Methods

toJSON :: ViaQ n a u -> Value #

toEncoding :: ViaQ n a u -> Encoding #

toJSONList :: [ViaQ n a u] -> Value #

toEncodingList :: [ViaQ n a u] -> Encoding #

(DefaultDecimalPlaces n, Newtype n (Quantity a u), Real a, Fractional a, KnownUnit (Unpack u)) => FromJSON (ViaQ n a u) Source # 

Methods

parseJSON :: Value -> Parser (ViaQ n a u) #

parseJSONList :: Value -> Parser [ViaQ n a u] #

(DefaultDecimalPlaces n, Newtype n (Quantity a u), Real a, Fractional a, KnownUnit (Unpack u)) => FromField (ViaQ n a u) Source # 

Methods

parseField :: Field -> Parser (ViaQ n a u) #

(DefaultDecimalPlaces n, Newtype n (Quantity a u), Real a, KnownUnit (Unpack u)) => ToField (ViaQ n a u) Source # 

Methods

toField :: ViaQ n a u -> Field #