module Components.Parsers.ServerSchemaJsonParser (fetchArguments) where
import Control.Exception (throw)
import Text.JSON (
JSValue(JSObject),
JSObject,
Result(Ok),
valFromObj,
decode
)
import Model.ServerExceptions (
SchemaException(
ReadSchemaFileException,
SchemaDuplicateServerObjectException,
SchemaDuplicateInterfaceException,
ReadJsonObjectsException,
ReadServerNameStringException,
ReadScalarFieldException,
ReadDatabaseTableException,
ReadJsonStringException,
ReadPseudonymsException,
ReadInterfaceInstancesException,
ReadDatabaseIdsException,
ReadJsonStringListException,
ReadDatabaseRelationshipsException,
ScalarFieldDataTypeException,
ReadDatabaseRelationshipsCardinalityException,
PrimaryObjectNotFoundException,
SchemaDuplicateException,
InterfaceScalarTypesException
)
)
import Components.Util (snd3,fst3,fst4)
fetchArguments :: FilePath -> IO ([(String,[String])],[(String,[(String,String,[(String,[(String,String,String,String)])])])],[(String,[(String,[String])])],[(String,[String],String)],[(String,String,[String])],[(String,[String],[String])])
fetchArguments fp = do
schema <- Prelude.readFile fp
return $ parseSchema schema
parseSchema :: String -> ([(String,[String])],[(String,[(String,String,[(String,[(String,String,String,String)])])])],[(String,[(String,[String])])],[(String,[String],String)],[(String,String,[String])],[(String,[String],[String])])
parseSchema str = parseHelper $ checkJSValueListValue (decode str :: Result (JSObject JSValue))
checkJSValueListValue :: Result (JSObject JSValue) -> (JSObject JSValue)
checkJSValueListValue (Ok a) = a
checkJSValueListValue _ = throw ReadSchemaFileException
parseHelper :: JSObject JSValue -> ([(String,[String])],[(String,[(String,String,[(String,[(String,String,String,String)])])])],[(String,[(String,[String])])],[(String,[String],String)],[(String,String,[String])],[(String,[String],[String])])
parseHelper json
| (isValidParentScalars soa sss)==False = throw InterfaceScalarTypesException
| (isWithoutDups svrobjs sss sos sor soa)==False = throw SchemaDuplicateException
| otherwise = (svrobjs,sss,sos,sdbn,sor,soa)
where
(svrobjs,sss,sos,sdbn,sor) = parsePrimitivesIterator [] [] [] [] [] $ getObjects (valFromObj "PrimaryObjects" json :: Result [JSObject JSValue])
soa = parseParentsIterator [] $ getObjects (valFromObj "Interfaces" json :: Result [JSObject JSValue])
parsePrimitivesIterator :: [(String,[String])] -> [(String,[(String,String,[(String,[(String,String,String,String)])])])] -> [(String,[(String,[String])])] -> [(String,[String],String)] -> [(String,String,[String])] -> [JSObject JSValue] -> ([(String,[String])],[(String,[(String,String,[(String,[(String,String,String,String)])])])],[(String,[(String,[String])])],[(String,[String],String)],[(String,String,[String])])
parsePrimitivesIterator svrobjs sss sos sdbn sor [] = (svrobjs,sss,sos,sdbn,sor)
parsePrimitivesIterator svrobjs sss sos sdbn sor (obj:t) = if any ((==) name . fst3) sdbn then throw SchemaDuplicateServerObjectException else parsePrimitivesIterator ((name,pseudonyms):svrobjs) ((name,scalars):sss) ((name,nestedobjects):sos) ((name,uids,table):sdbn) (sor++(processRelationships relationships)) t
where
name = getString (valFromObj "ServerName" obj :: Result String) 0
pseudonyms = getStringList (valFromObj "Pseudonyms" obj :: Result [String]) 0
scalars = getScalars $ getObjects (valFromObj "ScalarFields" obj :: Result [JSObject JSValue])
nestedobjects = getObjectFields $ getObjects (valFromObj "ObjectFields" obj :: Result [JSObject JSValue])
uids = getStringList (valFromObj "UniqueIds" obj :: Result [String]) 2
table = getString (valFromObj "DatabaseTable" obj :: Result String) 2
relationships = getListStringList (valFromObj "DatabaseRelationships" obj :: Result [[String]])
parseParentsIterator :: [(String,[String],[String])] -> [JSObject JSValue] -> [(String,[String],[String])]
parseParentsIterator soa (obj:t) = if any ((==) name . fst3) soa then throw SchemaDuplicateInterfaceException else parseParentsIterator ((name,pseudonyms,children):soa) t
where
name = getString (valFromObj "ServerName" obj :: Result String) 0
pseudonyms = getStringList (valFromObj "Pseudonyms" obj :: Result [String]) 0
children = getStringList (valFromObj "ServerChildren" obj :: Result [String]) 1
parseParentsIterator soa [] = soa
getObjects :: Result [JSObject JSValue] -> [JSObject JSValue]
getObjects (Ok objects) = objects
getObjects _ = throw ReadJsonObjectsException
getString :: Result String -> Int -> String
getString (Ok str) _ = str
getString _ 0 = throw ReadServerNameStringException
getString _ 1 = throw ReadScalarFieldException
getString _ 2 = throw ReadDatabaseTableException
getString _ _ = throw ReadJsonStringException
getStringList :: Result [String] -> Int -> [String]
getStringList (Ok rlt) _ = rlt
getStringList _ 0 = throw ReadPseudonymsException
getStringList _ 1 = throw ReadInterfaceInstancesException
getStringList _ 2 = throw ReadDatabaseIdsException
getStringList _ _ = throw ReadJsonStringListException
getListStringList :: Result [[String]] -> [[String]]
getListStringList (Ok rlt) = rlt
getListStringList _ = throw ReadDatabaseRelationshipsException
checkScalars :: Result [JSObject JSValue] -> [(String,String,[(String,[(String,String,String,String)])])]
checkScalars = getScalars . getObjects
getScalars :: [JSObject JSValue] -> [(String,String,[(String,[(String,String,String,String)])])]
getScalars [] = []
getScalars (obj:t) = (getString (valFromObj "Name" obj :: Result String) 1,getType (valFromObj "Type" obj :: Result String),getScalarArguments $ getObjects (valFromObj "Arguments" obj :: Result [JSObject JSValue])):getScalars t
getScalarArguments :: [JSObject JSValue] -> [(String,[(String,String,String,String)])]
getScalarArguments [] = []
getScalarArguments (h:t) = (name,options):getScalarArguments t
where
name = getString (valFromObj "Name" h :: Result String) 1
options = getScalarArgumentOptions (getObjects (valFromObj "Options" h :: Result [JSObject JSValue]))
getScalarArgumentOptions :: [JSObject JSValue] -> [(String,String,String,String)]
getScalarArgumentOptions (h:t) = (name,typ,prefix,suffix):getScalarArgumentOptions t
where
name = getString (valFromObj "Name" h :: Result String) 1
typ = getType (valFromObj "Type" h :: Result String)
prefix = getString (valFromObj "Prefix" h :: Result String) 1
suffix = getString (valFromObj "Suffix" h :: Result String) 1
getScalarArgumentOptions [] = []
getObjectFields :: [JSObject JSValue] -> [(String,[String])]
getObjectFields (h:t) = (obj, names):getObjectFields t
where
obj = getString (valFromObj "ServerName" h :: Result String) 0
names = getStringList (valFromObj "Names" h :: Result [String]) 0
getObjectFields [] = []
getType :: Result String -> String
getType (Ok "Text") = "Text"
getType (Ok "Double") = "Double"
getType (Ok "Int64") = "Int64"
getType (Ok "Boolean") = "Boolean"
getType _ = throw ScalarFieldDataTypeException
processRelationships :: [[String]] -> [(String,String,[String])]
processRelationships = map (\x->(getFirst x,getThird x, x))
getFirst :: [String] -> String
getFirst (h:t) = h
getFirst _ = throw ReadDatabaseRelationshipsCardinalityException
getThird :: [String] -> String
getThird (h1:h2:h3:t) = h3
getThird _ = throw ReadDatabaseRelationshipsCardinalityException
isWithoutDups :: [(String,[String])] -> [(String,[(String,String,[(String,[(String,String,String,String)])])])] -> [(String,[(String,[String])])] -> [(String,String,[String])] -> [(String,[String],[String])] -> Bool
isWithoutDups sobjs sss sos sor soa = (isNoDupsNames $ concat $ (++) (map snd sobjs) $ map snd3 soa)&&(isNoDupsScalars sss)&&(isNoDupsNestedObjects sos)&&(isNoDupsRelationships sor)
isNoDupsNames :: [String] -> Bool
isNoDupsNames (nm:rst) = (elem nm rst==False)&&isNoDupsNames rst
isNoDupsNames [] = True
isNoDupsScalars :: [(String,[(String,String,[(String,[(String,String,String,String)])])])] -> Bool
isNoDupsScalars = all (isNoDupsScalarNames . snd)
isNoDupsScalarNames :: [(String,String,[(String,[(String,String,String,String)])])] -> Bool
isNoDupsScalarNames ((name,_,args):rst) = (all ((/=) name . fst3) rst)&&(isNoDupsScalarArguments args)&&isNoDupsScalarNames rst
isNoDupsScalarNames [] = True
isNoDupsScalarArguments :: [(String,[(String,String,String,String)])] -> Bool
isNoDupsScalarArguments ((name,opts):rst) = (all (\(n,o)->n/=name&&isNoDupsArgumentOptions o) rst)&&isNoDupsScalarArguments rst
isNoDupsScalarArguments [] = True
isNoDupsArgumentOptions :: [(String,String,String,String)] -> Bool
isNoDupsArgumentOptions ((name,_,_,_):rst) = (all ((/=) name . fst4) rst)&&isNoDupsArgumentOptions rst
isNoDupsArgumentOptions [] = True
isNoDupsNestedObjects :: [(String,[(String,[String])])] -> Bool
isNoDupsNestedObjects ((_,[]):rst) = isNoDupsNestedObjects rst
isNoDupsNestedObjects ((obj,(no,nms):objs):rst) = noDupObj&&noDupNms&&isNoDupsNestedObjects ((obj,objs):rst)
where
noDupObj = all ((/=) no . fst) objs
noDupNms = isNoDupsNames nms
isNoDupsNestedObjects [] = True
isNoDupsRelationships :: [(String,String,[String])] -> Bool
isNoDupsRelationships ((from,to,_):rst) = (all (\(a,b,_)->from/=a||to/=b) rst)&&isNoDupsRelationships rst
isNoDupsRelationships [] = True
isValidParentScalars :: [(String,[String],[String])] -> [(String,[(String,String,[(String,[(String,String,String,String)])])])] -> Bool
isValidParentScalars ((_,_,(h:nxt:cld)):t) sss = (isValidScalarsType (getPrimitiveScalars h sss) (nxt:cld) sss)&&isValidParentScalars t sss
isValidParentScalars ((_,_,_:[]):t) sss = isValidParentScalars t sss
isValidParentScalars ((_,_,[]):t) sss = isValidParentScalars t sss
isValidParentScalars [] _ = True
getPrimitiveScalars :: String -> [(String,[(String,String,[(String,[(String,String,String,String)])])])] -> [(String,String)]
getPrimitiveScalars name ((nm,st):t) = if name==nm then map (\(n,tp,_)->(n,tp)) st else getPrimitiveScalars name t
getPrimitiveScalars _ [] = throw PrimaryObjectNotFoundException
isValidScalarsType :: [(String,String)] -> [String] -> [(String,[(String,String,[(String,[(String,String,String,String)])])])] -> Bool
isValidScalarsType ((name,typ):t) cld sss = all (\chld->all (\(n,tp)->(n==name&&tp==typ)||n/=name) $ getPrimitiveScalars chld sss) cld
isValidScalarsType [] _ _ = True