@@ -364,40 +364,44 @@ module Database.V5.Bloodhound.Types
364364 , EsPassword(..)
365365 ) where
366366
367−import Control.Applicative as A
368−import Control.Arrow (first)
367+import Control.Applicative as A
368+import Control.Arrow (first)
369369import Control.Monad.Catch
370370import Control.Monad.Except
371371import Control.Monad.Reader
372372import Control.Monad.State
373373import Control.Monad.Writer
374374import Data.Aeson
375−import Data.Aeson.Types (Pair, Parser, emptyObject,
376− parseEither, parseMaybe)
377−import qualified Data.ByteString.Lazy.Char8 as L
375+import Data.Aeson.Types (Pair, Parser,
376+ emptyObject,
377+ parseEither, parseMaybe)
378+import qualified Data.ByteString.Lazy.Char8 as L
378379import Data.Char
379−import Data.Hashable (Hashable)
380−import qualified Data.HashMap.Strict as HM
381−import Data.List (foldl', intercalate, nub)
382−import Data.List.NonEmpty (NonEmpty (..), toList)
383−import qualified Data.Map.Strict as M
380+import Data.Hashable (Hashable)
381+import qualified Data.HashMap.Strict as HM
382+import Data.List (foldl', intercalate,
383+ nub)
384+import Data.List.NonEmpty (NonEmpty (..), toList)
385+import qualified Data.Map.Strict as M
384386import Data.Maybe
385−import Data.Scientific (Scientific)
386−import Data.Text (Text)
387−import qualified Data.Text as T
387+import Data.Scientific (Scientific)
388+import Data.Semigroup
389+import Data.Text (Text)
390+import qualified Data.Text as T
388391import Data.Time.Calendar
389−import Data.Time.Clock (NominalDiffTime, UTCTime)
392+import Data.Time.Clock (NominalDiffTime,
393+ UTCTime)
390394import Data.Time.Clock.POSIX
391−import qualified Data.Traversable as DT
392−import Data.Typeable (Typeable)
393−import qualified Data.Vector as V
394−import qualified Data.Version as Vers
395+import qualified Data.Traversable as DT
396+import Data.Typeable (Typeable)
397+import qualified Data.Vector as V
398+import qualified Data.Version as Vers
395399import GHC.Enum
396−import GHC.Generics (Generic)
400+import GHC.Generics (Generic)
397401import Network.HTTP.Client
398−import qualified Network.HTTP.Types.Method as NHTM
399−import qualified Text.ParserCombinators.ReadP as RP
400−import qualified Text.Read as TR
402+import qualified Network.HTTP.Types.Method as NHTM
403+import qualified Text.ParserCombinators.ReadP as RP
404+import qualified Text.Read as TR
401405
402406import Database.V5.Bloodhound.Types.Class
403407import Database.V5.Bloodhound.Types.Internal
@@ -452,11 +456,11 @@ runBH :: BHEnv -> BH m a -> m a
452456runBH e f = runReaderT (unBH f) e
453457
454458{-| 'Version' is embedded in 'Status' -}
455−data Version = Version { number :: VersionNumber
456− , build_hash :: BuildHash
457− , build_date :: UTCTime
458− , build_snapshot :: Bool
459− , lucene_version :: VersionNumber } deriving (Eq, Read, Show, Generic, Typeable)
459+data Version = Version { number :: VersionNumber
460+ , build_hash :: BuildHash
461+ , build_date :: UTCTime
462+ , build_snapshot :: Bool
463+ , lucene_version :: VersionNumber } deriving (Eq, Read, Show, Generic, Typeable)
460464
461465-- | Traditional software versioning number
462466newtype VersionNumber = VersionNumber { versionNumber :: Vers.Version
@@ -494,7 +498,7 @@ defaultIndexSettings = IndexSettings (ShardCount 3) (ReplicaCount 2)
494498 for more info.
495499-}
496500data ForceMergeIndexSettings =
497− ForceMergeIndexSettings { maxNumSegments :: Maybe Int
501+ ForceMergeIndexSettings { maxNumSegments :: Maybe Int
498502 -- ^ Number of segments to optimize to. 1 will fully optimize the index. If omitted, the default behavior is to only optimize if the server deems it necessary.
499503 , onlyExpungeDeletes :: Bool
500504 -- ^ Should the optimize process only expunge segments with deletes in them? If the purpose of the optimization is to free disk space, this should be set to True.
@@ -847,8 +851,8 @@ data SortSpec = DefaultSortSpec DefaultSort
847851{-| 'DefaultSort' is usually the kind of 'SortSpec' you'll want. There's a
848852 'mkSort' convenience function for when you want to specify only the most
849853 common parameters.
850−
851− The `ignoreUnmapped`, when `Just` field is used to set the elastic 'unmapped_type'
854+
855+ The `ignoreUnmapped`, when `Just` field is used to set the elastic 'unmapped_type'
852856
853857<http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-sort.html#search-request-sort>
854858-}
@@ -1206,7 +1210,7 @@ data Query =
12061210 deriving (Eq, Read, Show, Generic, Typeable)
12071211
12081212-- | As of Elastic 2.0, 'Filters' are just 'Queries' housed in a Bool Query, and
1209−-- flagged in a different context.
1213+-- flagged in a different context.
12101214newtype Filter = Filter { unFilter :: Query }
12111215 deriving (Eq, Read, Show, Generic, Typeable)
12121216
@@ -1631,12 +1635,12 @@ data SearchHits a =
16311635 , maxScore :: Score
16321636 , hits :: [Hit a] } deriving (Eq, Read, Show, Generic, Typeable)
16331637
1638+instance Semigroup (SearchHits a) where
1639+ (SearchHits ta ma ha) <> (SearchHits tb mb hb) = SearchHits (ta + tb) (max ma mb) (ha <> hb)
16341640
16351641instance Monoid (SearchHits a) where
16361642 mempty = SearchHits 0 Nothing mempty
1637− mappend (SearchHits ta ma ha) (SearchHits tb mb hb) =
1638− SearchHits (ta + tb) (max ma mb) (ha <> hb)
1639−
1643+ mappend = (<>)
16401644
16411645data Hit a =
16421646 Hit { hitIndex :: IndexName
@@ -1659,7 +1663,7 @@ showText = T.pack . show
16591663readMay :: Read a => String -> Maybe a
16601664readMay s = case reads s of
16611665 (a, ""):_ -> Just a
1662− _ -> Nothing
1666+ _ -> Nothing
16631667
16641668parseReadText :: Read a => Text -> Parser a
16651669parseReadText = maybe mzero return . readMay . T.unpack
@@ -1708,8 +1712,8 @@ data Aggregation = TermsAgg TermsAggregation
17081712 | ValueCountAgg ValueCountAggregation
17091713 | FilterAgg FilterAggregation
17101714 | DateRangeAgg DateRangeAggregation
1711− | MissingAgg MissingAggregation
1712− | TopHitsAgg TopHitsAggregation
1715+ | MissingAgg MissingAggregation
1716+ | TopHitsAgg TopHitsAggregation
17131717 deriving (Eq, Read, Show, Generic, Typeable)
17141718
17151719data TopHitsAggregation = TopHitsAggregation
@@ -1846,21 +1850,21 @@ instance ToJSON ExecutionHint where
18461850 toJSON Map = "map"
18471851
18481852instance ToJSON Interval where
1849− toJSON Year = "year"
1853+ toJSON Year = "year"
18501854 toJSON Quarter = "quarter"
1851− toJSON Month = "month"
1852− toJSON Week = "week"
1853− toJSON Day = "day"
1854− toJSON Hour = "hour"
1855− toJSON Minute = "minute"
1856− toJSON Second = "second"
1855+ toJSON Month = "month"
1856+ toJSON Week = "week"
1857+ toJSON Day = "day"
1858+ toJSON Hour = "hour"
1859+ toJSON Minute = "minute"
1860+ toJSON Second = "second"
18571861
18581862instance Show TimeInterval where
1859− show Weeks = "w"
1860− show Days = "d"
1861− show Hours = "h"
1862− show Minutes = "m"
1863− show Seconds = "s"
1863+ show Weeks = "w"
1864+ show Days = "d"
1865+ show Hours = "h"
1866+ show Minutes = "m"
1867+ show Seconds = "s"
18641868
18651869instance Read TimeInterval where
18661870 readPrec = f =<< TR.get
@@ -1916,7 +1920,7 @@ instance ToJSON Aggregation where
19161920 toJSON (MissingAgg (MissingAggregation{..})) =
19171921 object ["missing" .= object ["field" .= maField]]
19181922
1919− toJSON (TopHitsAgg (TopHitsAggregation mfrom msize msort)) =
1923+ toJSON (TopHitsAgg (TopHitsAggregation mfrom msize msort)) =
19201924 omitNulls ["top_hits" .= omitNulls [ "size" .= msize
19211925 , "from" .= mfrom
19221926 , "sort" .= msort
@@ -1931,22 +1935,22 @@ instance ToJSON DateRangeAggregation where
19311935 ]
19321936
19331937instance ToJSON DateRangeAggRange where
1934− toJSON (DateRangeFrom e) = object [ "from" .= e ]
1935− toJSON (DateRangeTo e) = object [ "to" .= e ]
1938+ toJSON (DateRangeFrom e) = object [ "from" .= e ]
1939+ toJSON (DateRangeTo e) = object [ "to" .= e ]
19361940 toJSON (DateRangeFromAndTo f t) = object [ "from" .= f, "to" .= t ]
19371941
19381942instance ToJSON DateMathExpr where
19391943 toJSON (DateMathExpr a mods) = String (fmtA a <> mconcat (fmtMod <$> mods))
1940− where fmtA DMNow = "now"
1944+ where fmtA DMNow = "now"
19411945 fmtA (DMDate date) = (T.pack $ showGregorian date) <> "||"
1942− fmtMod (AddTime n u) = "+" <> showText n <> fmtU u
1946+ fmtMod (AddTime n u) = "+" <> showText n <> fmtU u
19431947 fmtMod (SubtractTime n u) = "-" <> showText n <> fmtU u
1944− fmtMod (RoundDownTo u) = "/" <> fmtU u
1945− fmtU DMYear = "y"
1946− fmtU DMMonth = "M"
1947− fmtU DMWeek = "w"
1948− fmtU DMDay = "d"
1949− fmtU DMHour = "h"
1948+ fmtMod (RoundDownTo u) = "/" <> fmtU u
1949+ fmtU DMYear = "y"
1950+ fmtU DMMonth = "M"
1951+ fmtU DMWeek = "w"
1952+ fmtU DMDay = "d"
1953+ fmtU DMHour = "h"
19501954 fmtU DMMinute = "m"
19511955 fmtU DMSecond = "s"
19521956
@@ -2026,8 +2030,8 @@ instance (FromJSON a, BucketAggregation a) => FromJSON (Bucket a) where
20262030instance FromJSON BucketValue where
20272031 parseJSON (String t) = return $ TextValue t
20282032 parseJSON (Number s) = return $ ScientificValue s
2029− parseJSON (Bool b) = return $ BoolValue b
2030− parseJSON _ = mempty
2033+ parseJSON (Bool b) = return $ BoolValue b
2034+ parseJSON _ = mempty
20312035
20322036instance FromJSON MissingResult where
20332037 parseJSON = withObject "MissingResult" parse
@@ -2086,11 +2090,11 @@ fieldTagged f o = case HM.toList o of
20862090 _ -> fail "Expected object with 1 field-named key"
20872091
20882092-- Try to get an AggregationResults when we don't know the
2089−-- field name. We filter out the known keys to try to minimize the noise.
2093+-- field name. We filter out the known keys to try to minimize the noise.
20902094getNamedSubAgg :: Object -> [Text] -> Maybe AggregationResults
20912095getNamedSubAgg o knownKeys = maggRes
20922096 where unknownKeys = HM.filterWithKey (\k _ -> k `notElem` knownKeys) o
2093− maggRes
2097+ maggRes
20942098 | HM.null unknownKeys = Nothing
20952099 | otherwise = Just . M.fromList $ HM.toList unknownKeys
20962100
@@ -2188,7 +2192,7 @@ instance ToJSON Query where
21882192 object ["exists" .= object
21892193 ["field" .= fieldName]
21902194 ]
2191− toJSON QueryMatchNoneQuery =
2195+ toJSON QueryMatchNoneQuery =
21922196 object ["match_none" .= object []]
21932197
21942198instance FromJSON Query where
@@ -2259,9 +2263,9 @@ instance FromJSON Query where
22592263
22602264omitNulls :: [(Text, Value)] -> Value
22612265omitNulls = object . filter notNull where
2262− notNull (_, Null) = False
2266+ notNull (_, Null) = False
22632267 notNull (_, Array a) = (not . V.null) a
2264− notNull _ = True
2268+ notNull _ = True
22652269
22662270instance ToJSON SimpleQueryStringQuery where
22672271 toJSON SimpleQueryStringQuery {..} =
@@ -2804,10 +2808,10 @@ instance FromJSON MultiMatchQuery where
28042808 <*> o .:? "lenient"
28052809
28062810instance ToJSON MultiMatchQueryType where
2807− toJSON MultiMatchBestFields = "best_fields"
2808− toJSON MultiMatchMostFields = "most_fields"
2809− toJSON MultiMatchCrossFields = "cross_fields"
2810− toJSON MultiMatchPhrase = "phrase"
2811+ toJSON MultiMatchBestFields = "best_fields"
2812+ toJSON MultiMatchMostFields = "most_fields"
2813+ toJSON MultiMatchCrossFields = "cross_fields"
2814+ toJSON MultiMatchPhrase = "phrase"
28112815 toJSON MultiMatchPhrasePrefix = "phrase_prefix"
28122816
28132817instance FromJSON MultiMatchQueryType where
@@ -2821,7 +2825,7 @@ instance FromJSON MultiMatchQueryType where
28212825
28222826instance ToJSON BooleanOperator where
28232827 toJSON And = String "and"
2824− toJSON Or = String "or"
2828+ toJSON Or = String "or"
28252829
28262830instance FromJSON BooleanOperator where
28272831 parseJSON = withText "BooleanOperator" parse
@@ -2840,7 +2844,7 @@ instance FromJSON ZeroTermsQuery where
28402844 parse q = fail ("Unexpected ZeroTermsQuery: " <> show q)
28412845
28422846instance ToJSON MatchQueryType where
2843− toJSON MatchPhrase = "phrase"
2847+ toJSON MatchPhrase = "phrase"
28442848 toJSON MatchPhrasePrefix = "phrase_prefix"
28452849
28462850instance FromJSON MatchQueryType where
@@ -2974,7 +2978,7 @@ instance FromJSON IndexSettingsSummary where
29742978 <*> (fmap (filter (not . redundant)) . parseSettings =<< o' .: "settings")
29752979 _ -> fail "Expected single-key object with index name"
29762980 redundant (NumberOfReplicas _) = True
2977− redundant _ = False
2981+ redundant _ = False
29782982
29792983-- | For some reason in several settings APIs, all leaf values get returned
29802984-- as strings. This function attepmts to recover from this for all
@@ -2984,7 +2988,7 @@ unStringlyTypeJSON (String "true") = Bool True
29842988unStringlyTypeJSON (String "false") = Bool False
29852989unStringlyTypeJSON (String "null") = Null
29862990unStringlyTypeJSON v@(String t) = case readMay (T.unpack t) of
2987− Just n -> Number n
2991+ Just n -> Number n
29882992 Nothing -> v
29892993unStringlyTypeJSON v = v
29902994
@@ -3001,7 +3005,7 @@ parseSettings o = do
30013005 return (catMaybes parses)
30023006
30033007oPath :: ToJSON a => NonEmpty Text -> a -> Value
3004−oPath (k :| []) v = object [k .= v]
3008+oPath (k :| []) v = object [k .= v]
30053009oPath (k:| (h:t)) v = object [k .= oPath (h :| t) v]
30063010
30073011attrFilterJSON :: NonEmpty NodeAttrFilter -> Value
@@ -3011,12 +3015,12 @@ attrFilterJSON fs = object [ n .= T.intercalate "," (toList vs)
30113015parseAttrFilter :: Value -> Parser (NonEmpty NodeAttrFilter)
30123016parseAttrFilter = withObject "NonEmpty NodeAttrFilter" parse
30133017 where parse o = case HM.toList o of
3014− [] -> fail "Expected non-empty list of NodeAttrFilters"
3018+ [] -> fail "Expected non-empty list of NodeAttrFilters"
30153019 x:xs -> DT.mapM (uncurry parse') (x :| xs)
30163020 parse' n = withText "Text" $ \t ->
30173021 case T.splitOn "," t of
30183022 fv:fvs -> return (NodeAttrFilter (NodeAttrName n) (fv :| fvs))
3019− [] -> fail "Expected non-empty list of filter values"
3023+ [] -> fail "Expected non-empty list of filter values"
30203024
30213025instance ToJSON ReplicaBounds where
30223026 toJSON (ReplicasBounded a b) = String (showText a <> "-" <> showText b)
@@ -3070,12 +3074,12 @@ instance ToJSON FSType where
30703074
30713075instance FromJSON FSType where
30723076 parseJSON = withText "FSType" parse
3073− where parse "simple" = pure FSSimple
3077+ where parse "simple" = pure FSSimple
30743078 parse "buffered" = pure FSBuffered
3075− parse t = fail ("Invalid FSType: " <> show t)
3079+ parse t = fail ("Invalid FSType: " <> show t)
30763080
30773081instance ToJSON CompoundFormat where
3078− toJSON (CompoundFileFormat x) = Bool x
3082+ toJSON (CompoundFileFormat x) = Bool x
30793083 toJSON (MergeSegmentVsTotalIndex x) = toJSON x
30803084
30813085instance FromJSON CompoundFormat where
@@ -3193,7 +3197,7 @@ instance ToJSON Search where
31933197 , "track_scores" .= sTrackSortScores
31943198 , "fields" .= sFields
31953199 , "_source" .= sSource]
3196−
3200+
31973201 where query' = case sFilter of
31983202 Nothing -> mquery
31993203 Just x -> Just . QueryBoolQuery $ mkBoolQuery (maybeToList mquery) [x] [] []
@@ -3334,8 +3338,8 @@ instance ToJSON SortMode where
33343338
33353339
33363340instance ToJSON Missing where
3337− toJSON LastMissing = String "_last"
3338− toJSON FirstMissing = String "_first"
3341+ toJSON LastMissing = String "_last"
3342+ toJSON FirstMissing = String "_first"
33393343 toJSON (CustomMissing txt) = String txt
33403344
33413345
@@ -3351,7 +3355,7 @@ instance FromJSON ScoreType where
33513355 parse "avg" = pure ScoreTypeAvg
33523356 parse "sum" = pure ScoreTypeSum
33533357 parse "none" = pure ScoreTypeNone
3354− parse t = fail ("Unexpected ScoreType: " <> show t)
3358+ parse t = fail ("Unexpected ScoreType: " <> show t)
33553359
33563360instance ToJSON Distance where
33573361 toJSON (Distance dCoefficient dUnit) =
@@ -3369,7 +3373,7 @@ instance FromJSON Distance where
33693373 validForNumber '-' = True
33703374 validForNumber '.' = True
33713375 validForNumber 'e' = True
3372− validForNumber c = isNumber c
3376+ validForNumber c = isNumber c
33733377 parseCoeff "" = fail "Empty string cannot be parsed as number"
33743378 parseCoeff s = return (read (T.unpack s))
33753379
@@ -3396,7 +3400,7 @@ instance FromJSON DistanceUnit where
33963400 parse "cm" = pure Centimeters
33973401 parse "mm" = pure Millimeters
33983402 parse "nmi" = pure NauticalMiles
3399− parse u = fail ("Unrecognized DistanceUnit: " <> show u)
3403+ parse u = fail ("Unrecognized DistanceUnit: " <> show u)
34003404
34013405instance ToJSON DistanceType where
34023406 toJSON Arc = String "arc"
@@ -3405,21 +3409,21 @@ instance ToJSON DistanceType where
34053409
34063410instance FromJSON DistanceType where
34073411 parseJSON = withText "DistanceType" parse
3408− where parse "arc" = pure Arc
3412+ where parse "arc" = pure Arc
34093413 parse "sloppy_arc" = pure SloppyArc
3410− parse "plane" = pure Plane
3411− parse t = fail ("Unrecognized DistanceType: " <> show t)
3414+ parse "plane" = pure Plane
3415+ parse t = fail ("Unrecognized DistanceType: " <> show t)
34123416
34133417
34143418instance ToJSON OptimizeBbox where
3415− toJSON NoOptimizeBbox = String "none"
3419+ toJSON NoOptimizeBbox = String "none"
34163420 toJSON (OptimizeGeoFilterType gft) = toJSON gft
34173421
34183422instance FromJSON OptimizeBbox where
34193423 parseJSON v = withText "NoOptimizeBbox" parseNoOptimize v
34203424 <|> parseOptimize v
34213425 where parseNoOptimize "none" = pure NoOptimizeBbox
3422− parseNoOptimize _ = mzero
3426+ parseNoOptimize _ = mzero
34233427 parseOptimize = fmap OptimizeGeoFilterType . parseJSON
34243428
34253429instance ToJSON GeoBoundingBoxConstraint where
@@ -4202,7 +4206,7 @@ instance SnapshotRepo FsSnapshotRepo where
42024206
42034207parseRepo :: Parser a -> Either SnapshotRepoConversionError a
42044208parseRepo parser = case parseEither (const parser) () of
4205− Left e -> Left (OtherRepoConversionError (T.pack e))
4209+ Left e -> Left (OtherRepoConversionError (T.pack e))
42064210 Right a -> Right a
42074211
42084212
@@ -4683,7 +4687,7 @@ instance FromJSON NodeProcessStats where
46834687 <*> o .: "open_file_descriptors"
46844688 <*> o .: "max_file_descriptors"
46854689 <*> cpu .: "percent"
4686− <*> (unMS <$> cpu .: "total_in_millis")
4690+ <*> (unMS <$> cpu .: "total_in_millis")
46874691 <*> mem .: "total_virtual_in_bytes"
46884692
46894693instance FromJSON NodeOSStats where
@@ -4720,7 +4724,7 @@ instance FromJSON NodeIndicesStats where
47204724 where
47214725 parse o = do
47224726 let (.::) mv k = case mv of
4723− Just v -> Just <$> v .: k
4727+ Just v -> Just <$> v .: k
47244728 Nothing -> pure Nothing
47254729 mRecovery <- o .:? "recovery"
47264730 mQueryCache <- o .:? "query_cache"
@@ -4965,8 +4969,8 @@ parseStringInterval s = case span isNumber s of
49654969 ("", _) -> fail "Invalid interval"
49664970 (nS, unitS) -> case (readMay nS, readMay unitS) of
49674971 (Just n, Just unit) -> return (fromInteger (n * unitNDT unit))
4968− (Nothing, _) -> fail "Invalid interval number"
4969− (_, Nothing) -> fail "Invalid interval unit"
4972+ (Nothing, _) -> fail "Invalid interval number"
4973+ (_, Nothing) -> fail "Invalid interval unit"
49704974 where
49714975 unitNDT Seconds = 1
49724976 unitNDT Minutes = 60
@@ -4985,8 +4989,8 @@ instance FromJSON ThreadPoolSize where
49854989 parseAsString = withText "ThreadPoolSize" $ \t ->
49864990 case first (readMay . T.unpack) (T.span isNumber t) of
49874991 (Just n, "k") -> return (ThreadPoolBounded (n * 1000))
4988− (Just n, "") -> return (ThreadPoolBounded n)
4989− _ -> fail ("Invalid thread pool size " <> T.unpack t)
4992+ (Just n, "") -> return (ThreadPoolBounded n)
4993+ _ -> fail ("Invalid thread pool size " <> T.unpack t)
49904994
49914995instance FromJSON ThreadPoolType where
49924996 parseJSON = withText "ThreadPoolType" parse
@@ -5001,10 +5005,10 @@ instance FromJSON NodeTransportInfo where
50015005 where
50025006 parse o = NodeTransportInfo <$> (maybe (return mempty) parseProfiles =<< o .:? "profiles")
50035007 <*> parseJSON (Object o)
5004− parseProfiles (Object o) | HM.null o = return []
5008+ parseProfiles (Object o) | HM.null o = return []
50055009 parseProfiles v@(Array _) = parseJSON v
5006− parseProfiles Null = return []
5007− parseProfiles _ = fail "Could not parse profiles"
5010+ parseProfiles Null = return []
5011+ parseProfiles _ = fail "Could not parse profiles"
50085012
50095013instance FromJSON NodeNetworkInfo where
50105014 parseJSON = withObject "NodeNetworkInfo" parse
@@ -5025,4 +5029,4 @@ newtype MaybeNA a = MaybeNA { unMaybeNA :: Maybe a }
50255029
50265030instance FromJSON a => FromJSON (MaybeNA a) where
50275031 parseJSON (String "NA") = pure $ MaybeNA Nothing
5028− parseJSON o = MaybeNA . Just <$> parseJSON o
5032+ parseJSON o = MaybeNA . Just <$> parseJSON o