Newer
Older
import JSON
import JSONInput
import JSONOutput
import JSONTransformer
import Result
{-| Main function that It gets filenames from the command line, reads and parses the JSON data and
filenames <- getFilenames
-- | Read the raw data in from the files.
rawTexts <- mapM readFile filenames
-- | Parse the raw text and handle errors.
inputJSONs <- mapM (abortOnError . stringToJSON) rawTexts
-- | Keep asking for queries and applying them until users types anything but y.
processqueries inputJSONs
{-| Function to repeatedly ask for queries and process them.
It processes each query on the data and either prints the results
or prompts the user to enter a new query if no results are found.
-}
processqueries :: [JSON] -> IO ()
processqueries inputJSONs = do
query <- getQuery
-- Run the query and collect the output.
let outputJSONs = concatMap query inputJSONs
if null outputJSONs
then do
putStrLn "No results found."
-- Ask the user for another query
processqueries inputJSONs
else do
mapM_ (putStrLn . renderJSON) outputJSONs
putStrLn "Do you want to enter another query (y/n)"
continue <- getLine
if continue == "y" || continue == "Y"
then processqueries inputJSONs
else putStrLn "Exiting Program."
-- It loops until a valid query is entered by the user.
getQuery :: IO Transformer
getQuery = do
getValidQuery
-- | Helper function to repeatedly prompt the user until a valid query is entered.
getValidQuery :: IO Transformer
getValidQuery = do
putStrLn "Enter the query expression for example (Height > 1000 or Country = S)"
queryStr <- getLine
let query = parseQuery queryStr
case query of
Nothing -> do
putStrLn "Invalid query format. Please use 'field operator value' for example (Height > 1000)"
getValidQuery
Just transformer -> return transformer
-- | Function to manually parse query expressions into a transformer.
-- Supports operators like '=', '>', '<', '>=', '<=','sub'.
parseQuery :: String -> Maybe Transformer
parseQuery queryStr =
case words queryStr of
[field, "=", value] ->
-- | Check if the value is a quoted string.
if isQuoted value then
let stringv = read value :: String
in Just $ getElements `pipe` select (binaryOp equal (getField field) (string stringv))
else
case reads value of
[(v, "")] -> Just $ getElements `pipe` select (binaryOp equal (getField field) (integer v))
_ -> Nothing
[field, ">", value] ->
case reads value of
[(v, "")] -> Just $ getElements `pipe` select (binaryOp greaterThan (getField field) (integer v))
_ -> Nothing
[field, "<", value] ->
case reads value of
[(v, "")] -> Just $ getElements `pipe` select (binaryOp lessThan (getField field) (integer v))
_ -> Nothing
[field, ">=", value] ->
case reads value of
[(v, "")] -> Just $ getElements `pipe` select (binaryOp greaterEqual (getField field) (integer v))
_ -> Nothing
[field, "<=", value] ->
case reads value of
[(v, "")] -> Just $ getElements `pipe` select (binaryOp lessEqual (getField field) (integer v))
_ -> Nothing
[field, "sub", value] ->
if isQuoted value then
let stringv = read value :: String
in Just $ getElements `pipe` select (binaryOp containsSubstring (getField field) (string stringv))
else
case reads value of
[(v, "")] -> Just $ getElements `pipe` select (binaryOp equal (getField field) (integer v))
_ -> Nothing
_ -> Nothing
-- | Helper function to check if a string is quoted
isQuoted :: String -> Bool
isQuoted ('"':xs) | last xs == '"' = True
isQuoted _ = False
-- | Function to safely get the filenames, with error handling.
-- It checks whether the files exist and prompts the user if any files are invalid.
getFilenames :: IO [String]
getFilenames = do
args <- getArgs
-- | Function to check if the given list of files exists.
-- If any files do not exist it prints an error and asks for filenames again.
-- zip puts two seperate lists into one this list has a filename and true or false if doesnt exists
checkFilesExist :: [String] -> IO [String]
checkFilesExist filenames = do
list <- mapM doesFileExist filenames
let invalidFiles = [f | (f, False) <- zip filenames list]
if null invalidFiles
then return filenames
else do
putStrLn $ "Error: The following files do not exist: " ++ unwords invalidFiles
-- | Function to repeatedly ask the user for valid filenames.
-- If invalid files are entered, it will prompt the user to try again.
-- words allow me to get the filename for each space
askfiles :: IO [String]
askfiles = do
putStrLn "Please enter the filenames (separate with spaces):"
filenames <- words <$> getLine
checkFilesExist filenames