22
33module Main where
44
5- import Control.Monad (forM_ , forever )
5+ import Control.Monad (forever )
66import Data.Aeson (Value (.. ), encode , object )
77import qualified Data.ByteString.Lazy.Char8 as BL
8- import qualified Data.List as L
9- import Data.Maybe (mapMaybe )
8+ import Data.Either (isRight , lefts )
9+ import Data.Maybe (fromJust , mapMaybe )
10+ import qualified Data.Scientific as S
1011import Data.Text (Text )
1112import qualified Data.Text as T
1213import qualified Data.Text.Read as T
1314import qualified Data.UUID as UUID
14- import qualified Data.UUID.V4 as UUID4
1515import qualified Data.UUID.V1 as UUID1
16- import Lib
16+ import qualified Data.UUID.V4 as UUID4
17+ import Expr (Expr (.. ), parseExpr )
1718import System.Environment (getArgs )
19+ import System.Random (getStdGen , randomR , setStdGen )
1820
21+ -- $setup
22+ -- >>> :set -XOverloadedStrings
1923
2024parseColumnDefinition :: String -> Maybe (Text , Text )
21- parseColumnDefinition x =
25+ parseColumnDefinition x =
2226 case parts of
23- [x, y] -> Just (x, y )
24- _ -> Nothing
27+ [columnName, providerName] -> Just (columnName, providerName )
28+ _ -> Nothing
2529 where
2630 text = T. pack x
2731 parts = T. splitOn " =" text
@@ -35,22 +39,63 @@ uuid1 = do
3539 Nothing -> uuid1
3640
3741
38- lookupProvider :: Text -> IO Value
39- lookupProvider " uuid4" = String . UUID. toText <$> UUID4. nextRandom
40- lookupProvider " uuid1" = String . UUID. toText <$> uuid1
41- lookupProvider _ = pure $ String " foobar"
42+ -- | Try to extract an Int from Value
43+ --
44+ -- >>> asInt (Number 10)
45+ -- 10
46+ --
47+ -- >>> asInt (String "10")
48+ -- 10
49+ --
50+ -- >>> asInt (String "foo")
51+ -- *** Exception: Expected an integer, but received: foo
52+ -- ...
53+ asInt :: Value -> Int
54+ asInt (Number n) = fromJust $ S. toBoundedInteger n
55+ asInt (String s) =
56+ case T. decimal s of
57+ (Right (n, _)) -> n
58+ (Left _) -> error $ " Expected an integer, but received: " <> T. unpack s
59+ asInt o = error $ " Expected an integer but received: " <> show o
60+
61+
62+ -- | Create a value getter for an expression
63+ --
64+ -- >>> eval $ FunctionCall "randomInt" [IntLiteral 1, IntLiteral 1]
65+ -- Number 1.0
66+ eval :: Expr -> IO Value
67+ eval (IntLiteral x) = pure $ Number $ fromInteger x
68+ eval (StringLiteral x) = pure $ String x
69+ eval (FunctionCall " uuid4" [] ) = String . UUID. toText <$> UUID4. nextRandom
70+ eval (FunctionCall " uuid1" [] ) = String . UUID. toText <$> uuid1
71+ eval (FunctionCall " randomInt" [lower, upper]) = do
72+ lower' <- asInt <$> eval lower
73+ upper' <- asInt <$> eval upper
74+ stdGen <- getStdGen
75+ let
76+ (rndNumber, newStdGen) = randomR (lower', upper') stdGen
77+ setStdGen newStdGen
78+ pure $ Number $ fromIntegral rndNumber
79+ eval (FunctionCall name _) = pure $ String $ " No random generator for " <> name
4280
4381
4482main :: IO ()
4583main = do
4684 args <- getArgs
4785 let
4886 columns = mapMaybe parseColumnDefinition args
49- providers = fmap (\ (x, y) -> (x, lookupProvider y)) columns
50- forever $ do
51- obj <- encode . object <$> mapM runProvider providers
52- BL. putStrLn obj
87+ allExpressions = fmap (\ (x, y) -> (x, parseExpr y)) columns
88+ expressions = fmap unpackRight (filter (isRight . snd ) allExpressions)
89+ errored = lefts $ fmap snd allExpressions
90+ providers = fmap (\ (x, y) -> (x, eval y)) expressions
91+ if null errored
92+ then forever $ do
93+ obj <- encode . object <$> mapM runProvider providers
94+ BL. putStrLn obj
95+ else mapM_ print errored
5396 where
97+ unpackRight (x, Right y) = (x, y)
98+ unpackRight _ = error " Tuple must only contain Right eithers"
5499 runProvider (column, provider) = do
55100 val <- provider
56101 pure (column, val)
0 commit comments