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
then enters a loop to process queries on the parsed data.
-}
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
-- | Get the JSON filename to read from the command line arguments.
filenames <- getFilenames
-- | Read the raw data in from the files.
rawTexts <- mapM readFile filenames
-- | Parse the raw text into structured JSON representations and handle errors.
inputJSONs <- mapM (abortOnError . stringToJSON) rawTexts -- List of parsed JSON values.
-- | Keep asking for queries and applying them until the user decides to stop
processqueries inputJSONs
{-| Function to repeatedly ask for queries and process them.
It processes each query on the parsed 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
-- | Print the output
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."
-- | Function to get a query expression from the user.
-- 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 strValue = read value :: String
in Just $ getElements `pipe` select (binaryOp equal (getField field) (string strValue))
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 strValue = read value :: String
in Just $ getElements `pipe` select (binaryOp containsSubstring (getField field) (string strValue))
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
if null args then askForFiles else checkFilesExist args
-- | 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.
checkFilesExist :: [String] -> IO [String]
checkFilesExist filenames = do
fileExistsList <- mapM doesFileExist filenames
let invalidFiles = [f | (f, False) <- zip filenames fileExistsList]
if null invalidFiles
then return filenames
else do
putStrLn $ "Error: The following files do not exist: " ++ unwords invalidFiles
askForFiles
-- | Function to repeatedly ask the user for valid filenames.
-- If invalid files are entered, it will prompt the user to try again.
askForFiles :: IO [String]
askForFiles = do
putStrLn "Please enter the filenames (separate with spaces):"
filenames <- words <$> getLine
checkFilesExist filenames